Redis高级特性——键的操作

生存时间

在日常业务需求中,总有一些要在某时间节点,做一些特殊的操作这样的需求。如下订单后,需要支付,用户支付一般有一个限制时间,京东15分钟未支付,订单取消;12306在45分钟内未支付则预定火车票取消;再比如登录手机验证码,一般获取一个验证有效期为1分钟,一方面为了保证用户不至于刷短线,另一方面也能够防止一个手机验证码可以长期使用。这些业务需求,在关系型数据库中,一般添加一个到期时间字段,记录每个业务的到期时间,再起一个任务,不断去检查任务是否到期,这样的做法代价太大,耗费资源严重。在Redis中针对每个键都提供了设置生存时间的功能,一旦设置后,到期后Redis自动清除该键值,业务系统只要读取不到就意味着数据到期。

生存时间很重要,但在开发阶段无法做到设置一个非常合理的过期时间。为了尽可能的提高网站的并发量,需要将一些DB中的数据经过整合后,放入到Redis中,以达到提高并发的目的。一般情况下,服务器的内存是有限的,如果将大量的数据键设置为永久有效或具有很长的生存时间如一年;结果可能是在短时间内Redis内存占满,而当用户再继续使用新的DB数据时,将不能够再写入Redis,而使得并发降低,大量的请求直接读库。如果反过来,设置了大量的数据键生存时间较短,如1个小时,这样将会导致Redis数据频繁过期,这一方面也会造成一定的浪费,同时大量的数据过期,也会降低缓存命中率,从而导致很多并发请求转到读库操作,也会降低并发量。

考虑到这些问题,一般情况对于Redis的缓存过期会采用设置生存时间和Redis自有淘汰规则的组合方案。具体的设置方法:

  • 修改Redis的maxmemory参数(最大内存),该参数将会限制Redis的最大使用内存,单位为字节

  • 当一个缓存系统超过了最大内存时,Redis将会按照配置的maxmemory-policy策略进行缓存内数据的淘汰,直到Redis的缓存数量达到最大内存配置为止

Redis的maxmemory-policy支持六种策略,其中LRU最近最少使用的两种策略较为常用(最近最少使用的键,在未来的一段时间内,也会被最少使用到),以下算法会一个键一个键进行删除,直到满足条件。

策略 描述
volatile-lru LRU算法,删除键,只针对设置了生存时间的键
allkeys-lru LRU算法,针对所有键
volatile-random 随机删除键,只针对设置了生存时间的键
allkeys-random 随机删除键,全部键
volatile-ttl 删除生存时间最近的键
noeviction 不删除键,只返回错误信息

LRU算法,并不是完全从全库中进行排序后进行删除,而是随机的从Redis中读取三个键(默认,可以通过maxmemory-samples进行配置),并删除这三个键中最久未使用的键,依此反复,直到满足需求为止。volatile-ttl算法也是按此方法进行。

获取生存时间
TTL key
PTTL key

TTL指令用于获取一个键的生存时间,返回键剩余的生存时间,单位为秒。如返回12,则意味着键还有12秒就过期了。

PTTL指令同TTL基本一致,当指定了有效期时,该指令返回的是毫秒单位。

  • 当键不存在时,该指令返回-2
  • 当键存在,但未设置生存时间,则为永久有效,返回-1
  • 其他情况均返回键的剩余生存时间,单位为秒
TTL a   # 键a不存在
# (integer) -2
SET a 1
# OK
TTL a   # 创建键a,但未设置有效时间,永久有效
# (integer) -1
EXPIRE a 12
# (integer) 1
TTL a
# (integer) 10
PEXPIRE a 12300
# (integer) 1
PTTL a
# (integer) 10116
设置生存时间
EXPIRE key ttl_seconds
PEXPIRE key ttl_millseconds
  • EXPIRE指令用于设置键key的生存时间,单位为秒
  • PEXPIRE指令同EXPIRE指令一致,区别是单位是毫秒

这两个指令可以与TTL/PTTL相对应。指令返回值

  • 当键存在,设置成功时,返回1
  • 当键不存在或设置失败时,返回0
SET a 1
# OK
TTL a
# (integer) -1
EXPIRE a 10
# (integer) 1
TTL a 
# (integer) 8
TTL a 
# (integer) 2
TTL a 
# (integer) -2
SET a 1
# OK
PEXPIRE a 12300
# (integer) 1
TTL a 
# (integer) 8

EXPIRE aa 12    # aa 不存在
# (integer) 0

当设置有效期时,指定的ttl值为-1,则意味着删除该键。

SET a 1
# OK
EXPIRE a -1
# (integer) 1
TTL a
# (integer) -2
清除生存时间
PERSIST key

PERSIST指令可以将一个键的生存时间调整为永久有效,即TTL=-1。当成功调整键有效期为永久有效时,返回1;当键不存在或者键本身为-1时,返回0

除了PERSIST指令可以清除生存时间外,重新使用SET等赋值指令,也可以将原有的生存时间重置为-1

PERSIST a   # 键a不存在
# (integer) 0
SET a 1
# OK
PERSIST a   # a未设置有效期,永久有效
# (integer) 0
EXPIRE a 12300
# (integer) 1
TTL a
# (integer) 12296
PERSIST a
# (integer) 1
TTL a
# (integer) -1
指定时间点到期
EXPIREAT key timestamp
PEXPIREAT key timestamp

EXPIREAT指令也是用于设置key的生存时间,与EXPIRE相比,该指令使用一个时间戳作为第二个参数,意思是到指定的时间点时,该key过期。如设置当天23:00过期,则只要计算出单天23:00的时间戳即可。时间戳单位为秒。

PEXPIREAT指令同EXPIREAT指令一致,唯一区别是单位为毫秒。

当成功设置时,返回1。当键不存在,返回0;当时间戳比当前时间小,返回1,意味着删除键。

SET a 1
# OK
EXPIREAT a 1576561888   # 距离当前还有190秒
# (integer) 1
TTL a
# (integer) 185
PEXPIREAT a 1576561990123   # 距离当前还有139秒又123毫秒
# (integer) 1
PTTL a
# (integer) 127294
TTL a 
# (integer) 125
EXPIREAT a 1476561888   # 时间戳已过去
# (integer) 1
TTL a       # 键不存在
# (integer) -2  

删除键

DEL key [key ...]

DEL指令用于删除指定的一个键或多个键,返回成功删除的键数量。当指定的键不存在时,则不执行操作。

SET a 1
# OK
SET aa 12
# OK
SET aaa 123
# OK
DEL a
# (integer) 1
DEL a aa aaa
# (integer) 2

判断键是否存在

EXISTS key [key ...]

EXISTS指令用于判断指定的key在Redis中是否存在,如果存在,则返回1,不存在返回0。该指令可以同时判断多个key,返回的数量是1的累加,但同时指定多个key,仍无法确认具体的key是否存在。

EXISTS a    # a不存在
# (integer) 0
SET a 1
# OK
SET aa 1
# OK
EXISTS a
# (integer) 1
EXISTS a aa aaa
# (integer) 2

返回指定的键列表

KEYS pattern

KEYS指令用于返回指定模式的键列表信息。如果keys *将返回全部键列表,该指令在库数据量较大时,会阻塞Redis,如果在生产环境下,将会有一定的时间无法正确使用Redis,因此一般都不建议在生产环境使用该指令。

KEYS *
# 全库键列表
KEYS a  #只返回键a
# "a"
KEYS aa*    # 返回aa开头的所有键
# "aa"
# "aaa"

库间移动

MOVE key db

MOVE指令将从当前的库中,移动键到指定的库db中。移动成功时返回1,移动失败时返回0。默认情况下Redis实例安装成功后,将会默认创建0-15索引的16个库。该指令一次只能移动一个键。

# 选择库0
SELECT 0
# OK
KYES a*
# "a"
# "aa"
# "aaa"
MOVE a 1
# (integer) 1
MOVE a 1
# (integer) 0
EXISTS a
# (integer) 0
# 切换库1,库1未使用过
SELECT 1
# OK
KEYS *
# "a"

修改键名

RENAME key newKey
RENAMENX key newKey
  • RENAME指令用于将一个键名为key的键,修改为新键名newKey。当修改成功时,返回OK,其他情况返回错误信息。

key和newKey相同时,返回OK,相当于没有修改(不同版本的Redis可能存在差异)

key不存在时,返回错误信息

当key,newKey存在时,则使用key的值覆盖已存在的newKey

  • RENAMENX指令用于修改键名,但必须指定的newKey不存在时,才修改,如果newKey存在,则不做调整

修改成功时,返回1

newKey存在时,返回0

当key不存在时,返回错误

# key不存在
RENAME aaaaa ad
# no such key
RENAME a ab
# OK
GET aa
# "1"
GET aaa
# "2"
RENAME aa aaa       # 使用aa的值覆盖aaa的值
# OK
GET aa
# nil
GET aaa     # 原有的aaa被覆盖
# "1"

SET a 1
# OK
SET aa 2
# OK
DEL aaa
# (integer) 1
# 将a重命名为aaa
RENAMENX a aaa
# (integer) 1
EXISTS a
# 0
EXISTS aaa
# 1
# aa存在,不会调整
RENAMENX aaa aa
# (integer) 0
RENAMENX aaaaa aa
# no such key

返回键类型

TYPE key

TYPE指令用于检查key的数据类型。

SET a 1
# OK
ZADD b 1 c 2 d
# (integer) 2
SADD c 1 2
# (integer) 2
LPUSH d 1 2
# (integer) 2
HSET e a 1
# (integer) 1
TYPE a
# string
TYPE b
# zset
TYPE c
# set
TYPE d
# list
TYPE e
# hash

你可能感兴趣的:(Redis高级特性——键的操作)