百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术资源 > 正文

面试官:如何实现多级缓存?

off999 2025-03-04 13:32 39 浏览 0 评论

对于高并发系统来说,有三个重要的机制来保障其高效运行,它们分别是:缓存、限流和熔断。而缓存是排在最前面也是高并发系统之所以高效运行的关键手段,那么问题来了:缓存只使用 Redis 就够了吗?

1.冗余设计理念

当然不是,不要把所有鸡蛋放到一个篮子里,成熟的系统在关键功能实现时一定会考虑冗余设计,注意这里的冗余设计不是贬义词。

冗余设计是在系统或设备完成任务起关键作用的地方,增加一套以上完成相同功能的功能通道(or 系统)、工作元件或部件,以保证当该部分出现故障时,系统或设备仍能正常工作,以减少系统或者设备的故障概率,提高系统可靠性。

例如,飞机的设计,飞机正常运行只需要两个发动机,但在每台飞机的设计中可能至少会设计四个发动机,这就有冗余设计的典型使用场景,这样设计的目的是为了保证极端情况下,如果有一个或两个发动机出现故障,不会因为某个发动机的故障而引起重大的安全事故。

2.多级缓存概述

缓存功能的设计也是一样,我们在高并发系统中通常会使用多级缓存来保证其高效运行,其中的多级缓存就包含以下这些:

  1. 浏览器缓存:它的实现主要依靠 HTTP 协议中的缓存机制,当浏览器第一次请求一个资源时,服务器会将该资源的相关缓存规则(如 Cache-Control、Expires 等)一同返回给客户端,浏览器会根据这些规则来判断是否需要缓存该资源以及该资源的有效期。
  2. Nginx 缓存:在 Nginx 中配置中开启缓存功能。
  3. 分布式缓存:所有系统调用的中间件都是分布式缓存,如 Redis、MemCached 等。
  4. 本地缓存:JVM 层面,单系统运行期间在内存中产生的缓存,例如 Caffeine、Google Guava 等。

以下是它们的具体使用。

2.1 开启浏览器缓存

在 Java Web应用中,实现浏览器缓存可以使用 HttpServletResponse 对象来设置与缓存相关的响应头,以开启浏览器的缓存功能,它的具体实现分为以下几步。

① 配置 Cache-Control

Cache-Control 是 HTTP/1.1 中用于控制缓存策略的主要方式。它可以设置多个指令,如 max-age(定义资源的最大存活时间,单位秒)、no-cache(要求重新验证)、public(指示可以被任何缓存区缓存)、private(只能被单个用户私有缓存存储)等,设置如下:

response.setHeader("Cache-Control", "max-age=3600, public"); // 缓存一小时

② 配置 Expires

设置一个绝对的过期时间,超过这个时间点后浏览器将不再使用缓存的内容而向服务器请求新的资源,设置如下:

response.setDateHeader("Expires", System.currentTimeMillis() + 3600 * 1000); // 缓存一小时

③ 配置 ETag

ETag(实体标签)一种验证机制,它为每个版本的资源生成一个唯一标识符。当客户端发起请求时,会携带上先前接收到的 ETag,服务器根据 ETag 判断资源是否已更新,若未更新则返回 304 Not Modified 状态码,通知浏览器继续使用本地缓存,设置如下:

String etag = generateETagForContent(); // 根据内容生成ETag
response.setHeader("ETag", etag);

④ 配置 Last-Modified

指定资源最后修改的时间戳,浏览器下次请求时会带上 If-Modified-Since 头,服务器对比时间戳决定是否返回新内容或发送 304 状态码,设置如下:

long lastModifiedDate = getLastModifiedDate();
response.setDateHeader("Last-Modified", lastModifiedDate);

整体配置

在 Spring Web 框架中,可以通过 HttpServletResponse 对象来设置这些头信息。例如,在过滤器中设置响应头以启用缓存:

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
       throws IOException, ServletException {
   HttpServletResponse httpResponse = (HttpServletResponse) response;
   // 设置缓存策略
   httpResponse.setHeader("Cache-Control", "max-age=3600");

   // 其他响应头设置...
   chain.doFilter(request, response);
}

以上就是在 Java Web 应用程序中利用 HTTP 协议特性控制浏览器缓存的基本方法。

2.2 开启 Nginx 缓存

Nginx 中开启缓存的配置总共有以下 5 步。

① 定义缓存配置

在 Nginx 配置中定义一个缓存路径和配置,通过 proxy_cache_path 指令完成,例如,以下配置:

proxy_cache_path /path/to/cache levels=1:2 keys_zone=my_cache:10m max_size=10g inactive=60m use_temp_path=off;

其中:

  • /path/to/cache:这是缓存文件的存放路径。
  • levels=1:2:定义缓存目录的层级结构。
  • keys_zone=my_cache:10m:定义一个名为 my_cache 的共享内存区域,大小为 10MB。
  • max_size=10g:设置缓存的最大大小为 10GB。
  • inactive=60m:如果在 60 分钟内没有被访问,缓存将被清理。
  • use_temp_path=off:避免在文件系统中进行不必要的数据拷贝。

② 启用缓存

在 server 或 location 块中,使用 proxy_cache 指令来启用缓存,并指定要使用的 keys zone,例如,以下配置:

server {  
    ...  
    location / {  
        proxy_cache my_cache;  
        ...  
    }  
}

③ 设置缓存有效期

使用 proxy_cache_valid 指令来设置哪些响应码的缓存时间,例如,以下配置:

location / {  
    proxy_cache my_cache;  
    proxy_cache_valid 200 304 12h;  
    proxy_cache_valid any 1m;  
    ...  
}

④ 配置反向代理

确保你已经配置了反向代理,以便 Nginx 可以将请求转发到后端服务器。例如,以下配置:

location / {  
    proxy_pass http://backend_server;  
    ...  
}

⑤ 重新加载配置

保存并关闭 Nginx 配置文件后,使用 nginx -s reload 命令重新加载配置,使更改生效。

2.3 使用分布式缓存

在 Spring Boot 项目中使用注解的方式来操作分布式缓存 Redis 的实现步骤如下。

① 添加依赖

在你的 pom.xml 文件中添加 Spring Boot 的 Redis 依赖,如下所示:

  
      
        org.springframework.boot  
        spring-boot-starter-data-redis  
      

② 配置 Redis 连接信息

在 application.properties 或 application.yml 文件中配置 Redis 的相关信息,如下所示。

# application.properties  
spring.redis.host=localhost  
spring.redis.port=6379

③ 启动缓存

在 Spring Boot 主类或者配置类上添加 @EnableCaching 注解来启用缓存。

import org.springframework.cache.annotation.EnableCaching;  
import org.springframework.boot.SpringApplication;  
import org.springframework.boot.autoconfigure.SpringBootApplication;  
  
@SpringBootApplication  
@EnableCaching  
public class Application {  
  
    public static void main(String[] args) {  
        SpringApplication.run(Application.class, args);  
    }  
  
}

④ 使用缓存

在服务类或方法上使用 @Cacheable,@CacheEvict,@CachePut 等注解来定义缓存行为。

例如,使用 @Cacheable 注解来缓存方法的返回值:

import org.springframework.cache.annotation.Cacheable;  
import org.springframework.stereotype.Service;  
  
@Service  
public class UserService {  
    @Cacheable("users")  
    public User findUserById(Long id) {  
        // 模拟从数据库中查询用户  
        return new User(id, "Alice");  
    }  
}

也可以使用 @CacheEvict 注解来删除缓存:

import org.springframework.cache.annotation.CacheEvict;  
import org.springframework.stereotype.Service;  
  
@Service  
public class UserService {  
    @CacheEvict(value = "users", key = "#id")  
    public void deleteUser(Long id) {  
        // 模拟从数据库中删除用户  
    }  
}

在这个例子中,deleteUser 方法会删除 "users" 缓存中 key 为 id 的缓存项。

可以使用 @CachePut 注解来更新缓存:

import org.springframework.cache.annotation.CachePut;  
import org.springframework.stereotype.Service;  
  
@Service  
public class UserService {  
  
    @CachePut(value = "users", key = "#user.id")  
    public User updateUser(User user) {  
        // 模拟更新数据库中的用户信息  
        return user;  
    }  
  
}

在这个例子中,updateUser 方法会更新 "users" 缓存中 key 为 user.id 的缓存项,缓存的值是方法的返回值。

2.4 使用本地缓存

以 Caffeine 本地缓存的使用为例,它在 Spring Boot 项目中的使用如下。

① 添加依赖


    org.springframework.boot
    spring-boot-starter-cache


    com.github.ben-manes.caffeine
    caffeine

② 配置 Caffeine 缓存

在 application.properties 或 application.yml 文件中配置 Caffeine 缓存的相关参数。例如:

# application.properties
spring.cache.type=caffeine
spring.cache.caffeine.spec=initialCapacity=100,maximumSize=1000,expireAfterWrite=10s

这里 spring.cache.caffeine.spec 是一个 Caffeine 规范字符串,用于设置初始容量、最大容量和写入后过期时间等缓存策略,其中:

  • initialCapacity:初始容器容量。
  • maximumSize:最大容量。
  • expireAfterWrite:写入缓存后 N 长时间后过期。

③ 自定义 Caffeine 配置类(可选步骤)

如果需要更复杂的配置,可以创建一个 Caffeine CacheManager 的配置类:

import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.interceptor.CacheResolver;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class CaffeineCacheConfig extends CachingConfigurerSupport {

    @Bean
    public CacheManager cacheManager() {
        Caffeine caffeine = Caffeine.newBuilder()
                .initialCapacity(100)
                .maximumSize(1000)
                .expireAfterWrite(10, TimeUnit.SECONDS) // 10 秒后过期
                .recordStats(); // 记录缓存统计信息

        return new CaffeineCacheManager("default", caffeine::build);
    }

    @Override
    public CacheResolver cacheResolver() {
        // 自定义缓存解析器(如果需要)
        // ...
        return super.cacheResolver();
    }
}

④ 开启缓存

若要利用 Spring Cache 抽象层,以便通过注解的方式更方便地管理缓存,需要在启动类上添加 @EnableCaching 注解,如下所示:

import org.springframework.cache.annotation.EnableCaching;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
@EnableCaching
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

⑤ 使用注解进行缓存操作

在业务逻辑类中使用 @Cacheable、@CacheEvict 等注解实现数据的缓存读取和更新,和上面分布式缓存的使用相同,具体示例如下:

import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

@Service
public class UserService {

    @Cacheable(value = "users", key = "#id") // 假设我们有一个名为"users"的缓存区域
    public User getUserById(Long id) {
        // 这里是真实的数据库查询或其他耗时操作
        return userRepository.findById(id).orElse(null);
    }

    @CacheEvict(value = "users", key = "#user.id")
    public void updateUser(User user) {
        userRepository.save(user);
    }
}

课后思考

除了以上的缓存之外,还有哪些缓存可以加速程序的执行效率呢?

本文已收录到我的面试小站 https://www.javacn.site,其中包含的内容有:Redis、JVM、并发、并发、MySQL、Spring、Spring MVC、Spring Boot、Spring Cloud、MyBatis、设计模式、消息队列等模块。

相关推荐

安全教育登录入口平台(安全教育登录入口平台官网)

122交通安全教育怎么登录:122交通网的注册方法是首先登录网址http://www.122.cn/,接着打开网页后,点击右上角的“个人登录”;其次进入邮箱注册,然后进入到注册页面,输入相关信息即可完...

大鱼吃小鱼经典版(大鱼吃小鱼经典版(经典版)官方版)

大鱼吃小鱼小鱼吃虾是于谦跟郭麒麟的《我的棒儿呢?》郭德纲说于思洋郭麒麟作诗的相声,最后郭麒麟做了一首,师傅躺在师母身上大鱼吃小鱼小鱼吃虾虾吃水水落石出师傅压师娘师娘压床床压地地动山摇。...

谷歌地球下载高清卫星地图(谷歌地球地图下载器)
  • 谷歌地球下载高清卫星地图(谷歌地球地图下载器)
  • 谷歌地球下载高清卫星地图(谷歌地球地图下载器)
  • 谷歌地球下载高清卫星地图(谷歌地球地图下载器)
  • 谷歌地球下载高清卫星地图(谷歌地球地图下载器)
哪个软件可以免费pdf转ppt(免费的pdf转ppt软件哪个好)
哪个软件可以免费pdf转ppt(免费的pdf转ppt软件哪个好)

要想将ppt免费转换为pdf的话,我们建议大家可以下一个那个wps,如果你是会员的话,可以注册为会员,这样的话,在wps里面的话,就可以免费将ppt呢转换为pdfpdf之后呢,我们就可以直接使用,不需要去直接不需要去另外保存,为什么格式转...

2026-02-04 09:03 off999

电信宽带测速官网入口(电信宽带测速官网入口app)

这个网站看看http://www.swok.cn/pcindex.jsp1.登录中国电信网上营业厅,宽带光纤,贴心服务,宽带测速2.下载第三方软件,如360等。进行在线测速进行宽带测速时,尽...

植物大战僵尸95版手机下载(植物大战僵尸95 版下载)

1可以在应用商店或者游戏平台上下载植物大战僵尸95版手机游戏。2下载教程:打开应用商店或者游戏平台,搜索“植物大战僵尸95版”,找到游戏后点击下载按钮,等待下载完成即可安装并开始游戏。3注意:确...

免费下载ppt成品的网站(ppt成品免费下载的网站有哪些)

1、Chuangkit(chuangkit.com)直达地址:chuangkit.com2、Woodo幻灯片(woodo.cn)直达链接:woodo.cn3、OfficePlus(officeplu...

2025世界杯赛程表(2025世界杯在哪个国家)

2022年卡塔尔世界杯赛程公布,全部比赛在卡塔尔境内8座球场举行,2022年,决赛阶段球队全部确定。揭幕战于当地时间11月20日19时进行,由东道主卡塔尔对阵厄瓜多尔,决赛于当地时间12月18日...

下载搜狐视频电视剧(搜狐电视剧下载安装)

搜狐视频APP下载好的视频想要导出到手机相册里方法如下1、打开手机搜狐视频软件,进入搜狐视频后我们点击右上角的“查找”,找到自已喜欢的视频。2、在“浏览器页面搜索”窗口中,输入要下载的视频的名称,然后...

pubg免费下载入口(pubg下载入口官方正版)
  • pubg免费下载入口(pubg下载入口官方正版)
  • pubg免费下载入口(pubg下载入口官方正版)
  • pubg免费下载入口(pubg下载入口官方正版)
  • pubg免费下载入口(pubg下载入口官方正版)
永久免费听歌网站(丫丫音乐网)

可以到《我爱音乐网》《好听音乐网》《一听音乐网》《YYMP3音乐网》还可以到《九天音乐网》永久免费听歌软件有酷狗音乐和天猫精灵,以前要跳舞经常要下载舞曲,我从QQ上找不到舞曲下载就从酷狗音乐上找,大多...

音乐格式转换mp3软件(音乐格式转换器免费版)

有两种方法:方法一在手机上操作:1、进入手机中的文件管理。2、在其中选择“音乐”,将显示出手机中的全部音乐。3、点击“全选”,选中所有音乐文件。4、点击屏幕右下方的省略号图标,在弹出菜单中选择“...

电子书txt下载(免费的最全的小说阅读器)

1.Z-library里面收录了近千万本电子书籍,需求量大。2.苦瓜书盘没有广告,不需要账号注册,使用起来非常简单,直接搜索预览下载即可。3.鸠摩搜书整体风格简洁清晰,书籍资源丰富。4.亚马逊图书书籍...

最好免费观看高清电影(播放免费的最好看的电影)

在目前的网上选择中,IMDb(互联网电影数据库)被认为是最全的电影网站之一。这个网站提供了各种类型的电影和电视节目的海量信息,包括剧情介绍、演员表、评价、评论等。其还提供了有关电影制作背后的详细信息,...

孤单枪手2简体中文版(孤单枪手2简体中文版官方下载)

要将《孤胆枪手2》游戏的征兵秘籍切换为中文,您可以按照以下步骤进行操作:首先,打开游戏设置选项,通常可以在游戏主菜单或游戏内部找到。然后,寻找语言选项或界面选项,点击进入。在语言选项中,选择中文作为游...

取消回复欢迎 发表评论: