文章目录
- 一 发布/订阅命令
- 1.1 消息系统
- 1.2 subscribe
- 1.3 psubscribe
- 1.4 publish
- 1.5 unsubscribe
- 1.6 punsubscribe
- 1.7 pubsub
- 1.7.1 pubsub channels
- 1.7.2 pubsub numsub
- 1.7.3 pubsub numpat
- 二 Redis 事务
- 2.1 Redis 事务特性
- Redis 事务实现
- 2.1.1 三个命令
- 2.1.2 基本使用
- 2.2. Redis 事务异常处理
- 2.2.1 语法错误
- 2.2.2 执行异常
- 2.3 Redis 事务隔离机制
- 2.3.1 需要事务隔离机制的原因
- 2.3.2 隔离的实现
- 2.3.3 隔离的实现原理
一 发布/订阅命令
1.1 消息系统
- 发布/订阅(pub/sub),是一种消息通信模式:发布者【消息生产者】,生产和发送消息到存储系统;订阅者【消息消费者】,从存储系统接收和消费消息。这个存储系统可以是文件系统 FS、消息中间件 MQ、数据管理系统 DBMS,也可以是 Redis。 整个消息发布者、订阅者与存储系统称为消息系统。
- 消息系统中的订阅者订阅了某类消息后,只要存储系统中存在该类消息,其就可不断的接收并消费这些消息。当存储系统中没有该消息后,订阅者的接收、消费阻塞。而当发布者将消息写入到存储系统后,会立即唤醒订阅者。当存储系统放满时,不同的发布者具有不同的处理方式:有的会阻塞发布者的发布,等待可用的存储空间;有的则会将多余的消息丢失。
- 不同的消息系统消息的发布/订阅方式也是不同的。例如 RocketMQ、Kafka 等消息中间件构成的消息系统中,发布/订阅的消息都是以主题 Topic 分类的。而 Redis 构成的消息系统中,发布/订阅的消息都是以频道 Channel 分类的。

1.2 subscribe
- 格式:
SUBSCRIBE channel *channel …+ - 功能:Redis 客户端通过一个
subscribe命令可以同时订阅任意数量的频道。在输出了订阅主题后,命令处于阻塞状态,等待相关频道的消息。


1.3 psubscribe
- 格式:
PSUBSCRIBE pattern *pattern …+ - 功能:订阅一个或多个符合给定模式的频道
- 说明:这里的模式只能使用通配符
*。 如,it*可以匹配所有以 it 开头的频道,如it.news、it.blog、it.tweets;news.*可以匹配所有以news.开头的频道。


1.4 publish
- 格式:
PUBLISH channel message - 功能:Redis 客户端通过一条 publish 命令可以发布一个频道的消息,返回值为接收到该消息的订阅者数量。

1.5 unsubscribe
- 格式:
UNSUBSCRIBE *channel *channel …++ - 功能:Redis 客户端退订指定的频道
- 说明:如果没有频道被指定,会执行一个无参数的
unsubscribe命令,客户端使用SUBSCRIBE命令订阅的所有频道都会被退订。在这种情况下,返回一个信息,告知客户端所有被退订的频道

1.6 punsubscribe
- 格式:
PUNSUBSCRIBE *pattern *pattern …++ - 功能:退订一个或多个符合给定模式的频道
- 说明:这里的模式只能使用通配符
*。如果没有频道被指定,其效果与 SUBSCRIBE 命令相同,客户端将退订所有订阅的频道。

1.7 pubsub
- 格式:
PUBSUB <subcommand> [argument *argument …++ - 功能:
PUBSUB是一个查看订阅与发布系统状态的内省命令集,它由数个不同格式的子命令组成
1.7.1 pubsub channels
- 格式:
PUBSUB CHANNELS [pattern] - 功能:列出当前所有的活跃频道。活跃频道指的是那些至少有一个订阅者的频道。
- 说明:pattern 参数是可选的。如果不给出 pattern 参数,将会列出订阅/发布系统中的所有活跃频道。如果给出 pattern 参数,那么只列出和给定模式 pattern 相匹配的那些活跃频道。pattern 中只能使用通配符*。

1.7.2 pubsub numsub
- 格式:
PUBSUB NUMSUB [channel-1 … channel-N] - 功能:返回给定频道的订阅者数量。不给定任何频道则返回一个空列表。

1.7.3 pubsub numpat
- 格式:
PUBSUB NUMPAT - 功能:查询当前 Redis 所有客户端订阅的所有频道模式的数量总和

二 Redis 事务
- Redis 的事务的本质是一组命令的批处理。这组命令在执行过程中会被顺序地、一次性全部执行完毕,只要没有出现语法错误,这组命令在执行期间是不会被中断。
2.1 Redis 事务特性
- Redis 的事务仅保证数据的一致性,不具有像 DBMS 一样的 ACID 特性。
- 不具备原子性:这组命令中的某些命令的执行失败不会影响其它命令的执行,不会引发回滚。
- 没有复杂的隔离级别:这组命令通过乐观锁机制实现了简单的隔离性。
- 与事务无关:这组命令的执行结果是被写入到内存的,是否持久取决于 Redis 的持久化策略。
Redis 事务实现
2.1.1 三个命令
- Redis 事务通过三个命令进行控制。
- muti:开启事务
- exec:执行事务
- discard:取消事务
2.1.2 基本使用
- 下面是定义并执行事务的用法:事务执行后,再访问事务中定义的变量,其值是修改过后。

- 下面是定义但取消事务的举例:事务取消后,事务中的命令是没有执行的

2.2. Redis 事务异常处理
2.2.1 语法错误
- 当事务中的命令出现语法错误时,整个事务在 exec 执行时会被取消

2.2.2 执行异常
- 如果事务中的命令没有语法错误,但在执行过程中出现异常,该异常不会影响其它命令的执行。


2.3 Redis 事务隔离机制
2.3.1 需要事务隔离机制的原因
- 在并发场景下可能会出现多个客户端对同一个数据进行修改的情况,造成数据不一致的情况!
- 如:有两个客户端 C 左与 C 右,C 左需要申请 40 个资源,C 右需要申请 30 个资源。它们首先查看了当前拥有的资源数量,即 resources 的值为50,都感觉资源数量可以满足自己的需求,于是修改资源数量,以占有资源。但结果却是资源出现了“超卖”情况。

- 如:有两个客户端 C 左与 C 右,C 左需要申请 40 个资源,C 右需要申请 30 个资源。它们首先查看了当前拥有的资源数量,即 resources 的值为50,都感觉资源数量可以满足自己的需求,于是修改资源数量,以占有资源。但结果却是资源出现了“超卖”情况。
- Redis 事务通过乐观锁机制实现了多线程下的执行隔离
2.3.2 隔离的实现
- Redis 通过 watch 命令再配合事务实现了多线程下的执行隔离

- 以上两个客户端执行的时间顺序为:

2.3.3 隔离的实现原理
- 当某一客户端对 key 执行了 watch 后,系统就会为该 key 添加一个 version 乐观锁,并初始化 version。例如初值为 1.0。
- 此后客户端 C 左将对该 key 的修改语句写入到了事务命令队列中,虽未执行,但其将该key 的 value 值与 version 进行了读取并保存到了当前客户端缓存。此时读取并保存的是version 的初值 1.0。
- 此后客户端 C 右对该 key 的值进行了修改,这个修改不仅修改了 key 的 value 本身,同时也增加了 version 的值,例如使其 version 变为了 2.0,并将该 version 记录到了该 key信息中。
- 此后客户端 C 左执行 exec,开始执行事务中的命令。不过,其在执行到对该 key 进行修改的命令时,该命令首先对当前客户端缓存中保存的 version 值与当前 key 信息中的version 值。如果缓存 version 小于 key 的 version,则说明客户端缓存的 key 的 value 已经过时,该写操作如果执行可能会破坏数据的一致性。所以该写操作不执行




















