错误收集
对于Redis服务应当加入异常监控系统,以便于监视发现出现的故障,常用的思路是加入日志信息,在捕获异常时监控日志的信息等级,监测超过指定次数就出发报警程序。同样也可以引入外部的检测平台监控
避免阻塞
1. 慢查询引起阻塞
- 原因:慢查询需要花费时间多
- 解决办法:利用
slowlog get{n}
语句可以获得最近执行时间超过10ms的命令,但是线上建议将其设置为1ms,发现毫秒级以上的操作,将引起慢查询的命令禁用或者改用时间复杂度底的命令
2. 大对象引起阻塞
- 原因:大对象使得持久化与复制会耗时很长
- 解决办法:利用命令
redis-cli -h {ip} -p{port} --bigkeys
来找出redis里面含有的大对象,其原理是利用scan
的扫描操作
3. 过度优化引起阻塞
- 原因:比如过度追求内部结构ziplist的低内存消耗(即过度放宽ziplist的使用条件),会导致命令在ziplist上的执行时间变长
- 解决办法:合理的使用类型的内部结构,转变为更为高效的结构
4. 持久化阻塞
- 原因:由folk操作,或者AOF持久化写入硬盘时硬盘压力过大,写入需要等待引起
- 解决办法:对于folk操作引起的阻塞应当优先使用物理机或者高效的支持folk操作的虚拟机,以及控制Redis示例最大可用内存,fork耗时跟内存成正比。对于后者,则应该对于硬盘开销的优化。比如不要和高硬盘负载的服务部署在一起。
5. 其它
由CPU竞争、内存交换、网络问题引起阻塞。
内存优化
- 缩减键值对象:尽量减少key与value的长度,比如使用外在的序列化方式,如:jackson等,来减少内存的使用
- 使用共享对象池:开启LRU淘汰策略后,该对象池无效,因为共享了LRU的信息。且只有整数对象池。
- 字符串优化:小心预分配机制带来的内存浪费,即尽量减少对字符串长修改的操作如:
append
、setrange
等 - 合理的使用编码类型:在满足需求的前提下可以使用低内存使用率的编码结构
- 控制键的数量:合理使用类型来减少键的使用量
缓存设计
1. 缓存的更新策略
- LRU/LFU/FIFO算法剔除:通常用于缓存使用量超过了预设的最大值的时候。
- 超时删除:通过给缓存设置一个过期时间。
- 主动更新:存储层数据更新后需要对缓存层立马更新。
2. 穿透优化
缓存穿透是指:查询一个根本不存在的数据,缓存层与存储层都不会命中。该问题可能会导致后端的存储负载过大,甚至可能宕掉。有两种解决方案:
- 缓存空的对象:在缓存层不命中,查询存储层的时候,没有命中则依旧缓存一个空的对象在存储层
- 布隆过滤器拦截:指的是在访问缓存层之前,将存在的key用布隆过滤器提前保存起来,做第一层的拦截
3. 无底洞优化
无底洞问题指的是:投入更多的节点,系统的整体性能反而下降了。引起的原因是网络的延迟以及连接数众多,造成节点的性能下降。
4. 雪崩优化
雪崩优化是指:出于某些原因,缓存层宕掉,从而使得大量的请求到达存储层,从而使得存储层也宕掉的情况。有三个解决办法:
- 保证缓存层的高可用:实行分布式,即使一个节点宕掉也没多大关系
- 依赖隔离组件为后端限流并降级:即某个模块宕掉后,用其它的模块数据进行填补,常用的组件有:Hystrix
- 提前演练:测压
5. 热点Key重建优化
热点Key重建优化是指:当前Key是一个热点Key,并发量特别大,且重建该Key指向的缓存不可能短时间完成,在这期间,有大量的请求(一个请求就够了)来重建缓存,造成后端负载过大,可能让服务器瘫痪。有两种解决方法:
- 利用锁:用互斥锁来保证只有当前一个线程可以来重建缓存
- 永远不过期:是指从缓存层上来看,不设置过期时间,但是在功能层上,为每个value设置一个逻辑的过期时间,当发现超过后,就用单独的线程去重构缓存