Redis过期--淘汰机制的解析和内存占用过高的解决方案
echo编辑整理,欢迎转载,转载请声明文章来源。欢迎添加echo微信(微信号:t2421499075)交流学习。 百战不败,依不自称常胜,百败不颓,依能奋力前行。——这才是真正的堪称强大!!!
Redis在我们平时的开发或者练习的时候,往往很容易忽略一个问题,那就是我们的Redis内存占满的问题。但是在真是的商业开发中,Redis的实际占满是真正会存在这样的问题的。那么如果Redis在某一刻占满内存,我们又没有对它进行相应的设置它会出现什么情况呢?会不会导致我们整个因为使用Redis而整个业务垮掉?这就是我们本篇文章所要讲述的问题。
什么是Redis淘汰机制
Redis内存淘汰机制其实简单讲就是将过期的数据或者很久没有访问,或者在一段时间内很少有访问的数据进行删除。它分为很多中,有主动的数据淘汰,如:用户设定过期时间。有被动的淘汰,比如:Redis数据占满了内存,这个时候就会将过期的数据或者很久没有访问的数据删除掉。
Redis的淘汰有哪些类型
- 定时过期:每个设置过期时间的key都需要创建一个定时器,到过期时间就会立即清除。该策略可以立即清除过期的数据,对内存很友好;但是会占用大量的CPU资源去处理过期的数据,从而影响缓存的响应时间和吞吐量。
- 惰性过期:只有当访问一个key时,才会判断该key是否已过期,过期则清除。该策略可以最大化地节省CPU资源,却对内存非常不友好。极端情况可能出现大量的过期key没有再次被访问,从而不会被清除,占用大量内存。
- 定期过期:每隔一定的时间,会扫描一定数量的数据库的expires字典中一定数量的key,并清除其中已过期的key。该策略是前两者的一个折中方案。通过调整定时扫描的时间间隔和每次扫描的限定耗时,可以在不同情况下使得CPU和内存资源达到最优的平衡效果。
(expires字典会保存所有设置了过期时间的key的过期时间数据,其中,key是指向键空间中的某个键的指针,value是该键的毫秒精度的UNIX时间戳表示的过期时间。键空间是指该Redis集群中保存的所有键。)
定时过期的问题:缓存雪崩
很多人可能对这个词很熟悉,因为有很多的商业案例展示了血淋淋的教训,但是也有一部分人估计没有接触过。缓存雪崩其实也不是什么新词,它主要的引起原因就是指缓存中数据大批量的到过期时间。定时过期它本身就有一个缺点,那就是会占用大量的CPU资源,如果我们主动设置过期时间的键过多,在同一时间过期,很有可能就会造就我们Redis挂掉。但是这并不是最可怕的,雪崩不仅仅影响自己,还在我们的业务中影响数据库。因为我们很多业务设计都是在我们Redis的数据过期之后,从新查询数据库,但我们Redis主动批量过期的时候,会有大量的请求发送到我们的数据库,很有可能导致我们的数据库也挂掉。这才是最大的问题所在。
解决方案:
- 缓存数据的过期时间设置随机,防止同一时间大量数据过期现象发生。
- 如果缓存数据库是分布式部署,将热点数据均匀分布在不同搞得缓存数据库中。
- 设置热点数据永远不过期。
从几种淘汰策略中其实我们可以看到基本的一些问题所在,所以我们在使用缓存的时候最好有一个全面的了解和全面的考虑应对。在实际开发中,我们更应该多去关注的和了解的是定期过期,因为它涉及真实开发中的一些问题。所以我们应该提前设置好。
怎么设置定期过期最大使用内存
定期过期的最大内存设置在我们的redis.conf文件中,我们可以在该文件中看到这个配置:maxmemory <bytes>,但是这个配置一般都是注释掉的,也就是说安装之后如果我们没有主动对他进行配置,那么他就不会有默认大小值。对应的它不设置的情况下,那么它可以使用多少的内存空间呢?这个跟系统有关。如果说我们将Redis安装在32位的系统上,它的最大使用内存空间应该是在3G左右,如果是64位的系统,那么可以将我们的内存占满。当然如果真正占满内存,这是一件比较恶劣的事情,不仅仅访问Redis的时候,我们不能在进行写的操作,而且我们系统本身的其他操作也会受到限制。所以我们可以采用命令来对它进行一个初始化的设置
config set maxmemory 268435456
使用命令进行设置之后我们需要重启Redis才能生效。当然我们也可以直接找到Redis的安装目录,然后使用vi命令,直接更改配置文件中的对应的该内容,更改完之后,重启即可。
定期过期的淘汰策略
- volatile-lru:根据LRU算法生成的过期时间来删除。
- allkeys-lru:根据LRU算法删除任何key。
- volatile-lfu:从所有配置了过期时间的键中驱逐使用频率最少的键
- allkeys-lfu:从所有键中驱逐使用频率最少的键
- volatile-random:根据过期设置来随机删除key。
- allkeys-random:无差别随机删。
- volatile-ttl:根据最近过期时间来删除(辅以TTL)
- noeviction:谁也不删,直接在写操作时返回错误。
随机淘汰策略
随机找hash桶再次hash指定位置的dictEntry即可。就是在场景REDIS_MAXMEMORY_VOLATILE_RANDOM和REDIS_MAXMEMORY_ALLKEYS_LRU情况下的待淘汰的key。我们可以一观它的源码:
dictEntry *dictGetRandomKey(dict *d)
{
dictEntry *he, *orighe;
unsigned int h;
int listlen, listele;
if (dictSize(d) == 0) return NULL;
if (dictIsRehashing(d)) _dictRehashStep(d);
if (dictIsRehashing(d)) {
// T = O(N)
do {
h = random() % (d->ht[0].size+d->ht[1].size);
he = (h >= d->ht[0].size) ? d->ht[1].table[h - d->ht[0].size] :
d->ht[0].table[h];
} while(he == NULL);
} else {
// T = O(N)
do {
h = random() & d->ht[0].sizemask;
he = d->ht[0].table[h];
} while(he == NULL);
}
/* Now we found a non empty bucket, but it is a linked
* list and we need to get a random element from the list.
* The only sane way to do so is counting the elements and
* select a random index. */
listlen = 0;
orighe = he;
while(he) {
he = he->next;
listlen++;
}
listele = random() % listlen;
he = orighe;
// T = O(1)
while(listele--) he = he->next;
return he;
}
TTL时间淘汰
for (k = 0; k < server.maxmemory_samples; k++) {
sds thiskey;
long thisval;
de = dictGetRandomKey(dict);
thiskey = dictGetKey(de);
thisval = (long) dictGetVal(de);
/* Expire sooner (minor expire unix timestamp) is better
* candidate for deletion */
if (bestkey == NULL || thisval < bestval) {
bestkey = thiskey;
bestval = thisval;
}
}
更多源码,请参考redis官网。这里只是简单的展示两种。我们可以根据这样的代码来对我们的redis的定期过期做一个合理的配置
思考:
基于一个数据结构做缓存,怎么实现一个LRU算法?
做一个有底线的博客主
Redis过期--淘汰机制的解析和内存占用过高的解决方案的更多相关文章
- Redis系列--内存淘汰机制(含单机版内存优化建议)
https://blog.csdn.net/Jack__Frost/article/details/72478400?locationNum=13&fps=1 每台redis的服务器的内存都是 ...
- [转帖]Linux中buff/cache内存占用过高解决办法
Linux中buff/cache内存占用过高解决办法 https://www.cnblogs.com/rocky-AGE-24/p/7629500.html /proc/sys/vm/drop_cac ...
- CLR Profile解决内存占用过高
CLR Profile解决内存占用过高的问题 炮哥:"嘿,哥们,忙啥呢,电脑卡成这逼样." 勇哥:"在用CLR Profile工具分析下FlexiPrint的内存占用情况 ...
- [2017-08-09]一则使用WinDbg工具调试iis进程调查内存占用过高的案例
最近遇到一个奇葩内存问题,跟了三四天,把Windbg玩熟了,所以打算分享下. 症状简介 我们团队的DEV开发环境只有一台4核16G的win2012r2. 这台服务器上装了SqlServer.TFS(项 ...
- 通过修改my.ini配置文件来解决MySQL 5.6 内存占用过高的问题
打开后台进程发现mysql占用的内存达到400+M. 修改一下my.ini这个配置文件的配置选项是可以限制MySQL5.6内存占用过高这一问题的,具体修改选项如下: performance_schem ...
- 【转】一则使用WinDbg工具调试iis进程调查内存占用过高的案例
最近遇到一个奇葩内存问题,跟了三四天,把Windbg玩熟了,所以打算分享下. 症状简介 我们团队的DEV开发环境只有一台4核16G的win2012r2.这台服务器上装了SqlServer.TFS(项目 ...
- Spring cloud开发内存占用过高解决方法
https://blog.csdn.net/wanhuiguizong/article/details/79289986 版权声明:本文为博主原创文章,转载请声明文章来源和原文链接. https:// ...
- (转)aix非计算内存 占用过高 案例一则
原文:http://www.talkwithtrend.com/Article/28621 两台小型机组成的RAC环境,在用topas查看资源使用情况时,发现一台机器的非计算内存占用过高: MEMOR ...
- Window下MySql 5.6 安装后内存占用很高的问题
Window下MySql 5.6 安装后内存占用很高的问题 刚刚准备玩一把mysql,初学者 环境是window 7和window sever 2008, mysql是最新的5.6, 发现的问题是安装 ...
随机推荐
- 阿里云Centos操作Mysql
1. CentOS7 yum方式安装MySQL5.7 2.Centos下mysql导入sql 3.Centos设置远程 4.CentOS下mysql数据库常用命令总结 5.centos出现“Fire ...
- Android资源管理利器Resources和AssetManager
前言 : Android工程在运行的时候往往需要引用资源.使用 Resources 来获取 res 目录下的各种与设备相关的资源.而使用 AssetManager 来获取 assets 目录下的资源 ...
- Swoole4-swoole创建Mysql连接池
一 .什么是mysql连接池 场景:每秒同时有1000个并发,但是这个mysql同时只能处理400个连接,mysql会宕机. 解决方案:连接池,这个连接池建立了200个和mysql的连接,这1000个 ...
- cocos2d-x C++ 工程初探
经过较为繁琐的环境搭建后,我们终于运行出了一个helloworld窗口,可以正式上手cocos了 现在我们就从改代码开始玩起 窗口 我们之前讲到AppDelegate类是程序的入口,所以和窗口有关的设 ...
- B-概率论-常见的概率分布模型
目录 常见的概率分布模型 一.离散概率分布函数 二.连续概率分布函数 三.联合分布函数 四.多项分布(Multinomial Distribution) 4.1 多项分布简介 4.2 多项分布公式解析 ...
- Python flask 构建微电影视频网站☝☝☝
Python flask 构建微电影视频网站☝☝☝ 1.安装数据库连接依赖包 pip install flask-sqlalchemy 2.创建movie数据库 在CentOS虚拟机,进入MaridD ...
- Jenkins邮件收发(qq邮箱)
首先确认QQ邮箱SMTP服务器的地址和端口号.如下图所示,请谨记,JENKINS全局邮箱配置需要使用: 步骤1:开启QQ邮箱的smtp服务:登陆QQ邮箱-设置-账户-开启POP3/SMTP服务-完成“ ...
- Cobalt Strike之CHM、LNK、HTA钓鱼
CHM钓鱼 CHM介绍 CHM(Compiled Help Manual)即“已编译的帮助文件”.它是微软新一代的帮助文件格式,利用HTML作源文,把帮助内容以类似数据库的形式编译储存.利用CHM钓鱼 ...
- PHP list的赋值
List右边的赋值对象是一个以数值为索引的数组,左边的变量的位置和赋值对象的键值一一对应,有些位置的变量可以省略不写.非末尾的被赋值变量省略时,分隔的逗号不能省略.左边变量被赋值的顺序是从右到左的. ...
- Cocos2d-x 学习笔记(11.9) FadeTo FadeIn FadeOut
1. 用处 FadeTo:由正常变透明,是另两个的父类,不支持reverse()方法.FadeIn:变完全不透明.FadeOut:变完全透明. 2. 使用 FadeTo: GLubyte _toOpa ...