redis相关文章
----redis原理概述
-----redis集群方案
----redis分区(分片)原理
----Redis实现分布式锁
----redis缓存穿透、雪崩和解决方案
redis穿透
- 用户请求透过redis去请求mysql服务器,导致mysql压力过载
- 一个web服务里,极容易出现瓶颈的就是mysql,所以才让redis去分担mysql 的压力,所以这种问题是万万要避免的
- 解决方法
- 从缓存取不到的数据,在数据库中也没有取到,这时也可以将key-value对写为key-null,缓存有效时间可以设置短点,如30秒(设置太长会导致正常情况也没法使用)。这样可以防止攻击用户反复用同一个id暴力攻击
- 代码实现
String get(String key) {
// 从缓存中获取数据
String cacheValue = cache.get(key);
// 缓存为空
if (StringUtils.isBlank(cacheValue)) {
// 从存储中获取
String storageValue = storage.get(key);
cache.set(key, storageValue);
// 如果存储数据为空, 需要设置一个过期时间(300秒)
if (storageValue == null) {
cache.expire(key, 60 * 5);
}
return storageValue;
} else {
// 缓存非空
return cacheValue;
}
}
- 接口层增加校验,如用户授权校验,id做基础校验,id<=0的直接拦截
- 采用布隆过滤器,将所有可能存在的数据哈希到一个足够大的 bitmap 中,一个一定不存在的数据会被这个 bitmap 拦截,从而避免了对底层存储系统的查询压力
- 分级缓存(缓存两份数据,第二份数据生存时间长一点作为备份,第一份数据用于被请求命中,如果第二份数据被命中说明第一份数据已经过期,要去mysql请求数据重新缓存两份数据)
redis雪崩
是redis服务由于负载过大而宕机,导致mysql也负载过大也宕机,最终整个系统瘫痪
- 解决方法
- . redis集群,将原来一个人干的工作,分发给多个人干
- 缓存预热(关闭外网访问,先开启mysql,通过预热脚本将热点数据写入缓存中,启动缓存。开启外网服务)
- 数据不要设置相同的生存时间,不然过期时,redis压力会大
缓存预热
将相关的缓存数据直接加载到缓存系统。这样就可以避免在用户请求的时候,先查询数据库,然后再将数据缓存的问题!用户直接查询事先被预热的缓存数据!
- 方案
- 写个缓存刷新页面,上线时手工操作一下
- 定时刷新缓存
缓存降级
当访问量剧增、服务出现问题(如响应时间慢或不响应)或非核心服务影响到核心流程的性能时,仍然需要保证服务还是可用的,即使是有损服务。系统可以根据一些关键数据进行自动降级,也可以配置开关实现人工降级
- 目的
- 保证核心服务可用,即使是有损的。而且有些服务是无法降级的(如加入购
物车、结算) - 了防止Redis服务故障,导致数据库跟着一起发生雪崩
- 对于不重要的缓存数据,可以采取服务降级策略,例如一个比较常见的做法就是,Redis出现问题,不去数据库查询,而是直接返回默认值给用户
- 保证核心服务可用,即使是有损的。而且有些服务是无法降级的(如加入购
- 进行降级之前要对系统进行梳理,哪些可降级,以参考日志级别设置预案
- 一般:比如有些服务偶尔因为网络抖动或者服务正在上线而超时,可以自动降级
- 警告:有些服务在一段时间内成功率有波动(如在95~100%之间),可以自动降级或人工降级,并发送告警
- 错误:比如可用率低于90%,或者数据库连接池被打爆了,或者访问量突然猛增到系统能承受的最大阀值,此时可以根据情况自动降级或者人工降级
- 严重错误:比如因为特殊原因数据错误了,此时需要紧急人工降级
缓存热点key
缓存中的一个Key(比如一个促销商品),在某个时间点过期的时候,恰好在这个时间点对这个Key有大量的并发请求过来,这些请求发现缓存过期一般都会从后端DB加载数据并回设到缓存,这个时候大并发的请求可能会瞬间把后端DB压垮
- 解决方案
对缓存查询加锁,如果KEY不存在,就加锁,然后查DB入缓存,然后解锁;其他进程如果发现有锁就等待,然后等解锁后返回数据或者进入DB查询
redis相关文章
----redis原理概述
-----redis集群方案
----redis分区(分片)原理
----Redis实现分布式锁
----redis缓存穿透、雪崩和解决方案