redis 突然大量逐出导致读写请求block

文章目录

[隐藏]

  • 现象
  • 背景
  • 原因
  • 解决方案
  • ref
现象

redis作为缓存场景使用,内存耗尽时,突然出现大量的逐出,在这个逐出的过程中阻塞正常的读写请求,导致 redis 短时间不可用;

背景

redis 中的LRU是如何实现的?

  • 当mem_used内存已经超过maxmemory的设定,对于所有的读写请求,都会触发redis.c/freeMemoryIfNeeded(void)函数以清理超出的内存。

  • 这个清理过程是阻塞的,直到清理出足够的内存空间。

  • 这里的LRU或TTL策略并不是针对redis的所有key,而是以配置文件中的maxmemory-samples个key作为样本池进行抽样清理。
    maxmemory-samples在redis-3.0.0中的默认配置为5,如果增加,会提高LRU或TTL的精准度,redis作者测试的结果是当这个配置为10时已经非常接近全量LRU的精准度.

原因

逐出qps突增非常大的原因:一次需要逐出释放太多的空间会导致阻塞;具体的原因是 mem_tofree 的计算逻辑有问题;
mem_tofree 统计的是:实际已分配的内存总量 – AOF 缓冲区相关的内存;
如果这时候有rehash,会临时分配一个桶来做rehash,这部分内存未排除,所以在rehash阶段,算出来的mem_tofree 就会很大,造成一个时刻需要逐出大量的key,逐出的loop是阻塞的,这个阶段会block redis的请求;

逐出qps的计算:

freeMemoryIfNeeded(...)      // 计算出 Redis 目前占用的内存总数,但有两个方面的内存不会计算在内:      // 1)从服务器的输出缓冲区的内存      // 2)AOF 缓冲区的内存      // 3)AOF 重写缓冲区中的内存      mem_used = zmalloc_used_memory();      if (slaves) {          listIter li;          listNode *ln;            listRewind(server.slaves,&li);          while((ln = listNext(&li))) {              redisClient *slave = listNodeValue(ln);              unsigned long obuf_bytes = getClientOutputBufferMemoryUsage(slave);              if (obuf_bytes > mem_used)                  mem_used = 0;              else                  mem_used -= obuf_bytes;          }      }      if (server.aof_state != REDIS_AOF_OFF) {          mem_used -= sdslen(server.aof_buf);          mem_used -= aofRewriteBufferSize();      }      // 计算需要释放多少字节的内存      mem_tofree = mem_used - server.maxmemory;      propagateExpire(db,keyobj);      // 计算删除键所释放的内存数量      delta = (long long) zmalloc_used_memory();      dbDelete(db,keyobj);      delta -= (long long) zmalloc_used_memory();      mem_freed += delta;      // 对淘汰键的计数器增一      server.stat_evictedkeys++;  
解决方案

github上 @Rosanta 给出的解决方案:释放内存的循环逻辑中最多执行一定次数,达到阈值了就不再逐出,到下个请求来时再释放一点空间;这个方案的好处是不会 block 整个进程,正常的业务读写请求无影响;潜在问题是可能单次写入的数据比释放的空间还大,导致总的内存是一直上升,而不是下降;

@antirez 给的方案:同样是迭代删除,但会加个标志,保证在迭代删除的逻辑下内存是逐渐下降的,而如果是上升的,还是会block住正常的请求(要控制主总的内存大小);
详见:
https://github.com/antirez/redis/pull/4583

ref

关于 redis 4.0的逐出算法优化
http://antirez.com/news/109

原文出处:cnblogs -> http://www.cnblogs.com/me115/p/8516838.html

本站所发布的一切资源仅限用于学习和研究目的;不得将上述内容用于商业或者非法用途,否则,一切后果请用户自负。本站信息来自网络,版权争议与本站无关。您必须在下载后的24个小时之内,从您的电脑中彻底删除上述内容。如果您喜欢该程序,请支持正版软件,购买注册,得到更好的正版服务。如果侵犯你的利益,请发送邮箱到 [email protected],我们会很快的为您处理。
超哥软件库 » redis 突然大量逐出导致读写请求block