O!NO!缓存又挂了,redis不给力啊;哎哟我去,内存爆了?DBA干啥去了,怎么老是挂啊?
你的缓存是不是经常爆掉呢?是不是讨厌DBA经常叨叨叨的?跟唐僧一个样?如果是,那么可能是你还没玩会redis哦,为什么?因为缓存是用来对抗高并发热点数据请求的,而你可能将大量的长时间不使用的数据也放在里面了,白白浪费了内存。
今天教你一招,解决大量冷点数据白白浪费内存。
Redis中有个设置时间过期的功能,即对存储在redis数据库中的值可以设置一个过期时间。作为一个缓存数据库,这是非常实用的。然而很多的程序员并没有认识到这一点,比如我们要缓存用户的token,那么是不是你会将所有的都放入缓存?是的,然后问题是,下次又想缓存用户登录账号和密码加密串,又放入缓存,如果你有1000万用户,是不是发现内存不够了?
那么我们有必要将所有用户的token都一直保存在内存中吗?
答案显然不是,我们只需要缓存最近经常用的。那些1、2年都不登录一次的,显然放mysql更经济实惠。
那问题又来了,我怎么知道用户什么时候登录?
是的,不知道,所以用户注册之后,我们需要放进入,但是如果用户1个月没有登录,我们就可以删除了,释放内存。
哦。OK,我知道了,我写个定时任务,自动去判断就是了。
NO,NO,NO,根本用不着,redis已经给你解决方案了。那就是过期时间。只需要写入key的时候,设置好过期时间即可,剩下的交给redis。
如我们一般项目中的token或者一些登录信息,尤其是短信验证码都是有时间限制的。这正是它的用武之地。
有效时间设置:
redis对存储值的过期处理实际上是针对该值的键(key)处理的,即时间的设置也是设置key的有效时间。Expires字典保存了所有键的过期时间,Expires也被称为过期字段。
redis> SET key va1ue
OK
redis> EXPlRE key 1000
(integer) 1
四种处理策略
1. EXPIRE 将key的生存时间设置为ttl秒
2. PEXPIRE 将key的生成时间设置为ttl毫秒
3. EXPIREAT 将key的过期时间设置为timestamp所代表的的秒数的时间戳
4. PEXPIREAT 将key的过期时间设置为timestamp所代表的的毫秒数的时间戳
其实以上几种处理方式都是根据PEXPIREAT来实现的,设置生存时间的时候是redis内部计算好时间之后在内存处理的,最终的处理都会转向PEXPIREAT。 1、2两种方式是设置一个过期的时间段,就是咱们处理验证码最常用的策略,设置三分钟或五分钟后失效,把分钟数转换成秒或毫秒存储到redis中。 3、4两种方式是指定一个过期的时间 ,比如优惠券的过期时间是某年某月某日,只是单位不一样。
过期处理
过期键的处理就是把过期键删除,这里的操作主要是针对过期字段处理的。 Redis中有三种处理策略:定时删除、惰性删除和定期删除。
1. 定时删除:在设置键的过期时间的时候创建一个定时器,当过期时间到的时候立马执行删除操作。不过这种处理方式是即时的,不管这个时间内有多少过期键,不管服务器现在的运行状况,都会立马执行,所以对CPU不是很友好。因此,请注意,不要将大量的key过期时间设置到同一时间,因为同一时间删除操作,将消耗大量资源,可能导致线上redis不稳定,甚至crash。
2. 惰性删除:惰性删除策略不会在键过期的时候立马删除,而是当外部指令获取这个键的时候才会主动删除。处理过程为:接收get执行、判断是否过期(这里按过期判断)、执行删除操作、返回nil(空)。这种策略需要注意,因为可能会导致内存大量最近很少使用的key,占据内存,很少使用,则这个key没有访问,也就不会删除,还是占着内存。
3. 定期删除:这个一般是线上推荐方式,定期删除是设置一个时间间隔,每个时间段都会检测是否有过期键,如果有执行删除操作。同时也要注意,不要将大量的key过期时间设置为同一时间,同1策略类似。没有2策略的问题。
看完上面三种策略后可以得出以下结论: (1) 1、3为主动删除,2为被动删除。 (2) 1是实时执行的,线上慎重使用。(3) 2、3为被动删除,所以过期键应该会存在一定的时间,这样就使得过期键不会被立马删除,仍然占用着内存。但是惰性删除的时候一般是单个删除,相对来说对线上业务基本没有影响。(4)定期删除执行不能过于频繁,否则就可能会演变成定时删除,如果执行的过少就有可能造成过多过期键未被删除而占用过多内存。因此应该根据线上情况进行合理设置。
持久化与复制的影响
过期键删除策略对持久化以及复制的影响大致如下。
RDB: 1. 主服务器模式运行在载入RDB文件时,程序会检查文件中的键,只会加载未过期的,过期的会被忽略,所以RDB模式下过期键不会对主服务器产生影响。 2. 从服务器运行载入RDB文件时,会载入所有键,包括过期和未过期。当主服务器进行数据同步的时候,从服务器的数据会被清空,所以RDB文件的过期键一般不会对从服务器产生影响。
AOF: AOF文件不会受过期键的影响。如果有过期键未被删除,会执行以下动作: 客户端请求时(过期键):
1. 从数据库充删除被访问的过期键;
2. 追加一条DEL 命令到AOF文件;
3. 向执行请求的客户端回复nil(空)。
复制:
1. 主服务器删除过期键之后,向从服务器发送一条DEL指令,告知删除该过期键。
2. 从服务器接收到get指令的时候不会对过期键进行处理,只会当做未过期键一样返回。(为了保持主从服务器数据的一致性)
3. 从服务器只有接到主服务器发送的DEL指令后才会删除过期键。
清理内存全局策略
当前已用内存超过maxmemory限定时,将触发主动清理策略。因为内存已经使用完了,然而缓存的数据中,可能存在一些长时间没有使用的数据,这时候我们可以根据一定的策略,进行有选择的删除清理,以保障内存中缓存的都尽可能是热点数据。
volatile-lru:只对设置了过期时间的key进行LRU(默认值)因此采用这种策略的redis,请将所有key设置过期时间。一般线上我们也推荐设置过期时间。
allkeys-lru : 删除lru算法的key,这种策略不区分是否设置过期时间,key是否过期,是判断哪些是最近最少使用的,进行删除,避免有的设置了过期时间,而有的没有设置,永不过期。
volatile-random:随机删除即将过期key,随机删除,但只是删除快要过期的当中去随机删除。如果你没有设置过期时间,则不会删除。
allkeys-random:随机删除,这是类似volatile-random,不同的是,它不区分是否过期,对所有key有效。
volatile-ttl : 删除即将过期的。这个策略,则不计算LRU原则,而是只判断即将要过期的,如果没有设置过期时间,则不会删除。
noeviction : 永不过期,返回错误。如果你所有的key都设置的永不过期,那么你有000万用户登录过,你的redis将会很快内存用完。无法写入的问题。线上杜绝全部都是永不过期。
Lru是什么?就是按照最近最少使用的原则,比如长时间没有登录过的用户,就可以删除它的key,下次登录从数据库读取出来。因为redis大多在内存操作,因此内存是很宝贵的,一定是给最常用的进行缓存,也就是缓存热点数据。
看完今天的内容,是不是应该理解一下数据库管理的抱怨,数据库被爆满,内存枯竭,其实很多都是我们程序写入数据的时候,不配置过期时间,导致实际上存了大量不常用的数据,而内存经常不够用,或是内存消耗过高。
尊敬的程序员朋友们,今天的小知识mark到了吗?