文档章节

你为什么在Redis里读到了本应过期的数据

IT--小哥
 IT--小哥
发布于 09/25 00:18
字数 1866
阅读 31
收藏 12

一个事故的故事

晚上睡的正香突然被电话吵醒,对面是开发焦急的声音:我们的程序在访问redis的时候读到了本应过期的key导致整个业务逻辑出了问题,需要马上解决。

看到这里你可能会想:这是不是又是所谓的“redis的坑”啊?

不不不,我们从来不会随便把一些问题归类到“xxx的坑”里,那么这个问题真的存在吗?

是的,这个问题真实存在并且你很可能已经碰到了只是并未发觉。

那么造成这一问题的原因是什么呢?

简单的说,redis的从库是无法主动的删除已经过期的key的,所以如果你做了读写分离,那么就很可能会在从库读到脏数据。

复杂的说,这个问题的答案相对复杂或者你根本不想知道这么详细,所以如果你只是想简单的了解如何避免这个问题,那么请继续看,很简单,我们有两种做法:

1.通过一个程序循环遍历所有key,例如scan

2.升级到redis3.2

OK,你已经遇到/可能遇到/即将遇到的问题我们已经帮你解决了,那么如果你仍然对本文有兴趣那么可以继续往下看,因为在下文中对这个问题的分析以及更细化的解决方案一定会为你增加面试、讨论、对喷时的资本!

“通俗易懂”Redis过期策略解读

Redis key的三种过期策略

  • 惰性删除:当读/写一个已经过期的key时,会触发惰性删除策略,直接删除掉这个过期key,很明显,这是被动的!

  • 定期删除:由于惰性删除策略无法保证冷数据被及时删掉,所以redis会定期主动淘汰一批已过期的key。(在第二节中会具体说明)

  • 主动删除:当前已用内存超过maxmemory限定时,触发主动清理策略,该策略由启动参数的配置决定,可配置参数及说明如下:

volatile-lru:从已设置过期时间的数据集中根据LRU算法删除数据(redis3.0之前的默认策略)

volatile-ttl:从已设置过期时间的数据集中挑选过期时间最小的数据删除

volatile-random:从已设置过期时间的数据集中随机选择数据删除

allkeys-lru:从所有数据集中根据LRU算法删除数据

allkeys-random:从所有数据集中任意选择删除数据

noenviction:禁止从内存中删除数据(从redis3.0 开始默认策略)

maxmemory-samples:删除数据的抽样样本数,redis3.0之前默认样本数为3,redis3.0开始默认样本数为5,该参数设置过小会导致主动删除策略不准确,过大会消耗多余的cpu

Redis过期key删除策略之定期删除

因为redis本身的定位为轻量、快速的内存数据库,所以如果为所有key都加上定时器,过期即删除的定时策略显然会消耗大量的性能,这与redis作者的价值观有着巨大差异;由于redis中key的过期删除只会在主库上进行,对于目前redis使用的组合策略来说,单位时间过期的数据量越多,越可能会带来key的过期延迟,对于做了读写分离的业务,很容易导致从库读取到过期的脏数据。

redis源码activeExpireCycle函数的解读结果请看下文(如果你懒得看,可以直接跳过本节看第三节):

相关参数默认值:

hz 10 :每秒执行10次activeExpireCycle 函数

activeExpireCycle函数解析:

每次循环随机拿出的key的数量

正常过期模式最大cpu耗时率

过期模式:

“正常过期”模式 :执行时间限制:25ms;计算公式为

“快速过期”模式 :执行时间限制为1ms,触发条件为上次的执行时间超过了timelimit,之后函数会使timelimit_exit=1 为真,并从上次发生超时的db的下一个db开始继续处理。

过期策略:redis会遍历所有db,每次从db中随机拿出20个带有过期时间属性的key做过期判断。

循环检测:对随机拿出的20个key进行检测,如果在本次检测中发现有超过25%的key被判定为过期则持续执行过期检测循环,直到这批key中需要过期的key的比例低于25%或某次循环超过timelimit执行时间限制。

上文已经提到,过期删除行为只会在主库中进行。这是因为key的过期删除依赖于expireIfNeeded函数,这个函数在任何访问数据的操作中都会被调用并用来检测客户端访问的数据是否过期。

如果当前数据库实例角色是master,则不进行key过期的删除操作。反之,它会先调用另一个函数propagateExpire发送del key命令到aof和当前redis实例的所有slave,最后将该key从数据库中删除。此时,从库中的该key才真正意义上的过期/消失/你访问不到了!

所以一旦一个redis集群的内存没有触及maxmemory,而它每时每刻都有大量的key需要过期导致定期删除忙不过来,并且这些过期了的key不会再被访问到,那么你就很可能会在从库莫名其妙的读到了本应过期的key了。

如何避免从库读取到脏数据

  1. 通过scan命令扫库:
    当redis中的key被scan的时候,相当于访问了该key,同样也会做过期检测,充分发挥redis惰性删除的策略。这个方法能大大降低了脏数据读取的概率,但缺点也比较明显,会造成一定的数据库压力,谨慎合理使用,否则有可能影响线上业务的效率。

  2. 升级redis到新的版本:
    在redis 3.2-rc1版本中,redis加入了一个新特性来解决主从不一致导致读取到过期数据的问题(好吧,虽然这个新特性我们一直觉得是个bug fix),在源码db.c文件中,作者对lookupKeyRead做了相应的修改,增加了key是否过期以及对主从库的判断(代码如下),如果key已过期,当前访问的是master则返回null;当前访问的是从库,且执行的是只读命令也返回null(老版本从库真实的返回该操作的结果,如果该key过期后主库没有删除),源码片段如下:

那么,不想通过自己写程序解决问题的同学,快快升级redis到新的版本吧。

本文转载自:https://mp.weixin.qq.com/s?__biz=MzIyNzUwMjM2MA==&mid=2247483696&idx=1&sn=c69e364b189fe261a466e4f...

共有 人打赏支持
IT--小哥
粉丝 47
博文 118
码字总数 90243
作品 0
东城
数据库管理员
私信 提问
redis主从复制常见的一些坑

读写分离的问题 1.数据复制的延迟 读写分离时,master会异步的将数据复制到slave,如果这是slave发生阻塞,则会延迟master数据的写命令,造成数据不一致的情况 解决方法:可以对slave的偏移量...

吴正宇
04/03
0
0
经典:Redis分布式锁的正确实现方式

分布式锁一般有三种实现方式:1. 数据库乐观锁;2. 基于Redis的分布式锁;3. 基于ZooKeeper的分布式锁。本篇博客将介绍第二种方式,基于Redis实现分布式锁。虽然网上已经有各种介绍Redis分布...

架构之家
01/14
0
0
Memcached原理与应用

Memcached原理与应用 标签: linux 笔者Q:972581034 交流群:605799367。有任何疑问可与笔者或加群交流 1.Memcached是什么 高性能 支持高并发 分布式内存缓存系统 协议简单且部署方便 服务端...

陈天刚
2017/04/14
0
0
分享30道Redis面试题,面试官能问到的我都找到了

1、什么是Redis?简述它的优缺点? Redis本质上是一个Key-Value类型的内存数据库,很像memcached,整个数据库统统加载在内存当中进行操作,定期通过异步操作把数据库数据flush到硬盘上进行保...

Java大蜗牛
09/11
0
0
Redis学习笔记之基本数据结构

Redis基础数据结构 Redis有5种基本数据结构:String(字符串)、list(列表)、set(集合)、hash(哈希)、zset(有序集合) 字符串string 字符串类型是Redis的value最简单的数据结构,类似与Java语言...

smileNicky
09/26
0
0

没有更多内容

加载失败,请刷新页面

加载更多

js垃圾回收机制和引起内存泄漏的操作

JS的垃圾回收机制了解吗? Js具有自动垃圾回收机制。垃圾收集器会按照固定的时间间隔周期性的执行。 JS中最常见的垃圾回收方式是标记清除。 工作原理:是当变量进入环境时,将这个变量标记为“...

Jack088
昨天
10
0
大数据教程(10.1)倒排索引建立

前面博主介绍了sql中join功能的大数据实现,本节将继续为小伙伴们分享倒排索引的建立。 一、需求 在很多项目中,我们需要对我们的文档建立索引(如:论坛帖子);我们需要记录某个词在各个文...

em_aaron
昨天
13
0
"errcode": 41001, "errmsg": "access_token missing hint: [w.ILza05728877!]"

Postman获取微信小程序码的时候报错, errcode: 41001, errmsg: access_token missing hint 查看小程序开发api指南,原来access_token是直接当作parameter的(写在url之后),scene参数一定要...

两广总督bogang
昨天
18
0
MYSQL索引

索引的作用 索引类似书籍目录,查找数据,先查找目录,定位页码 性能影响 索引能大大减少查询数据时需要扫描的数据量,提高查询速度, 避免排序和使用临时表 将随机I/O变顺序I/O 降低写速度,占用磁...

关元
昨天
11
0
撬动世界的支点——《引爆点》读书笔记2900字优秀范文

撬动世界的支点——《引爆点》读书笔记2900字优秀范文: 作者:挽弓如月。因为加入火种协会的读书活动,最近我连续阅读了两本论述流行的大作,格拉德威尔的《引爆点》和乔纳伯杰的《疯传》。...

原创小博客
昨天
30
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部