现象

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

背景

redis 中的LRU是如何实现的?

  1. 当mem_used内存已经超过maxmemory的设定,对于所有的读写请求,都会触发redis.c/freeMemoryIfNeeded(void)函数以清理超出的内存。
  2. 这个清理过程是阻塞的,直到清理出足够的内存空间。
  3. 这里的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

redis 突然大量逐出导致读写请求block的更多相关文章

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

    redis 突然大量逐出导致读写请求block   内容目录: 现象 背景 原因 解决方案 ref 现象 redis作为缓存场景使用,内存耗尽时,突然出现大量的逐出,在这个逐出的过程中阻塞正常的读写请 ...

  2. Redis+MongoDB 最佳实践 做到读写分离 -摘自网络

    方案1. (被否定) 加上Redis,做到MongoDB的读写分离,单一进程从MongoDB及时把任务同步到Redis中. 看起来很完美,但是上线后出现了各种各样的问题,列举一下: 1.Redis队列 ...

  3. 5.3 存储器、I/O和配置读写请求TLP

    本节讲述PCIe总线定义的各类TLP,并详细介绍这些TLP的格式.在这些TLP中,有些格式对于初学者来说较难理解.读者需要建立PCIe总线中与TLP相关的一些基本概念,特别是存储器读写相关的报文格式. ...

  4. IE浏览器缓存导致Ajax请求失败

    在IE浏览器中通过Ajax请求后台的数据,如果Page请求是postback类型的,可能会导致Ajax请求失败的问题 我们都知道ajax能提高页面载入的速度主要的原因是通过ajax减少了重复数据的载入 ...

  5. 解决ASP.NET中Redis 每小时6000次访问请求的问题

    原文:解决ASP.NET中Redis 每小时6000次访问请求的问题 虽然ServiceStack v4是商业支持的产品,但我们也允许免费使用小型项目和评估目的.上面的NuGet包中包含可以使用许可证 ...

  6. redis快照关闭了导致不能持久化的问题

    在使用redis的时候我们经常会遇到这种bug:   Python与Redis交互时,设置数据出现下列报错信息:   MISCONF Redis is configured to save RDB s ...

  7. Kafka技术内幕 读书笔记之(六) 存储层——服务端处理读写请求、分区与副本

    如下图中分区到 日 志的虚线表示 : 业务逻辑层的一个分区对应物理存储层的一个日志 . 消息集到数据文件的虚线表示 : 客户端发送的消息集最终会写入日志分段对应的数据文件,存储到Kafka的消息代理节 ...

  8. IOS网络第二天 - 02-异步HTTP请求block回调 解析

    ************** #import "HMViewController.h" #import "MBProgressHUD+MJ.h" @interf ...

  9. asp.net session锁导致ajax请求阻塞

    问:为了可以顺序访问Session的状态值,Session是否提供了锁定机制?答:Session实现了Reader/Writer的锁机制:当页面对Session具有可写功能(即页面有<%@Pag ...

随机推荐

  1. 本篇将记录python开发过程中常见问题

    1.Django 外键on_delete的使用 之前用的Django1.8 换成2.0后,出现以下问题: TypeError: init() missing 1 required positional ...

  2. Java基础知识(一)

    类与对象 1.对象:客观存在的一切事物称之为对象 类:具有相同属性和方法的对象的集合 2.类:属性,方法 3.修饰符: public protected  默认(不写)  private 任何地方   ...

  3. ng机器学习视频笔记(一)——线性回归、代价函数、梯度下降基础

    ng机器学习视频笔记(一) --线性回归.代价函数.梯度下降基础 (转载请附上本文链接--linhxx) 一.线性回归 线性回归是监督学习中的重要算法,其主要目的在于用一个函数表示一组数据,其中横轴是 ...

  4. 换行符\n和回车符\r

    问题始于社区的一个帖子,楼主的问题如下: “在c语言中,对一个不知道大小的文件进行读操作,我用fread()将文件的内容先放到一个缓存区,然后将缓存区中的内容打印出来, 缓存区中的内容和文件中的内容不 ...

  5. 基于Controller接口的控制器及简单应用

    DispatcherServlet在Spring当中充当一个前端控制器的角色,它的核心功能是分发请求.请求会被分发给对应处理的Java类,Spring MVC中称为Handle.在Spring 2.5 ...

  6. 利用innodb_force_recovery修复MySQL数据页损坏

    现象:启动MySQL服务时报1067错误,服务无法启动. 查看xxx.err错误日志发现有数据页损坏信息: InnoDB: Database page corruption on disk or a  ...

  7. [转载]完全版线段树 by notonlysuccess大牛

    原文出处:http://www.notonlysuccess.com/ (好像现在这个博客已经挂掉了,在网上找到的全部都是转载) 今天在清北学堂听课,听到了一些很令人吃惊的消息.至于这消息具体是啥,等 ...

  8. 对.Net Core结合Docker和Jexus的实践

    本文基于上次尝试之后的进一步尝试,加入Docker容器.编写Dockerfile,并且jexus结合Docker的使用,总结下自己的个人感想. 一.环境介绍 当前的场景有两种方式将Demo实现运行,一 ...

  9. java单例模式学习笔记

    最近一直在学习多线程,在学习过程中遇到了关于单例模式的多线程安全问题,内容如下: 一:首先什么是单例模式 单例模式具有的三要点: 一个类只能有一个实例: 必须是由它自己创建的这个实例: 它必须自行向外 ...

  10. sparksql工程小记

    最近做一个oracle项目迁移工作,跟着spark架构师学着做,进行一些方法的总结. 1.首先,创建SparkSession对象(老版本为sparkContext) val session = Spa ...