Redis数据“丢失”问题

from: https://zhuoroger.github.io/2016/08/14/redis-data-loss/?hmsr=toutiao.io&utm_medium=toutiao.io&utm_source=toutiao.io?ref=myread

Redis数据“丢失”问题

Redis大部分应用场景是纯缓存服务,请求后端有Primary Storage的组件,如MySQL,HBase;请求Redis的键未命中,会从primary Storage中获取数据返回,同时更新Redis缓存。
如果少量数据丢失,相当于请求”缓冲未命中“; 一般对业务的影响是无感知的。
但现在Redis用作存储的业务场景变多,数据丢失对业务是致命的影响。
本文简单讨论Redis常见数据”丢失“现象,以及怎么规避;会列举几个生产中有意思的情节。


记1次Redis”数据丢失“的故障排查

Redis数据被丢失问题,发生次数也很多; 如何快速定位问题和避免呢。
先分享一个小故事(大家都喜欢带情节的片,不对是技术文章)

情节:我的Redis掉了90000多个Keys, 是不是DBA有删除操作?

(时间:12-04日;故事人物:RD(研发工程师)和DBA; 故事:Redis一夜之间不见90000个key)

RD:我们Redis集群中,以“t_list”前缀的90000多key今早发现都掉了,其他key都在,是不是DBA有清理操作啊?
DBA:没有维护性操作(一脸懵B和无辜),先止损,把Key从Primary store中导入Redis;我先分析一下原因,有结果了通知你;定位问题前,你也关注一下,避免二次发生。
RD:“已从MySQL把key导入到Redis. 好的,等你消息。”
然后RD就下楼了,DBA扣上他的25元的boss耳机,开始自言自语Troubleshooting.
“这部分key未设置TTL, 查看监控的 expired_keys基本都是0”
“是否达到了maxmeory,key被强制驱逐淘汰了? 查看监控 used_memory_pct未到100%,查看 evicted_keys一直为0,最近24小时无key被淘汰”
“只是部分key丢失,而且都是同一个key前缀,说明这个凶手很了解业务;查看监控的实例总key数, keys指标,发现果断keys果断下降,但未变为0,排除Flushall/flushdb和Redis, 定位是程序或人为操作”
“如果程序主动删除key, 就只能是DEL操作,查看监控comdstat_del指标,表示每秒执行的Del次数,果然平时基本为0,昨晚22:01开始有每秒几十个的del”
“再查看slowlog, 22:01时,执行 ‘ KEYS tlist*’ 的命令,获取这类key,进行批量清理”
这时问题定位了, 一首歌多的时间。 然后DBA通知RD排查的结论,让其他排查程序或人为操作;

分析证据简述如下:
从03日的Redis key监控可见,22:00到22:40这个数据key个数下降30000(1个分片,此集群共3个分片)
redis_keys
03日22:00~22:40分之间,Redis的DEL操作大约12个,持续40min; 删除126040约29000个key.(3个分片,共删除约90000个key)
redis_del
查看slowlog监控,2015-12-03 22:01:01 时间点,执行KEYS “tlist*” 获取所有key的前缀, 目的应该是执行后面的DEL操作
redis_keys

说明:精细化的监控告警很重要。

数据丢失的影响

  • Redis存储的应用场景,数据丢失是不能接受的;
    因为Redis的持久化特性,数据还原很难保证一致性,因rdb全备和aof重写备份,RPO不能像MySQL这样保证恢复到故障操作的前一个事务。
  • 缓存的应用场景,如果大量缓存数据丢失,往往导致后端存储组件”打死“,应用程序雪崩的情况

常见Redis数据丢失的情况

  • 程序bug或人为误操作
  • 因客户端缓冲区内存使用过大,导致大量键被LRU淘汰
  • 主库故障后自动重启,可能导致数据丢失
  • 网络分区的问题,可能导致短时间的写入数据丢失
  • 主从复制数据不一致,发生故障切换后,出现数据丢失
  • 大量过期键,同时被淘汰清理

程序bug或人为误操作

如前文情节1,程序bug误删除数据; DBA/RD误操作执行flushall/flushdb这类命令。
这类问题的预防和监控
1 重命名危险命令:keys(程度大批量误删除,很多通过keys获取键后再删除),flushall,flushdb
2 细化几个重要的监控项:

  • 实例当前的键个数(dbsize/info), 当大量键丢失时,可通过此项历史监控图,定位发生的时间范围
  • 各类删除命令的执行数监控:cmdtats_flushall, cmdstats_flushdb,cmdstat_del
    对应时间范围,确认具体是什么操作

因客户端缓冲区内存使用过大,导致大量键被LRU淘汰

因客户端缓冲区的内存大小很难限制,它们消耗的内存数会计算在used_memory内;如果使用不当,
导致缓冲区内存使用过大,达到maxmemory限制;(缓存场景)会导致大量的键被淘汰,最坏会把所有键清理,缓冲无键可淘汰,写入失败。相当于整个缓冲失效,对业务影响较大。

关于Redis客户端缓冲区问题,详细分析见之前文章Redis Clients Two Buffers

这类问题的预防和监控:
1 业务容量规划时把缓冲正常消耗计算在内,合理高大maxmemory的限制;
每个实例最好可预留几百M(大小根据客户端连接数和key的使用有关,根据大小集群合理调整)
2 对输出缓冲区设置合理limit;如normal设置10MB, SLAVE设置1GB等。 如果复制因slave线程输出缓冲区反复同步,需临时调大slave client-output-buffer,要同时调大maxmemory限制。

说明:关于Redis复制中断和无限同步,详细分析请见Redis复制中断和无限同步问题

3 主要监控

  • 监控内存使用大小 used_memory
  • 监控两个buffer的使用量client_longest_output_list和client_biggest_input_buf
  • 监控键的LRU驱逐数量:evicted_keys

主库故障后自动重启,可能导致数据全部丢失

这种故障发生,极有可能数据全部丢失。
问题发生的现象:时间点T1,主库故障关闭了,因设置有自动重启的守护程序,时间点T2主库被重新拉起,因(T2-T1)时间间隔过小,未达到Redis集群或哨兵的主从切换判断时长;这样从库发现主库runid变了或断开过,会全量同步主库rdb清理,并清理自己的数据。
而为保障性能,Redis主库往往不做数据持久化设置,那么时间点T2启动的主库,很有可能是个空实例(或很久前的rdb文件)。

这种问题发生时间间隔,一般小于1分钟,可能监控告警无法感知到。
这类总是的预防和监控:
1 强烈反对Redis粗暴地设置自动重启
2 这种监控键个数的变化,缓存命中率,同时ELK类型准实时监控redis日志变化并告警

建议:数据库这类重“状态性”服务,不建议程序暴力自动重启

网络分区的问题,可能导致短时间的写入数据丢失

这种问题出现丢失数据都很少,网络分区时,Redis集群或哨兵在判断故障切换的时间窗口,这段时间写入到原主库的数据,5秒~15秒的写入量。
详细分析参考:
Reply to Aphyr attack to Sentinel
redis-sentinel-at-flickr

图片(引至参考2): Redis哨兵结构的网络分区导致的“split-brain”场景
redis_keys

主从复制数据不一致,发生故障切换后,出现数据丢失

主从数据出现不一致,发生故障切换,从库提升为主后,导致数据丢失的情况。
关于Redis复制数据不一致,请参考Redis复制主从数据不-致

大量过期键,同时被淘汰清理

这类情况不是真正的“数据丢失”,只是定期主动清理Redis堆积的过期键,会导致Redis的键个数(dbsize)出现陡降(最大能达20%)。业务方常误以为有数据丢失。

这时可通过监控过期键淘汰的数量:expireed_keys的增长量,与dbsize键总数减少数据量是否相等。

说明:关于过期键,大量堆积成为“死键”问题,详细分析参考Redis的“死键”问题

欢迎大家留言补充,遇到的数据丢失场景。

 Redis复制主从数据不-致
 
细说Redis监控和告警(待完善) 
  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值