分享

Redis数据“丢失”问题

问题导读:
1.如何进行Redis”数据丢失“的故障排查?
2.数据丢失的影响是什么?
3.常见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个分片)


2016-08-17_130627.png

03日22:00~22:40分之间,Redis的DEL操作大约12个,持续40min; 删除126040约29000个key.(3个分片,共删除约90000个key)

2016-08-17_130711.png

查看slowlog监控,2015-12-03 22:01:01 时间点,执行KEYS “tlist*” 获取所有key的前缀, 目的应该是执行后面的DEL操作

2016-08-17_130739.png

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

数据丢失的影响


  • 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

这类问题的预防和监控:

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


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

  • 主要监控


  • 监控内存使用大小 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”场景


2016-08-17_131401.png

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

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

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

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

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

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

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


来源:今天
作者:汝林的Blog


已有(2)人评论

跳转到指定楼层
yangelar 发表于 2016-8-18 09:07:18
写的很好   谢谢
回复

使用道具 举报

CM潜修 发表于 2016-8-19 15:21:13
如果redis出现雪崩的情况,你们的解决方案是什么?楼主
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关闭

推荐上一条 /2 下一条