Redis 快速上手 - 进阶

611 阅读5分钟

这是我参与8月更文挑战的第 7 天,活动详情查看:8月更文挑战

本章重点介绍 redis 的高级应用,如应用于要求不是太严格的基于 发布-订阅模型 的消息队列;如对多条 redis 指令进行事务化管理以提高效率

我的 redis 系列,感兴趣的朋友也可以来看看

Redis 快速上手 - 安装配置

Redis 快速上手 - 常见数据结构和用法(一)

Redis 快速上手 - 常见数据结构和用法(二)

发布-订阅模式

图片.png

就好比我们大家都关注了一个微信订阅号,订阅号他一更新文章,就自动向所有关注了他的人去推送这篇文章

相关命令

pubsub subcommand [argument [argument ...]]

查看订阅与发布系统状态

127.0.0.1:16379> pubsub channels
(empty list or set)

subscribe channel [channel ...]

订阅给定的一个或多个频道的信息

127.0.0.1:16379> SUBSCRIBE channel-1
Reading messages... (press Ctrl-C to quit)
1) "subscribe"		# 指令
2) "channel-1"		# 订阅的频道
3) (integer) 1		# 成功订阅的数量

psubscribe pattern [pattern ...]

订阅一个或多个符合给定模式的频道

pattern 规则详解
?		占位符,必定匹配一个字符
*		通配符,匹配 0-n 个任意字符

消息订阅端

订阅满足表达式为 a?a, b*b 的频道

127.0.0.1:16379> PSUBSCRIBE a?a b*b
Reading messages... (press Ctrl-C to quit)
1) "psubscribe"
2) "a?a"
3) (integer) 1
1) "psubscribe"
2) "b*b"
3) (integer) 2

消息推送端

127.0.0.1:16379> publish aa 'hello'
(integer) 0
127.0.0.1:16379> publish aba 'hello'
(integer) 1
127.0.0.1:16379> publish abba 'hello'
(integer) 0
127.0.0.1:16379> publish bb 'hello'
(integer) 1
127.0.0.1:16379> publish bab 'hello'
(integer) 1
127.0.0.1:16379> publish baab 'hello'
(integer) 1

订阅端收到推送的消息

1) "pmessage"		# 消息类型
2) "a?a"		# 匹配的频道规则 
3) "aba"		# 实际匹配的频道
4) "hello"		# 收到的消息
---------------------------------
1) "pmessage"
2) "b*b"
3) "bb"
4) "hello"
---------------------------------
1) "pmessage"
2) "b*b"
3) "bab"
4) "hello"
---------------------------------
1) "pmessage"
2) "b*b"
3) "baab"
4) "hello"

publish channel message

将信息发送到指定的频道

# 消息推送端,像管道 channel-2 发送消息,推送失败,暂时没有客户端监听此管道
127.0.0.1:16379> PUBLISH channel-2 hello
(integer) 0
---------------------------
# 消息推送端,像管道 channel-1 发送消息,推送成功
127.0.0.1:16379> PUBLISH channel-1 hello
(integer) 1
# 监听管道的客户端,收到消息
127.0.0.1:16379> SUBSCRIBE channel-1
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "channel-1"
3) (integer) 1
1) "message"
2) "channel-1"
3) "hello"

unsubscribe [channel [channel ...]

退订所有给定模式的频道

punsubscribe [pattern [pattern ...]]

退订所有给定模式的频道

备注:如果尝试向一个未被监听的频道发送消息,会返回 0,表示 false

相关的命令可以总结为:

客户端订阅具体的频道 (subscribe),或者根据表达式去订阅(psubscribe)

客户端向具体的频道发送单条消息

客户端退订具体的频道,或者是根据表达式去退订频道

示例代码总结

图片.png

使用场景

最常见的使用场景就是替代 MQ

这里的替代是指,不接受引入 MQ 后系统的会变得更加复杂,不太好维护,并且,对消息的接收消费要求不严格,能容许消息丢失的风险,毕竟,MQ都会提供消息确认送达的机制来保证每一条信息都会被消费

这里,来和主流的 RabbitMQ 做对比:

  • redis: 轻量级,低延迟,高并发,低可靠性;
  • rabbitmq:重量级,高可靠,异步,不保证实时;

Redis 事务

介绍

或许很多人第一反应,redis 的事务,应该会和 spring 的事务是差不多的一个玩意,实际上,完全不同

redis 的事务,或者更加符合实际的描述,可以理解为 redis 命令的批量执行,具备如下特性:

  • 被事务包含的命令,会顺序执行,并且不会被其他客户端的命令打断
  • 事务命令在执行的过程中,假定中间有一条执行失败,不会中断事务,已经执行的命令不会回滚,后续的命令仍然会继续执行

一个标准事务的执行流程:

  1. 开启事务(使用指令 MULTI)
  2. 命令入队
    1. 输入 redis 的操作命令,不会立即执行,会先压入队列当中
    2. 可选操作,放弃当前事务,清空事务队列,使用指令 DISCARD
  3. 执行事务(使用指令 EXEC)

注:redis 的事务成功或者失败的点,只会依赖与 exec 指令是否执行

相关命令

multi

标记一个事务块的开始

exec

执行所有事务块内的命令

discard

取消事务,放弃执行事务块内的所有命令

watch key [key...]

监听1个或多个key,如果在事务执行之前这个(或这些) key 被其他命令所改动,那么事务将被打断


摘抄自 官方文档

为什么Redis不支持回滚?

如果你了解关系数据库,那么Redis事务处理机制看起来有点奇怪。

Redis事务中的命令允许失败,但是Redis会继续执行其它的命令而不是回滚所有命令。

这么做的原因有两点:

  • Redis 命令只在两种情况失败:
  • 语法错误的时候才失败(在命令输入的时候不检查语法)。
  • 要执行的key数据类型不匹配:这种错误实际上是编程错误,这应该在开发阶段被测试出来,而不是生产上。
  • 因为不需要回滚,所以Redis内部实现简单并高效。

当出现bug的时候Redis的这种做法并不友好,可是需要注意的是回滚并不能解决程序bug。

例如,对于需要增加1的逻辑增加了2,或者操作的key类型不对,这些情况回滚并没有什么帮助。

考虑到没有人能避免程序员错误,并且这种错误也基本不能进入生产环境,我们选择了更简单且更高效的方法,不支持错误回滚。