Redis String类型应用场景

Redis作为一个KV数据库服务,其中K(Key)一般都是String类型,V(Value)有很多类型,如:

  • String
  • Hash哈希表
  • List列表
  • Set集合(分无序和有序)

基本操作

对于一个K-V类数据库,常用的操作有GET,SET,DELETE,EXIST等

String类型

常用的操作是

Set

127.0.0.1:6379> set hello 1
OK

Get

127.0.0.1:6379> get hello
"1"

但是这样操作数据是永久保存的(正常情况下不会消失)
可以用TTL命令查看key的到期时间

127.0.0.1:6379> ttl hello
(integer) -1

这里返回-1就表示key永远不会过期;

也可以给key设置一个到期时长,使用EXPIRE命令

127.0.0.1:6379> expire hello 10
(integer) 1

返回1表示成功

然后再查看TTL 可以看到key的剩余到期时间

127.0.0.1:6379> ttl hello
(integer) 8

如果key已经过期了 使用ttl会返回-2,表示key不存在

127.0.0.1:6379> ttl hello
(integer) -2

这个时候再使用GET 返回nil,表示key确实已经不存在了

127.0.0.1:6379> get hello
(nil)

有些时候我们需要在set的同时并设置过期时间,这样可以作为一个原子操作,可以使用setex

127.0.0.1:6379> setex hello 10 1
OK
127.0.0.1:6379> ttl hello
(integer) 8

或者

127.0.0.1:6379> set hello 10 EX 1
OK
127.0.0.1:6379> ttl hello
(integer) 8

实际应用场景

1.热销商品信息的缓存

需要展示的商品信息序列化后以string的方式存放在redis里。

127.0.0.1:6379> set hot_goods '[{"goods_id":1,"goods_name":"xxx"},{"goods_id":2,"goods_name":"xxx"}]'
OK

查询的时候可以直接查redis然后反序列化。


2.设置一个有到期时间的锁

使用场景分布式锁,设置一个60s到期的key
先检查锁是否存在

127.0.0.1:6379> exists lock
(integer) 0

设置锁

127.0.0.1:6379> setex lock 60 1 
OK

中间进行业务逻辑操作

最后删除锁

127.0.0.1:6379> del lock
(integer) 1

这样就保证只能同时有一个任务在进行业务逻辑操作执行,其他操作在exists命令的时候 会返回1 表示lock这个key存在,业务逻辑上就可以进行跳过不处理;
但是这里面还有一个问题,比如有两条同时执行的任务,都同时触发了exists命令,这时都会返回0
那么都会进入setex lock 60 1命令,并且都会返回OK,这样不就不符合设计的预期了。
可以这样改
将setex命令换成

127.0.0.1:6379> set lock 1 EX 10 NX
OK

在lock过期之前再次执行,将返回nil 表示不成功,这样就可以判断已经有其他任务在执行,业务上也进行跳过处理;

127.0.0.1:6379> set lock 1 EX 10 NX
(nil)

EX(expiration)表示设置到期时间,NX表示在key不存在时才set成功,当然还有一个反向的XX表示key存在时才set成功。


3.时间段内限频

场景为1秒内只能处理10个请求,这是一种很常见的接口限频策略。
基于INCR命令 做自增,在不存在key的情况下 会默认创建一个key默认0 并自增+1,返回1

127.0.0.1:6379> incr i
(integer) 1

第二次调用,在原来的key的基础上自增+1 返回2;

127.0.0.1:6379> incr i
(integer) 2

但是这个key没有到期时间,无法满足在指定时间内判断有多少个请求的预期
所以还需要调用expire,设置1s

127.0.0.1:6379> expire i 1
(integer) 1

可以这样写程序逻辑

# 伪代码
maxCount = 10
count = redis.incr("i")
if count == 1 {
	// 第一次设置key 添加过期时间
	redis.expire("i", 1)
}
// 如果超过最大允许值,返回false
if count > maxCount {
	return false
}
return true

以上就是一些常用的使用场景


对于第三个场景,还是会有一种极限情况导致功能出现bug