• 欢迎访问 winrains 的个人网站!
  • 本网站主要从互联网整理和收集了与Java、网络安全、Linux等技术相关的文章,供学习和研究使用。如有侵权,请留言告知,谢谢!

Redis使用教程(5):高可用

Redis winrains 来源:田守芝 11个月前 (10-20) 50次浏览

6 reids高可用

6.1 持久化

Redis 持久化
提供了多种不同级别的持久化方式:
  • RDB 持久化可以在指定的时间间隔内生成数据集的时间点快照(point-in-time snapshot)。
  • AOF 持久化记录服务器执行的所有写操作命令,并在服务器启动时,通过重新执行这些命令来还原数据集。 AOF 文件中的命令全部以 Redis 协议的格式来保存,新命令会被追加到文件的末尾。 Redis 还可以在后台对 AOF 文件进行重写(rewrite),使得 AOF 文件的体积不会超出保存数据集状态所需的实际大小。Redis 还可以同时使用 AOF 持久化和 RDB 持久化。 在这种情况下, 当 Redis 重启时, 它会优先使用 AOF 文件来还原数据集, 因为 AOF 文件保存的数据集通常比 RDB 文件所保存的数据集更完整。
  • 你甚至可以关闭持久化功能,让数据只在服务器运行时存在。了解 RDB 持久化和 AOF 持久化之间的异同是非常重要的, 以下几个小节将详细地介绍这这两种持久化功能, 并对它们的相同和不同之处进行说明。

Redis的强劲性能很大程度上是由于其将所有数据都存储在了内存中,为了使Redis在重启之后仍能保证数据不丢失,需要将数据从内存中以某种形式同步到硬盘中,这一过程就是持久化。
Redis支持两种方式的持久化,一种是RDB方式,一种是AOF方式。可以单独使用其中一种或将二者结合使用。

6.1.1 RDB方式

RDB方式的持久化是通过快照(snapshotting)完成的,当符合一定条件时Redis会自动将内存中的所有数据进行快照并存储在硬盘上。进行快照的条件可以由用户在配置文件中自定义,由两个参数构成:时间和改动的键的个数。当在指定的时间内被更改的键的个数大于指定的数值时就会进行快照。RDB是Redis默认采用的持久化方式,在配置文件中已经预置了3个条件:

save 900 1
save 300 10
save 60 10000

save参数指定了快照条件,可以存在多个条件,条件之间是“或”的关系。如上所说,save900 1的意思是在15分钟(900秒钟)内有至少一个键被更改则进行快照。如果想要禁用自动快照,只需要将所有的save参数删除即可。
Redis默认会将快照文件存储在当前目录的dump.rdb文件中,可以通过配置dirdbfilename两个参数分别指定快照文件的存储路径和文件名。
理清Redis实现快照的过程对我们了解快照文件的特性有很大的帮助。快照的过程如下。
(1)Redis使用fork函数复制一份当前进程(父进程)的副本(子进程);
(2)父进程继续接收并处理客户端发来的命令,而子进程开始将内存中的数据写入硬盘中的临时文件;
(3)当子进程写入完所有数据后会用该临时文件替换旧的RDB文件,至此一次快照操作完成。
在执行fork的时候操作系统(类Unix操作系统)会使用写时复制(copy-on-write)策略,即fork函数发生的一刻父子进程共享同一内存数据,当父进程要更改其中某片数据时(如执行一个写命令),操作系统会将该片数据复制一份以保证子进程的数据不受影响,所以新的RDB文件存储的是执行fork一刻的内存数据。
通过上述过程可以发现Redis在进行快照的过程中不会修改RDB文件,只有快照结束后才会将旧的文件替换成新的,也就是说任何时候RDB文件都是完整的。这使得我们可以通过定时备份RDB文件来实现Redis数据库备份。RDB文件是经过压缩(可以配置rdbcompression参数以禁用压缩节省CPU占用)的二进制格式,所以占用的空间会小于内存中的数据大小,更加利于传输。
除了自动快照,还可以手动发送SAVEBGSAVE命令让Redis执行快照,两个命令的区别在于,前者是由主进程进行快照操作,会阻塞住其他请求,后者会通过fork子进程进行快照操作。
Redis启动后会读取RDB快照文件,将数据从硬盘载入到内存。根据数据量大小与结构和服务器性能不同,这个时间也不同。通常将一个记录一千万个字符串类型键、大小为1GB的快照文件载入到内存中需要花费20~30秒钟。
通过RDB方式实现持久化,一旦Redis异常退出,就会丢失最后一次快照以后更改的所有数据。这就需要开发者根据具体的应用场合,通过组合设置自动快照条件的方式来将可能发生的数据损失控制在能够接受的范围。如果数据很重要以至于无法承受任何损失,则可以考虑使用AOF方式进行持久化。

RDB 的优点

RDB是一种表示某个即时点的Redis数据的紧凑文件。RDB文件适合用于备份。例如,你可能想要每小时归档最近24小时的RDB文件,每天保存近30天的RDB快照。这允许你很容易的恢复不同版本的数据集以容灾。
RDB非常适合于灾难恢复,作为一个紧凑的单一文件,可以被传输到远程的数据中心,或者是Amazon S3(可能得加密)。
RDB最大化了Redis的性能,因为Redis父进程持久化时唯一需要做的是启动(fork)一个子进程,由子进程完成所有剩余工作。父进程实例不需要执行像磁盘IO这样的操作。
RDB在重启保存了大数据集的实例时比AOF要快。

RDB 的缺点

当你需要在Redis停止工作(例如停电)时最小化数据丢失,RDB可能不太好。你可以配置不同的保存点(save point)来保存RDB文件(例如,至少5分钟和对数据集100次写之后,但是你可以有多个保存点)。然而,你通常每隔5分钟或更久创建一个RDB快照,所以一旦Redis因为任何原因没有正确关闭而停止工作,你就得做好最近几分钟数据丢失的准备了。
RDB需要经常调用fork()子进程来持久化到磁盘。如果数据集很大的话,fork()比较耗时,结果就是,当数据集非常大并且CPU性能不够强大的话,Redis会停止服务客户端几毫秒甚至一秒。AOF也需要fork(),但是你可以调整多久频率重写日志而不会有损(trade-off)持久性(durability)。

6.1.2 AOF方式

AOF 的优点

使用AOF Redis会更具有可持久性(durable):你可以有很多不同的fsync策略:没有fsync,每秒fsync,每次请求时fsync。使用默认的每秒fsync策略,写性能也仍然很不错(fsync是由后台线程完成的,主线程继续努力地执行写请求),即便你也就仅仅只损失一秒钟的写数据。
AOF日志是一个追加文件,所以不需要定位,在断电时也没有损坏问题。即使由于某种原因文件末尾是一个写到一半的命令(磁盘满或者其他原因),redis-check-aof工具也可以很轻易的修复。
当AOF文件变得很大时,Redis会自动在后台进行重写。重写是绝对安全的,因为Redis继续往旧的文件中追加,使用创建当前数据集所需的最小操作集合来创建一个全新的文件,一旦第二个文件创建完毕,Redis就会切换这两个文件,并开始往新文件追加。
AOF文件里面包含一个接一个的操作,以易于理解和解析的格式存储。你也可以轻易的导出一个AOF文件。例如,即使你不小心错误地使用FLUSHALL命令清空一切,如果此时并没有执行重写,你仍然可以保存你的数据集,你只要停止服务器,删除最后一条命令,然后重启Redis就可以。

AOF 的缺点

对同样的数据集,AOF文件通常要大于等价的RDB文件。
AOF可能比RDB慢,这取决于准确的fsync策略。通常fsync设置为每秒一次的话性能仍然很高,如果关闭fsync,即使在很高的负载下也和RDB一样的快。不过,即使在很大的写负载情况下,RDB还是能提供能好的最大延迟保证。
在过去,我们经历了一些针对特殊命令(例如,像BRPOPLPUSH这样的阻塞命令)的罕见bug,导致在数据加载时无法恢复到保存时的样子。这些bug很罕见,我们也在测试套件中进行了测试,自动随机创造复杂的数据集,然后加载它们以检查一切是否正常,但是,这类bug几乎不可能出现在RDB持久化中。为了说得更清楚一点:Redis AOF是通过递增地更新一个已经存在的状态,像MySQL或者MongoDB一样,而RDB快照是一次又一次地从头开始创造一切,概念上更健壮。但是,1)要注意Redis每次重写AOF时都是以当前数据集中的真实数据从头开始,相对于一直追加的AOF文件(或者一次重写读取老的AOF文件而不是读内存中的数据)对bug的免疫力更强。2)我们还没有收到一份用户在真实世界中检测到崩溃的报告。
默认情况下Redis没有开启AOF(append only file)方式的持久化,可以通过appendonly参数开启:

appendonly yes

开启AOF持久化后每执行一条会更改Redis中的数据的命令,Redis就会将该命令写入硬盘中的AOF文件。AOF文件的保存位置和RDB文件的位置相同,都是通过dir参数设置的,默认的文件名是appendonly.aof,可以通过appendfilename参数修改:

appendfilename appendonly.aof

下面讲解AOF持久化的具体实现,假设在开启AOF持久化的情况下执行了如下4个命令:

SET foo 1
SET foo 2
SET foo 3
GET foo

Redis会将前3条命令写入AOF文件中,此时AOF文件中的内容如下:

*2
$6
SELECT
$1
*3
$3
set
$3
foo
$1
1
*3
$3
set
$3
foo
$1
2
*3
$3
set
$3
foo
$1
3

可见AOF文件是纯文本文件,其内容正是Redis客户端向Redis发送的原始通信协议的内容(Redis的通信协议会在7.4节中介绍,为了便于阅读,这里将实际的命令部分以粗体显示),从中可见Redis确实只记录了前3条命令。然而这时有一个问题是前2条命令其实都是冗余的,因为这两条的执行结果会被第三条命令覆盖。随着执行的命令越来越多,AOF文件的大小也会越来越大,即使内存中实际的数据可能并没有多少。很自然地,我们希望Redis可以自动优化AOF文件,就上例而言,就是将前两条无用的记录删除,只保留第三条。实际上Redis也正是这样做的,每当达到一定条件时Redis就会自动重写AOF文件,这个条件可以在配置文件中设置:

auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb

auto-aof-rewrite-percentage参数的意义是当目前的AOF文件大小超过上一次重写时的AOF文件大小的百分之多少时会再次进行重写,如果之前没有重写过,则以启动时的AOF文件大小为依据。auto-aof-rewrite-min-size参数限制了允许重写的最小AOF文件大小,通常在AOF文件很小的情况下即使其中有很多冗余的命令我们也并不太关心。除了让Redis自动执行重写外,我们还可以主动使用BGREWRITEAOF命令手动执行AOF重写。
上例中的AOF文件重写后的内容为:

*2
$6
SELECT
$1
*3
$3
SET
$3
foo
$1
3

可见冗余的命令已经被删除了。重写的过程只和内存中的数据有关,和之前的AOF文件无关,这与RDB很相似,只不过二者的文件格式完全不同。
在启动时Redis会逐个执行AOF文件中的命令来将硬盘中的数据载入到内存中,载入的速度相较RDB会慢一些。
需要注意的是虽然每次执行更改数据库内容的操作时,AOF都会将命令记录在AOF文件中,但是事实上,由于操作系统的缓存机制,数据并没有真正地写入硬盘,而是进入了系统的硬盘缓存。在默认情况下系统每30秒会执行一次同步操作,以便将硬盘缓存中的内容真正地写入硬盘,在这30秒的过程中如果系统异常退出则会导致硬盘缓存中的数据丢失。一般来讲启用AOF持久化的应用都无法容忍这样的损失,这就需要Redis在写入AOF文件后主动要求系统将缓存内容同步到硬盘中。在Redis中我们可以通过appendfsync参数设置同步的时机:

# appendfsync always
appendfsync everysec
# appendfsync no

默认情况下Redis采用everysec 规则,即每秒执行一次同步操作。always表示每次执行写入都会执行同步,这是最安全也是最慢的方式。no表示不主动进行同步操作,而是完全交由操作系统来做(即每30秒一次),这是最快但最不安全的方式。一般情况下使用默认值everysec就足够了,既兼顾了性能又保证了安全。
Redis允许同时开启AOF和RDB,既保证了数据安全又使得进行备份等操作十分容易。此时重新启动Redis后Redis会使用AOF文件来恢复数据,因为AOF方式的持久化可能丢失的数据更少。

RDB 和 AOF ,我应该用哪一个?

一般来说,如果想达到足以媲美 PostgreSQL 的数据安全性, 你应该同时使用两种持久化功能。
如果你非常关心你的数据,但仍然可以承受数分钟以内的数据丢失, 那么你可以只使用 RDB 持久化。
有很多用户单独使用AOF,但是我们并不鼓励这样,因为时常进行RDB快照非常方便于数据库备份,启动速度也较之快,还避免了AOF引擎的bug。
注意:基于这些原因,将来我们可能会统一AOF和RDB为一种单一的持久化模型(长远计划)。
参考文档
http://ifeve.com/redis-persistence/

6.2 主从复制

通过持久化功能,Redis保证了即使在服务器重启的情况下也不会损失(或少量损失)数据。但是由于数据是存储在一台服务器上的,如果这台服务器的硬盘出现故障,也会导致数据丢失。为了避免单点故障,我们希望将数据库复制多个副本以部署在不同的服务器上,即使有一台服务器出现故障其他服务器依然可以继续提供服务。这就要求当一台服务器上的数据库更新后,可以自动将更新的数据同步到其他服务器上,Redis提供了复制(replication)功能可以自动实现同步的过程。

6.2.1 配置

同步后的数据库分为两类,一类是主数据库(master),一类是从数据库(slave)。主数据库可以进行读写操作,当发生写操作时自动将数据同步给从数据库。而从数据库一般是只读的,并接受主数据库同步过来的数据。一个主数据库可以拥有多个从数据库,而一个从数据库只能拥有一个主数据库,如图7-1所示。
QQ截图20160318221047.png
在Redis中使用复制功能非常容易,只需要在从数据库的配置文件中加入“slaveof主数据库IP主数据库端口”即可,主数据库无需进行任何配置。
为了能够更直观地展示复制的流程,下面将进行简单的演示。我们要在一台服务器上启动两个Redis实例,监听不同端口,其中一个作为主数据库,另一个作为从数据库。首先我们不加任何参数来启动一个Redis实例作为主数据库:

$redis-server

该实例默认监听6379端口。然后加上slaveof参数启动另一个Redis实例作为从数据库,并让其监听6380端口:

redis-server --port 6380--slaveof 127.0.0.16379

此时在主数据库中的任何数据变化都会自动同步到从数据库中。我们打开redis-cli实例A并连接到主数据库:

redis-cli

再打开redis-cli实例B并连接到从数据库:

redis-cli -p 6380

在实例A中使用SET命令设置一个键的值:

redis A>SET foo bar
OK

此时在实例B中就可以获得该值了:

redis B>GET foo
"bar"

但在默认情况下从数据库是只读的,如果直接修改从数据库的数据会出现错误:

redis B>SET foo hi
(error) READONLY You can't write against a read only slave.

可以通过设置从数据库的配置文件中的slave-read-only为no以使从数据库可写,但是对从数据库的任何更改都不会同步给任何其他数据库,并且一旦主数据库中更新了对应的数据就会覆盖从数据库中的改动。
配置多台从数据库的方法也一样,在所有的从数据库的配置文件中都加上 slaveof参数指向同一个主数据库即可。
除了通过配置文件或命令行参数设置slaveof参数,还可以在运行时使用SLAVEOF命令修改:

redis>SLAVEOF 127.0.0.16379

如果该数据库已经是其他主数据库的从数据库了,SLAVEOF命令会停止和原来数据库的同步转而和新数据库同步。还可以使用SLAVEOF NO ONE来使当前数据库停止接收其他数据库的同步转成主数据库。

6.2.2 原理

了解Redis复制的原理对日后运维有很大的帮助。
当一个从数据库启动后,会向主数据库发送SYNC命令,主数据库接收到SYNC命令后会开始在后台保存快照(即RDB持久化的过程),并将保存期间接收到的命令缓存起来。当快照完成后,Redis会将快照文件和所有缓存的命令发送给从数据库。从数据库收到后,会载入快照文件并执行收到的缓存的命令。当主从数据库断开重连后会重新执行上述操作,不支持断点续传。
实际的过程略微复杂一些,由于Redis服务器使用TCP协议通信,所以我们可以使用telnet工具伪装成一个从数据库来了解同步的具体过程。首先在命令行中连接主数据库(默认端口为6379,且没有任何从数据库连接):

telnet 127.0.0.16379
Trying127.0.0.1...
Connected to localhost.
Escape character is '^]'.

然后作为从数据库,我们先要发送PING命令确认主数据库是否可以连接:

PING
+PONG

主数据库会回复+PONG。如果没有收到主数据库的回复,则向用户提示错误。如果主数据库需要密码才能连接,我们还得发送AUTH命令进行验证(关于Redis的安全设置会在7.3节介绍)。而后向主数据库发送REPLCONF命令说明自己的端口号(这里随便选择了一个):

REPLCONF listening-port 6381
+OK

这时就可以开始同步的过程了:向主数据库发送SYNC命令开始同步,此时主数据库发送回快照文件和缓存的命令。目前主数据库中只有一个foo键,所以收到的内容如下(快照文件是二进制格式,从第三行开始):

SYNC
$29
REDIS0006?foobar?6_?"

从数据库会将收到的内容写入到硬盘上的临时文件中,当写入完成后从数据库会用该临时文件替换RDB快照文件(RDB快照文件的位置就是持久化时配置的位置,由dir和dbfilename两个参数确定),之后的操作就和RDB持久化时启动恢复的过程一样了。需要注意的是在同步的过程中从数据库并不会阻塞,而是可以继续处理客户端发来的命令。默认情况下,从数据库会用同步前的数据对命令进行响应。可以配置slave-serve-stale-data参数为no来使从数据库在同步完成前对所有命令(除了INFO和SLAVEOF)都回复错误:“SYNC with master in progress.”
之后主数据库的任何数据变化都会同步给从数据库,同步的内容和Redis通信协议一样,比如我们在主数据库中执行SET foo hi,通过telnet我们收到了:

*3
$3
set
$3
foo
$2
hi

在复制的过程中,快照无论在主数据库还是从数据库中都起了很大的作用,只要执行复制就会进行快照,即使我们关闭了RDB方式的持久化(通过删除所有save参数)。更进一步,无论是否启用了RDB方式的持久化,Redis在启动时都会尝试读取dir和dbfilename两个参数指定的RDB文件来恢复数据库。

6.2.3 图结构

从数据库不仅可以接收主数据库的同步数据,自己也可以同时作为主数据库存在,形成类似图的结构,如图7-2所示,数据库A的数据会同步到B和C中,而B中的数据会同步到D和E中。向B中写入数据不会同步到A或C中,只会同步到D和E中。
QQ截图20160318221958.png

6.2.4 读写分离

通过复制可以实现读写分离以提高服务器的负载能力。在常见的场景中,读的频率大于写,当单机的Redis无法应付大量的读请求时(尤其是较耗资源的请求,比如SORT命令等)可以通过复制功能建立多个从数据库,主数据库只进行写操作,而从数据库负责读操作。

6.2.5 从数据库持久化

另一个相对耗时的操作是持久化,为了提高性能,可以通过复制功能建立一个(或若干个)从数据库,并在从数据库中启用持久化,同时在主数据库禁用持久化。当从数据库崩溃时重启后主数据库会自动将数据同步过来,所以无需担心数据丢失。而当主数据库崩溃时,需要在从数据库中使用SLAVEOF NO ONE命令将从数据库提升成主数据库继续服务,并在原来的主数据库启动后使用SLAVEOF命令将其设置成新的主数据库的从数据库,即可将数据同步回来。

6.2.6 总结

Redis主从复制的配置十分简单,它可以使slave是master的完全拷贝。下面是关于Redis主从复制的几点重要内容:

  1. Redis使用异步复制。但从Redis 2.8开始,slave会周期性的应答从复制流中处理的数据量。
  2. 一个master可以有多个slave。
  3. slave也可以接受其他slave的连接。除了多个slave连接到一个master之外,多个slave也可以连接到一个slave上,形成一个图状结构
  4. Redis主从复制不阻塞master端。也就是说当若干个slave在进行初始同步时,master仍然可以处理请求。
  5. 主从复制也不阻塞slave端。当slave进行初始同步时,它使用旧版本的数据来应对查询请求,假设你在redis.conf配置文件是这么配置的。否则的话,你可以配置当复制流关闭时让slave给客户端返回一个错误。但是,当初始同步完成后,需要删除旧的数据集和加载新的数据集,在这个短暂的时间内,slave会阻塞连接进来的请求。
  6. 主从复制可以用来增强扩展性,使用多个slave来处理只读的请求(比如,繁重的排序操作可以放到slave去做),也可以简单的用来做数据冗余。
  7. 使用主从复制可以为master免除把数据写入磁盘的消耗:在master的redis.conf文件中配置“避免保存”(注释掉所有“保存“命令),然后连接一个配置为“进行保存”的slave即可。但是这个配置要确保master不会自动重启

当主服务器不进行持久化时复制的安全性

在进行主从复制设置时,强烈建议在master服务器上开启持久化,当不能这么做时,比如考虑到延迟的问题,应该将实例配置为避免自动重启。
为什么不持久化的master服务器自动重启非常危险呢?为了更好的理解这个问题,看下面这个失败的例子,其中master服务器和slave服务器中数据库都被删除了。
我们设置节点A为master,关闭持久化,节点B和C从节点A复制数据。
这时出现了一个崩溃,但Redis具有自动重启系统,重启了进程,因为关闭了持久化,节点重启后只有一个空的数据集。
节点B和C从节点A进行复制,现在节点A是空的,所以节点B和C上的复制数据也会被删除。
当在高可用系统中使用Redis Sentinel,关闭了master服务器的持久化,并且允许自动重启,这种情况是很危险的。比如master服务器可能在很短的时间就完成了重启,以至于Sentinel都无法检测到这次失败,那么上面说的这种失败的情况就发生了。
如果数据比较重要,并且在使用主从复制时关闭了主服务器持久化功能的场景中,都应该禁止实例自动重启。

部分重新同步

从Redis 2.8开始,如果遭遇连接断开,重新连接之后可以从中断处继续进行复制,而不必重新同步。
它的工作原理是这样,主服务器端为复制流维护一个内存缓冲区(in-memory backlog)。主从服务器都维护一个复制偏移量(replication offset)和master run id ,当连接断开时,从服务器会重新连接上主服务器,然后请求继续复制,假如主从服务器的两个master run id相同,并且指定的偏移量在内存缓冲区中还有效,复制就会从上次中断的点开始继续。如果其中一个条件不满足,就会进行完全重新同步(在2.8版本之前就是直接进行完全重新同步)。因为主运行id不保存在磁盘中,如果从服务器重启了的话就只能进行完全同步了。
部分重新同步这个新特性内部使用PSYNC命令,旧的实现中使用SYNC命令。Redis2.8版本可以检测出它所连接的服务器是否支持PSYNC命令,不支持的话使用SYNC命令。

无磁盘复制

通常来讲,一个完全重新同步需要在磁盘上创建一个RDB文件,然后加载这个文件以便为从服务器发送数据。
如果使用比较低速的磁盘,这种操作会给主服务器带来较大的压力。Redis从2.8.18版本开始尝试支持无磁盘的复制。使用这种设置时,子进程直接将RDB通过网络发送给从服务器,不使用磁盘作为中间存储。
这一特性目前只是实验性的。
关于部分重新同步,还有一些针对复制内存缓冲区的优化参数。查看Redis介质中的Redis.conf示例获得更多信息。
使用repl-diskless-sync配置参数来启动无磁盘复制。使用repl-diskless-sync-delay 参数来配置传输开始的延迟时间,以便等待更多的从服务器连接上来。

设置从服务器到主服务器验证

如果主服务器设置了密码,配置从服务器在所有同步中使用这个密码十分简单。
对于运行中的实例,使用redis-cli并输入:

config set masterauth <password>

要使配置永久生效,把如下命令加入到配置文件中:

masterauth <password>

限制有N个以上从服务器才允许写入

从Redis 2.8版本开始,可以配置主服务器连接N个以上从服务器才允许对主服务器进行写操作。但是,因为Redis使用的是异步主从复制,没办法确保从服务器确实收到了要写入的数据,所以还是有一定的数据丢失的可能性。
这一特性的工作原理如下:

  • 从服务器每秒钟ping一次主服务器,确认处理的复制流数量。
  • 主服务器记住每个从服务器最近一次ping的时间。
  • 用户可以配置最少要有N个服务器有小于M秒的确认延迟。
  • 如果有N个以上从服务器,并且确认延迟小于M秒,主服务器接受写操作。

你可以把这看做是CAP原则(一致性,可用性,分区容错性)不严格的一致性实现,虽然不能百分百确保一致性,但至少保证了丢失的数据不会超过M秒内的数据量。
如果条件不满足,主服务器会拒绝写操作并返回一个错误。
min-slaves-to-write(最小从服务器数)
min-slaves-max-lag(从服务器最大确认延迟)
参考文档:
http://ifeve.com/redis-replication/

6.3 redis-sentinel

Redis Sentinel为Redis提供了高可用解决方案。实际上这意味着使用Sentinel可以部署一套Redis,在没有人为干预的情况下去应付各种各样的失败事件。
Redis Sentinel同时提供了一些其他的功能,例如:监控、通知、并为client提供配置。
下面是Sentinel的功能列表:
  1. 监控(Monitoring):Sentinel不断的去检查你的主从实例是否按照预期在工作。
  2. 通知(Notification):Sentinel可以通过一个api来通知系统管理员或者另外的应用程序,被监控的Redis实例有一些问题。
  3. 自动故障转移(Automatic failover):如果一个主节点没有按照预期工作,Sentinel会开始故障转移过程,把一个从节点提升为主节点,并重新配置其他的从节点使用新的主节点,使用Redis服务的应用程序在连接的时候也被通知新的地址。
  4. 配置提供者(Configuration provider):Sentinel给客户端的服务发现提供来源:对于一个给定的服务,客户端连接到Sentinels来寻找当前主节点的地址。当故障转移发生的时候,Sentinels将报告新的地址。

Sentinel的分布式特性

Redis Sentinel是一个分布式系统,Sentinel运行在有许多Sentinel进程互相合作的环境下,它本身就是这样被设计的。有许多Sentinel进程互相合作的优点如下:

  1. 当多个Sentinel同意一个master不再可用的时候,就执行故障检测。这明显降低了错误概率。
  2. 即使并非全部的Sentinel都在工作,Sentinel也可以正常工作,这种特性,让系统非常的健康。
  3. 所有的Sentinels,Redis实例,连接到Sentinel和Redis的客户端,本身就是一个有着特殊性质的大型分布式系统。在这篇文章中,我将逐步地介绍这些概念,最开始是一些基本的信息来理解Sentinel的基本属性,后面是更复杂的信息来理解Sentinel是怎么工作的。

快速开始

获取 Sentinel
当前版本的Sentinel的被称为 Sentinel 2 。它使用更强更简单的预测算法重写了Sentinel的初始化实现(文章的后面将会解释)。
Redis Sentinel 的一个稳定版本是随着Redis2.8和3.0一起的。这两个是Redis最新的稳定版。
新的进展在unstable分支下进行,一旦新的特性是稳定的,就会被合并到2.8和3.0分支。
和Redis 2.6一起的Redis Sentinel版本1,是过时的。我们不该使用它。

运行Sentinel

如果你使用redis-sentinel可执行文件,你可以使用下面的命令来运行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实例的连接,否则,Sentinels不能互相交流,也不知道该干什么,也不会执行故障转移。

部署之前了解关于Sentinel的基本东西

  1. 一个健康的集群部署,至少需要三个Sentinel实例
  2. 三个Sentinel实例应该被放在失败独立的电脑上或虚拟机中,比如说不同的物理机或者在不同的可用区域上执行的虚拟机。
  3. Sentinel + Redis 分布式系统在失败期间并不确保写入请求被保存,因为Redis使用异步拷贝。可是有很多部署Sentinel的方式来让窗口把丢失写入限制在特定的时刻,当然也有另外的不安全的方式来部署。
  4. 如果你在开发环境中没有经常测试,或者在生产环境中也没有,那就没有高可用的设置是安全的。你或许有一个错误的配置而仅仅只是在很晚的时候才出现(凌晨3点你的主节点宕掉了)。
  5. 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

你仅仅只需要指定要监控的主节点,并给每个单独的主节点一个不同的名称。不需要指定从节点,从节点会被自动发现。Sentinel将会根据从节点额外的信息自动更新配置(为了在重启时保留信息)。在故障转移中每当一个从节点被提升为主节点或者当一个新的Sentinel被发现的时候,配置信息也被重新写入。
示例配置在上面,监控两个Redis实例集合,每个集合由一个主节点和不明确数量的从节点组成。一个集合叫做mymaster,另外一个叫做resque。
sentinel monitor参数的意思在下面

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

为了更加清晰明了,让我们一行一行来检查配置选项的意思:
第一行用来告诉Redis监控一个叫做mymaster的主节点,地址是 127.0.0.1 端口号是6379,并且有2个仲裁机器。所有的意思都很明显,但是除了这个quorum 参数:

  • quorum 是 需要同意主节点不可用的Sentinels的数量
  • 然而quorum 仅仅只是用来检测失败。为了实际的执行故障转移,Sentinels中的一个需要被选定为leader并且被授权进行操作,这仅仅发生在大多数Sentinels进行投票的时候。

比如如果你有五个Sentinel进程,对于一个主节点quorum被设置为2,下面是发生的事情:

  • 同时有两个Sentinels同意主节点不可用,其中的一个将会尝试开始故障转移。
  • 如果至少有三个Sentinels是可用的,故障转移将会被授权并且开始

实际中,这意味着在失败时,如果大多数的Sentinel进程没有同意,Sentinel永远不会开始故障转移。
设置quorum的原因是,如果一个Sentinel进程检到master不可用,并不能一定代表这个master不可用,可能只是这个sentinel进程自己存在问题。所以必须和其他Sentinel进程进行通信,多个Sentinel进程都认为不可用,则说明这个master的确不可用了。

其他的Sentinels选项

其他的选项几乎都是如下形式:

sentinel <option_name> <master_name> <option_value>

用途如下:
down-after-milliseconds:当一个实例失去联系(要么不回复我们的请求,要么回复一个错误)超过了这个时间(毫秒为单位),Sentinel就开始认为这个实例挂掉了。
parallel-syncs:设置的从节点的数量,这些从节点在一次故障转移过后可以使用新的主节点进行重新配置。数量越少,完成故障转移过程将花费更多的时间,如果从节点为旧的数据提供服务,你或许不想所有的从节点使用主节点进行重新同步。复制进程对于从节点来说大部分是非阻塞的,还是有一个时刻它会停下来去从主节点加载数据。你或许想确保一次只有一个从节点是不可达的,可以通过设置这个选项的值为1来完成。
别的选项在文章的其他部分进行描述。
所有的配置参数都可以在运行时使用SENTINEL SET命令进行更改,查看 Reconfiguring Sentinel at runtime章节获取更多内容。

Sentinel部署示例

现在你已经知道了Sentinel的基本信息,你或许想知道哪里放置你的Sentinel进程,需要多少个Sentinel进程等等。这个章节给出了几个部署的例子。
为了以图形(graphical )格式展示配置示例,我们使用ASCII艺术。下面是不同的符号的意思:
+——————–+
| 这是一个独立电脑   |
| 或者VM。我们称它为 |
| “box”            |
+——————–+
我们把我们想要运行的东西写到boxes里:
+——————-+
| Redis master M1   |
| Redis Sentinel S1 |
+——————-+
不同的box之间通过一条线连接,表示他们之间可以互相交流:
+————-+               +————-+
| Sentinel S1 |—————| Sentinel S2 |
+————-+               +————-+
中断的线条表示不同的网络分区:
+————-+                +————-+
| Sentinel S1 |—— // ——| Sentinel S2 |
+————-+                +————-+
同时还要注意:

  • 主节点称为M1,M2,M3,…,Mn。
  • 从节点称为R1,R2,R3,…,Rn。
  • Sentinels称为S1,S2,S3,…,Sn。
  • 客户端称为C1,C2,C3,…,Cn。
  • 当一个实例因为Sentinels的行为转换角色,我们把它放在方括号里,所以[M1]表示一个实例现在是主节点。

注意永远不要设置只有两个Sentinels,因为开始一个故障转移,Sentinels总是需要和大多数Sentinels交流。

示例1:仅仅只有两个Sentinels,永远不要这么做

+—-+         +—-+
| M1 |———| R1 |
| S1 |         | S2 |
+—-+         +—-+
Configuration: quorum = 1
在这个设置中,如果M1宕掉了,R1将会被提升至主节点,因为两个Sentinels将会达成一致(显然把quorum设置为1),并且授权开始一个故障转移因为大多数是两个。显然,表面上可以工作,但是请检查下一个点来看看为什么这种设置是不可以的。
如果M1的box停止工作,M1也会停止。运行在另外一个box中的S2将不会被授权进行故障转移,所以系统将不可用。
注意,需要大多数是为了应付不同的故障,最新的配置稍后会传播给所有的Sentinels。同时注意在上述设置中单独一边的故障转移能力,没有任何协议,将是非常危险的:
+—-+           +——+
| M1 |—-//—–| [M1] |
| S1 |           | S2   |
+—-+           +——+
在上面的配置中,我们完美对称地创建了两个主节点(假设S2在没有授权的情况下可以进行故障转移),客户端或许会不确定写往哪一边,并且没有办法理解当分区治愈时候哪边的配置是正确的。
所以请至少部署三个Sentinels在三个不同的box当中。

示例2:三个box的基本设置

这是一个非常简单的设置,拥有更加安全的优点。它是基于三个boxes的,每个box运行一个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实例。Redis发现它不能写入至少一个1从节点,作为主节点的Reids将会停止接受写入请求。由于复制是异步,不能写入也意味着从节点也是断开的,或者超过了指定的max-lag秒数没有发送异步回应。
在上面的示例中,使用这个配置的旧的主节点M1,在10秒过后就不可用了。当分区治愈,Sentinel配置将会统一为新的,客户端C1将获取到一个有效的配置并且继续。
然而天下没有免费的午餐,在这种改进下,如果两个从节点挂掉了,主节点将会停止接收写入请求,这就是一个权衡。

示例3:Sentinel在客户端所在的box中

有时候,我们只有两个Redis box是可用的,一个给主节点,一个给从节点。在那种情况下,示例2中的配置是不可行的,我们可以采取下面的方法,Sentinels被放置在客户端所在的地方:
+—-+         +—-+
| M1 |—-+—-| R1 |
| S1 |    |    | S2 |
+—-+    |    +—-+
|
+————+————+
|            |            |
|            |            |
+—-+        +—-+      +—-+
| C1 |        | C2 |      | C3 |
| S1 |        | S2 |      | S3 |
+—-+        +—-+      +—-+
Configuration: quorum = 2
在这种设置下,Sentinels的视角和客户端是 一样的:如果大部分的客户端认为一个主节点是可用的,它就是可用的。这里的C1,C2,C3是一般的客户端, 并不意味着C1是连接到Redis的单个客户端,它更像一个应用服务器,一个Redis app,或者类似的东西。
如果M1和S1所在的box挂掉了,故障转移将会进行,但是很明显的看到不同的网络分区将导致不同的行为。比如说,如果客户端和Redis服务断开连接,Sentinel将不会被设置,因为Redis的主节点和从节点都是不可用的。
注意如果C3和M1在一个分区,我们有了一个和示例2中描述的类似的问题,不同的是,这里我们没有办法打破对称,因为只有一个主节点和从节点,所以主节点不会停止接收请求。
所以这是一个有效的设置,但是实例2中的设置更有优势,比如Redis高可用系统,Redis运行在同一个box中,更容易被管理,并且可以限制在小部分的分区中主节点接收写入请求的时间。

示例4:Sentinel 客户端 这一边少于三个客户端

示例3描述的设置中,如果客户端这一边的box少于不够三个,这个 设置就不能使用。在这种情况下,我们需要借助混合设置,像下面这样:
+—-+         +—-+
| M1 |—-+—-| R1 |
| S1 |    |    | S2 |
+—-+    |    +—-+
|
+——+—–+
|            |
|            |
+—-+        +—-+
| C1 |        | C2 |
| S3 |        | S4 |
+—-+        +—-+
Configuration: quorum = 3
这和示例3中的设置非常相似,但是这里我们在可用的四个box中运行了四个Sentinel。如果主节点M1变成不可用节点,其他三个Sentinel将执行故障转移。
理论上,当移除S2和S4正在运行的box,这个设置可以工作,把quorum设置为2。然而,在应用层没有高可用的系统,想在Redis这一边得到高可用是不太可能的。

Sentinel,Docker,NAT 和可能的问题

Docker使用被称为端口映射的技术:与一个程序认为他使用的端口相比,运行在Docker容器里面的程序可能被暴露在不同的端口上。为了运行多个容器在相同的服务器上同时使用同一个端口,这是非常有用的。
Docker不是唯一会发生这件事情的软件系统,也有其他的网络地址转换设置导致端口是被重映射,并且有时候没有端口,只有IP地址。
端口和地址重映射在两个方面制造了与Sentinel有关的问题:

  1. Sentinel的自动发现服务将停止工作,因为它使基于每个Sentinel 往它监听的端口和IP地址广播hello消息来实现的。但是Sentinels没有办法来理解端口和IP地址被重映射了,所以他会宣布它和其他的Sentinels的连接是不正常的。
  2. 在一个主节点的INFO输出中,从节点 被列出来也是类似的方式:主节点检查远端对等的TCP连接来发现地址,在握手过程中,从节点自己广告他的端口,然而由于相同的原因,端口或许是错误的。

因为Sentinels自动发现从节点使用主节点的INFO输出信息,发现的从节点是不可达的,并且Sentinel将永远不会开始故障转移,因为从系统的观点来看,没有好的从节点,所以目前没有方式监控使用Docker部署的主节点和从节点实例,除非你通知Docker以1:1映射端口。
对于第一个问题,万一你想使用Docker运行一堆Sentinel实例,你可以使用下面的两个Sentinel配置,为了强迫Sentinel宣布一个指定的端口和IP:

sentinel announce-ip <ip>
sentinel announce-port <port>

注意,Docker可以运行host networking模式。这就不会有问题因为端口不会被重新映射。

快速教程

在文章接下来的部分中,所有的说明都是关于Sentinel API,配置和语义。对于想尽快上手的人,这部分的教程展示了三个Sentinel怎么配置和交互。
现在我假设三个实例分别在端口5000、5001、5002上。我也假设你在6379上有一个主节点Redis实例,6380上有一个从节点实例。在本教程中我们将使用IPV4回调地址127.0.0.1,假设你在你的电脑上运行了 模拟环境。
三个Sentinel配置文件应该看起来像下面这样:

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

另外的两个配置文件也是相同的,但是使用5001,5002作为端口号。
上面的配置中需要注意的一些事情:
主节点集群称为mymaster,它定义了主节点和它的从节点。因为每个master set 有一个不同的名称,Sentinel能同时监控不同的主节点和从节点的集合。
quorum被设置为2。
down-after-milliseconds的值是5000毫秒,就是5秒钟,所以在这个时间内一旦我们不能收到回复,主节点将发现失败。
一旦你启动了三个Sentinels,可以看到他们打印的一些信息:

+monitor master mymaster 127.0.0.1 6379 quorum 2

这是一个Sentinel事件,如果你SUBSCRIBE 了指定名称的事件,你可以收到这种事件通过发布/订阅。
Sentinel在故障检测和故障转移中生成和打印不同的事件。
询问Sentinel关于主节点的状态
Sentinel开始启动的时候,要做的事情是检查主节点的监控是否正常:

$ redis-cli -p 5000
127.0.0.1:5000> sentinel master mymaster
 1) "name"
 2) "mymaster"
 3) "ip"
 4) "127.0.0.1"
 5) "port"
 6) "6379"
 7) "runid"
 8) "953ae6a589449c13ddefaee3538d356d287f509b"
 9) "flags"
10) "master"
11) "link-pending-commands"
12) "0"
13) "link-refcount"
14) "1"
15) "last-ping-sent"
16) "0"
17) "last-ok-ping-reply"
18) "735"
19) "last-ping-reply"
20) "735"
21) "down-after-milliseconds"
22) "5000"
23) "info-refresh"
24) "126"
25) "role-reported"
26) "master"
27) "role-reported-time"
28) "532439"
29) "config-epoch"
30) "1"
31) "num-slaves"
32) "1"
33) "num-other-sentinels"
34) "2"
35) "quorum"
36) "2"
37) "failover-timeout"
38) "60000"
39) "parallel-syncs"
40) "1"

像你所见的,它打印了主节点的一些信息。有几个是我们特别有兴趣的:
num-other-sentinels 是2,所以我们知道对于这个主节点Sentinel已经发现了两个以上的Sentinels。如果你检查日志,你可以看到+sentinel事件发生。
flags是master。如果主节点挂掉了,我们可以看到s_down或者o_down标志。
num-slaves现在是1,所以Sentinel发现有一个从节点。
为了探测关于这个实例更多的信息,你可以尝试下面的两个命令:

SENTINEL slaves mymaster
SENTINEL sentinels mymaster

第一个将提供关于从节点类似的信息,第二个是关于另外的Sentinels。

获取当前主节点的地址

Sentinel也作为一个配置提供者,提供给客户端它们想连接的主节点和从节点的集群。因为可能的故障转移和重配置,客户端不知道一个集群实例内当前的活着的主节点,所以Sentinel提供了一个API:

127.0.0.1:5000> SENTINEL get-master-addr-by-name mymaster
1) "127.0.0.1"
2) "6379"

故障转移测试

现在我们部署Sentinel可以被测试了。我们可以杀死主节点然后查看配置变化。做我们可以做的:

redis-cli -p 6379 DEBUG sleep 30

这个命令让我们的主节点变为不可达,睡眠30秒,它基本上模拟了主节点挂掉的一些原因。
如果你检查Sentinel的日志,你应该能看到许多动作:
QQ截图20160320152458.png

  1. 每个Sentinel发现了主节点挂掉了并有一个+sdown事件
  2. 这个事件稍候升级到+odown,意味着大多数Sentinel已经同意了主节点是不可达的。
  3. Sentinels开始投票一个Sentinel开始并尝试故障转移
  4. 故障转移开始

如果你重新询问mymaster的当前主节点的地址,这次我们会得到一个不同的回复:

127.0.0.1:5000> SENTINEL get-master-addr-by-name mymaster
1) "127.0.0.1"
2) "6380"

目前为止一切都很顺利,现在你可以创建你自己的Sentinel部署或者阅读更多来理解Sentinel的命令和内部原理。

Sentinel API

Sentinel提供了一个API,可以用来检查它的状态,检查主节点和从节点的健康,订阅具体的通知并在运行时改变Sentinel的配置。
默认情况下Sentinel使用TCP端口号26379。Sentinels接收使用Redis的协议命令,所以你可以使用redis-cli或者其他未修改的Redis客户端来和Sentinel交流。
直接查询一个Sentinel来检查所监控的Redis实例的状态,看看另外的Sentinels所知道是可能的。有两种方式,使用发布/订阅,每当一些事件发生,比如说一次故障转移,或一个实例发生错误等,都可能接收到一个从Sentinels推送过来的通知。

Sentinel命令

下面是可以接收的命令列表,没有覆盖到那些用来改变Sentinel配置的命令:

  • PING 这个命令仅仅返回PONG。
  • SENTINEL masters  展示监控的主节点和它们的状态列表
  • SENTINEL master <master name> 展示指定的主节点的信息
  • SENTINEL salves <master name> 展示这个主节点的从节点,以及它们的状态
  • SENTINEL  sentinels <master name> 展示这个主节点的sentinel实例,以及它们的状态
  • SENTINEL  get-master-addr-by-name  <master name> 返回主节点的IP和端口号。如果这个主节点的一次故障转移正在进行,就返回提升的从节点的IP和端口号
  • SENTINEL reset <pattern> 这个命令将会根据匹配的名称重置主节点,pattern参数是通配符(glob-style)类型,重置进程清除主节点中之前的所有状态,并且移除主节点发现和关联的从节点和sentinel。
  • SENTINEL failover <master name> 如果主节点不可达,强制开始故障转移,不需要另外的Sentinels同意。
  • SENTINEL ckquorum <master name> 检查当前的Sentinel配置对于主节点的故障转移是否能达到仲裁人数,并且大多数是需要的来授权故障转移。这个命令应该在监控系统中使用来检查一个Sentinel部署是否正常。
  • SENTINEL flushconfig  强制Sentinel重新写入它的配置到磁盘上,包括当前Sentinel状态。通常,每次当它状态里的一些东西改变,Sentinel就会重写配置信息。然而有时候配置文件会丢失,由于错误的操作、磁盘故障、包升级脚本、或配置管理。在那种情况下,强制Sentinel重写它的配置文件是容易的。甚至之前的配置文件完全丢失,这个命令也能很好的工作。

运行时重新配置Sentinel

从Redis 2.8.4开始,Sentinel提供了一个API为了增加、移除或者改变一个给定的主节点的配置。注意如果你有多个sentinels,为了工作正常,你应该改变所有的Redis Sentinel 实例。这意味着改变单个Sentinel的配置不会把变化发送给在网络中另外的Sentinels.
下面是SENTINEL自命令列表,用来更新一个Sentinel实例的配置:

  • SENTINEL MONITOR <name> <ip> <port> <quorum> 这个命令告诉Sentinel开始监控一个指定名称、IP、端口号、quorum的主节点,它和sentinel.conf配置文件中的sentinel monitor配置指令是完全相同的,不同的是这里不能使用主机名作为IP,需要提供一个IPV4或IPV6地址。
  • SENTINEL REMOVE <name> 用来移除指定的主节点:主节点不再被监控,并且将被从Sentinel的内部状态中被完全移除,所以不会被SENTINEL masters列出。
  • SENTINEL SET <name> <option> <value> SET命令和Reids的CONFIG SET指令非常相似,被用来改变一个指定主节点的配置参数。多个选项-值可以被指定。所有通过sentinel.conf配置的参数可以使用SET命令重新配置。

下面是SENTINEL SET命令的一个例子,为了修改一个名为objects-cache的主节点的down-after-milliseconds配置:

SENTINEL SET objects-cache-master down-after-milliseconds 1000

正如我们提到的,SENTINEL SET可以被用来设置所有的在启动配置文件中被设置的参数。而且,还可以仅仅改变主节点的quorum配置,而不需要使用SENTINEL REMOVE和SENTINEL MONITOR来删除或者增加主节点,只需要使用:

SENTINEL SET objects-cache-master quorum 5

注意,没有等价的GET命令,因为SENTINEL MASTER以一种易于解析的格式提供了所有的配置参数。

添加和移除sentinels

添加一个新的sentinel到你的部署中是很容易的一个过程,因为Sentinel有自动发现机制。所有的你需要做的事情是开启一个新的Sentinel来监控当前的主节点。10秒过后,Sentinel将获取到其他的Sentinels列表和当前主节点的从节点。
如果你想一次性增加多个Sentinels,建议你一个接一个的增加,等所有的Sentinels已经知道第一个再添加另一个。在添加的新的Sentinels过程中错误有可能发生,在这时候保证在一次网络分区内中大部分是可用是很有用的。
在没有网络分区时,通过在30秒后增加每个新的节点,这是很容易实现的。
最后,可以使用SENTINEL MASTER mastername命令来检查是否全部Sentinels都同意了监控主节点的Sentinels的总数。
移除一个Sentinel稍微复杂一点:Sentinels永远不会忘记已经看到的Sentinels,甚至他们在相当长的一段时间内不可达,因为我们不想动态的改变授权一次故障转移和创建新的配置所需要的大多数。在没有网络分区的说话,需要执行下面的步骤来移除一个Sentinel:

  1. 停止你想要移除的Sentinel的进程
  2. 发送一个SENTINEL RESET *命令到其他的Sentinel实例,相继的,两次发送到实例之间至少等待30秒
  3. 检查所有的Sentinels赞同的当前存活的Sentinels的数量,通过检查每个SENTINEL MASTER mastername的输出。

移除旧的主节点或不可达的从节点

Sentinels永远不会忘记一个主节点的从节点,甚至当他们很长时间都不可达。这是很有用的,因为在一次网络分区或失败事件发生后,Sentinels应该能正确地重新配置一个返回的从节点。
而且,在故障转移发生之后,被故障转移的主节点实际上被添加为新的主节点的从节点,一旦它可用的时候,这种方式将重新配置来复制新的主节点。
然而有时候你想从Sentinels监控的从节点列表中