深圳做公司英文网站多少钱,网页制作学什么东西,多种网站建设,网站怎么做直播功能吗#x1f3f7;️个人主页#xff1a;牵着猫散步的鼠鼠 #x1f3f7;️系列专栏#xff1a;Java全栈-专栏 #x1f3f7;️个人学习笔记#xff0c;若有缺误#xff0c;欢迎评论区指正 前些天发现了一个巨牛的人工智能学习网站#xff0c;通俗易懂#xff0c;风趣幽默️个人主页牵着猫散步的鼠鼠 ️系列专栏Java全栈-专栏 ️个人学习笔记若有缺误欢迎评论区指正 前些天发现了一个巨牛的人工智能学习网站通俗易懂风趣幽默忍不住分享一下给大家。点击跳转到网站AI学习网站。 目录
前言
冗余设计理念
多级缓存概述
开启浏览器缓存
① 配置 Cache-Control
② 配置 Expires
③ 配置 ETag
④ 配置 Last-Modified
整体配置
2.2 开启 Nginx 缓存
① 定义缓存配置
② 启用缓存
③ 设置缓存有效期
④ 配置反向代理
⑤ 重新加载配置
2.3 使用分布式缓存
① 添加依赖
② 配置 Redis 连接信息
③ 启动缓存
④ 使用缓存
2.4 使用本地缓存
① 添加依赖
② 配置 Caffeine 缓存
③ 自定义 Caffeine 配置类可选步骤
④ 开启缓存
⑤ 使用注解进行缓存操作 前言
对于高并发系统来说有三个重要的机制来保障其高效运行它们分别是缓存、限流和熔断。而缓存是排在最前面也是高并发系统之所以高效运行的关键手段那么问题来了缓存只使用 Redis 就够了吗
冗余设计理念
当然不是不要把所有鸡蛋放到一个篮子里成熟的系统在关键功能实现时一定会考虑冗余设计注意这里的冗余设计不是贬义词。 冗余设计是在系统或设备完成任务起关键作用的地方增加一套以上完成相同功能的功能通道or 系统、工作元件或部件以保证当该部分出现故障时系统或设备仍能正常工作以减少系统或者设备的故障概率提高系统可靠性。 例如飞机的设计飞机正常运行只需要两个发动机但在每台飞机的设计中可能至少会设计四个发动机这就有冗余设计的典型使用场景这样设计的目的是为了保证极端情况下如果有一个或两个发动机出现故障不会因为某个发动机的故障而引起重大的安全事故。
多级缓存概述
缓存功能的设计也是一样我们在高并发系统中通常会使用多级缓存来保证其高效运行其中的多级缓存就包含以下这些
浏览器缓存它的实现主要依靠 HTTP 协议中的缓存机制当浏览器第一次请求一个资源时服务器会将该资源的相关缓存规则如 Cache-Control、Expires 等一同返回给客户端浏览器会根据这些规则来判断是否需要缓存该资源以及该资源的有效期。Nginx 缓存在 Nginx 中配置中开启缓存功能。分布式缓存所有系统调用的中间件都是分布式缓存如 Redis、MemCached 等。本地缓存JVM 层面单系统运行期间在内存中产生的缓存例如 Caffeine、Google Guava 等。
以下是它们的具体使用。
开启浏览器缓存
在 Java Web应用中实现浏览器缓存可以使用 HttpServletResponse 对象来设置与缓存相关的响应头以开启浏览器的缓存功能它的具体实现分为以下几步。
① 配置 Cache-Control
Cache-Control 是 HTTP/1.1 中用于控制缓存策略的主要方式。它可以设置多个指令如 max-age(定义资源的最大存活时间单位秒)、no-cache要求重新验证、public指示可以被任何缓存区缓存、private只能被单个用户私有缓存存储等设置如下
response.setHeader(Cache-Control, max-age3600, 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-age3600);// 其他响应头设置...chain.doFilter(request, response);
}以上就是在 Java Web 应用程序中利用 HTTP 协议特性控制浏览器缓存的基本方法。
开启 Nginx 缓存
Nginx 中开启缓存的配置总共有以下 5 步。
① 定义缓存配置
在 Nginx 配置中定义一个缓存路径和配置通过 proxy_cache_path 指令完成例如以下配置
proxy_cache_path /path/to/cache levels1:2 keys_zonemy_cache:10m max_size10g inactive60m use_temp_pathoff;其中
/path/to/cache这是缓存文件的存放路径。levels1:2定义缓存目录的层级结构。keys_zonemy_cache:10m定义一个名为 my_cache 的共享内存区域大小为 10MB。max_size10g设置缓存的最大大小为 10GB。inactive60m如果在 60 分钟内没有被访问缓存将被清理。use_temp_pathoff避免在文件系统中进行不必要的数据拷贝。
② 启用缓存
在 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 命令重新加载配置使更改生效。
RedisCaffeine实现应用层二级缓存
在SpringBoot中实现多级缓存需要解决两个关键问题缓存数据的读取顺序和数据的一致性。以下是实现多级缓存的步骤
导入依赖
dependenciesdependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-cache/artifactId/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-data-redis/artifactId/dependencydependencygroupIdcom.github.ben-manes.caffeine/groupIdartifactIdcaffeine/artifactId/dependency!-- 其他依赖 --
/dependencies
编写redis相关配置
spring:redis:host: 127.0.0.1port: 6379password:jedis:pool:max-active: 8max-wait: -1max-idle: 500min-idle: 0lettuce:shutdown-timeout: 0
本地缓存配置类
/*** 本地缓存Caffeine配置类*/
Configuration
public class LocalCacheConfiguration {Bean(localCacheManager)public CacheString, Object localCacheManager() {return Caffeine.newBuilder()//写入或者更新5s后缓存过期并失效, 实际项目中肯定不会那么短时间就过期根据具体情况设置即可.expireAfterWrite(5, TimeUnit.SECONDS)// 初始的缓存空间大小.initialCapacity(50)// 缓存的最大条数通过 Window TinyLfu算法控制整个缓存大小.maximumSize(500)//打开数据收集功能.recordStats().build();}}
Redis客户端配置类
Configuration
public class RedisConfig {Beanpublic RedisTemplateString, Object redisTemplate(RedisConnectionFactory factory) {RedisTemplateString, Object template new RedisTemplate();//关联template.setConnectionFactory(factory);//设置key的序列化方式
// template.setKeySerializer();//设置value的序列化方式
// template.setValueSerializer();return template;}
}
编写测试用的服务类接口
public interface UserService {void add(User user);User getById(String id);User update(User user);void deleteById(String id);
}
编写测试用的服务类
这里本地缓存也可以用注解式缓存来实现这里就不细写啦~
import com.alibaba.fastjson.JSON;
import com.github.benmanes.caffeine.cache.Cache;
import com.wsh.springboot_caffeine.entity.User;
import com.wsh.springboot_caffeine.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;import java.util.HashMap;
import java.util.Objects;
import java.util.concurrent.TimeUnit;Service
public class UserServiceImpl implements UserService {/*** 模拟数据库存储数据*/private static HashMapString, User userMap new HashMap();private final RedisTemplateString, Object redisTemplate;private final CacheString, Object caffeineCache;Autowiredpublic UserServiceImpl(RedisTemplateString, Object redisTemplate,Qualifier(localCacheManager) CacheString, Object caffeineCache) {this.redisTemplate redisTemplate;this.caffeineCache caffeineCache;}static {userMap.put(1, new User(1, zhangsan));userMap.put(2, new User(2, lisi));userMap.put(3, new User(3, wangwu));userMap.put(4, new User(4, zhaoliu));}Overridepublic void add(User user) {// 1.保存Caffeine缓存caffeineCache.put(user.getId(), user);// 2.保存redis缓存redisTemplate.opsForValue().set(user.getId(), JSON.toJSONString(user), 20, TimeUnit.SECONDS);// 3.保存数据库(模拟)userMap.put(user.getId(), user);}Overridepublic User getById(String id) {// 1.先从Caffeine缓存中读取Object o caffeineCache.getIfPresent(id);if (Objects.nonNull(o)) {System.out.println(从Caffeine中查询到数据...);return (User) o;}// 2.如果缓存中不存在则从Redis缓存中查找String jsonString (String) redisTemplate.opsForValue().get(id);User user JSON.parseObject(jsonString, User.class);if (Objects.nonNull(user)) {System.out.println(从Redis中查询到数据...);// 保存Caffeine缓存caffeineCache.put(user.getId(), user);return user;}// 3.如果Redis缓存中不存在则从数据库中查询user userMap.get(id);if (Objects.nonNull(user)) {// 保存Caffeine缓存caffeineCache.put(user.getId(), user);// 保存Redis缓存,20s后过期redisTemplate.opsForValue().set(user.getId(), JSON.toJSONString(user), 20, TimeUnit.SECONDS);}System.out.println(从数据库中查询到数据...);return user;}Overridepublic User update(User user) {User oldUser userMap.get(user.getId());oldUser.setName(user.getName());// 1.更新数据库userMap.put(oldUser.getId(), oldUser);// 2.更新Caffeine缓存caffeineCache.put(oldUser.getId(), oldUser);// 3.更新Redis数据库redisTemplate.opsForValue().set(oldUser.getId(), JSON.toJSONString(oldUser), 20, TimeUnit.SECONDS);return oldUser;}Overridepublic void deleteById(String id) {// 1.删除数据库userMap.remove(id);// 2.删除Caffeine缓存caffeineCache.invalidate(id);// 3.删除Redis缓存redisTemplate.delete(id);}}
总结
多级缓存是提升高并发系统性能的关键策略之一。它不仅能够减少系统的响应时间提高用户体验还能有效降低后端系统的负载防止系统过载。在实际应用中开发者应根据系统的具体需求和资源情况灵活设计和调整多级缓存策略以达到最佳的性能表现。大部分情况下我们使用redis作为缓存是可以满足需求的加入本地缓存后虽然带来了部分性能提升但是存在数据一致性的问题一定程度上添加了维护难度。