redis的三种模式

可爱的wzz 2021-02-23 13:57:52
Sentinel rdb


1 概述

一般的文档,都把redis的集群方式分成三种:主从、哨兵、集群(这里的集群只是广义集群的一种)。但是这么分类很不严谨,哨兵模式,单独使用是没有意义的,哨兵的作用有两个:

  • 监控:监控主节点和从节点是否正常运行
  • 提醒:当被监控的某个Redis节点出现问题时, 哨兵(sentinel) 可以通过 API 向管理员或者其他应用程序发送通知。
  • 故障迁移:主数据库出现故障时自动将从数据库转换为主数据库

说白了,哨兵就是一个打辅助的,本身并不提供数据存储功能,能独立使用的方式只有两种,主从模式和集群模式,所以我认为将redis分为两类比较合适:

  1. 主从集群配合哨兵使用
  2. 分布式(分区)集群

2 主从集群

主从集群,将数据库分为两中角色,一种是主数据库(master),另一种是从数据库(slave)。主数据库可以进行读写操作,从数据库只能有读操作(并不一定,只是推荐这么做,后续会说明)。当主数据库有数据写入,会将数据同步复制给从节点,一个主数据库可以同时拥有多个从数据库,而从数据库只能拥有一个主数据库。值得一提的是,从节点也可以有从节点,级联结构。
图片来源:https://www.cnblogs.com/kevingrace/p/5685332.html
配置
在从节点的redis.conf配置文件中加入
slaveof 主数据库ip 主数据库port
先启动主节点,再启动从节点即可

2.1 复制原理

当从节点启动后,会向主数据库发送SYNC命令。同时主数据库收到SYNC命令后会开始在后台保存快照(即RDB持久化,在主从复制时,会无条件触发RDB),并将保存快照期间接收到的命令缓存起来,当快照完成后,redis会将快照文件和所有缓存命令发送给数据库。从数据库接收到快照文件和缓存命令后,会载入快照文件和执行命令,也就是说redis是通过RDB持久化文件和redis缓存命令来时间主从复制。一般在建立主从关系时,一次同步会进行复制初始化。
以上过程为复制初始化,复制初始化结束后,主数据库每当受到写命令时,就会将命令同步给从数据库,保证主从数据一致性。
这里需要提一句,在Redis2.6之前,每次主从数据库断开连接后,Redis需要重新执行复制初始化,在数据量大的情况下,非常低效。而在Redis2.8之后,在断线重连后,主数据库只需要将断线期间执行的命令传送给从数据库。
在这里插入图片描述

2.2 乐观复制

Redis采用了乐观复制的策略,也就是在一定程度内容忍主从数据库的内容不一致。具体来说,Redis在主从复制的过程中,本身就是异步的,在主从数据库执行完客户端请求后会立即将结果返回给客户端,并异步的将命令同步给从数据库,但是这里并不会等待从数据库完全同步之后,再返回客户端。这一特性虽然保证了主从复制期间性能不受影响,但是也会产生一个数据不一致的时间窗口,如果在这个时间窗口期间网络突然断开连接,就会导致两者数据不一致。如果不在配置文件中添加其他策略,那就默认会采用这种方式,乐观二字也就体现在这里(是不是有点想当然的认为自己不会这么倒霉的停在这个空窗期)。
当然了,上面这种方式并不是绝对的,只要牺牲一点性能,还是可以避免上述问题。在配置文件中:

min-slaves-to-write 3
min-slaves-max-lag 10

前者表示当3个或者3个以上的从数据库同步主数据库时,主数据库才是可写的,否则会返回错误。
后者表示允许从数据库最长失联时间(单位s),如果从数据库最后与主数据库保持联的时间小于这个时间,则认为还存活。

2.3 增量复制

增量复制是基于以下4点实现的:

  1. 主节点除了备份RDB文件之外还会维护者一个环形积压队列,以及环形队列的写索引和从节点同步的全局offset,环形队列用于存储最新的操作数据。
  2. 从数据库会存储主数据库的运行id,每个redis实例会拥有一个唯一的运行id,当实例重启后,就会自动生成一个新的id。
  3. 主节点在复制同步阶段,主数据库每将一个命令传递给从数据库时,都会将命令存放到积压队列,并记录当前积压队列中存放命令的偏移量。
  4. 从数据库接收到主数据库传来的命令时,会记录下偏移量。

在2.8之后,主从复制不再发送SYNC命令,取而代之的是PSYNC,格式为:“PSYNC ID offset”。
当从节点和主节点断开重连之后,会把从节点维护的offset,也就是上一次同步到哪里的这个值告诉主节点,同时会告诉主节点上次和当前从节点连接的主节点的runid,满足下面两个条件,Redis不会全量复制,也就是说,不满足以下条件还是会全量复制

1.从节点传递的run id和master的run id一致。
2.主节点在环形队列上可以找到对应offset的值。

积压队列本质上是一个固定长度的循环队列,默认情况下积压队列的大小为1MB,可以通过配置文件:

repl-backlog-size 1mb

来设置,积压队列越大,允许主从数据库断线的时间就越长
Redis同时也提供了当没有slave需要同步的时候,多久可以释放环形队列,默认一小时:

repl-backlog-ttl 3600

3 哨兵模式

哨兵的作用就是健康redis节点的运行状态。

1.监控主数据库和从数据库是否能够正常运行
2.主数据库出现故障时自动将从数据库转换为主数据库。

普通的主从模式,当主数据库崩溃时,需要手动切换从数据库成为主数据库:

  1. 在从数据库中使用SLAVE NO ONE命令将从数据库提升成主数据继续服务。

  2. 启动之前崩溃的主数据库,然后使用SLAVEOF命令将其设置成新的主数据库的从数据库,即可同步数据。

注意: 当开启复制并且主数据库关闭持久化功能时,一定不能使用Suoervisor自动重启功能。当主数据库重启后,因为没有开启持久化功能,数据都被清空,从数据库也会同步清空,导致从数据库的持久化失去意义。

手动重启和恢复都相对麻烦,这时候就需要哨兵登场了。
哨兵是一个独立的进程:
在这里插入图片描述
哨兵本身也有单点故障的问题,所以在一个一主多从的Redis系统中,可以使用多个哨兵进行监控,哨兵不仅会监控主数据库和从数据库,哨兵之间也会相互监控。

在这里插入图片描述

3.1 哨兵实现原理

哨兵在启动进程时,会读取配置文件的内容,通过如下的配置找出需要监控的主数据库:

sentinel monitor master-name ip port quorum
master-name是主数据库的名字
ip和port 是当前主数据库地址和端口号
quorum表示在执行故障恢复操作前需要多少哨兵节点同意。

这里之所以只需要连接主节点,是因为通过主节点的info命令,获取从节点信息,从而和从节点也建立连接,同时也能通过主节点的info信息知道新增从节点的信息。

一个哨兵节点可以监控多个主节点,但是并不提倡这么做,因为当哨兵节点崩溃时,同时有多个集群切换会发生故障。
哨兵启动后,会与主数据库建立两条连接。

1.订阅主数据库_sentinel_:hello频道以获取同样监控该数据库的哨兵节点信息
2.定期向主数据库发送info命令,获取主数据库本身的信息。

和主数据库建立连接后会定时执行以下三个操作:

  1. 每隔10s向主数据库和从数据库发送info命令
  2. 每隔2s向主数据里和从数据库的_sentinel_:hello频道发送自己的信息。
  3. 每隔1s向所有数据库节点和所有哨兵节点发送ping命令。

第一条操作的作用是获取当前数据库信息,比如发现新增从节点时,会建立连接,并加入到监控列表中,当主从数据库的角色发生变化进行信息更新。

第二条操作的作用是将自己的监控数据和哨兵分享,发送的内容为:
<哨兵地址>,<哨兵端口>,<哨兵运行id>,<哨兵配置版本>,<主数据库名字>,<主数据库地址>,<主数据库端口>,<主数据库配置版本>,每个哨兵会订阅数据库的_sentinel_:hello频道,当其他哨兵收到消息后,会判断该哨兵是不是新的哨兵,如果是则将其加入哨兵列表,并建立连接。

第三条操作的作用是监控节点是否存活。该时间间隔有down-after-millisecond实现,当该值小于1s时,哨兵会按照设定的值发送ping,当大于1s时,哨兵会间隔1s发送ping命令。

3.2 主观下线和客观下线

当超过down-after-millisecond时间后,如果节点未回复,则哨兵认为主观下线。主观下线表示当前哨兵认为该节点已经下面,如果该节点为主数据库,哨兵会进一步判断是够需要对其进行故障恢复,这时候就要发送SENTINEL is-master-down-by-addr命令询问其他哨兵节点是否认为该主节点是主观下线,当达到指定数量时,哨兵就会认为是客观下线,该数量由sentinel monitor master-name ip port quorum的quorum参数设定。
当主节点客观下线时就需要进行主从切换,主从切换的步骤为:

  1. 选出领头哨兵
  2. 领头哨兵从在线的从数据库中,选择优先级最高的从数据库。优先级可以通过slave-priority选项设置。
  3. 如果优先级相同,则从复制的命令偏移量越大(即复同步数据越多,数据越新),越优先。
  4. 如果以上条件都一样,则选择run ID较小的从数据库。

选择一个从数据库后,哨兵发送slave no one命令升级为主数据库,并发送slaveof命令将其他从节点的主数据库设置为新的主数据库。
其中选择领头哨兵的过程使用了Raft算法,其具体思想如下:

  1. 发送主数据库客观下线的哨兵向每个哨兵命令,要求对方选择自己为领头。
  2. 如果没有选择过其他哨兵,则会同意请求
  3. 如果发现有超过半数,且超过quorum的哨兵同意自己的请求,则自己就是哨兵领头。

这种算法在多个哨兵同时参选时,会出现没有任何节点当选的可能。此时,每个哨兵会等待一个随机时间重新参选,每个节点的随机时间不一定相同,进行下一轮选举,直到成功。

版权声明
本文为[可爱的wzz]所创,转载请带上原文链接,感谢
https://my.oschina.net/u/4580084/blog/4960360

  1. Lazy load lazy load of SAP ui5 JavaScript files
  2. Add filter and execute filter in excel by Java
  3. Liteos: inventory those important data structures
  4. HDFS依然是存储的王者
  5. [MySQL]事务的MVCC原理与幻读
  6. 93.7%的程序员!竟然都不知道Redis为什么默认16个数据库?
  7. Java 集合处理/ 空值处理/ 异常处理,使用心得分享!
  8. Spring Authorization Server 全新授权服务器整合使用
  9. Spring Security 实战干货:OAuth2登录获取Token的核心逻辑
  10. Java中各种锁的原理解析
  11. java的byte和C#的byte的不同之处
  12. Java 在Excel中添加筛选器并执行筛选
  13. HDFS is still the king of storage
  14. Mvcc principle and unreal reading of [MySQL] transaction
  15. 93.7% of programmers! Why does redis default to 16 databases?
  16. Java collection processing / null value processing / exception processing, use experience sharing!
  17. Integrated use of new authorization server of spring authorization server
  18. Spring security real combat dry goods: the core logic of oauth2 login to obtain token
  19. Principle analysis of various locks in Java
  20. Differences between Java byte and C byte
  21. Add filter and execute filter in excel by Java
  22. Dialogue in spring
  23. 解决Docker MySQL无法被宿主机访问的问题
  24. Oracle OCP 19c 认证1Z0-083考试题库(第1题)
  25. Solve the problem that docker MySQL cannot be accessed by the host
  26. Oracle OCP 19C certification 1z0-083 examination question bank (question 1)
  27. 在 2021 年你需要掌握的 7 种关于 JavaScript 的数组方法
  28. Seven array methods for JavaScript you need to master in 2021
  29. 在 2021 年你需要掌握的 7 种关于 JavaScript 的数组方法
  30. Struts2 + Json _ 配置,异常解决及深入了解Struts2返回JSON数据的原理及具体应用范例
  31. Seven array methods for JavaScript you need to master in 2021
  32. Struts2 + Json _ Configuration, exception resolution and in-depth understanding of Struts2 return JSON data principle and specific application examples
  33. (三)MySQL锁机制 + 事务
  34. (3) MySQL lock mechanism + transaction
  35. 在 2021 年你需要掌握的 7 种关于 JavaScript 的数组方法
  36. Seven array methods for JavaScript you need to master in 2021
  37. 基于Kafka和Elasticsearch构建实时站内搜索功能的实践
  38. Practice of building real time search function in the website based on Kafka and elasticsearch
  39. Golang 实现 Redis(9): 使用GeoHash 搜索附近的人
  40. RxHttp - 轻量级、可扩展、易使用、完美兼容MVVM、MVC架构的网络封装类库
  41. Golang 实现 Redis(9): 使用GeoHash 搜索附近的人
  42. RxHttp - 轻量级、可扩展、易使用、完美兼容MVVM、MVC架构的网络封装类库
  43. Golang realizes redis (9): using geohash to search nearby people
  44. Rxhttp - lightweight, extensible, easy to use, perfectly compatible with MVVM, MVC architecture network encapsulation class library
  45. Golang realizes redis (9): using geohash to search nearby people
  46. Rxhttp - lightweight, extensible, easy to use, perfectly compatible with MVVM, MVC architecture network encapsulation class library
  47. 读懂框架设计的灵魂 — Java 反射机制
  48. 治疗磁盘空间不足焦虑症,释放容器占用空间——Win10+docker篇
  49. 别再用jodatime了!全网最权威Java8日期时间类LocalDate、LocalDateTime详解
  50. Understanding the soul of framework design java reflection mechanism
  51. 配置客户端以安全连接到Apache Kafka集群4:TLS客户端身份验证
  52. Treating anxiety of insufficient disk space and releasing space occupied by containers -- win10 + docker
  53. Don't use jodatime any more! The most authoritative java 8 date and time classes in the whole network: detailed explanation of localdate and localdatetime
  54. Configure clients to connect securely to Apache Kafka Cluster 4: TLS client authentication
  55. Spring break
  56. 高性能MySQL(三):Schema与数据类型优化
  57. High performance mysql (3): schema and data type optimization
  58. redis解决缓存、击穿、雪崩
  59. redis
  60. 骑士卡:基于Kafka搭建消息中心,上亿消息推送轻松完成