redis详解(三)redis场景与实战
一、场景问题
1.数据丢失场景
持久化数据丢失:
- RDB采用定时备份,有可能丢失间隔区间内的数据
- AOF使用追加,也有可能丢失1s的数据
主从切换:主从切换是异步的,必定会导致数据丢失
脑裂问题:出现多个master,网络恢复时丢失一些master上的数据
2.跟数据库数据一致性问题
缓存一致性问题:mysql数据变更,如何保证redis的数据一致性呢?
常见的答案是延时双删,即先删redis,再该数据库,然后间隔一定时间再删redis
防止修改数据期间从redis读到不一致数据
但是实际上,这个间隔时间如何确定?工作中也基本上没有人用延时双删,因为redis本来就不是一个保证强一致性的数据库,它的优点在于快
所以最常见的方式,就是直接把redis的数据删除即可,下次查询数据库时再放进去就行了
常见数据一致性解决方案:
- 加锁:牺牲性能,不建议使用
- 延时双删:间隔时间不好确定,不建议使用
- 最终一致性方案
- 给缓存设置过期时间,允许一部分时间内的数据不一致
- canal监听,在数据变更后同步修改redis数据
3.缓存穿透、击穿、雪崩
缓存穿透
定义:查询的key,redis里面没有,db里面也没有
解决方案:
- 封禁ip:如果某ip大量请求不存在的key,直接把这个ip干掉
- 布隆过滤器:不存在的一定无法经过布隆过滤器
缓存击穿
定义:某热点key突然失效,全部请求都打到了db
解决方案:加互斥锁,不影响正常访问,但是过期后会加锁,防止大量请求到db
缓存雪崩
定义:大量热点key同时失效
解决方案:
- 保证redis高可用:防止出现redis挂了导致的缓存雪崩
- 设置不同的过期时间
- 加互斥锁:很少这么干
但是实际上,现在mysql也都是集群部署,崩不了
4.慢查询、阻塞和bigkey
慢查询
所谓慢查询,就是很慢的查询-_-#
如何找到?
在默认配置中,超过10ms的查询就是慢查询(不包含网络时间)
会保存在慢查询日志当中,也可以通过监控工具进行监控,报警
如何解决?
拆分数据
阻塞
通常是指Redis服务器无法立即响应客户端请求的情况
可以通过业务日志,监控命令来判断阻塞原因
- 外部原因:网络阻塞,cpu被占用
- 内部原因:
- 指令查询耗时
- 数据结构设置不合理,导致查询过久
- fork子线程在进行aof刷盘
bigKey
指一个key对应的value过大
可以采用拆分,压缩,分片等方式解决
- 拆分:比如hash类型,可以将里面的键值对多拆分拆分,变成小一点的结构
- 压缩:采用一定的压缩算法,将数据规模变小,提高存储效率
- 分片:想办法把数据映射到不同哈希槽上,对key拆分,别都放到一起
二、实战
1.客户端选择
Jedis
- 简单,使用较多
- 非线程安全
- 支持多种模式
Lettuce
- 线程安全
- 支持同步、异步
- 支持读写分离
- 支持多种模式
Redission
- 支持分布式锁
- 支持分布式容器等高级功能
2.实战之授权
存储分布式session
3.实战之用户状态保存
使用bitmap数据结构,记录用户的一些状态,比如是否点过新人引导,是否领过优惠券,使用0/1表示即可,状态不可逆,以用户为粒度进行读写
同时,mysql里面也要有一个bigint的结构与其对应,保证最终一致性
4.实战之流量限制
限流基本概念:
- 对访问频率的限制
- 对连接数的限制
- 对客户端的限制
- 对速率的限制
限流常用算法:
- 时间窗算法:设定一段时间内的请求次数上限来进行限流的
- 漏桶算法:桶大小固定,出桶速度固定,可能会溢出
- 令牌桶算法:能在短时间内处理大量请求
- 桶里最多x个令牌,因此同时最多能支持x个取令牌操作
- 有一个线程检测桶里令牌是否低于x,是的话就定时产生令牌放桶里
- 拿走令牌的线程也可以在任务处理完毕后,在桶里令牌不到x时放回去
在分布式系统中,可以使用令牌桶算法,使用redis搭配搭配网关gateWay,来进行分布式系统限流






