redis 服务基本上坑不多,基本上注意一下几点:
- 主动设置 key 过期时间
- 注意不要有大 key
最近遇到了一个新的问题,查看了 redis 源码和文档,发现代码设计上存在另一个坑。
背景
场景: redis 实例启动的时候,自动加载 aof 文件,如果文件超过 6G,加载需要 5分钟。
启动时,redis 会先监听端口,再进行 aof 数据加载,以便于客户端及时掌握redis的加载进度。
加载 aof 时,ping 命令会返回 LOADING,此时redis 不可读也不可写。
如果他是主节点,主节点 loading=1, 客户端的状态 master_link_status=down
如果他是从节点, loading=1, master_link_status=err, flags=slaves
一般 redis 驱动只有判断 flags 为 s_down o_down disconnected 这三种状态判断节点不可用。
问题:loading 时, redis 和 sentinel 都认为此节点可正常提供服务,其实这个时候不可读也不可写。
从节点
情景1: loading 数据节点为从节点,客户端做了读写分离
问题:多数客户端的驱动只检测端口,不检测loading状态,会认为此节点为正常节点,导致部分业务读数据失败。
改进思路:
- sentinel 判断为 loading 的状态认为此节点不可用。
- 客户端驱动判断 loading 节点为不可用
- redis 先加载数据,后监听端口
我们的做法: 修改驱动代码,客户端判断 redis 节点为 flags=slave and master-link-status=err 状态时,判断此从节点不可用。
主节点
情景2:loading 数据节点为主节点,客户端没做读写分离,读写都在主节点
问题:sentinel 认为该主节点为正常状态,不做故障转移,导致所有业务读写都失败。
改进思路:
- sentinel 判断为 loading 的状态认为此节点不可用,主动进行故障转移
- redis 先加载数据,后监听端口
总结:
- 监控 master_link_status 的状态,还可以监控 loading 的状态,发现异常情况及时告警。
- redis 加载 AOF 为异步操作,尝试修改代码先加载数据后监听端口,最后还是端口先监听,此路不可行。
- 读写分离的节点,可以通过修改驱动来剔除loading的从节点。
- 主动设置 key 的过期时间可以有效的降低 aof 的大小,从而缩短加载时间来规避问题。
- 对于节点为 loading 的状态,通过修改 sentinel 的判断逻辑来解决此问题,将此节点设置为 o_down。
参考:
https://github.com/scenbuffalo/redis/commit/840df3c9dc88de671ae294f4942ec5fd62c456b7 说明:此补丁在 5.0 不适用