Redis数据“丢失”问题

标签: Redis Redis | 发表时间:2016-08-14 14:42 | 作者:
出处:http://yoursite.com/

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 t list*’ 的命令,获取这类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; 删除12 6040约29000个key.(3个分片,共删除约90000个key)
redis_del
查看slowlog监控,2015-12-03 22:01:01 时间点,执行KEYS “t list*” 获取所有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数据“丢失”问题

- - 今天
Redis大部分应用场景是纯缓存服务,请求后端有Primary Storage的组件,如MySQL,HBase;请求Redis的键未命中,会从primary Storage中获取数据返回,同时更新Redis缓存. 如果少量数据丢失,相当于请求”缓冲未命中“; 一般对业务的影响是无感知的. 但现在Redis用作存储的业务场景变多,数据丢失对业务是致命的影响.

Redis 数据类型

- - ITeye博客
该文章是对Redis官方文档的翻译. 字符串是Redis值的最基础的类型. Redis字符串是二进制安全的,这意味着一个Redis字符串可以包含任何种类的数据,例如一个JPEG图像或者一个序列化的Ruby对象. 一个字符串值最多可以保存512M字节的内容. 你可以使用Redis的字符串做一些有趣的事情,例如你可以:.

redis 性能问题查找

- - 开源软件 - ITeye博客
          使用redis作为数据库时,系统出现少量超时,通过日志信息发现,超时发生在bgsave时. bgsave命令会fork一个子进程,子进程会将redis数据库信息dump到rdb文件中. 因此不能确定使用bgsave命令时,是fork一个子进程引起超时,还是dump文件时与主进程的sync同步同时写磁盘引起的超时.

redis超时问题分析

- - 搜索技术博客-淘宝
Redis在分布式应用中占据着越来越重要的地位,短短的几万行代码,实现了一个高性能的数据存储服务. 最近dump中心的cm8集群出现过几次redis超时的情况,但是查看redis机器的相关内存都没有发现内存不够,或者内存发生交换的情况,查看redis源码之后,发现在某些情况下redis会出现超时的状况,相关细节如下.

Redis集群“倾斜”问题

- - 今天
对分布式存储系统的架构和运维管理,如何保证每个Node的数据存储容量和请求量尽量均衡,是非常重要的. 本文介绍Redis大集群运维过程中,常见导致数据和请求量“倾斜”的场景,及规避措施. Redis数据容量或请求量严重”倾斜”的影响. 以下从运维的角度解释,Redis数十节点的集群,出现数据容量和请求量倾斜情况下,存在的一些痛点:.

Redis响应延迟问题排查

- - searchdatabase
  本文将有助于你找出Redis 响应延迟的问题所在.   文中出现的延迟(latency)均指从客户端发出一条命令到客户端接受到该命令的反馈所用的最长响应时间. Reids通常处理(命令的)时间非常的慢,大概在次微妙范围内,但也有更长的情况出现.   如果你正在经历响应延迟问题,你或许能够根据应用程序的具体情况算出它的延迟响应时间,或者你的延迟问题非常明显,宏观看来,一目了然.

Redis时延问题分析及应对

- - 博客 - 伯乐在线
Redis的事件循环在一个线程中处理,作为一个单线程程序,重要的是要保证事件处理的时延短,这样,事件循环中的后续任务才不会阻塞;. 当redis的数据量达到一定级别后(比如20G),阻塞操作对性能的影响尤为严重;. 下面我们总结下在redis中有哪些耗时的场景及应对方法;. keys、sort等命令.

  导致Redis超时(Timeouts)常见问题

- - 移动开发 - ITeye博客
因实际应用中出现经常 Redis 超时问题,StackExchange.Redis 在 Github 上 Timeouts 一文从多个方面进行分析,并提供相应的解决方案, 为方便日后再次出现该问题时快速查阅,特写下本文作为技术笔记,同时给英文不太好的程序员(媛)提供参考,帮助大家更好的学习redis http://www.maiziedu.com/course/337/.

Redis数据分片以及扩容

- - NoSQLFan
投稿介绍:xiaotianqio,资深linux菜鸟程序员,搜索系统砖家,曾混迹于百度的互联网吊丝. 刚开始接触 Redis,大言不惭,聊卿一读. 一开始数据比较少,一台服务器的内存就足够,因此一个Redis 就能满足需求,但是随着业务发展,数据量变大,可能需要在多台服务器上运行多个Redis,所以需要将已有的数据进行 分片(避免数据丢失),不同的片交给不同的Redis 服务.

从Redis的数据丢失说起

- - 开源小站
碰到一个悲催的事情:一台Redis服务器,4核,16G内存且没有任何硬件上的问题. 持续高压运行了大约3个月,保存了大约14G的数据,设置了比较完备的Save参数. 而就是这台主机,在一次重起之后,丢失了大量的数据,14G的数据最终只恢复了几百兆而已. 正常情况下,像Redis这样定期回写磁盘的内存数据库,丢失几个数据也是在情理之中,可超过80%数据丢失率实在太离谱.