利用 Ehcache 分布式缓存,轻松打造商业级高并发、高性能API接口

1、前言,我们为什么要用缓存?

①普通API接口或应用,当访问量较小时,可以不考虑缓存。但大型API接口、应用,当QPS达到2000左右时(QPS一般指每秒查询率,即每秒2000次访问),MySQL数据库即开始报警,如果不使用缓存,系统很可能会出现延迟、拒绝、服务器资源占满,最后崩溃宕机。

②缓存无非就是不想频繁去读数据库、不想频繁去调用接口,主要实现两个用途:高性能、高并发。一个商业级API接口,当加入缓存技术,可以轻松实现几万甚至十几万QPS。

③今天,我们就在上一讲利用Spring Data REST+JPA实现RESTFul API接口的基础上,添加Ehcache分布式缓存,打造商业级高并发、高性能API接口。

2、Ehcache分布式缓存简介

①EhCache是一个广泛使用的纯Java进程内缓存框架,在Java开发领域久负盛名,它快速精干、部署简单、效率高门槛低、操作简便,但同时功能较少,可扩展性和集群应用较弱。

②简单来说,Ehcache是一个轻量级缓存容器,在接口方面支持RESTFul和SOAP API。

3、项目基本框架

  • Spring-boot 2.5+

  • JDK 11+或者JDK13+

  • 数据库MySQL 8.0+

  • Ehcache 3+,详细了解可访问https://www.ehcache.org

  • 接口测试工具Postman

4、添加项目依赖

①关于如何利用Spring Data REST+JPA创建RESTFul API接口,可以参考

  • https://blog.csdn.net/m0_59562547/article/details/119203351

②加入Ehcache缓存依赖

<!--ehcache依赖-->
<dependency>
    <groupId>net.sf.ehcache</groupId>
    <artifactId>ehcache</artifactId>
</dependency>
<!--spring cache依赖-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-cache</artifactId>
</dependency>

5、添加缓存配置文件

我们在resources资源目录下面创建ehcache.xml缓存配置文件。

<?xml version="1.0" encoding="UTF-8"?>
<ehcache>
    <!-- 磁盘缓存位置 -->
    <diskStore path="java.io.tmpdir/cache"/>
    <!--默认缓存 600秒强制过期或300秒内无人访问缓存过期-->
    <defaultCache
            maxElementsInMemory="10000"
            eternal="false"
            timeToIdleSeconds="300"
            timeToLiveSeconds="600"
            overflowToDisk="false"
            diskPersistent="false"
            diskExpiryThreadIntervalSeconds="120"
    />

    <!--业务缓存 300秒强制过期或180秒内无人访问缓存过期-->
    <cache name ="book_cache"
           maxElementsInMemory="10000"
           eternal="false"
           timeToIdleSeconds="180"
           timeToLiveSeconds="300"
           overflowToDisk="false"
           diskPersistent="false"
           diskExpiryThreadIntervalSeconds="600"
    />

</ehcache>

这是一个常规的Ehcache配置文件,提供两种缓存策略,一种是默认缓存,一种是book-cache业务缓存,业务缓存可自定义名字。

Ehcache缓存属性说明

利用 Ehcache 分布式缓存,轻松打造商业级高并发、高性能API接口

这里着重讲一下timeToIdleSeconds发呆秒数和timeToLiveSeconds总存活秒数的理解:

  • timeToIdleSeconds表示在多少时间内缓存无访问则过期,如果有访问则不会过期。

  • timeToLiveSeconds表示该缓存总存活的时间,如达到该时间则会过期。

  • timeToLiveSeconds必须大于timeToIdleSeconds才有意义。

6、开启缓存

在项目入口添加上@EnableCaching开启缓存。

package com.example.demohelloworld;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
@SpringBootApplication
//开启缓存
@EnableCaching
public class DemohelloworldApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemohelloworldApplication.classargs);
    }
}

7、为JPA RESTFul接口类BookRepository添加缓存注解实现缓存功能

Ehcache相关注解说明

利用 Ehcache 分布式缓存,轻松打造商业级高并发、高性能API接口

代码如下:

package com.example.demohelloworld.restful;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
import org.springframework.data.rest.core.annotation.RestResource;
import javax.transaction.Transactional;
import java.util.List;
import java.util.Optional;
 
//指明使用缓存的名称,这个配置可选,若不使用@CacheConfig,则直接在@Cacheable中指明即可
@CacheConfig(cacheNames = {"book_cache"})
@RepositoryRestResource(path = "bs",collectionResourceRel = "bs",itemResourceRel = "b")
public interface BookRepository extends JpaRepository<Book,Integer{
    //根据作者名字来查询,对作者名字进行缓存
    @Cacheable(key = "#author")
    @RestResource(path = "author" ,rel="author")
    List<Book> findAllByAuthorContains(@Param("author") String author);
    //根据书名来查询,对书名进行缓存
    @Cacheable(key = "#name")
    @RestResource(path = "name" ,rel="name")
    Book findByNameEquals(@Param("name") String name);
    
    //对排序进行缓存
    @Cacheable(key = "#sort")
    List<Book> findAll(Sort sort);
    //对页码进行缓存
    @Cacheable(key = "#pageable")
    Page<Book> findAll(Pageable pageable);
    //Optional 类是一个可以为null的容器对象,调用get()方法会返回该对象,它可以保存类型T的值,不用显式进行空值检测,对ID进行缓存
    @Cacheable(key = "#id")
    Optional<Book> findById(Integer id);
    //@CachePut一般用户更新方法,每次执行时不检查缓存,直接执行方法,然后将方法结果缓存,如果该KEY已经被缓存起来了,则会覆盖之前的缓存,对实体类进行缓存
    @CachePut(key = "#entity")
    <S extends Book> save(S entity);
    //@CacheEvict一般用于删除方法,表示移除一个KEY对应缓存
    @CacheEvict(key = "#id")
    void deleteById(Integer id);
 
    //新增书Get请求
    //@CacheEvict(beforeInvocation = true)表示在方法执行之前清空缓存,默认false表示在方法执行之后清空缓存
    @CacheEvict(beforeInvocation = true)
    @Transactional
    @Modifying(clearAutomatically = true)//表示数据表和实体缓存同步更新
    @Query(value = "insert into t_book(name,author) values (?1,?2)",nativeQuery = true)
    int addBook(@Param("name") String name,@Param("author") String author);//返回值为添加成功数量
    //@CacheEvict(allEntries = true)表示将所有的缓存全部清空,默认false
    //根据id更新书Get请求
    @CacheEvict(allEntries = true)
    @Transactional
    @Modifying(clearAutomatically = true)//表示数据表和实体缓存同步更新
    @Query(value = "update t_book set name=?1,author=?2 where id=?3",nativeQuery = true)
    int updateBook(@Param("name") String name,@Param("author") String author,@Param("id") Integer id);//返回值为更新成功数量
}

8、启动项目,利用Postman进行测试

我们创建一个GET请求,输入http://localhost:8080/bs/2,点击Send,服务器会返回相应的Book值。

服务器后端会出现Hibernate:的提示,表明我们执行optional<Book> findById(Integer id)方法。

利用 Ehcache 分布式缓存,轻松打造商业级高并发、高性能API接口

当我们在180秒内(缓存保留时间)点击Send再次发送这个GET请求的时候,服务器后端则不会出现任何消息,表明optional<Book> findById(Integer id)方法没有被执行,而是直接从缓存value中取值并返回给前端了。我们的缓存生效了!

利用 Ehcache 分布式缓存,轻松打造商业级高并发、高性能API接口

同理,大家还可以测试一下PUT更新数据请求、DELETE删除数据请求,了解相应方法的执行情况和缓存的使用情况。

①更新数据:不检查缓存,直接执行方法并将最新的执行结果缓存起来。(更新数据+更新缓存)

②删除数据:直接执行方法并移除相对应的缓存,(删除数据+删除对应缓存)。如果有allEntries = true属性,则会清空所有缓存。

9、总结

1、缓存使API接口实现了高性能+高并发。

2、对JPA打造的RESTFul接口来说,仅需@EnableCaching开启缓存,在对应方法加上@Cacheable等注解就可以实现缓存功能了,可以说非常简单方便。

3、除了Ehcache缓存外,Redis等同样可以实现缓存功能,大家可以根据实际需要使用。

后端专属技术群

构建高质量的技术交流社群,欢迎从事编程开发、技术招聘HR进群,也欢迎大家分享自己公司的内推信息,相互帮助,一起进步!

文明发言,以交流技术职位内推行业探讨为主

广告人士勿入,切勿轻信私聊,防止被骗

利用 Ehcache 分布式缓存,轻松打造商业级高并发、高性能API接口
加我好友,拉你进群

原文始发于微信公众号(Java知音):利用 Ehcache 分布式缓存,轻松打造商业级高并发、高性能API接口

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/148928.html

(0)
小半的头像小半

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!