Redis学习之主从复制(二)

379 阅读23分钟

主从复制

在Redis复制的基础上(不包括由Redis Cluster或Redis Sentinel作为附加层提供的高可用性功能),有一个非常简单的使用和配置leader follower(主从)复制:它允许从属Redis实例准确主实例的副本。每次链接断开时,slave将自动重新连接到master,并且无论master发生什么情况,它都会尝试成为它的精确副本。

该系统使用三种主要机制:

  1. 当主实例和从属实例连接良好时,主设备通过向从设备发送命令流来保持从设备更新,以便复制对主设备端发生的数据集的影响,原因是:客户端写入,key已过期或驱逐,更改主数据集的任何其他操作。
  2. 当主设备和从设备之间的链路中断时,对于网络问题或者由于主设备或从设备中检测到超时,从设备重新连接并尝试继续部分重新同步:这意味着它将尝试仅获取部件它在断开连接时错过的命令流。
  3. 当无法进行部分重新同步时,slave将要求完全重新同步。这将涉及一个更复杂的过程,其中主机需要创建其所有数据的快照,将其发送到从机,然后在数据集更改时继续发送命令流。

Redis默认使用异步复制,即低延迟和高性能,是绝大多数Redis用例的自然复制模式。但是,Redisslave异步确认它们与master定期收到的数据量。因此主设备不会每次等待从设备处理命令,但是如果需要,它知道哪个从设备已经处理了什么命令。这允许具有可选的同步复制。

客户端可以使用WAIT命令请求某些数据的同步复制。但是,WAIT只能确保在其他Redis实例中存在指定数量的已确认副本,但它不会将一组Redis实例转换为具有强一致性的CP系统:在故障转移期间,确认的写入仍然可能丢失,具体取决于关于Redis持久性的确切配置。然而,对于WAIT,在失败事件之后丢失写入的概率大大降低到某些难以触发的故障模式。

您可以查看Sentinel或Redis集群文档,以获取有关高可用性和故障转移的更多信息。本文档的其余部分主要描述了Redis基本复制的基本特征。

以下是有关Redis复制的一些非常重要的事实:

  • Redis使用异步复制,异步slave到master确认处理的数据量。
  • 主设备可以有多个从设备。
  • Slaves能够接受来自其他Slaves的连接。除了将多个从设备连接到同一主设备之外,从设备还可以以类似级联的结构连接到其他从设备。从Redis 4.0开始,所有子slave将从master接收完全相同的复制流。
  • Redis复制在主端是非阻塞的。这意味着当一个或多个从服务器执行初始同步或部分重新同步时,主服务器将继续处理查询。
  • 复制在从属端也很大程度上是非阻塞的。当slave正在执行初始同步时,它可以使用旧版本的数据集处理查询,假设您在redis.conf中配置了Redis。否则,您可以将Redis从属配置为在复制流关闭时向客户端返回错误。但是,在初始同步之后,必须删除旧数据集并且必须加载新数据集。slave将在此简短窗口期间阻止传入连接(对于非常大的数据集,可能长达数秒)。从Redis 4.0开始,可以配置Redis,以便删除旧数据集在不同的线程中发生,但是加载新的初始数据集仍然会在主线程中发生并阻塞slave。
  • 复制可以用于可伸缩性,以便为只读查询提供多个slave(例如,可以将慢速O(N)操作卸载到slave),或者仅用于提高数据安全性和高可用性。
  • 可以使用复制来避免让主服务器花费巨大的开支将完整数据集写入磁盘:典型的技术是配置主服务器redis.conf以避免持久存储到磁盘,然后连接配置为save from time to time的从服务器,或者启用AOF。但是,必须小心处理此设置,因为重新启动的主服务器将以空数据集开始:如果从服务器尝试与其同步,则从服务器也将被清空。

工作原理

每个Redis主服务器都有一个replication ID:它是一个大的伪随机字符串,用于标记数据集的给定叙述。每个主服务器还会为生成的每个复制流字节递增一个偏移量,以便将其发送到从属服务器,方便使用修改数据集的新更改来更新从属服务器的状态。即使没有实际连接的slave,复制偏移也会增加,如下:

Replication ID, offset

用来标识主数据集的确切版本。

命令./redis-cli -p 6379 -a 你的密码 info server | grep run可以查看具体的id:

当slave连接到master时,它们使用PSYNC命令发送它们的旧主replication ID以及它们到目前为止处理的偏移量。这样master只用发送所需的增量部分。但是,如果主缓冲区中没有足够的backlog,或者从属设备指不知道历史记录(复制ID),则发生完全重新同步:在这种情况下,从属设备将获得数据集的完整副本, 从头开始。

这是完全同步在更多细节中的工作方式:

主服务器启动后台保存过程以生成RDB文件。同时它开始缓冲从客户端收到的所有新写命令。后台保存完成后,主服务器将数据库文件传输到从服务器,从服务器将其保存在磁盘上,然后将其加载到内存中。然后,主设备将所有缓冲的命令发送到从设备。这是作为命令流完成的,并且与Redis协议本身的格式相同。

您可以通过telnet自己尝试。在服务器执行某些工作时连接到Redis端口并发出SYNC命令。您将看到批量传输,然后主服务器接收的每个命令都将在telnet会话中重新发出。实际上,较新的Redis实例不再使用SYNC旧协议,但其仍然存在向后兼容性:它不允许部分重新同步,因此现在用PSYNC代替。

如前所述,当主 - 从链路由于某种原因而关闭时,从设备能够自动重新连接。如果主设备接收到多个并发从属同步请求,它将执行单个后台保存以便为所有这些请求提供服务。

全量复制

开销

1)bgsave时间。

2)RDB文件网络传输时间。

3)从节点清空数据时间。

4)从节点加载RDB的时间。

5)可能的AOF重写时间。

部分复制

配置

配置基本Redis复制很简单:只需将以下行添加到从属配置文件:

slaveof 192.168.1.1 6379

当然,您需要将192.168.1.1 6379替换为您的主IP地址(或主机名)和端口。或者,您可以调用SLAVEOF命令,主控主机将启动与slave的同步。

还有一些参数用于调整主机在内存中采取的replication backlog以执行部分重新同步。

可以使用repl-diskless-sync配置参数启用无盘复制。传输开始后,等待在第一个slave之后到达的更多slaves的延迟由repl-diskless-sync-delay 参数控制。

具体步骤

1)进入redis目录,复制redis.conf文件为redis-6380.conf

cp redis.conf redis-6380.conf

2)修改redis-6380.conf的端口号,保存的rdb文件名,日志名等参数。

3)找到REPLICATION模块,修改如下:

replicaof 127.0.0.1 6379

4)如果主节点redis设置了密码,修改masterauth属性:

在箭头处填上密码。

5)启动从结点:

./redis-server ../redis-6380.conf

6)使用命令./redis-cli -p 6380 -a 你的密码 info replication查看从节点状态:

可以发现role为slave,并且master_link_status为up,说明启动成功。说明一下,上图的slave_repl_offset就是所谓的偏移量。

尝试使用redis-cli在主节点中写入一个值:

./redis-cli -p 6379 -a 你的密码
> set hello world

进入从节点,输入get hello,可以发现已经能够正确获取值。

7)可以使用命令slaveof no one取消从节点模式。

只读slave

从Redis 2.6开始,slave支持默认启用的只读模式。此行为由slave-read-onlyredis.conf文件中的选项控制,可以在运行时使用CONFIG SET启用和禁用。

只读slave将拒绝所有写入命令,因此由于错误而写入slave是不可能的。这并不意味着该功能旨在将从属实例暴露给互联网,或者更普遍地意味着将不受信任的客户端存在的网络,因为管理命令喜欢DEBUGCONFIG仍然启用。但是,通过使用该rename-command指令禁用redis.conf中的命令,可以提高只读实例的安全性。

您可能想知道为什么可以恢复只读设置并具有可以通过写入操作作为目标的从属实例。如果slave和master重新同步或者slave重新启动,那么这些写操作将被丢弃,但有一些合法的用例可用于在可写slave中存储短暂数据。

例如,计算慢速设置或排序集合操作并将它们存储到本地key中是多次观察可写slave的用例。

但是请注意,版本4.0之前的可写slave无法设置到期时间。这意味着如果您使用EXPIRE或为key设置最大TTL的其他命令,key将泄漏,虽然您在使用读取命令访问key时可能再也看不到它,您将在key计数中看到它仍在使用内存。因此,通常混合可写slave(以前的版本4.0)和带有TTL的键会产生问题。

Redis 4.0 RC3及更高版本完全解决了这个问题,现在可写的从设备能够像主设备那样用TTL删除key,但用DB编号大于63的key除外(但默认情况下Redis实例只有16个数据库)。

另请注意,由于Redis 4.0从属写入仅是本地的,并且不会传播到附加到实例的子从属。相反,子slave将始终接收与顶层master向中间slave发送的复制流相同的复制流。例如,在以下设置中:

A ---> B ---> C

即使B是可写的,C也不会看到B写入,而是具有与主实例相同的数据集A

开发中运维的常见问题

读写分离

1)读写分离:读流量分摊到从节点,写流量分摊到主节点。

2)可能遇到的问题

1、复制数据延迟。

2、读到过期数据(3.2已解决)。

3、从节点故障。

规避全量复制

1)第一次全量复制

1、第一次不可避免。

2、小主节点、低峰。

2)节点运行ID不匹配

1、主节点重启(运行ID变化)。

2、故障转移,例如哨兵或集群。

3)复制积压缓冲区不足

1、网络中断,部分复制无法满足。

2、增大复制缓冲区配置rel_backlog_size,网络“增强”。

规避复制风暴

1)单节点复制风暴

问题:主节点重启,多从节点复制。

解决:更换复制拓扑。

2)单机器复制风暴

问题:机器宕机后,大量全量复制。

解决:主节点分散多机器。

Redis Sentinel

Redis Sentinel为Redis提供高可用性。实际上,这意味着使用Sentinel可以创建一个Redis部署,可以在没有人为干预的情况下抵御某些类型的故障。

Redis Sentinel还提供其他附属任务,如监控,通知,并充当客户端的配置提供程序。

这是宏观级别的Sentinel功能的完整列表(即大图):

  • 监控。Sentinel会不断检查主实例和从属实例是否按预期工作。
  • 通知。Sentinel可以通过API通知系统管理员,另一台计算机程序,其中一个受监控的Redis实例出现问题。
  • 自动故障转移。如果主服务器未按预期工作,Sentinel可以启动故障转移过程,其中从服务器被提升为主服务器,其他服务器将重新配置为新主服务器,并且使用Redis服务器的应用程序会通知有关新服务器的地址。连接。
  • 配置提供商。Sentinel充当客户端服务发现的权限来源:客户端连接到Sentinels,以便询问负责给定服务的当前Redis主服务器的地址。如果发生故障转移,Sentinels将报告新地址。

Sentinel的分布式特性

Redis Sentinel是一个分布式系统:

Sentinel本身设计为在多个Sentinel进程协同工作的配置中运行。让多个Sentinel进程协作的优势如下:

  1. 当多个Sentinels认为给定主设备不再可用时,将执行故障检测。这降低了误报的可能性。
  2. 即使并非所有Sentinel进程都正常工作,Sentinel也能正常工作,从而使系统能够抵御故障。毕竟,拥有故障转移系统本身就是一个单一的故障点并不是一件好事。

Sentinels,Redis实例(主服务器和从服务器)以及连接到Sentinel和Redis的客户端的总和也是具有特定属性的更大的分布式系统。在本文档中,将逐步介绍概念,从了解Sentinel的基本属性所需的基本信息,到更复杂的信息(可选),以了解Sentinel的工作原理。

获得哨兵

Sentinel的当前版本称为Sentinel 2。它是使用更强大和更简单的预测算法(本文档中解释)重写初始Sentinel实现。

自Redis 2.8发布Redis Sentinel的稳定版本。

不稳定的分支中进行了新的开发,一旦它们被认为是稳定的,新的特征有时会被反导到最新的稳定分支中。

Redis 2.6附带的Redis Sentinel版本1已弃用,不应使用。

运行Sentinel

如果您正在使用redis-sentinel可执行文件(或者如果您的可执行文件具有该名称的符号链接redis-server),则可以使用以下命令行运行Sentinel:

redis-sentinel /path/to/sentinel.conf

或者,您可以直接使用redis-server在Sentinel模式下启动它的可执行文件:

redis-server /path/to/sentinel.conf --sentinel

两种方式都是一样的。

但是**,在运行Sentinel时必须**使用配置文件,因为系统将使用此文件以保存重新启动时将重新加载的当前状态。如果没有给出配置文件或配置文件路径不可写,Sentinel将拒绝启动。

默认情况下,Sentinels会侦听与TCP端口26379的连接,因此要使 Sentinels正常工作,必须打开服务器的端口26379 以接收来自其他Sentinel实例的IP地址的连接。否则,Sentinels无法通话,也无法就该怎么做达成一致,因此永远不会执行故障转移。

在部署之前要了解Sentinel的基本知识

  1. 您需要至少三个Sentinel实例才能实现强大的部署。
  2. 应将三个Sentinel实例放入被认为不能以独立方式启动的计算机或虚拟机中。例如,在不同的可用区域上执行的不同物理服务器或虚拟机。
  3. Sentinel + Redis分布式系统不保证在故障期间保留已确认的写入,因为Redis使用异步复制。但是,有一些方法可以部署Sentinel,使窗口丢失限制在某些时刻的写入,同时还有其他不太安全的方式来部署它。
  4. 您需要在客户端获得Sentinel支持。流行的客户端库具有Sentinel支持,但不是全部。
  5. 如果您不在开发环境中实时进行测试,则没有HA设置是安全的,在生产环境中,如果它们可以工作,则更好。您可能有一个错误的配置,只有在为时已晚(凌晨3点,当您的master节点停止工作)时才会变得明显。
  6. Sentinel,Docker或其他形式的网络地址转换或端口映射应谨慎使用:Docker执行端口重新映射,中断其他Sentinel进程的Sentinel自动发现以及主服务器的从属列表。有关详细信息,请查看本文档后面有关Sentinel和Docker的部分。

配置Sentinel

Redis源代码分发包含一个名为sentinel.conf的文件 ,它是一个可以用来配置Sentinel的自我记录的示例配置文件,但是典型的最小配置文件如下所示:

sentinel monitor mymaster 127.0.0.1 6379 2
sentinel down-after-milliseconds mymaster 60000
sentinel failover-timeout mymaster 180000
sentinel parallel-syncs mymaster 1

sentinel monitor resque 192.168.1.3 6380 4
sentinel down-after-milliseconds resque 10000
sentinel failover-timeout resque 180000
sentinel parallel-syncs resque 5

您只需要指定要监视的主服务器,为每个单独的主服务器(可能有任意数量的从服务器)提供不同的名称。无需指定可被自动发现的slaves。Sentinel将自动更新配置有关slaves的其他信息(以便在重新启动时保留信息)。每次在故障转移期间将slave升级为master并且每次发现新的Sentinel时,也会重写该配置。

上面的示例配置基本上监视两组Redis实例,每组实例由主设备和未定义数量的从设备组成。一组实例被调用mymaster,另一组被调用resque

sentinel monitor语句参数的含义如下:

sentinel monitor <master-group-name> <ip> <port> <quorum>

为清楚起见,让我们逐行检查配置选项的含义:

第一行用于告诉Redis监视一个名为mymaster的主服务器,它位于地址127.0.0.1和端口6379,连接数为2。一切都很明显,但是quorum参数:

  • quorum是认为master不可达的哨兵的数量,为了真正把slave标志为失败,并最终启动关闭作业。
  • 但是**,quorum仅用于检测故障**。为了实际执行故障转移,其中一个Sentinels需要被选为故障转移的领导者并被授权继续进行。其由大多数Sentinel进程的投票而来。

因此,例如,如果您有5个Sentinel进程,并且给定主服务器的quorum设置为值2,则会发生以下情况:

  • 如果两个Sentinels同时认定主服务器无法访问,则其中一个将尝试启动故障转移。
  • 如果至少总共有三个Sentinel可达,则故障转移将被授权并实际开始。

实际上,这意味着在故障期间,如果大多数Sentinel进程无法通话(在少数分区中也没有故障转移),Sentinel永远不会启动故障转移

其他Sentinel选项

其他选项几乎总是以下列形式:

sentinel <option_name> <master_name> <option_value>

并用于以下目的:

  • down-after-milliseconds 是对于Sentinel开始认为它已关闭并且实例不能到达的(无论是不回复我们的PING还是回复错误)以毫秒为单位的时间。
  • parallel-syncs设置可在同一故障转移后重新配置以使用新主服务器的从服务器数。数字越小,故障转移过程完成所需的时间就越多,但是如果从属服务器配置为提供旧数据,则可能不希望所有从属服务器同时与主服务器重新同步。虽然复制过程对于从属设备大部分是非阻塞的,但是有一段时间它停止从主设备加载批量数据。您可能希望通过将此选项设置为值1来确保一次只能访问一个slave。

其他选项在本文档的其余部分中进行了描述,并记录在sentinel.confRedis发行版附带的示例文件中。

可以使用该SENTINEL SET命令在运行时修改所有配置参数。有关详细信息,请参阅“ **在运行时重新配置Sentinel”**部分。

示例Sentinel部署

现在您已了解Sentinel的基本信息,您可能想知道应该在哪里放置Sentinel进程,需要多少Sentinel进程等等。本节介绍几个示例部署。

  • Masters称为M1,M2,M3,...,Mn。
  • Slaves称为R1,R2,R3,...,Rn(R代表复制品)。
  • Sentinels称为S1,S2,S3,...,Sn。
  • Clients称为C1,C2,C3,...,Cn。
  • 当实例由于Sentinel操作而更改角色时,我们将其放在方括号内,因此[M1]表示由于Sentinel干预而现在成为主实例的实例。

请注意,我们永远不会显示仅使用两个Sentinels的设置,因为Sentinels总是需要与大多数人交谈才能启动故障转移。

例1:只有两个哨兵,不要这样做

+----+         +----+
| M1 |---------| R1 |
| S1 |         | S2 |
+----+         +----+

Configuration: quorum = 1
  • 在此设置中,如果主M1发生故障,R1将被提升,因为两个Sentinels可以就故障达成协议(显然将quorum设置为1),并且还可以授权故障转移,因为大多数是两个。所以显然它可以表面上工作,但请检查下一点,看看为什么这个设置被打破。
  • 如果M1运行的框停止工作,S1也停止工作。在另一个框S2中运行的Sentinel将无法授权故障转移,因此系统将无法使用。

请注意,为了执行不同的故障转移,需要多数,然后将最新配置传播到所有Sentinels。另请注意,在没有任何协议的情况下,在上述设置的单个方面进行故障转移的能力将非常危险:

+----+           +------+
| M1 |----//-----| [M1] |
| S1 |           | S2   |
+----+           +------+

在上面的配置中,我们以完全对称的方式创建了两个主服务器(假设S2可以在未经授权的情况下进行故障转移)。客户端可以无限期地向双方写入,并且无法理解分区何时恢复正确的配置,以防止永久性的裂脑情况

所以请始终在三个不同的盒子中至少部署三个Sentinels

示例2:具有三个框的基本设置

这是一个非常简单的设置,其优点是易于调整以获得额外的安全性。它基于三个框,每个框都运行Redis进程和Sentinel进程。

       +----+
       | M1 |
       | S1 |
       +----+
          |
+----+    |    +----+
| R2 |----+----| R3 |
| S2 |         | S3 |
+----+         +----+

Configuration: quorum = 2

如果主M1发生故障,S2和S3将同意故障,并且能够授权故障转移,使客户能够继续。

在每个Sentinel设置中,Redis被异步复制,总是存在丢失一些写入的风险,因为给定的已确认写入可能无法到达被提升为主设备的从设备。但是在上面的设置中,由于客户端使用旧主服务器进行分区,因此风险较高,如下图所示:

         +----+
         | M1 |
         | S1 | <- C1 (writes will be lost)
         +----+
            |
            /
            /
+------+    |    +----+
| [M2] |----+----| R3 |
| S2   |         | S3 |
+------+         +----+

在这种情况下,网络分区隔离了旧的主M1,因此从属R2被提升为主。但是,与旧主服务器位于同一分区的客户端(如C1)可能会继续将数据写入旧主服务器。这个数据将永远丢失,因为当分区将愈合时,主机将被重新配置为新主机的从机,丢弃其数据集。

使用以下Redis复制功能可以缓解此问题,如果主服务器检测到不再能够将其写入传输到指定数量的从服务器,则允许停止接受写入。

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

使用上述配置(请参阅redis.confRedis发行版中的自注释示例以获取更多信息)Redis实例作为主服务器时,如果无法写入至少1个从服务器,将停止接受写入。由于复制是异步的,因此无法实际写入意味着从属设备已断开连接,或者未向我们发送超过指定max-lag秒数的异步确认。

使用此配置,上例中的旧Redis主M1将在10秒后变为不可用。当分区恢复时,Sentinel配置将收敛到新的配置,客户端C1将能够获取有效配置并继续使用新主设备。

但是没有免费的午餐。通过这种改进,如果两个从属设备关闭,主设备将停止接受写入。这是一个折衷。

具体步骤

1)将三个redis(一主二从)启动。

2)配置sentinel.conf文件:

1、去掉protected-mode no的注释,即让它生效

2、将daemonize改成yes

3、修改logfile为26379.log

4、写入redis密码:sentinel auth-pass mymaster 你的密码(注意这里需要将其配置在sentinel monitor mymaster 你的服务器ip 6379 2语句之下,不然会报“No such master with specified name.”的错误。

5、修改dir

3)进入src目录,使用命令./redis-sentinel ../sentinel.conf进行启动。

4)使用命令:

./redis-cli -p 26379
>info

得到结果如下:

5)复制sentinel.conf为sentinel-26380.conf与sentinel-26381.conf,修改端口等信息,重复上述步骤。并且需要将myid注释,最终,sentinels的数目将等于3。

Java客户端

1)Sentinel地址集合。

2)masterName。

3)不是代理模式。

RedisUtils

package com.lamarsan.sentinel.util;

import redis.clients.jedis.*;
import redis.clients.jedis.exceptions.JedisConnectionException;

import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Logger;

/**
 * className: RedisUtil
 * description: TODO
 *
 * @author hasee
 * @version 1.0
 * @date 2018/12/26 10:57
 */
public class RedisUtil {
    private static final Logger myLogger = Logger.getLogger("com.lamarsan.sentinel.util");

    private static JedisSentinelPool pool = null;

    static {
        try {
            Set<String> sentinels = new HashSet<String>();
            sentinels.add("你的ip:26380");
            sentinels.add("你的ip.140:26379");
            sentinels.add("你的ip:26381");
            String masterName = "mymaster";
            String password = "123456";
            JedisPoolConfig config = new JedisPoolConfig();
            config.setMinIdle(8);
            config.setMaxTotal(100);
            config.setMaxIdle(100);
            config.setMaxWaitMillis(10000);
            pool = new JedisSentinelPool(masterName, sentinels, config, password);
            try {
                pool.getResource();
            } catch (JedisConnectionException e) {
                myLogger.info(e.getMessage());
                e.printStackTrace();
            }
        } catch (Exception e) {
            myLogger.info(e.getMessage());
            e.printStackTrace();
        }
    }

    private static void returnResource(JedisSentinelPool pool, Jedis jedis) {
        if (jedis != null) {
            jedis.close();
        }
    }

    /**
     * <p>通过key获取储存在redis中的value</p>
     * <p>并释放连接</p>
     *
     * @param key
     * @return 成功返回value 失败返回null
     */
    public static String get(String key) {
        Jedis jedis = null;
        String value = null;
        try {
            jedis = pool.getResource();
            value = jedis.get(key);
        } catch (Exception e) {
            if (jedis != null) {
                jedis.close();
            }
            e.printStackTrace();
        } finally {
            returnResource(pool, jedis);
        }
        return value;
    }

    /**
     * <p>向redis存入key和value,并释放连接资源</p>
     * <p>如果key已经存在 则覆盖</p>
     *
     * @param key
     * @param value
     * @return 成功 返回OK 失败返回 0
     */
    public static String set(String key, String value) {
        Jedis jedis = null;
        try {
            jedis = pool.getResource();
            return jedis.set(key, value);
        } catch (Exception e) {
            if (jedis != null) {
                jedis.close();
            }
            e.printStackTrace();
            return "0";
        } finally {
            returnResource(pool, jedis);
        }
    }
    
    .....
}

main

package com.lamarsan.sentinel;

import com.lamarsan.sentinel.util.RedisUtil;

/**
 * className: Test
 * description: TODO
 *
 * @author hasee
 * @version 1.0
 * @date 2019/9/13 15:54
 */
public class Test {
    public static void main(String[] args) throws InterruptedException {
        RedisUtil.setnx("hello", "world");
        while (true) {
            Thread.sleep(10000);
            String result = RedisUtil.get("hello");
            System.out.println(result);
        }
    }
}

结果

三个定时任务

1)每10秒每个sentinel对master和slave执行info

1、发现slave结点。

2、确认主从关系。

2)每2秒每个sentinel通过master结点的channel交换信息(pub/sub)

1、通过_sentinel_:hello频道交互。

2、交互对节点的”看法“和自身信息。

3)每1秒每个sentinel对其他sentinel和redis执行ping。

节点运维

1)机器下线:例如过保等情况。

2)机器性能不足:例如CPU、内存、硬盘、网络等。

3)节点自身故障:例如服务不稳定等。

主节点

sentinel failover <masterName>

从节点

临时下线还是永久下线,例如是否做一些清理工作,也要考虑读写分离的情况。