Redis学习笔记---进阶篇

Redis学习笔记—进阶篇

一、事务

1.MULTI命令

Redis中的事务(transaction)是一组命令的集合。一个事务中的命令要么都执行,要么都不执行。Redis通过MULTI开启事务,之后的命令将被存储在等待执行的事务队列中,使用EXEC命令将等待执行的事务队列中的所有命令按照发送顺序依次执行。EXEC命令的返回值就是这些命令的返回值组成的列表。返回值顺序和命令的顺序相同。

127.0.0.1:6379> multi
OK

127.0.0.1:6379> sadd "user:1:following" 2
QUEUED
127.0.0.1:6379> sadd "user:2:followers" 1
QUEUED

127.0.0.1:6379> exec
1) (integer) 1
2) (integer) 1

2.错误处理

a. 语法错误。指命令不存在或者命令参数的个数不对。只要有一个命令有语法错误,执行EXEC命令之后Redis就会直接返回错误,连语法正确的命令也不会执行。

127.0.0.1:6379> multi
OK

127.0.0.1:6379> set key value
QUEUED
127.0.0.1:6379> set key
(error) ERR wrong number of arguments for 'set' command
127.0.0.1:6379> errorcommand key
(error) ERR unknown command `errorcommand`, with args beginning with: `key`,

127.0.0.1:6379> exec
(error) EXECABORT Transaction discarded because of previous errors.

b. 运行错误。如果事务里的一条命令出现了运行错误,事务里其他的命令依然会继续执行。

127.0.0.1:6379> multi
OK

127.0.0.1:6379> set  key 1
QUEUED
127.0.0.1:6379> sadd key 2
QUEUED
127.0.0.1:6379> set key 3
QUEUED

127.0.0.1:6379> exec
1) OK
2) (error) WRONGTYPE Operation against a key holding the wrong kind of value
3) OK

127.0.0.1:6379> get key
"3"

Redis的事务没有关系数据库事务提供的回滚(rollback)功能。

3.WATCH命令

watch命令可以监控一个或多个键,一旦其中有一个键被修改(或删除),之后的事务就不执行。监控一直持续到EXEC命令。

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"

执行EXEC命令后会取消对所有键的监控,如果不想执行事务中的命令也可以使用UNWATCH命令来取消监控。

二、过期时间

1.EXPIRE命令

使用expire命令设置一个键的过期时间,到时间后Redis会自动删除它。

EXPIRE命令的使用方法为 EXPIRE key seconds,其中seconds参数表示为键的过期时间,单位为秒。

EXPIRE命令返回1表示设置成功,返回0则表示键不存在或设置失败

TTL命令可以查看一个键还有多少时间会被删除。当键不存在时TTL命令返回-2没有为键设置过期时间返回为 -1.

127.0.0.1:6379> set  username jenkin
OK
127.0.0.1:6379> expire username 60
(integer) 1

127.0.0.1:6379> ttl username
(integer) 44

127.0.0.1:6379> del username
(integer) 1

127.0.0.1:6379> expire username 60
(integer) 0

127.0.0.1:6379> ttl username
(integer) -2

127.0.0.1:6379> set username jenkin
OK

127.0.0.1:6379> ttl username
(integer) -1

PERSIST命令可以取消键的过期时间(即将键恢复成永久的)。如果过期时间被成功清除,则返回1,否则返回0.

127.0.0.1:6379> set foo bar
OK

127.0.0.1:6379> expire foo 44
(integer) 1

127.0.0.1:6379> persist foo
(integer) 1

127.0.0.1:6379> ttl foo
(integer) -1

使用setgetset命令为键赋值也会同时清除键的过期时间。

EXPIRE命令的seconds参数必须是整数,最小单位是1秒。

PEXPIRE命令可以设置更精确的过期时间,最小单位是1毫秒,可以使用PTTL命令以毫秒为单位返回键的剩余时间。

2.缓存

通过修改配置文件/usr/local/etc/redis.conf(mac系统,通过homebrew安装的Redis)的maxmemory参数,限制Redis最大可用内存大小(单位是字节),当超出这个限制时Redis会根据maxmemory-policy参数指定的策略来删除不需要的键直到Redis占用的内存小于指定内存。默认的策略是noeviction

maxmemory-policy支持的规则:

volatile-lru:使用LRU算法删除一个键(只对设置了过期时间的键)

allkeys-lru:使用LRU算法删除一个键

volatile-random:随机删除一个键(只对设置了过期时间)

allkeys-random:随机删除一个键

volatile-ttl:删除过期时间最近的一个键

noeviction:不删除键,只返回错误

三、排序

1.有序集合的集合操作

有序集合的操作是将运算结果存入新的键中,以便后续处理。比如zinterstorezunionstore等操作。如果需要直接获取运算结果,可以使用multi、zinterstore、zrange、del和exec等命令自己实现。

127.0.0.1:6379> sadd num1 1 2 3
(integer) 3
127.0.0.1:6379> sadd num2 2 3 4
(integer) 3

127.0.0.1:6379> multi
OK
127.0.0.1:6379> zinterstore d 2 num1 num2
QUEUED
127.0.0.1:6379> zrange d 0 -1
QUEUED

127.0.0.1:6379> exec
1) (integer) 2
2) 1) "2"
   2) "3"

2.SORT命令

sort命令可以对列表类型、集合类型和有序集合类型键进行排序。

127.0.0.1:6379> lpush score 45 89 76 65 91
(integer) 5
127.0.0.1:6379> lrange score 0 -1
1) "91"
2) "65"
3) "76"
4) "89"
5) "45"

127.0.0.1:6379> sort score
1) "45"
2) "65"
3) "76"
4) "89"
5) "91"

在对有序集合类型排序时会忽略元素的分数,只针对元素自身的值进行排序。

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

除了可以对数字排列外,还可以通过ALPHA参数实现按照字典顺序排列非数字元素。

sort默认是按从小到大的顺序排列,通过DESC参数可以实现将元素按照从大到小的顺序排列。LIMIT参数返回指定范围的结果。

127.0.0.1:6379> lpush letter a d c G B e F
(integer) 7

127.0.0.1:6379> sort letter
(error) ERR One or more scores can't be converted into double

127.0.0.1:6379> sort letter alpha
1) "B"
2) "F"
3) "G"
4) "a"
5) "c"
6) "d"
7) "e"

127.0.0.1:6379> sort letter alpha desc
1) "e"
2) "d"
3) "c"
4) "a"
5) "G"
6) "F"
7) "B"

127.0.0.1:6379> sort letter alpha desc limit 2 4
1) "c"
2) "a"
3) "G"
4) "F"

3.BY参数

语法为 BY 参考键,参考键可以是字符串类型键或者是散列类型键的某个字段(表示为键名->字段名)

如果提供了BY参数,sort命令将不再依据元素自身的值进行排序,而是对每个元素使用元素的值替换参考键中的第一个“*”并获取其值,然后依据该值对元素排序。

127.0.0.1:6379> lpush l 2 1 3
(integer) 3
127.0.0.1:6379> set itemscore:1 50
OK
127.0.0.1:6379> set itemscore:2 100
OK
127.0.0.1:6379> set itemscore:3 -10
OK

127.0.0.1:6379> sort l by itemscore:*
1) "3"
2) "1"
3) "2"
127.0.0.1:6379> sort l by itemscore:* desc
1) "2"
2) "1"
3) "3"

当参考键名不包含“*”时(即常量键名,与元素值无关),sort命令将不会执行排序操作。

如果几个元素的参考键值相同,则sort命令会再比较元素本身的值来决定元素的顺序。

当某个元素的参考键不存在时,会默认参考键值的值为 0.

4.GET参数

get参数不影响排序,他的作用是使sort命令的返回结果不再是元素自身的值,而是GET参数中指定的键值。get参数也支持字符串类型和散列类型的键,并使用“*****”作为占位符。有N个get参数,每个元素返回的结果就有N行。

127.0.0.1:6379> sort tag:ruby:posts by post:*->time desc get post:*->title get post:*->time get #
1) "Windows 8 app designs"
2) "1345667878"
3) "12"
4) "Uses for cURL"
5) "1345667877"
6) "12"
7) "The nature of ruby"
8) "1345667876"
9) "6"

get # 会返回元素本身的值

5.STORE参数

默认下SORT会直接返回排序结果,如果希望保存排序结果,可以使用STORE参数。保存后的键的类型为列表类型,如果键已经存在则会覆盖它。加上store参数后sort命令返回的是结果的个数。

127.0.0.1:6379> sort tag:ruby:posts by post:*->time desc get post:*->title get post:*->time get # store sort.result
(integer) 9

127.0.0.1:6379> lrange sort.list 0 -1
1) "Windows 8 app designs"
2) "1345667878"
3) "12"
4) "Uses for cURL"
5) "1345667877"
6) "12"
7) "The nature of ruby"
8) "1345667876"
9) "6"

STORE参数常用来结合EXPIRE命令缓存排序结果。

6.性能优化

SORT命令的时间复杂度O(n+mlog(m)),其中n表示要排序的列表中的元素个数,m表示要返回的元素个数。

使用SORT命令时需注意几点:

①尽可能减少待排序键中元素的数量(使N尽可能小)。

②使用LIMIT参数只获取需要的数据(使M尽可能小)。

③如果要排序的数据数量较大,尽可能使用STORE参数将结果缓存。

四、消息通知

1.任务队列

使用任务队列的好处:

​ ①松耦合:生产者和消费者无需知道彼此的实现细节,只需要约定好任务的描述格式。

​ ②易于扩展:消费者可以有多个,而且可以分布在不同服务器中,也能降低单台服务器的负载。

2.使用Redis实现任务队列

通过使用LPUSHRPOP命令就可实现队列的概念。如果要实现任务队列,只需要让生产者将任务使用LPUSH命令加入到某个键中,另一个边让消费者不断地使用RPOP命令从改建中取出任务即可。

BRPOP命令与RPOP命令相似,区别在于当列表中没有元素时BRPOP命令会一直阻塞住连接,直到有新的元素加入。

BRPOP命令接收两个参数:第一个是键名,第二个是超时时间,单位是秒,当超过此时间仍然没有获得新元素的话就会返回nil。超时时间为”0“,表示不限制等待时间,即如果没有新元素加入列表就会永远阻塞下去。

3.队列优先级

BRPOP命令可以同时接收多个键,意义是同时检测多个键,如果所有键都没有元素则阻塞,如果其中有一个键有元素则会从该键中弹出元素。

如果多个建都有元素则按照从左到右的顺序取第一个键中的一个元素。

4."发布/订阅"模式

发布/订阅“模式中包含两种角色,分别是发布者订阅者。订阅者可以订阅一个或若干个频道(channel),而发布者可以向指定的频道发送消息,所有订阅此频道的订阅者都会收到此消息。

  1. 发布者发布消息的命令是PUBLISH,用法是 PUBLISH channel message。发出去的消息不会被持久化,也就是说当有客户端订阅channel后只能收到后续发布到该频道的消息,之前发送的就收不到了。

  2. 订阅频道的命令是SUBSCRIBE,可以同时订阅多个频道,用法是 SUBSCRIBE channel [channel...]。

  3. UNSUBSCRIBE命令可以取消订阅指定的频道,如果不指定频道则会取消订阅所有频道。

5.按照规则订阅

使用PSUBSCRIBE命令可以订阅指定的规则。

PUNSUBSCRIBE命令可以退订指定的规则,如果没有参数则会退订所有规则。

使用PUNSUBSCRIBE命令只能退订通过PSUBSCRIBE命令订阅的规则,不会影响直接通过SUBSCRIBE命令订阅的频道。UNSUBSCRIBE命令也不会影响通过PSUBSCRIBE命令订阅的规则。

五、管道

不管是客户端向Redis发送命令还是Redis向客户端返回命令的执行结果,都需要经过网络传输,这两个部分的总耗时称为往返时延

Redis的底层通信协议对管道(pipelining)提供了支持。通过管道可以一次性发送多条命令并在执行完后一次性将结果返回,当一组命令中每条命令都不依赖于之前命令的执行结果时就可以将这组命令一起通过管道发出。管道通过减少客户端与Redis的通信次数来实现降低往返时延累计值的目的。

六、节省空间

1.精简键名和键值

2.内部编码优化


个人博客:https://jenkinwang.github.io/

参考书籍:《Redis入门指南(第二版)》李子骅 编著

你可能感兴趣的:(Redis学习笔记---进阶篇)