Redis入门总结(二):主从复制,事务和发布订阅

(尊重劳动成果,转载请注明出处:https://yangwenqiang.blog.csdn.net/article/details/90414751冷血之心的博客)

关注微信公众号(文强的技术小屋),学习更多技术知识,一起遨游知识海洋~

快速导航:

Redis入门总结(一):redis配置文件,五种数据结构,线程模型和持久化方式

Redis入门总结(二):主从复制,事务和发布订阅

Redis入门总结(三):redis实现分布式锁的正确姿势

这篇文章主要总结了:redis的主从复制,redis的事务以及redis实现发布订阅。

  1. 主从复制:

    1. 背景:

      1. 随着项目访问量的增加,对Redis服务器的操作也越加频繁,虽然Redis读写速度都很快,但是一定程度上也会造成一定的延时,那么为了解决访问量大的问题,通常会采取的一种方式是主从架构Master/Slave,Master 以写为主,Slave 以读为主,Master 主节点更新后根据配置,自动同步到从机Slave 节点。

    2. 通过  info replication 命令查看节点角色

    3. 哨兵模式:

      1. 解决了主节点挂掉之后,从节点还是从节点,无法自动转为主节点,导致系统无法正常工作的问题

      2. 哨兵模式监控redis是否按照预期良好地运行(至少是保证主节点是存在的),若一台主机出现问题时,哨兵会自动将该主机下的某一个从机设置为新的主机,并让其他从机和新主机建立主从关系。

      3. 哨兵模式也可以设置为集群模式,解决哨兵的单节点故障

    4. 主从复制原理:

      1. 旧版同步:

        1. 当从节点发出 SLAVEOF 命令,要求从服务器复制主服务器时,从服务器通过向主服务器发送 SYNC 命令来完成。该命令执行步骤:

          1. 从服务器向主服务器发送 SYNC 命令

          2. 收到 SYNC 命令的主服务器执行 BGSAVE 命令,在后台生成一个 RDB 文件,并使用一个缓冲区记录从开始执行的所有写命令

          3. 当主服务器的 BGSAVE 命令执行完毕时,主服务器会将 BGSAVE 命令生成的 RDB 文件发送给从服务器,从服务器接收此 RDB 文件,并将服务器状态更新为RDB文件记录的状态。

          4. 主服务器将缓冲区的所有写命令也发送给从服务器,从服务器执行相应命令。

      2. 命令传播:

        1. 当同步操作完成之后,主服务器会进行相应的修改命令,这时候从服务器和主服务器状态就会不一致。

        2. 为了让主服务器和从服务器保持状态一致,主服务器需要对从服务器执行命令传播操作,主服务器会将自己的写命令发送给从服务器执行。从服务器执行相应的命令之后,主从服务器状态继续保持一致。

        3. 问题:

          1. 如果从服务器正在同步,但是断开了连接,在其恢复之前,主服务器又进行了一系列的写操作,那么我们需要重新生成RDB文件来进行同步操作,这样会导致效率降低。

          2. 这样虽然能够保证一致性,但是其实断开连接之前主从服务器状态是保持一致的,不一致的是从服务器断开连接,而主服务器执行了一些写命令,那么从服务器恢复连接后能不能只要断开连接的哪些写命令,而不是整个RDB快照呢?

        4. 解决办法:

          1. Redis从2.8版本之后,使用了新的同步命令 PSYNC 来代替 SYNC 命令。该命令的部分重同步功能用于处理断线后重复制的效率问题。也就是说当从服务器在断线后重新连接主服务器时,主服务器只将断开连接后执行的写命令发送给从服务器,从服务器只需要接收并执行这些写命令即可保持主从一致。

      3. 主从复制的缺点:

        1. 当系统繁忙的时候,主从延迟会比较大。

  2. redis对事务的支持:

    1. redis 是单进程程序,并且它保证在执行事务时,不会对事务进行中断,事务可以运行直到执行完所有事务队列中的命令为止。因此,Redis的事务支持隔离性

    2. redis会将一个事务中的所有命令序列化,然后按顺序执行。Redis不可能在一个Redis事务的执行过程中插入执行另一个客户端发出的请求。这样便能保证Redis将这些命令作为一个单独的隔离操作执行。

    3. 操作事务的相关命令:

      1. MULTI  :标记一个事务块的开始。

      2. EXEC :执行所有事务块内的命令。

      3. DISCARD :取消事务,放弃执行事务块内的所有命令。

      4. UNWATCH :取消 WATCH 命令对所有 key 的监视。

      5. WATCH key [key ...] :监视一个(或多个) key ,如果在事务执行之前这个(或这些) key 被其他命令所改动,那么事务将被打断。

    4. redis事务不支持回滚:

      1. 只有当被调用的Redis命令有语法错误时,这条命令才会执行失败(在将这个命令放入事务队列期间,Redis能够发现此类问题),或者对某个键执行不符合其数据类型的操作:实际上,这就意味着只有程序错误才会导致Redis命令执行失败,这种错误很有可能在程序开发期间发现,一般很少在生产环境发现。

      2. Redis已经在系统内部进行功能简化,这样可以确保更快的运行速度,因为Redis不需要事务回滚的能力。

    5. redis以 MULTI 开始一个事务,然后将多个命令入队到事务中,最后由 EXEC 命令触发事务, 一并执行事务中的所有命令:

      1. Redis入门总结(二):主从复制,事务和发布订阅_第1张图片

    6. 单个 Redis 命令的执行是原子性的,但 Redis 没有在事务上增加任何维持原子性的机制,所以 Redis 事务的执行并不是原子性的

      1. 当EXEC调用之后,开始从队列里边取出命令执行,一条命令执行失败,并不会影响到其余命令的继续执行。

      2. redis事务为什么不支持原子性?

        1. 当我们开启事务时,将一系列的命令都封装塞进了一个队列,当EXEC开始执行的时候,只有错误的命令才会导致执行失败,而这通常在将该命令塞进队列的时候已经报错,我们应该可以提前发现该错误才对。

    7. 事务内部错误如何处理?

      1. 错误分类:

        1. 一个命令可能会在被放入队列时失败。因此,事务有可能在调用EXEC命令之前就发生错误。例如,这个命令可能会有语法错误(参数的数量错误、命令名称错误,等等),或者可能会有某些临界条件(例如:如果使用maxmemory指令,为Redis服务器配置内存限制,那么就可能会有内存溢出条件)。

        2. 在调用EXEC命令之后,事务中的某个命令可能会执行失败。例如,我们对某个键执行了错误类型的操作(例如,对一个字符串(String)类型的键执行列表(List)类型的操作)。

      2. 解决办法:

        1. 可以使用Redis客户端检测第一种类型的错误,在调用EXEC命令之前,这些客户端可以检查被放入队列的命令的返回值:

          1. 如果命令的返回值是QUEUE字符串,那么就表示已经正确地将这个命令放入队列;

          2. 否则,Redis将返回一个错误。如果将某个命令放入队列时发生错误,那么大多数客户端将会中止事务,并且丢弃这个事务。

        2. 在Redis 2.6.5版本之前,如果发生了上述的错误,那么在客户端调用了EXEC命令之后,Redis还是会运行这个出错的事务,执行已经成功放入事务队列的命令,而不会关心先前发生的错误。从2.6.5版本开始,Redis在遭遇上述错误时,服务器会记住事务积累命令期间发生的错误。然后,Redis会拒绝执行这个事务,在运行EXEC命令之后,便会返回一个错误消息。最后,Redis会自动丢弃这个事务。这样便能轻松地混合使用事务和管道。在这种情况下,客户端可以一次性地将整个事务发送至Redis服务器,稍后再一次性地读取所有的返回值。

        3. 相反,在调用EXEC命令之后发生的事务错误,Redis不会进行任何特殊处理:在事务运行期间,即使某个命令运行失败,所有其他的命令也将会继续执行。

    8. redis通过WATCH监视命令实现乐观锁:

      1. redis使用 check-and-set 操作实现乐观锁。WATCH 命令可以为 Redis 事务提供 check-and-set (CAS)行为。

      2. 类似Java中的CompareAndSet机制,被 WATCH 的键会被监视,并会发觉这些键是否被改动过了。

      3. 如果有至少一个被监视的键在 EXEC 执行之前被修改了, 那么整个事务都会被取消, EXEC 返回空多条批量回复(null multi-bulk reply)来表示事务已经失败。

    9. redis事务总结:

      1. 单独的隔离操作:事务中的所有命令会被序列化、按顺序执行,在执行的过程中不会被其他客户端发送来的命令打断

      2. 没有隔离级别的概念:队列中的命令在事务没有被提交之前不会被实际执行

      3. 不保证原子性:redis中的一个事务中如果存在命令执行失败,那么其他命令依然会被执行,没有回滚机制

  3. redis信息通知(发布/订阅模式):

    1. 优点:

      1. 松耦合。生产者和消费者无需知道彼此的实现细节,只需要约定好任务的描述格式。这使得生产者和消费者可以由不同的团队使用不同的编程语言编写

      2. 易于扩展。消费者可以有多个,而且可以分布在不同的服务器中, 借此可以轻易地降低单台服务器的负载

    2. 使用LPUSH和RPOP命令实现队列

    3. 利用BRPOP命令可以检测多个key的功能。如果多个键都有元素,则按照从左到右顺序取第一个键中的一个元素。因此,要实现优先级队列,把优先级高的key放到前面就ok了。

    4. 发布订阅模式:

      1. "发布/订阅"模式中包含两种角色,分别是发布者和订阅者。

      2. 订阅者可以订阅一个或若干个频道(channel)

      3. 发布者可以向指定的频道发送消息,所有订阅此频道的订阅者都会收到此消息。

以上内容摘抄总结与网络,感谢各位前辈的总结与铺垫。接下来我会继续更新Redis相关文章,全部会以这种笔记形式给出,大家对笔记中不太懂的地方,可以发表评论,我们一起研究学习,此处权当给大家列个学习提纲了。

如果对你有帮助,记得点赞哦~欢迎大家关注我的博客,可以进群366533258一起交流学习哦~

本群给大家提供一个学习交流的平台,内设菜鸟Java管理员一枚、精通算法的金牌讲师一枚、Android管理员一枚、蓝牙BlueTooth管理员一枚、Web前端管理一枚以及C#管理一枚。欢迎大家进来交流技术。

关注微信公众号(文强的技术小屋),学习更多技术知识,一起遨游知识海洋~

你可能感兴趣的:(Redis)