【大家好,我是爱干饭的猿,本文重点介绍Redis7 事务、管道和发布订阅。
后续会继续分享Redis7和其他重要知识点总结,如果喜欢这篇文章,点个赞👍,关注一下吧】
上一篇文章:《【Redis7】Redis7 持久化(重点:RDB与AOF重写机制)》
目录
🍣1. 事务
1.1 概述
- 可以一次执行多个命令,本质是一组命令的集合。一个事务中的所有命令都会序列化, 按顺序地串行化执行而不会被其他命令插入,不许加塞
- 一个队列中,一次性、顺序性、排他性的执行一系列命令
1.2 Redis事务和数据库事务
编辑
1.3 redis 事务命令
DISCARD // 取消事务,放弃执行事务块内的所有命令。 EXEC // 执行所有事务块内的命令。 MULTI // 标记—个事务块的开始。 UNWATCH // 取消WATCH命令对所有key的监视。 WATCH key [key ...] // 监视一个(或多个) key,如果在事务执行之前这个(或这些)key被其他命令所改动,那么事务将被打断。
case1: 正常执行
MULTI // 事务开始 set ... EXEC // 执行
case2: 放弃事务
MULTI // 事务开始 set ... DISCARD // 放弃事务
case3: 全体连坐
若执行语句语法编译不成功,则全部执行失败
MULTI // 事务开始 set k1 // 语法编译不成功 EXEC // 执行
case4: 冤头债主
- Redis 不提供事务回滚的功能,开发者必须在事务执行出错后,自行恢复数据库状态
- 注意和传统数据库事务区别,不一定要么一起成功要么一起失败
set k1 aabb MULTI // 事务开始 incr k1 // 语法编译成功,但运行失败 EXEC // 执行
前期语法都没错,编译通过,执行exec后报错: 对的执行,错的停
case5: watch监控
Watch 监控
- Redis使用Watch 来提供乐观锁定,类似于 CAS(Check-and-Set)
- 悲观锁
- 认为每次去拿数据都很认为别人会修改,所以每次拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁
- 乐观锁
- 认为每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据
- 提交版本必须 大于 记录当前版本才能执行更新
- CAS
- check-and-set(JUC中CAS操作相似)
watch
- 初始化 键值(k1 和 balance 两个key),先监控再开启multi,保证两key变动在同一事务内
set k1 111 watch k1 multi set k1 222 exec
有加塞篡改的话
- watch 命令是一种乐观锁的实现,Redis 在修改的时候会检测数据是否被更改,如果更改了,则执行失败
// 事务1 set k1 111 watch k1 multi set k1 222 exec // 事务2 在事务1监控k1之后,修改数据,事务1执行失败 set k1 333
unwatch
- 放弃对键值监控
set k1 111 watch k1 nuwatch k1 multi set k1 222 exec // 执行成功
小结:
- 一旦执行了 exec 之前加的watch监控锁都会被取消掉
- 当客户端连接丢失的时候(比如退出连接),所有东西都会被取消监视
1.4 总结
- 开启
- 以 MULTI 开始一个事务
- 入队
- 将多个命令入队到事务中,接到这些命令并不会立即执行,而是放到等待执行的事务队列里面
- 执行
- 由EXEC命令触发事务
🍣2. 管道
2.1 面试题
如何优化频繁命令往返造成的性能瓶颈?
Redis是一种基于客户端-服务端模型以及请求/响应协议的TCP服务。一个请求会遵循以下步骤:
- 客户端向服务端发送命令分四步(发送命令→命令排队→命令执行→返回结果),并监听Socket返回,通常以阻塞模式等待服务端响应。
- 服务端处理命令,并将结果返回给客户端。
上述两步称为:Round Trip Time(简称RTT,数据包往返于两端的时间)
编辑
如果同时需要执行大量的命令,那么就要等待上一条命令应答后再执行,这中间不仅仅多了RTT(Round Time Trip),而且还频繁调用系统IO,发送网络请求,同时需要redis调用多次read()和write()系统方法,系统方法会将数据从用户态转移到内核态,这样就会对进程上下文有比较大的影响了,性能不太好,o(╥﹏╥)o
利用管道来解决
2.2 概述
管道(pipeline)可以一次性发送多条命令给服务端。
- 服务端依次处理完完毕后,通过一条响应一次性将结果返回,通过减少客户端与redis的通信次数来实现降低往返延时时间。
- pipeline实现的原理是队列,先进先出特性就保证数据的顺序性。
编辑
也就是批处理
- 将多个命令都存在一个txt文件中,然后一同批处理,验证批处理
- 命令:cat ***.txt | redis-cli -a 密码 --pipe
编辑
2.3 总结
- Pipeline 与原生批量
- 原生批量命令是原子性(如:mset,mget),pipeline是非原子性
- 原生批量命令一次只能执行一种命令,pipeline支持批量执行不同命令
- 原生批命令是服务端实现,而pipeline需要服务端与客户端共同完成
- Pipeline 与事务对比
- 事务具有原子性,管道不具有原子性
- 管道一次性将多条命令发送到服务器,事务是一条一条发的,事务只有在接收到exec命令后才会执行,管道不会
- 执行事务时会阻塞其他命令的执行,而执行管道中的命令时不会
- Pipeline 注意事项
- pipeline缓冲的指令只是会依次执行,不保证原子性,如果执行中指令发生异常,将会继续执行后续的指令
- 使用pipeline组装的命令个数不能太多,不然数据量过大客户端阻塞的时间可能过久,同时服务器也被迫回复一个队列答复,占用很多内存
🍣3. 发布订阅
3.1 概述
- 是一种消息通信模式:
- 发送者(PUBLISH)发送消息
- 订阅者(SUBSCRIBE)接收消息,可以实现进程间的消息传递
- Redis可以实现消息中间件MQ的功能,通过发布订阅实现消息的引导和分流
- 功能
- Redis客户端可以订阅任意数量的频道,类似我们微信关注多个公众号
编辑
发布/订阅其实是一个轻量的队列,只不过数据不会被持久化,一般用来处理实时性较高的异步消息
编辑
3.2 常用命令
SUBSCRIBE channel [channel] // 订阅多个频道 PUBLISH channel message // 对一个频道发布信息 PSUBSCRIBE pattern [pattern...] // 按照模式批量订阅,订阅一个或多个符合给定模式(支持*号?号之类的)的频道 PUSUB CHANNELS // 由活跃频道组成的列表 PUSUB NUMSUB channel [channel...] // 某个频道有几个订阅者 PUBSUB NUMPAT // 只统计使用PUBSCRIBE 命令执行的,返回客户端订阅的唯一模式的数量 UNSUBSCRIBE channel [channel...] // 取消订阅 PUNSUBSCRIBE pattern [pattern...] // 退订所有给定模式的频道
3.3 总结
- 优点
- Redis可以实现消息中间件MQ的功能,通过发布订阅实现消息的引导和分流。(但不建议用,专业的事交给专业的工具MQ、kafka、RabbitMQ)
- 缺点
- 发布的消息在Redis系统中不能持久化,因此,必须先执行订阅,再等待消息发布。如果先发布了消息,那么该消息由于没有订阅者,消息将被直接丢弃
- 消息只管发送对于发布者而言消息是即发即失的,不管接收,也没有ACK机制,无法保证消息的消费成功。
- 以上的缺点导致Redis的Pub/Sub模式就像个小玩具,在生产环境中几乎无用武之地,为此,Redis5.0版本新增了stream数据结构,不但支持多播,还支持数据持久化,相比Pub/Sub更加的强大
分享到此,感谢大家观看!!!
如果你喜欢这篇文章,请点赞加关注吧,或者如果你对文章有什么困惑,可以私信我。
🏓🏓🏓