缓存穿透优化方案
- 布隆过滤器
- 原理:布隆过滤器可以理解为一个很长的二进制向量和一系列随机映射函数。当一个元素被加入集合时,通过K个散列函数将这个元素映射成一个位数组中的K个点,把它们置为1 。查询时,只要看看这些点是不是都是1就(大约)知道集合中有没有它了:如果这些点有任何一个0,则被查询元素一定不在;如果都是1,则被查询元素很可能存在。
- 技术选型:在Java中可以使用Google Guava库中的BloomFilter来实现布隆过滤器。在Redis中也有一些开源的布隆过滤器实现,如RedisBloom模块。在高并发电商场景中,可将商品ID等关键信息通过布隆过滤器进行预过滤,在查询缓存前先判断ID是否可能存在,避免无效查询穿透到数据库。
- 缓存空值
- 原理:当查询数据库发现数据不存在时,也将这个空值缓存起来,并设置较短的过期时间。下次再查询相同数据时,直接从缓存中获取空值,避免再次查询数据库。
- 技术选型:可以使用Redis作为缓存,通过SET命令将空值缓存起来。例如,
SET key value EX 60
,其中EX 60
表示设置过期时间为60秒。
缓存雪崩优化方案
- 设置随机过期时间
- 原理:避免大量缓存数据在同一时间过期。给每个缓存数据设置一个随机的过期时间,这样可以使缓存过期时间分散,降低同一时刻大量缓存过期的风险。
- 技术选型:在使用Redis缓存时,可以通过
SET key value EX (randomExpirationTime)
来设置随机过期时间。假设正常过期时间范围是60 - 120秒,可以通过代码生成一个在这个范围内的随机数作为过期时间。例如在Java中使用Random
类生成随机数:
Random random = new Random();
int randomExpirationTime = 60 + random.nextInt(60);
jedis.setex(key, randomExpirationTime, value);
- 使用二级缓存
- 原理:主缓存(如Redis)失效时,从二级缓存(如本地缓存Guava Cache)获取数据。二级缓存可以作为一个兜底方案,在主缓存失效时提供一定的数据支持,减少数据库压力。
- 技术选型:主缓存使用Redis,二级缓存使用Guava Cache。在代码中,先尝试从Redis获取数据,如果获取不到,再从Guava Cache获取。如果Guava Cache也没有,则查询数据库,将数据放入Redis和Guava Cache。
// 从Redis获取数据
String valueFromRedis = jedis.get(key);
if (valueFromRedis != null) {
return valueFromRedis;
} else {
// 从Guava Cache获取数据
String valueFromGuava = guavaCache.getIfPresent(key);
if (valueFromGuava != null) {
// 将数据重新放入Redis
jedis.setex(key, expirationTime, valueFromGuava);
return valueFromGuava;
} else {
// 查询数据库
String valueFromDB = getValueFromDB(key);
if (valueFromDB != null) {
// 放入Redis和Guava Cache
jedis.setex(key, expirationTime, valueFromDB);
guavaCache.put(key, valueFromDB);
return valueFromDB;
}
return null;
}
}
- 构建缓存集群
- 原理:通过增加缓存服务器的数量,将缓存数据分布在多个节点上,降低单个节点失效对整体系统的影响。即使某个节点出现问题,其他节点仍能提供缓存服务。
- 技术选型:可以使用Redis Cluster搭建缓存集群。Redis Cluster是Redis的分布式解决方案,它将数据分布在多个节点上,提供高可用性和可扩展性。通过集群的方式,当某个节点出现故障时,集群会自动进行故障转移,其他节点继续提供服务。
CDN与缓存联合优化方案
- CDN缓存预热
- 原理:在流量高峰前,主动将热门商品图片等静态资源推送到CDN节点。这样当用户请求时,CDN可以直接从本地缓存中返回资源,减少源站压力,提高响应速度。
- 技术选型:可以使用CDN提供商提供的API来进行缓存预热。例如阿里云CDN提供了通过OpenAPI发起预热任务的方式,通过调用相应的接口,将热门商品图片的URL列表提交给CDN,CDN会将这些资源提前缓存到各个节点。
- CDN与缓存数据一致性
- 原理:当商品数据或图片发生更新时,需要及时通知CDN和缓存更新。对于商品数据,更新缓存时,同时通知CDN刷新相关的缓存数据(如果CDN也缓存了部分商品数据信息)。对于图片,更新图片源后,通知CDN刷新图片缓存。
- 技术选型:对于缓存,可以使用Redis的发布订阅功能。当商品数据更新时,发布一个更新消息到Redis的某个频道,相关的服务订阅这个频道,接收到消息后更新本地缓存。对于CDN,使用CDN提供商提供的刷新接口,例如腾讯云CDN提供了API用于刷新文件或目录缓存,调用该接口将更新的图片URL或目录提交,CDN会自动刷新相关缓存。
- 基于CDN的负载均衡
- 原理:CDN不仅可以缓存静态资源,还可以根据用户的地理位置等信息,将用户请求分配到距离用户最近的CDN节点。同时,结合应用层的负载均衡(如Nginx),将请求合理分配到后端的缓存服务器和应用服务器,提高系统整体的处理能力。
- 技术选型:CDN提供商(如七牛云、网宿科技等)本身具备智能的负载均衡功能,根据用户的IP地址等信息将请求分配到最优节点。在应用层,可以使用Nginx作为反向代理和负载均衡器,将请求分发到后端的缓存服务器集群和应用服务器集群。例如,在Nginx配置文件中可以通过
upstream
模块定义后端服务器集群,并使用proxy_pass
指令将请求转发到相应的服务器。
upstream cache_servers {
server cache1.example.com:6379;
server cache2.example.com:6379;
}
server {
location / {
proxy_pass http://cache_servers;
}
}