复制功能是Redis提供的多机功能中最基础的一个,这个功能是通过主从复制(master-slave replication)模式实现的,它允许用户为存储着目标数据库的服务器创建出多个拥有相同数据库副本的服务器,其中存储目标数据库的服务器被称为主服务器(master server),而存储数据库副本的服务器则被称为从服务器(slave server,或者称为replica)
在默认情况下,处于复制模式的主服务器既可以执行写操作也可以执行读操作,而从服务器则只能执行读操作。
Redis的复制功能可以从性能、安全性和可用性3个方面提升整个Redis系统:
用户可以通过执行REPLICAOF命令,将接收这个命令的Redis服务器设置为另一个Redis服务器的从服务器:
REPLICAOF host port
命令的host
参数用于指定主服务器的地址,而port
参数则用于指定主服务器的端口号。因为Redis的复制操作是以异步方式进行的,所以收到REPLICAOF命令的服务器在记录主服务器的地址和端口之后就会向客户端返回OK,至于实际的复制操作则会在后台开始执行。
-- 先启动一个端口为6379和端口为1234的redis-server
127.0.0.1:1234> REPLICAOF 127.0.0.1 6379 -- 把1234变成6379的从服务器
OK
127.0.0.1:6379> SET msg "hello world"
OK
127.0.0.1:6379> GET msg
"hello world"
127.0.0.1:1234> GET msg -- 主服务器上的key从服务器也可以访问
"hello world"
用户除了可以使用REPLICAOF命令将运行中的Redis服务器设置为从服务器之外,还可以修改redis.conf文件的replicaof选项
replicaof <masterip> <masterport>
还可以通过设置replicaof配置选项,在启动Redis服务器的同时将它设置为从服务器
redis-server --port 1234 --replicaof 127.0.0.1 6379
在使用REPLICAOF命令或者replicaof配置选项将一个服务器设置为从服务器之后,我们可以通过执行以下命令,让从服务器停止复制,重新变回主服务器:
REPLICAOF no one
服务器在停止复制之后不会清空数据库,而是会继续保留复制产生的所有数据。
127.0.0.1:1234> REPLICAOF no one
OK
127.0.0.1:1234> GET msg
"hello world"
用户可以通过执行ROLE
命令来查看服务器当前担任的角色:ROLE
如果执行ROLE命令的是主服务器,那么命令将返回一个由3个元素组成的数组作为结果:
127.0.0.1:6379> ROLE
1) "master" -- 这是一个主服务器
2) (integer) 2460 -- 它的复制偏移量为2460
3) 1) 1) "127.0.0.1" -- 第1个从服务器的IP地址为127.0.0.1
2) "1234" -- 这个从服务器的端口号为1234
3) "2460" -- 它的复制偏移量为2460
2) 1) "127.0.0.1" -- 第2个从服务器的IP地址为127.0.0.1
2) "1235" -- 端口号为1235
3) "2460" -- 复制偏移量为2460
如果执行ROLE命令的是从服务器,那么命令将返回一个由5个元素组成的数组作为结果:
当用户将一个服务器设置为从服务器,让它去复制另一个服务器的时候,主从服务器需要通过数据同步机制来让两个服务器的数据库状态保持一致。
当一个Redis服务器接收到REPLICAOF
命令,开始对另一个服务器进行复制的时候,主从服务器会执行以下操作:
1) 主服务器执行BGSAVE
命令,生成一个RDB文件,并使用缓冲区存储起在BGSAVE
命令之后执行的所有写命令。
2) 当RDB文件创建完毕,主服务器会通过套接字将RDB文件传送给从服务器。
3) 从服务器在接收完主服务器传送过来的RDB文件之后,就会载入这个RDB文件,从而获得主服务器在执行BGSAVE
命令时的所有数据。
4) 当从服务器完成RDB文件载入操作,并开始上线接受命令请求时,主服务器就会把之前存储在缓存区中的所有写命令发送给从服务器执行。
为了提高数据同步操作的执行效率,如果主服务器在接收到REPLICAOF
命令之前已经完成了一次RDB创建操作,并且它的数据库在创建RDB文件之后没有发生过任何变化,那么主服务器将直接向从服务器发送已有的RDB文件,以此来避免无谓的RDB文件生成操作。
此外,如果在主服务器创建RDB文件期间,有多个从服务器向主服务器发送数据同步请求,那么主服务器将把发送请求的从服务器全部放入队列中,等到RDB文件创建完毕之后,再把它发送给队列中的所有从服务器,以此来复用RDB文件并避免多余的RDB文件创建操作。
主从服务器在执行完完整同步操作之后,它们的数据就达到了一致状态,但这种一致并不是永久的:每当主服务器执行了新的写命令之后,它的数据库就会被改变,这时主从服务器的数据一致性就会被破坏。
为了让主从服务器的数据一致性可以保持下去,让它们一直拥有相同的数据,Redis会对从服务器进行在线更新:
需要注意的是,因为在线更新是异步进行的,所以在主服务器执行完写命令之后,直到从服务器也执行完相同写命令的这段时间里,主从服务器的数据库将出现短暂的不一致,因此要求强一致性的程序可能需要直接读取主服务器而不是读取从服务器。
此外,因为主服务器可能在执行完写命令并向从服务器发送相同写命令的过程中因故障而下线,所以从服务器在主服务器下线之后可能会丢失主服务器已经执行的一部分写命令,导致从服务器的数据库与下线之前的主服务器数据库处于不一致状态。
当因故障下线的从服务器重新上线时,主从服务器的数据通常已经不再一致,因此它们必须重新进行同步,让两者的数据库再次回到一致状态。
为了解决这个问题,Redis从2.8版本开始使用新的重同步功能去代替原来的重同步功能:
因为新的重同步功能需要使用先进先出队列来记录主服务器执行过的写命令,所以这个队列的体积越大,它能够记录的写命令就越多,从服务器断线之后能够快速地重新回到一致状态的机会也就越大。Redis为这个队列设置的默认大小为1MB,用户也可以根据自己的需要,通过配置选项repl-backlog-size
来修改这个队列的大小。
主服务器在进行完整同步的时候,需要在本地创建RDB文件,然后通过套接字将这个RDB文件传送给从服务器。创建RDB文件引起的大量硬盘写入将对主服务器的性能造成影响,并导致复制进程变慢。为了解决这个问题,Redis从2.8.18版本开始引入无须硬盘的复制特性(diskless replication):启用了这个特性的主服务器在接收到REPLICAOF
命令时将不会再在本地创建RDB文件,而是会派生出一个子进程,然后由子进程通过套接字直接将RDB文件写入从服务器。
要使用无须硬盘的复制特性,我们只需要将repl-diskless-sync
配置选项的值设置为yes即可:
repl-diskless-sync <yes|no>
$ redis-server --repl-diskless-sync yes
无须硬盘的复制特性只是避免了在主服务器上创建RDB文件,但仍然需要在从服务器上创建RDB文件。
因为复制的在线更新操作以异步方式进行,所以当主从服务器之间的连接不稳定,或者从服务器未能收到主服务器发送的更新命令时,主从服务器就会出现数据不一致的情况。
为了尽可能地降低数据不一致的出现概率,Redis从2.8版本开始引入了两个以min-replicas
开头的配置选项:
min-replicas-max-lag <seconds>
min-replicas-to-write <numbers>
用户设置了这两个配置选项之后,主服务器只会在从服务器的数量大于等于min-replicas-to-write
选项的值,并且这些从服务器与主服务器最后一次成功通信的间隔不超过min-replicas-max-lag
选项的值时才会执行写命令。
通过使用这两个配置选项,我们可以让主服务器只在主从服务器连接良好的情况下执行写命令。因为在线更新的异步性质,min-replicas-max-lag
和min-replicas-to-write
并没有办法完全地杜绝数据不一致的情况出现,但它们可以有效地减少因为主从服务器连接不稳定而导致的数据不一致,并降低因为没有从服务器可用而导致数据丢失的可能性。
从Redis 2.6版本开始,Redis的从服务器在默认状态下只允许执行读命令。如果用户尝试对一个只读从服务器执行写命令,那么从服务器将返回以下错误信息:
127.0.0.1:1234> REPLICAOF 127.0.0.1 6379
OK
127.0.0.1:1234> SET msg "hello world"
(error) READONLY You can't write against a read only replica.
Redis之所以将从服务器默认设置为只读服务器,是为了确保从服务器只能通过与主服务器进行数据同步来得到更新,从而保证主从服务器之间的数据一致性。
但在某些情况下,我们可能想要将一些不太重要或者临时性的数据存储在从服务器中,或者不得不在从服务器中执行一些带有写性质的命令(比如ZINTERSTORE
命令,有序集合求交集,它只能将计算结果存储在数据库中,不能直接返回计算结果)。这时我们可以通过将replica-read-only
配置选项的值设置为no来打开从服务器的写功能:
replica-read-only <yes|no>
比如,如果我们在启动服务器127.0.0.1:1234的时候,将replica-read-only
配置选项的值设置为no:
$ redis-server --port 1234 --replica-read-only no
那么即使它变成了一个从服务器,也能够正常地执行客户端发送的写命令:
127.0.0.1:1234> REPLICAOF 127.0.0.1 6379
OK
127.0.0.1:1234> SET msg "hello world again!"
OK
127.0.0.1:1234> GET msg
"hello world again!"
在使用可写的从服务器时,用户需要注意以下几个方面:
处于脚本传播模式的主服务器会将被执行的脚本及其参数(也就是EVAL命令本身)复制到AOF文件以及从服务器中。因为带有副作用的函数在不同服务器上运行时可能会产生不同的结果,从而导致主从服务器不一致,所以在这一模式下执行的脚本必须是纯函数,换句话说,对于相同的数据集,相同的脚本以及参数必须产生相同的效果。
为了保证脚本的纯函数性质,Redis对处于脚本传播模式的Lua脚本设置了以下限制:
处于命令传播模式的主服务器会将执行脚本产生的所有写命令用事务包裹起来,然后将事务复制到AOF文件以及从服务器中。因为命令传播模式复制的是写命令而不是脚本本身,所以即使脚本本身包含副作用,主服务器给所有从服务器复制的写命令仍然是相同的,因此处于命令传播模式的主服务器能够执行带有副作用的非纯函数脚本。
除了脚本可以不是纯函数之外,与脚本传播模式相比,命令传播模式对Lua环境还有以下放松:
·用户可以在执行RANDOMKEY、SRANDMEMBER等带有随机性质的命令之后继续执行写命令。
·脚本的伪随机数生成器在每次调用之前,都会随机地设置种子。换句话说,被执行的每个脚本在默认情况下产生的伪随机数列都是不一样的。
除了以上两点之外,命令传播模式与脚本传播模式的Lua环境限制是一样的,比如,即使在命令传播模式下,脚本还是无法访问Lua的时间模块以及内部状态。
为了开启命令传播模式,用户在使用脚本执行任何写操作之前,需要先在脚本中调用以下函数:
redis.replicate_commands()
redis.replicate_commands()
只对调用该函数的脚本有效:在使用命令传播模式执行完当前脚本之后,服务器将自动切换回默认的脚本传播模式。
如果我们在主服务器执行以下命令:
EVAL "redis.replicate_commands();redis.call('SET', KEYS[1], 'hello world');redis.call('SET', KEY
S[2], 10086);redis.call('SADD', KEYS[3], 'apple', 'banana', 'cherry')" 3 'msg' 'number' 'fruits'
那么主服务器将向从服务器复制以下命令:
MULTI
SET "msg" "hello world"
SET "number" "10086"
SADD "fruits" "apple" "banana" "cherry"
EXEC
为了进一步提升命令传播模式的作用,Redis允许用户在脚本中选择性地打开或者关闭命令传播功能,这一点可以通过在脚本中调用redis.set_repl()
函数并向它传入以下4个值来完成:
redis.set_repl()
函数也只对执行该函数的脚本有效。用户可以通过这一功能来定制被传播的命令序列,以此来确保只有真正需要的命令才会被传播至AOF文件以及从服务器。
存储并集计算结果的脚本
--打开目录传播模式
--以便在执行SRANDMEMBER之后继续执行DEL
redis.replicate_commands()
--集合键
local set_a = KEYS[1]
local set_b = KEYS[2]
local result_key = KEYS[3]
--随机元素的数量
local count = tonumber(ARGV[1])
--计算并集,随机选出指定数量的并集元素,然后删除并集
redis.call('SUNIONSTORE', result_key, set_a, set_b)
local elements = redis.call('SRANDMEMBER', result_key, count)
redis.call('DEL', result_key)
--返回随机选出的并集元素
return elements
如果我们使用以下方式执行这个脚本:
redis-cli --eval union_random.lua set_a set_b union_random , 3
那么主服务器将向从服务器复制以下写命令:
MULTI
SUNIONSTORE "union_random" "set_a" "set_b"
DEL "union_random"
EXEC
但仔细地思考一下就会发现,SUNIONSTORE命令创建的union_random实际上只是一个临时集合,脚本在取出并集元素之后就会使用DEL命令将其删除,因此主服务器即使不将SUNIONSTORE命令和DEL命令复制给从服务器,主从服务器包含的数据也是相同的。
修改之后得出的新脚本,新旧两个脚本在执行时将得到相同的结果,但主服务器在执行新脚本时将不会向从服务器复制任何命令。
带有选择性命令传播特性的脚本
--打开目录传播模式
--以便在执行SRANDMEMBER之后继续执行DEL
redis.replicate_commands()
--因为这个脚本即使不向从服务器传播SUNIONSTORE命令和DEL命令
--也不会导致主从服务器数据不一致,所以我们可以把命令传播功能关掉
redis.set_repl(redis.REPL_NONE)
--集合键
local set_a = KEYS[1]
local set_b = KEYS[2]
local result_key = KEYS[3]
--随机元素的数量
local count = tonumber(ARGV[1])
--计算并集,随机选出指定数量的并集元素,然后删除并集
redis.call('SUNIONSTORE', result_key, set_a, set_b)
local elements = redis.call('SRANDMEMBER', result_key, count)
redis.call('DEL', result_key)
--返回随机选出的并集元素
return elements
需要注意的是,虽然选择性复制功能非常强大,但用户如果没有正确地使用这个功能,就可能导致主从服务器的数据出现不一致,因此用户在使用这个功能的时候必须慎之又慎。
既然存在着两种不同的脚本复制模式,那么如何选择正确的模式来复制脚本就显得至关重要了。一般来说,用户可以根据以下情况来判断应该使用哪种复制模式:
举个例子,假设我们正在开发一个游戏系统,该系统的其中一项功能就是在节日给符合条件的一批用户增加指定数量的金币。为此,我们可能会写出包含以下代码的脚本,并在执行这个脚本的时候,通过KEYS变量将数量庞大的用户余额键名传递给脚本:
local user_balance_keys = KEYS
local increment = ARGV[1]
--遍历所有给定的用户余额键,对它们执行INCRBY操作
for i = 1, #user_balance_keys do
redis.call('INCRBY', user_balance_keys[i], increment)
end
很明显,这个脚本将产生相当于传入键数量的INCRBY
命令:在用户数量极其庞大的情况下,使用命令传播模式对这个脚本进行复制将耗费大量网络资源,但使用脚本传播模式复制这个脚本则会是一件非常容易的事。
现在,考虑另一种情况,假设我们正在开发一个数据聚合脚本,它包含了一个需要进行大量聚合计算以及大量数据库读写操作的aggregate_work()
函数:
local result_key = KEYS[1]
local aggregate_work =
function()
--省略大量代码
end
redis.call('SET', result_key, aggregate_work())
因为执行aggregate_work()
函数需要耗费大量计算资源,所以如果我们直接复制整个脚本,那么相同的操作就要在每个从服务器上面都执行一遍,这对于宝贵的计算资源来说无疑是一种巨大的浪费;相反,如果我们使用命令传播模式来复制这个脚本,那么主服务器在执行完这个脚本之后,就可以通过SET命令直接将函数的计算结果复制给各个从服务器。
Sentinel(哨岗、哨兵)是redis的高可用性解决方案:有一个或多个sentinel实例组成的sentinel系统可以监视任意多个主服务器,以及这些主服务器属下的所有从服务器,并在被监视的主服务器进入下线状态时,自动将下线主服务器属下的某个从服务器升级为新的主服务器,然后有新的主服务器代替已下线的主服务器继续处理命令请求。
Redis Sentinel的程序文件名为redis-sentinel,它通常和普通Redis服务器redis-server位于同一个文件夹。因为用户需要在配置文件中指定想要被Sentinel监视的主服务器,并且Sentinel也需要在配置文件中写入信息以记录主从服务器的状态,所以用户在启动Sentinel的时候必须传入一个可写的配置文件作为参数,就像这样:
$ redis-sentinel /etc/sentinel.conf
一个Sentinel配置文件至少需要包含以下选项,用于指定Sentinel要监视的主服务器:
sentinel monitor <master-name> <ip> <port> <quorum>
修改sentinel.conf文件里面的选项:
sentinel monitor mymaster 127.0.0.1 1235 1
因为我们目前只启动了一个Sentinel,所以quorum参数的值被设置成了1。也就是说,只要有一个Sentinel认为mymaster主服务器下线了,Sentinel就可以对mymaster实施故障转移了。
因为Sentinel开始监视一个主服务器之后,就会去获取被监视主服务器的从服务器名单,并根据名单对各个从服务器实施监视,整个过程是完全自动的,所以用户只需要输入待监视主服务器的地址就可以了,并不需要输入从服务器的地址。除此之外,Sentinel还会对每个被监视的主从服务器实施心跳检测,并记录各个服务器的在线状态、响应速度等信息,当Sentinel发现被监视的主服务器进入下线状态时,它就会开始对下线的主服务器实施故障转移。
因为Redis Sentinel实际上就是一个运行在特殊模式下的Redis服务器,所以用户也可以使用命令redis-server sentinel.conf --sentinel
去启动一个Sentinel:这里的--sentinel参数用于指示Redis服务器进入Sentinel模式,从而变成一个Redis Sentinel而不是普通的Redis服务器。
一个Sentinel可以监视任意数量的主服务器,而不是仅仅监视一个主服务器。如果用户想要使用Sentinel去监视多个主服务器,那么只需要在配置文件中指定多个sentinel monitor选项,并为每个被监视的主服务器设置不同的名字即可.
Sentinel在对下线的主服务器实施故障转移之后,仍然会继续对它进行心跳检测,当这个服务器重新上线的时候,Sentinel将把它转换为当前主服务器的从服务器。
用户可以通过replica-priority配置选项来设置各个从服务器的优先级,优先级较高的从服务器在Sentinel选择新主服务器的时候会优先被选择。
replica-priority的默认值为100,这个值越小,从服务器的优先级就越高。
通过这个配置选项,用户可以给性能较高的从服务器设置较高的优先级来尽可能地保证新主服务器的性能。因为主服务器在下线并重新上线之后也会变成从服务器,所以用户也应该为主服务器设置相应的优先级。
replica-priority值为0的从服务器永远不会被选为主服务器,用户可以通过这一设置将不适合用作主服务器的从服务器排除在新主服务器的候选名单之外。
当Sentinel需要在多个从服务器中选择一个作为新的主服务器时,首先会根据以下规则从候选名单中剔除不符合条件的从服务器:
1) 否决所有已经下线以及长时间没有回复心跳检测的疑似已下线从服务器。
2) 否决所有长时间没有与主服务器通信,数据状态过时的从服务器。
3) 否决所有优先级为0的从服务器。
然后根据以下规则,在剩余的候选从服务器中选出新的主服务器:
1) 优先级最高的从服务器获胜。
2) 如果优先级最高的从服务器有两个或以上,那么复制偏移量最大的那个从服务器获胜。
3) 如果符合上述两个条件的从服务器有两个或以上,那么选出它们当中运行ID(运行ID是服务器启动时自动生成的随机ID,这条规则可以确保条件完全相同的多个从服务器最终得到一个有序的比较结果)最小的那一个。
单个Sentinel监视主从服务的弊端:
·单个Sentinel可能会形成单点故障,当唯一的Sentinel出现故障时,针对主从服务器的自动故障转移将无法实施。如果同时有多个Sentinel对主服务器进行监视,那么即使有一部分Sentinel下线了,其他Sentinel仍然可以继续进行故障转移工作。
·单个Sentinel可能会因为网络故障而无法获得主服务器的相关信息,并因此错误地将主服务器判断为下线,继而执行实际上并无必要的故障转移操作。如果同时有多个Sentinel对主服务器进行监视,那么即使有一部分Sentinel与主服务器的连接中断了,其他Sentinel仍然可以根据自己对主服务器的检测结果做出正确的判断,以免执行不必要的故障转移操作。
组建Sentinel网络的方法非常简单,与启动单个Sentinel时的方法一样:用户只需要启动多个Sentinel,并使用sentinel monitor配置选项指定Sentinel要监视的主服务器,那些监视相同主服务器的Sentinel就会自动发现对方,并组成相应的Sentinel网络。
sentinel.conf
//...
port 26379
sentinel monitor mymaster 127.0.0.1 6379 2
//...
$ ./redis-sentinel sentinel.conf --port 26380
我们只需要修改这个命令的端口,以免造成端口冲突,然后就可以启动多个Sentinel。
用户应该将Sentinel和被监视的Redis服务器放到不同的机器上运行,并且各个Sentinel也应该放到不同的机器上运行,这样Sentinel网络才能够更准确、有效地判断出服务器的实际状态。
通过向Sentinel发送以下命令,用户可以获得Sentinel正在监视的所有主服务器的相关信息:
SENTINEL masters
$ ./redis-cli -p 26379
127.0.0.1:26379> sentinel masters
1) 1) "name"
2) "mymaster"
3) "ip"
4) "127.0.0.1"
5) "port"
6) "1235"
7) "runid"
8) "1f558be473579a3cf1dc8c89b899afbc14286e9a"
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) "49"
19) "last-ping-reply"
20) "49"
21) "down-after-milliseconds"
22) "30000"
23) "info-refresh"
24) "1512"
25) "role-reported"
26) "master"
27) "role-reported-time"
28) "98411085"
29) "config-epoch"
30) "1"
31) "num-slaves"
32) "2"
33) "num-other-sentinels"
34) "0"
35) "quorum"
36) "1"
37) "failover-timeout"
38) "180000"
39) "parallel-syncs"
40) "1"
因为这个Sentinel目前只监视了127.0.0.1:26379一个主服务器,所以SENTINEL masters命令只返回了一个主服务器的信息。
如果你只想获取特定主服务器的信息而不是全部主服务器的信息,可以使用以下命令代替SENTINEL masters命令:
SENTINEL master <master-name>
通过使用以下命令,用户可以让Sentinel返回指定主服务器属下所有从服务器的相关信息:
SENTINEL slaves <master-name>
在SENTINEL slaves命令返回的字段当中,大部分字段都与SENTINEL masters命令返回的字段相同,下面是未介绍过的从服务器专有字段。
用户可以通过执行以下命令,获取监视同一主服务器的其他所有Sentinel的相关信息:
SENTINEL sentinels <master-name>
SENTINEL sentinels命令返回的大部分信息项都与SENTINEL masters命令以及SENTINEL slaves命令相同,下面是未介绍过的Sentinel专有信息项。
用户可以通过执行以下命令,通过给定主服务器的名字来获取该服务器的IP地址以及端口号:
SENTINEL get-master-addr-by-name <master-name>
127.0.0.1:26379> SENTINEL get-master-addr-by-name mymaster
1) "127.0.0.1"
2) "6379"
SENTINEL reset命令接受一个glob风格的模式作为参数,接收到该命令的Sentinel将重置所有与给定模式相匹配的主服务器:
SENTINEL reset <pattern>
127.0.0.1:26379> SENTINEL reset website_db
(integer) 1 --有一个主服务器被重置了
127.0.0.1:26379> SENTINEL reset website_* -- 对所有带有website_前缀的主服务器进行重置的方法
(integer) 1
因为SENTINEL reset命令可以让Sentinel忘掉主服务器之前的记录,并重新开始对主服务器进行监视,所以它通常只会在Sentinel网络或者被监视主从服务器的结构出现重大变化时使用。
复杂度:O(N),其中N为被重置的主服务器数量。
通过执行以下命令,用户可以强制对指定的主服务器实施故障转移,就好像它已经下线了一样:
SENTINEL failover <master-name>
接收到这一命令的Sentinel会直接对主服务器执行故障转移操作,而不会像平时那样,先在Sentinel网络中进行投票,然后再根据投票结果决定是否执行故障转移操作。
127.0.0.1:26379> SENTINEL failover website_db
OK
用户可以通过执行以下命令,检查Sentinel网络当前可用的Sentinel数量是否达到了判断主服务器客观下线并实施故障转移所需的数量:
SENTINEL ckquorum <master-name>
127.0.0.1:26379> SENTINEL ckquorum website_db
OK 3 usable Sentinels. Quorum and failover authorization can be reached
SENTINEL ckquorum命令一般用于检查Sentinel网络的部署是否成功。
比如,如果我们在部署了3个Sentinel之后,却发现SENTINEL ckquorum只能识别到2个可用的Sentinel,那就说明有什么地方出错了。
用户可以通过向Sentinel发送以下命令,让Sentinel将它的配置文件重新写入硬盘中:
SENTINEL flushconfig
因为Sentinel在被监视服务器的状态发生变化时就会自动重写配置文件,所以这个命令的作用就是在配置文件基于某些原因或错误而丢失时,立即生成一个新的配置文件。此外,当Sentinel的配置选项发生变化时,Sentinel内部也会使用这个命令创建新的配置文件来替换原有的配置文件。
$ ls -l
total 8
-rw-r--r-- 1 huangz staff 550 1 21 21:30 sentinel.conf
$ rm sentinel.conf
$ ls -l
$
然后在客户端中执行重写命令:
127.0.0.1:26379> SENTINEL flushconfig
OK
这样Sentinel将重新生成一个配置文件:
$ ls -l
total 8
-rw-r--r-- 1 huangz staff 549 1 21 21:44 sentinel.conf
最后要注意的是,只有接收到SENTINEL flushconfig命令的Sentinel才会重写配置文件,Sentinel网络中的其他Sentinel并不会受到这个命令的影响。
通过执行以下命令,用户可以让Sentinel开始监视一个新的主服务器:
SENTINEL monitor <master-name> <ip> <port> <quorum>
SENTINEL monitor命令本质上就是SENTINEL monitor配置选项的命令版本,当我们想要让Sentinel监视一个新的主服务器,但是又不想重启Sentinel并手动修改Sentinel配置文件时就可以使用这个命令。
127.0.0.1:26379> SENTINEL monitor message_queue_db 127.0.0.1 10086 2
OK
在此之后,如果我们执行SENTINEL masters命令,就会看到Sentinel现在除了监视着website_db主服务器之外,还监视着message_queue_db主服务器:
127.0.0.1:26379> SENTINEL masters
1) 1) "name"
2) "message_queue_db"
3) "ip"
4) "127.0.0.1"
5) "port"
6) "10086"
...
39) "parallel-syncs"
40) "1"
2) 1) "name"
2) "website_db"
3) "ip"
4) "127.0.0.1"
5) "port"
6) "6379"
...
39) "parallel-syncs"
40) "1"
当用户想要在线取消Sentinel对某个主服务器的监视时,可以使用以下命令:
SENTINEL remove <masters-name>
接收到这个命令的Sentinel会停止对给定主服务器的监视,并删除Sentinel内部以及Sentinel配置文件中与给定主服务器有关的所有信息,然后返回OK表示操作执行成功。
我们通过使用SENTINEL monitor命令,让Sentinel开始监视message_queue_db主服务器。现在,我们也可以通过执行以下命令,让Sentinel取消对essage_queue_db主服务器的监视:
127.0.0.1:26379> SENTINEL remove message_queue_db
OK
在执行了这个命令之后,message_queue_db主服务器就会从Sentinel的监视名单中消失,现在Sentinel只会继续监视website_db主服务器:
127.0.0.1:26379> SENTINEL masters
1) 1) "name"
2) "website_db"
3) "ip"
4) "127.0.0.1"
5) "port"
6) "6379"
...
39) "parallel-syncs"
40) "1"
通过使用以下命令,用户可以在线修改Sentinel配置文件中与主服务器相关的配置选项值:
SENTINEL set <master-name> <option> <value>
只要是Sentinel配置文件中与主服务器有关的配置选项,都可以使用SENTINEL set命令在线进行配置。命令在成功修改给定的配置选项值之后将返回OK作为结果。
127.0.0.1:26379> SENTINEL masters
1) 1) "name"
2) "website_db"
...
35) "quorum"
36) "2"
...
39) "parallel-syncs"
40) "1"
现在,如果我们想要将这个选项的值修改为3,那么可以执行以下命令:
127.0.0.1:26379> SENTINEL set website_db quorum 3
OK
在执行以上命令之后,我们可以通过再次查看website_db的配置选项来确认修改已经发生:
127.0.0.1:26379> SENTINEL masters
1) 1) "name"
2) "website_db"
...
35) "quorum"
36) "3"
...
39) "parallel-syncs"
40) "1"
需要注意的是,以上介绍的各个在线配置命令只会对接收到命令的单个Sentinel生效,但并不会对同一个Sentinel网络的其他Sentinel产生影响。为了将新的配置选项传播给整个Sentinel网络,用户需要对同一个Sentinel网络中的所有Sentinel都执行相同的命令。
我们通过向Sentinel 26379发送SENTINEL set website_db quorum 3命令,把该Sentinel对于website_db主服务器的quorum值修改成了3,但这个修改只对Sentinel 26379有效,Sentinel网络中的其他两个Sentinel——Sentinel 26380和Sentinel 26381的quorum值仍然是2。为了让整个Sentinel网络的所有Sentinel都拥有相同的quorum值,我们必须向剩下的两个Sentinel发送相同的SENTINEL set命令:
127.0.0.1:26380> SENTINEL set website_db quorum 3
OK
127.0.0.1:26381> SENTINEL set website_db quorum 3
OK
现在,Sentinel网络中的3个Sentinel都把自身对于website_db主服务器的quorum值设置成了3。
Redis Sentinel允许用户为Sentinel网络中的每个Sentinel分别设置主服务器的quorum值,而不是让所有Sentinel都共享同一个quorum值,这种做法使得用户可以在有需要时,灵活地根据各个Sentinel所处的环境来调整自己的quorum值。
如果一部分Sentinel与被监视主服务器的网络连接情况较好,或者两者在网络上的距离较近,那么这些Sentinel对于主服务器的下线判断就会更为准确,用户就可以把它们的quorum值调得小一些,使得这些Sentinel可以快速地对下线的主服务器进行故障转移。
相反,如果一部分Sentinel与被监视主服务器的网络连接情况较差,或者两者在网络上的距离较远,那么这些Sentinel对于主服务器的下线判断的准确性就会差一些,如果把它们的quorum值设置得太小,可能会错误地触发故障转移操作。为此,用户可以把这些Sentinel的quorum值调大一些,确保只有在多个Sentinel都认为主服务器已下线时,才执行故障转移操作。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。