[缓存系列] redis那点事

iagme.png

本文,你将阅读到以下内容:

  • 如何应对缓存击穿和缓存雪崩的问题;
  • Redis 的过期策略以及内存淘汰机制;

1.如何应对缓存击穿和缓存雪崩的问题?
  • 场景:在大并发情况下,流量几百万左右;

  • 概念:

    • 缓存穿透:故意去请求缓存中不存在的数据,导致所有的请求都怼到数据库上,然而数据库中也不存在,直接返回null,要是有人利用不存在的key频繁攻击我们的应用,那就有可能造成数据库的崩溃;
    • 缓存雪崩:设置缓存时采用了相同的过期时间,导致缓存在某一时刻同时失效,请求全部转发到DB,DB瞬时压力过重雪崩;
    • 缓存击穿:缓存中的某一个key在某个时间点过期的时候,恰好在这个时间点对这个Key有大量的并发请求过来,这些请求发现缓存过期一般都会从后端DB加载数据并回设到缓存,这个时候大并发的请求可能会瞬间把后端DB压垮;
  • 解决:

    • 缓存穿透 or 缓存击穿解决方案
      • 布隆过滤器:将所有可能存在的数据哈希到一个足够大的bitmap中,一个一定不存在的数据会被这个bitmap拦截掉,从而避免了对底层存储系统的查询压力;
      • 缓存null值:如果一个查询返回的数据为空(不管是数 据不存在,还是系统故障),我们仍然把这个空结果进行缓存,但它的过期时间会很短,最长不超过五分钟。
    • 缓存雪崩解决方案:
      • 缓存失效时间分散开来:可以在原有的失效时间基础上增加一个随机值,比如1-5分钟随机,这样每一个缓存的过期时间的重复率就会降低,就很难引发集体失效的事件;
      • 使用互斥锁(该方案吞吐量明显会下降):用加锁或者队列的方式保证缓存的单线 程(进程)写,从而避免失效时大量的并发请求落到底层存储系统上;
      • 双缓存:设计两个缓存,缓存A和缓存B,缓存A的设置过期时间,缓存B不设失效时间,自己做缓存预热操作;(可以细分下设计:从缓存A 读数据,有则直接返回;A没有数据,直接从B读数据,直接返回,并且异步启动一个更新线程,更新线程同时更新缓存A和缓存B);
2.Redis 的过期策略以及内存淘汰机制
  • 场景:
    比如你的Redis只能存5G数据,可是你写了10G,那会删5G的数据,怎么删的? 这个问题思考过么?
    或者,你的数据已经设置了过期时间,但是时间到了,内存占用率还是比较高,有思考过原因么?

  • 概念

    • 被动删除:用到的时候才会去检验key是不是已过期,过期就删除;
    • 主动删除:Redis会定期主动淘汰一批已过去的key;
  • 原因:

    • 定时删除(主动删除)
      • 含义:在设置key的过期时间的同时,为该key创建一个定时器,让定时器在key的过期时间来临时,对key进行删除;
      • 优点:保证内存被尽快释放;
      • 缺点:若过期key很多,删除这些key会占用很多的CPU时间,在CPU时间紧张的情况下,CPU不能把所有的时间用来做要紧的事儿,还需要去花时间删除这些key定时器的创建耗时,若为每一个设置过期时间的key创建一个定时器(将会有大量的定时器产生)性能影响严重没人用;
    • 定期删除(主动删除)
      • 含义:每隔一段时间执行一次删除(在redis.conf配置文件设置hz,1s刷新的频率)过期key操作
      • 优点:通过限制删除操作的时长和频率,来减少删除操作对CPU时间的占用--处理"定时删除"的缺点定期删除过期key--处理"惰性删除"的缺点.
      • 缺点:在内存友好方面,不如"定时删除"在CPU时间友好方面,不如"惰性删除"
      • 难点:合理设置删除操作的执行时长(每次删除执行多长时间)和执行频率(每隔多长时间做一次删除)这个要根据服务器运行情况来定了.
    • 惰性删除(被动删除)
      • 含义:key过期的时候不删除,每次从缓存中获取key的时候去检查是否过期,若过期,则删除,返回null。
      • 优点:删除操作只发生在从数据库取出key的时候发生,而且只删除当前key,所以对CPU时间的占用是比较少的,而且此时的删除是已经到了非做不可的地步(如果此时还不删除的话,我们就会获取到了已经过期的key了)
      • 缺点:若大量的key在超出超时时间后,很久一段时间内,都没有被获取过,那么可能发生内存泄露(无用的垃圾占用了大量的内存);
  • 过期策略配置

    • redis 内部默认采用的是定期删除+惰性删除策略;
      • 定期删除+惰性删除流程:
        • 惰性删除流程:在进行get或setnx等操作时,先检查key是否过期,若过期,删除key,然后执行相应操作;若没过期,直接执行相应操作;
        • 定期删除流程:遍历每个数据库(就是redis.conf中配置的"database"数量,默认为16),循环遍历当前库中的指定个数个key(默认是每个库检查20个key),如果当前库中没有一个key设置了过期时间,直接执行下一个库的遍历,随机获取一个设置了过期时间的key,检查该key是否过期,如果过期,删除key.判断定期删除操作是否已经达到指定时长(配置redis.conf 的hz选项),若已经达到,直接退出定期删除. 也可以通过配置redis.conf的maxmemory最大值,当已用内存超过maxmemory限定时,就会触发定期删除策略;
    • 过期key对持久化RDB和AOF的影响
      • 从内存数据库持久化数据到RDB文件,持久化key之前,会检查是否过期,过期的key不进入RDB文件;
      • 从RDB文件恢复数据到内存数据库,在数据载入内存数据库之前,会对key先进行过期检查,如果过期,不导入数据库.
      • 从内存数据库持久化数据到AOF文件,当key过期后,还没有被删除时,此时进行执行持久化操作(该key是不会进入aof文件的,因为没有发生修改命令).
      • 当key过期后,在发生删除操作时,程序会向aof文件追加一条del命令(在将来的以aof文件恢复数据的时候该过期的键就会被删掉);
      • AOF重写时,会先判断key是否过期,已过期的key不会重写到aof文件.
    • 采用定期删除+惰性删除就没其他问题了么?
      • 并不是这样的,如果定期删除没删除Key,然后你也没即时去请求Key,也就是说惰性删除也没生效.这样,Redis的内存会越来越高.那么就应该采用内存淘汰机制.
  • 内存淘汰机制

    • 原因:Redis内存淘汰指的是用户存储的一些键被可以被它主动地从实例中删除,从而产生读miss的情况,内存的淘汰机制的初衷是为了更好地使用内存,用一定的缓存miss来换取内存的使用效率;
    • 配置:
      • Redis内存淘汰通过配置redis.conf中的maxmemory这个值来开启,maxmemory为0的时候表示我们对Redis的内存使用没有限制;
      • 淘汰策略的选择可以通过redis.conf中的maxmemory-policy来配置;
      • 主键空间 && 设置了过期时间的键空间:在redis中,如果有一批键存储在Redis中,则有那么一个哈希表用于存储这批键及其值,如果这批键中有一部分设置了过期时间,那么这批键还会被存储到另外一个哈希表中.设置了过期时间的键空间为主键空间的子集。
    • 淘汰策略:
      • noeviction:当redis内存数据达到maxmemory,在该策略下,新写入数据时直接返回OOM错误;
      • allkeys-lru:当内存不足以容纳新写入数据时,在主键空间中,优先移除最近未使用的一些key[以配置文件中的maxmemory-samples个key作为样本池进行抽样清理];
      • allkeys-random:当内存不足以容纳新写入数据时,在主键空间中,随机移除某些key[以配置文件中的maxmemory-samples个key作为样本池进行抽样清理];
      • volatile-lru:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,移除最近最少使用的key[以配置文件中的maxmemory-samples个key作为样本池进行抽样清理],这种情况一般是把redis既当缓存,又做持久化存储的时候才用.
      • volatile-random:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,随机移除某些key.
      • volatile-ttl:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,有更早过期时间的key[以配置文件中的maxmemory-samples个key作为样本池进行抽样清理]优先移除;
    • 注意:
      • 淘汰策略的清理过程是阻塞的,直到清理出足够的内存空间.所以如果在达到maxmemory并且调用方还在不断写入的情况下,可能会反复触发主动清理策略,导致请求会有一定的延迟.
      • 尽量不要触发maxmemory,最好在mem_used内存占用达到maxmemory的一定比例后,需要考虑调大hz以加快淘汰,或者进行集群扩容.
      • 如果能够控制住内存,则可以不用修改maxmemory-samples配置;如果Redis本身就作为LRU cache服务(这种服务一般长时间处于maxmemory状态,由Redis自动做LRU淘汰),可以适当调大maxmemory-samples.
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,390评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,821评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,632评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,170评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,033评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,098评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,511评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,204评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,479评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,572评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,341评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,213评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,576评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,893评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,171评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,486评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,676评论 2 335

推荐阅读更多精彩内容