如何给redis集合中的元素设置过时时间

咱们知道redis中的过时时间只能做用于key上。对于string数据结构来讲,由于它是key/value的形式,只有一个value与key对应,因此当过时时间到了,整个key/value被移除,符合心理预期,皆大欢喜。但好多时候咱们用到的是其余数据结构,好比:一个拥有多个元素的集合。因为过时时间只能做用于key(集合数据结构能够理解为集合ID)上,当过时时间到了,整个集合被移除。通常使用集合的场景都不但愿各个元素在同一时间过时,有时也但愿进行与时间相关的查询,这该怎么办呢?redis

 

redis有一种数据结构是Sorted Set,有序集合,它的实现是hash table(element->score, 用于实现zscore及判断element是否在集合内)和skiplist(score->element,按score排序)的混合体。 skiplist有点像平衡二叉树那样,不一样范围的score被分红一层一层,每层是一个按score排序的链表。其中zadd/zrem是O(log(N)),zrangebyscore/zremrangebyscore是O(log(N)+M),N是Set大小,M是结果/操做元素的个数。可见,本来可能很大的N被很关键的Log了一下,1000万大小的Set,复杂度也只是几十不到。固然,若是一次命中不少元素M很大那谁也没办法了。数据结构

 

这里咱们用到了它以下特性:运维

1. 元素惟一性能

2. 每一个元素拥有一个score优化

3. 全部元素依据score进行有序排列编码

4. 可经过score来进行查询unix

咱们能够借助这些特性来让集合中的元素拥有时间维度。每当add一个元素时,把当前时间的unix timestamp做为score设置到这个元素上,这样sorted set会根据这个timestamp将元素排序存储。排序

 

场景一:当咱们查询最近1分钟内有更新的元素时,能够使用命令 zrangebyscore key min max来获取。例如:three

zadd set1 1522598879 "one"ip

zadd set1 1522598969 "two"

zadd set1 1522598979 "three"

执行查询:zrangebyscore set1 1522598920 1522598980

返回值:"two"和"three"

 

场景二:当咱们查询最新更新的2个元素,能够使用 zrevrange key start stop来获取。例如:

zadd set1 1522598879 "one"

zadd set1 1522598969 "two"

zadd set1 1522598979 "three"

执行查询:zrevrange set1 0 1

返回值:"three"和"two"

 

场景三:当咱们须要删除最近1分钟没有过更新的元素,能够使用 zremrangebyscore key min max 来删除过时元素。例如:

zadd set1 1522598879 "one"

zadd set1 1522598969 "two"

zadd set1 1522598979 "three"

执行命令: zremrangebyscore set1 0 1522598920

执行结果:删除了元素"one"

通常来说,咱们会启动一个后台任务来不断进行过时元素的删除操做,任务的重复执行间隔能够视业务对过时数据的容忍度。若是容忍度较高,能够设置时间久一点,相反能够设置时间短一些。

 

当咱们应用到生产环境时,还应该考虑内存占用和访问效率。有序集合的长度较短或者体积较小的时候,Redis能够选择使用ziplist的紧凑存储方式来存储这些结构,从而达到优化存储空间的目的。然而,ziplist会以序列化的方式存储数据,这些序列化数据每次被读取的时候都要就行解码,每次被写入的时候都要进行局部的从新编码,而且可能须要对内存里的数据进行移动。所以读写一个长度较大的ziplist可能会形成性能问题。从咱们的生产运维经验上来说,如下参数设置能够借鉴(根据业务和实际状况进行不断调整):

zset-max-ziplist-entries 128

zset-max-ziplist-value 64

即:当有序集合的元素都小于64字节而且元素数量小于128个的时候,使用ziplist,反之使用skiplist。

相关文章
相关标签/搜索