首页 > 技术文章 > Redis删除策略,逐出算法,核心配置,高级数据类型

yugehard 2020-11-10 00:56 原文

Redis删除策略

Redis中的数据特征

过期数据:Redis是一种内存级数据库,所有数据均存放在内存中,内存中的数据可以通过TTL指令获取其状态

XX:具有时效性的数据 ;-1:永久有效的数据 ; -2:已经过期的数据或被删除的数据或未定义的数据。

时效性数据的存储结构

数据删除策略的目标

在内存占用与CPU占用之间寻找一种平衡,丢掉任何一个都会造成整体redis性能的下降,甚至引发服务器宕机或内存泄露。

定时删除

创建一个定时器,当key设置有过期时间,当过期时间一到达,由定时器任务马上会对键执行删除操作 。优点:节约Redis内存空间,快速释放掉不必要的内存占用 。缺点:会给CPU造成很大的压力,不管什么情况均占用CPU,会影响redis服务器响应时间和指令吞吐量 总的来说,是用处理器性能换取存储空间。

惰性删除

数据到达过期时间,不做处理。等下次访问该数据时,如果未过期,返回数据 ,如果已过期,删除,返回不存在 。优点:节约CPU性能,发现必须删除的时候才删除 。 缺点:给内存造成压力,长期会出现占用内存的数据 。总的来说,用存储空间换取处理器性能 。

定期删除

为了优化删除策略,可以采取定期删除。Redis启动服务器初始化时,读取配置server.hz的值,默认为10。每秒钟执行server.hz次serverCron()-->databasesCron()-->activeExpireCycle()。activeExpireCycle()对每个expires[]逐一进行检测,每次执行250ms/server.hz。 对某个expires[]检测时,随机挑选W个key检测:如果key超时,删除key;如果一轮中删除的key的数量>W25%,循环该过程,并随机删除多余的值;如果一轮中删除的key的数量<=W25%,检查下一个expires[],0-15循环(默认值设置为16的话);W取值=ACTIVE_EXPIRE_CYCLE_LOOKUPS_PER_LOOP属性值;参数curret_db用于记录activeExpireCycle()进入哪个expires[]执行;如果activeExpireCycle()执行时间到期,下次从current_db继续向下执行。

特点

周期性轮询redis库中的时效性数据,采用随机抽取的策略,利用过期数据占比的方式控制删除频度 。 特点:CPU性能占用设置有峰值,检测频度可自定义设置 。内存压力不是很大,长期占用内存的不平凡活跃的数据会被持续清理 。 总结:周期性随机抽查存储空间。

删除策略选择

在不同的场合采取不同的方案,当然,也可以折中选者,定时删除,节约内存,占用CPU频率高,惰性删除,内存占用严重,延时执行,CPU利用率高,定期删除:内存定期随机清理,CPU频率稳定,随机抽查。一般来说,选择定期清理是比较好的选择。

逐出算法

概念

为了检测内存是否充足,在执行每一个命令前,会调用freeMemoryIfNeeded()检测内存是否充足。如果内存溢出了,redis要临时删除一些数据为当前指令清理存储空间。清理数据的策略称为逐出算法。

逐出数据的过程不是完全能够清理出足够的可使用的内存空间,如果不成功则反复执行。当对所有数据尝试完毕后,如果不能达到内存清理的要求,将出现错误信息。

(error) OOM command not allowed when used memory >'maxmemory'

数据逐出的相关配置

最大可使用内存 maxmemory 默认值为0,表示占用物理内存的比例不限制,通常设置在50%以上。

每次选取待删除数据的个数 maxmemory-samples 采用随机获取数据的方式作为待检测删除数据。

删除策略 maxmemory-policy 达到最大内存后的,对被选出来的数据进行删除的策略。

检测易失数据(可能会过期的数据集server.db[i].expires ) volatile-lru:挑选最近最长时间未使用的数据淘汰 volatile-lfu:挑选最近使用次数最少数据淘汰 volatile-ttl:挑选将要过期的数据淘汰 volatile-random:任意选择数据淘汰

检测全库数据(所有数据集server.db[i].dict ) allkeys-lru:挑选最近最长时间未使用的数据淘汰 allkeys-lfu:挑选最近使用次数最少的数据淘汰 allkeys-random:任意选择数据淘汰

放弃数据驱逐 no-enviction:禁止驱逐数据(redis4.0中默认策略),当内存不足以容纳新写入数据时,新写入操作或报错会引发错误OOM(Out Of Memory)。

通过info可以查看命中和丢失次数。

Redis核心配置

服务器端设定

绑定主机地址 bind 127.0.0.1 设置数据库数量 databases 16

日志配置

设置服务器以指定日志记录级别 loglevel debug|verbose|notice|warning

日志记录文件名 logfile 端口号.log 在开发时期设置为verbose,在生产环境时期

设置为notice,简化日志,降低IO频率。

客户端配置

设置同一时间最大客户端连接数,默认0为无限制。当客户端连接到达上限,Redis会关闭新的连接 maxclients 0

客户端闲置等待最大时长,达到最大值后关闭连接。如需关闭该功能,设置为 0 timeout 300

多服务器快捷配置

导入并加载指定配置文件信息 include /path/server-端口号.conf

高级数据类型

Bitmaps类型的基础操作

获取指定key对应偏移量上的bit值 getbit key offset

设置指定key对应偏移量上的bit值,value只能是1或0 setbit key offset value

设置offset偏移量值不易过大,容易耗费性能,然而我这里没有显示耗费时间信息

Bitmaps类型的扩展操作

应用场景:电影网站统计状态(信息状态统计)

对指定key按位进行交、并、非、异或操作,并将结果保存到destKey中

bitop op destKey key1 [key2...] and:交 or:并 not:非 xor:异或

统计指定key的数量 bitcount key [start end]

统计的是状态,而不是数量。

HyperLogLog

应用于统计独立UV

基数:是数据集去重后元素个数,HyperLogLog是用来做基数统计的,运用了LogLog算法。例如:{2, 4, 6, 7, 6, 7, 8} 基数集: {2,4,6,7,8} 基数:5;{6, 6, 6, 6, 6, 9, 6} 基数集: {6,9} 基数:2.

基本操作

添加数据 pfadd key element [element ...] 统计数据 pfcount key [key ...] 合并数据 pfmerge destkey sourcekey [sourcekey...]

实操

应用于独立信息统计

相关说明

仅仅只用于基数统计,不保存数据,只是记录数量而不是具体数据,运用的是基数估算算法,最终数值存在一定误差,其误差范围大概是0.81%标准错误的近似值,占用空间小,每个键占用了12k的内存用于标记基数,添加命令不是一次分配12k内存使用,而是会随着基数的增加消耗的内存逐渐增大,Pfmerge命令合并后占用的存储空间为12K,不管合并之前数据量是多少。

GEO

应用场景: 应用于地理位置计算

基本操作:

添加坐标点 geoadd key longitude latitude member [longitude latitude member ...] ; 获取坐标点 geopos key member [member ...]

计算坐标点距离geodist key member1 member2 [unit]

添加坐标点 georadius key longitude latitude radius m|km|ft|mi [withcoord] (坐标)[withdist] (返回结果会带上匹配位置与给定地理位置的距离) [withhash] (hash值) [count count] (指定数量的结果)

获取坐标点 georadiusbymember key member radius m|km|ft|mi [withcoord] [withdist] [withhash] [count count]

计算经纬度 geohash key member [member ...]

先添加数据,根据成员名称和范围获取坐标点

根据给定地理位置坐标获取指定范围内的地理位置集合。geohash可以获取某个地理位置的geohash值

推荐阅读