Redis高级用法

介绍Redis高级用法。

事务

Redis事务是一组命令的集合。

事务命令一样都是Redis的最小执行单元

首先需要multi命令来开始事务,用exec命令来执行事务,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
127.0.0.1:6379> multi
OK
127.0.0.1:6379> hset user:1 name xiaoming
QUEUED
127.0.0.1:6379> hset user:1 name daxiong
QUEUED
127.0.0.1:6379> exec
1) (integer) 0
2) (integer) 0
127.0.0.1:6379> hgetall user:1
1) "name"
2) "daxiong"
3) "score"
4) "61"
  • multi代表事务的开始,返回ok表示成功;
  • exec代表事务的执行,返回各个命令的执行结果;
  • multiexec中间添加需要执行的命令。

multi开始后,所有命令都不会执行,而是全部暂时保存起来,在执行exec命令后会按照命令保存的顺序依次执行各个命令。

Redis的事务仅保证命令的顺序执行。
Redis事务中的异常无法回滚。

某一个命令执行失败后其他命令不会继续执行,但失败之前的命令无法撤销。

watch

watch命令可以监控一个或多个键值的变化,一旦其中一个键被改变,之后的事务就不会执行,而且监控会一直持续到exec命令。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
127.0.0.1:6379> set key 1
OK
127.0.0.1:6379> watch key
OK
127.0.0.1:6379> set key 2
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set key 3
QUEUED
127.0.0.1:6379> exec
(nil)
127.0.0.1:6379> get key
"2"

生存时间

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#设置key的超时时间,超时后redis会自动删除给key值,类似于memcache中的超时时间。

expire key seconds
//设置成功返回1,失败返回0
127.0.0.1:6379> set session:aabb uid1122
OK
127.0.0.1:6379> expire session:aabb 300
(integer) 1
127.0.0.1:6379> del session:aabb
(integer) 1
127.0.0.1:6379> expire session:aabb 300
(integer) 0

127.0.0.1:6379> expire session:aabb 300
(integer) 1
127.0.0.1:6379> ttl session:aabb
(integer) 290

# 查询剩余超时时间

ttl key
127.0.0.1:6379> expire session:aabb 300
(integer) 1
127.0.0.1:6379> ttl session:aabb
(integer) 290

# 取消超时时间

127.0.0.1:6379> get session:aabb
"300"
127.0.0.1:6379> ttl session:aabb
(integer) 280
127.0.0.1:6379> persist session:aabb
(integer) 1
127.0.0.1:6379> ttl session:aabb
(integer) -1

缓存数据

当Redis作为缓存使用的时候,需要考虑缓存的大小以及缓存的失效时间,尽量避免触发Redis内存清理策略。

maxmemory参数用来配置Redis的最大内存,及时调整该参数以满足系统对于缓存的需求,避免不需要的缓存失效,造成缓存穿透等问题。

当超过maxmemory的限制后,Redis会根据maxmemory-policy参数指定的策略(包括LRU等算法)来删除不需要的键。

排序

sort命令支持对集合类型、类表类型、有序集合类型进行排序。

对于排序命令来说,需要注意排序的数据集的大小,否则会影响性能。

sort命令的时间复杂度O(n+mlogm ),n是集合元素个数,m表示要返回的元素个数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# 列表排序

127.0.0.1:6379> lpush list 1 2 6 3 4 9 8
(integer) 7
127.0.0.1:6379> sort list
1) "1"
2) "2"
3) "3"
4) "4"
5) "6"
6) "8"
7) "9"

# 有序集合的值进行排序:

127.0.0.1:6379> zadd set 50 2 40 3 20 1 60 5
(integer) 4
127.0.0.1:6379> sort set
1) "1"
2) "2"
3) "3"
4) "5"

# 倒序排序

127.0.0.1:6379> sort set desc
1) "5"
2) "3"
3) "2"
4) "1"

BY参数

by参数是配合sort命令使用的,类似MySQL中的Order By

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# 向userids中添加三个用户id

127.0.0.1:6379> lpush userids 1 2 3
(integer) 3

# 其次,分别对三个用户添加分数

127.0.0.1:6379> set user_score_1 50
OK
127.0.0.1:6379> set user_score_2 30
OK
127.0.0.1:6379> set user_score_3 70
OK

# 最后,使用sort、by命令来对对用户按照默认情况以及分数的递增和递减进行排序。

127.0.0.1:6379> sort userids
1) "1"
2) "2"
3) "3"
127.0.0.1:6379> sort userids by user_score_*
1) "2"
2) "1"
3) "3"
127.0.0.1:6379> sort userids by user_score_* desc
1) "3"
2) "1"
3) "2"

GET参数

get参数是配合sort命令使用的。

sort命令返回的结果往往不是我们需要的,通过get参数中指定的键值。

1
2
3
4
5
6
7
8
127.0.0.1:6379> sort userids by user_score_* get user_name_*
1) "xiaoming"
2) "daxiong"
3) "xiaohong"
127.0.0.1:6379> sort userids by user_score_* desc get user_name_*
1) "xiaohong"
2) "daxiong"
3) "xiaoming"

任务队列

任务队列一般适用于生产者和消费者之间通信的。

通过Redis中列表类型来实现任务队列,保持一个先进先出的顺序,具体方法:

  • 创建一个List
  • 生产者主动lpush数据
  • 消费者去rpop数据。

问题:消费者需要主动去请求数据,周期性的请求会造成资源的浪费。

Redis提供了brpop命令来解决这个问题。

brpop命令拉取数据的过程中,如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。

1
BRPOP     key     timeout # 如果`timeout`设置为0,那么就会无限等待下去

优先级队列

基于任务队列,如何实现优先级队列呢?

通过配置多个任务队列,代码层面上定义队列的优先级,从而实现优先级队列

发布/订阅模式

Redis提供了rabitmq类似的发布订阅模式,通过生产者使用下面的命令来发布消息,

1
2
PUBLISH       CHANNEL     MESSAGE  # 发布
SUBSCRIBE CHANNEL MESSAGE # 订阅
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 生产者向channel.test发布消息

127.0.0.1:6379> publish channel.test hello
(integer) 0 #返回0表明订阅者为0,没有发布消息
127.0.0.1:6379> publish channel.test hello
(integer) 1 #返回n表明订阅者为n,成功发布给1个消费者

# 消费者订阅channel.test消息

127.0.0.1:6379> subscribe channel.test
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "channel.test"
3) (integer) 1

# 消费者接收到来自channel.test的消息
1) "message"
2) "channel.test"
3) "hello"

管道

Redis的底层通信协议对管道提供了支持。

在多个命令没有相互关联的关系情况下,可以实现

  • 多条命令批量发送
  • 结果批量返回
  • 批量请求和执行提高执行效率

通过管道可以一次性发送多条命令并在执行完后一次性将结果返回;
当一组命令中每条命令都不依赖之前命令的执行结果时就可以将这组命令一起通过管道发出;
管道通过减少客户端与Redis的通信次数来实现降低往返实验累计值的目的。

节省内存空间

Redis的使用虽然很方便,但是还是需要我们掌握合理的使用方式。

  • 精简缓存的键
  • 适当压缩缓存的值(Hessian/ProtoBuf)