Redis事务
可以一次性执行多个命令,本质是一组命令的集合。一个事务中所有的命令都会序列化,按照顺序的串行化执行而不会被其他的命令插入
,不许加塞。用于在一个队列,一次性,顺序性,排他性的执行一系列命令。
1.Redis事务与数据库事务的区别
单独的隔离操作 | Redis的仅仅是保证事务里的操作会被连续独占的执行,redis命令执行是单线程架构,在执行完事务内所有的指令前是不可能去同时执行其他客户端的请求的 |
---|---|
没有隔离级别的概念 | 因为事务提交前任何指令都不会被实际执行,也就不存在“事务内的查询要看到事务里的更新,在事务外查询不能看到”这种问题 |
不能保证原子性 | Redis的事务不能保证原子性,也就是不保证所有指令同事成功或者同时失败,只有决定是否开始执行全部指令的能力,没有执行到一半进行回滚的能力 |
排他性 | redis会保证一个事务内的命令依次执行,而不会被其他命令插入 |
2.Redis事务命令
MULTI | 标记一个事务块的开始 |
---|---|
DISCARD | 取消事务,放弃执行事务块内的所有命令 |
EXEC | 执行事务块内的所有命令 |
UNWATCH | 取消watch命令对手所有key的监视 |
WATCH | 监视一个key或者多个key,如果在事务执行之前这些key被其他的命令所改动,那么事务将会被打断 |
Redis管道
客户端向服务端发送命令分为四步(发送命令-排队执行-命令执行-返回结果),并监听socket返回,通常以阻塞模式等待服务器响应
服务端处理命令,并将结果返回给客户端
上述两步称为:Round Trip Time (简称RTT,数据包往返于两端的时间)
如果同时需要执行大量的命令,那么就要等待上一条命令回答后再执行,这中间不仅仅多了RTT,而且还频繁地调用系统IO,发送网络请求,同时需要redis调用多次read()和write()系统方法,系统方法会将数据从用户态转移到内核态,这样就会对进程上下文有比较大的影响了,性能不太好。解决的方法就是使用管道一次性发送多条命令给服务端,服务端依次处理完成之后,通过一条响应一次性将结果返回,通过减少客户端与redis的通信次数来实现降低往返延时时间。pipleline实现的原理是队列,先进先出就保证了数据的顺序性
1.pipeline与原生批量命令对比
原生批量命令是原子性,pipeline是非原子性
原生批量命令一次只能执行一种命令,pipeline支持批量执行不同命令
原生批命令是服务端实现,而pipeline需要服务端与客户端共同完成
2.pipeline与事务对比
事务具有原子性,而管道不具有原子性
管道一次性将多条命令发送到服务端,事务是一条一条发,事务只有在接收到exec命令后才会执行
执行事务时会阻塞其他命令的执行,而执行管道中的命令时不会
3.使用pipeline注意事项
pipeline缓冲的指令只是会依次执行,不保证原子性,如果执行中指令发生异常,将会继续执行后续的指令
使用pipeline组装的命令个数不能太多,不然数据量过大客户端阻塞的时间可能过久,同时服务端也被迫回复一个队列答复,占用很多内存
redis发布订阅
定义:是一种消息通信模式,发送者发送消息,订阅者接收消息,可以实现进程间的消息传递。
发布订阅其实就是一个轻量级的队列,只不过数据不会被持久化,一般用来处理实时性较高的异步消息
1.常用命令
PSUBSCRIBE pattern [pattern...] | 订阅一个或多个符合给定模式的频道 |
---|---|
PUBSUB subcommand argument [argument...] | 查看订阅与发布系统状态 |
PUBLISH cannel [cannel...] | 将信息发送到指定的系统频道 |
PUNSUBSCRIBE [pattern [pattern...]] | 退订所有给定模式的频道 |
SUBSCRIBE channel [channel...] | 订阅给定的一个或多个频道的消息 |
UNSUBSCRIBE [channel [channel]] | 退订给定的频道 |
Redis可以实现消息中间件的MQ的功能,通过发布订阅实现消息的引导和分流。
2.pub/sub缺点
-
发布的消息在Redis系统中不能持久化,因此必须先订阅,再等待消息发布。如果先发布了消息,那么该消息由于没有订阅者,消息将被直接丢弃
-
消息只管发送对于发布者而言消息是即发即失的,不管接受,也没有ACK机制,无法保证消息的消费成功
-
以上的缺点就导致了redis的消息订阅在生产环境中几乎无用武之地,为此redis在5.0版本新增了TSream数据结构,不但支持多播而且支持数据持久化,相比于发布订阅更加强大。