redis sentinel 高可用架构

参考
https://blog.csdn.net/tengxing007/article/details/77462578
http://www.cnblogs.com/xuanzhi201111/p/5249626.html

Redis的高可用架构有比如keepalived+redis,redis cluster,twemproxy,codis,下面我们主要针对Redis Sentinel高可用架构展开学习。

哨兵的任务
监控(Monitoring):Sentinel会不断地检查你的主服务器和从服务器是否运作正常

提醒(Notification):当被监控的某个Redis服务器出现问题时,Sentinel可以通过API向管理员或者其他应用程序发送通知

自动故障迁移(Automatic failover):当一个主服务器不能正常工作时,Sentinel 会开始一次自动故障迁移操作,它会将失效主
服务器的其中一个从服务器升级为新的主服务器,并让失效主服务器的其他从服务器改为复制新的主服务器;当客户端试图连接失效的主
服务器时,集群也会向客户端返回新主服务器的地址,使得集群可以使用新主服务器代替失效服务器

Sentinel是一个监视器,它可以根据被监视实例的身份和状态来判断应该执行何种动作。Sentinel是如何发现其他Sentinel的呢?Sentinel会通过命令连接向被监视的主从服务器发送HELLO信息,该消息包含Sentinel的IP、端口号、ID等内容,以此来向其他Sentinel宣告自己的存在。与此同时,Sentinel会通过订阅连接接收其他Sentinel的HELLO信息,以此来发现监视同一个主服务器的其他Sentinel。
redis sentinel 高可用架构_第1张图片

Sentinel之间会互相创建命令连接,用于进行通信。因为已经有主从服务器作发送和接收HELLO信息的中介,所以Sentinel之间不会创建订阅连接:
以下是Redis Sentinel的架构图,Sentinel节点数最好是单数
redis sentinel 高可用架构_第2张图片

进到conf目录,编辑文件26379.conf,三台Sentinel服务器,配置都一样:

sentinel conf 配置

6379

sentinel monitor master-6379 192.168.10.131 6379 2
sentinel down-after-milliseconds master-6379 15000
sentinel parallel-syncs master-6379 1
sentinel failover-timeout master-6379 180000
sentinel auth-pass master-6379 123456
sentinel client-reconfig-script master-6379 /data/script/python/notify.py
[root@Sentinel_1 conf]#
复制代码
26379.conf配置文件解释:
1、前4行是定义sentinel的一些基本信息,跟redis很类似,不作过多解释。

2、sentinel monitor master-6379 192.168.10.131 6379 2(这一行代表sentinel监控的master的名字叫做master-6379,地址为192.168.10.131:6379,这个2代表,当集群中有2个sentinel认为master死了时,才能真正认为该master已经不可用了)

3、down-after-milliseconds (sentinel会向master发送心跳PING来确认master是否存活,如果master在“一定时间范围”内不回应PONG 或者是回复了一个错误消息,那么这个sentinel会主观地(单方面地)认为这个master已经不可用,而这个down-after-milliseconds就是用来指定这个“一定时间范围”的,单位是毫秒。)

4、parallel-syncs(在发生failover主备切换时,这个选项指定了最多可以有多少个slave同时对新的master进行同步,这个数字越小,完成failover所需的时间就越长,但是如果这个数字越大,就意味着越多的slave因为replication而不可用。可以通过将这个值设为 1 来保证每次只有一个slave处于不能处理命令请求的状态)

5、failover-timeout(sentinel集群都遵守一个规则:如果sentinel A推荐sentinel B去执行failover,B会等待一段时间后,自行再次去对同一个master执行failover,这个等待的时间是通过failover-timeout配置项去配置的。从这个规则可以看出,sentinel集群中的sentinel不会再同一时刻并发去failover同一个master,第一个进行failover的sentinel如果失败了,另外一个将会在一定时间内进行重新进行failover,以此类推)

6、auth-pass(这选项主要针对redis master/slave架构设置了密码认证,如果配置主从时没有设定密码,就不需要些选项,若有密码,这里要指定连接的密码)

7、client-reconfig-script (该参数是定义故障转移脚本,当master故障转移后,执行发短信或者IP切换等)

集群配置
1. master.conf

port 8001
bind 127.0.0.1

redis将以守护进程的方式运行,这样可以在redis服务启动的窗口中再可以进行其它操作

daemonize yes
pidfile “/var/run/redis_8001.pid”

cluster-enabled yes

cluster-config-file nodes_8001.conf

cluster-node-timeout 15000

appendonly yes

requirepass test123 设置redis客户端或者远程机器连接redis服务器需要的密码

masterauth test123 从服务器和哨兵连接主服务器需要的密码

cluster-require-full-coverage no

Generated by CONFIG REWRITE

dir “/home/tengxing/Dtt/redis-cluster”

  1. slave.conf(配置两个文件,不同的port)

port 8015
daemonize yes
slave-read-only yes

requirepass “yjxxclub”

slaveof 127.0.0.1 8001

masterauth “yjxxclub”

bind 0.0.0.0

cluster-require-full-coverage no

Generated by CONFIG REWRITE

dir “/home/tengxing/Dtt/redis-cluster”

  1. sentinel.conf(配置三个文件,不同的port)

    port 8101
    daemonize yes
    protected-mode no
    logfile “/opt/redis-cluster/logs/sentinel_8101.log”

    master-1

    sentinel monitor master-1 10.211.55.10 6381 1
    sentinel down-after-milliseconds master-1 5000
    sentinel failover-timeout master-1 18000
    sentinel auth-pass master-1 test123
    sentinel parallel-syncs master-1 1

redis sentinel 与redis cluster

sentinel:
上一篇提到了主从切换,sentinel的作用是将这个过程自动化,实现高可用。
它的主要功能有以下几点:

不时地监控redis是否按照预期良好地运行;
如果发现某个redis节点运行出现状况,能够通知另外一个进程(例如它的客户端);
能够进行自动切换。当一个master节点不可用时,能够选举出master的多个slave(如果有超过一个slave的话)中的一个来作为新的master,其它的slave节点会将它所追随的master的地址改为被提升为master的slave的新地址。
Sentinel本身也支持集群,只使用单个sentinel进程来监控redis集群是不可靠的,当sentinel进程宕掉后,sentinel本身也有单点问题。所以有必要将sentinel集群,这样有几个好处:

如果只有一个sentinel进程,如果这个进程运行出错,或者是网络堵塞,那么将无法实现redis集群的主备切换(单点问题)。
如果有多个sentinel,redis的客户端可以随意地连接任意一个sentinel来获得关于redis集群中的信息。
sentinel集群自身也需要多数机制,也就是2个sentinel进程时,挂掉一个另一个就不可用了。
在默认情况下,Sentinel 使用TCP端口26379(普通 Redis 服务器使用的是 6379)。Sentinel 接受 Redis 协议格式的命令请求, 所以可以使用 redis-cli 或者任何其他 Redis 客户端来与 Sentinel 进行通讯。

redis-cli -p 26379

127.0.0.1:26379> ping
PONG
启动sentinel:
配置文件:

port 26329
sentinel monitor myredis 127.0.0.1 6379 2
sentinel down-after-milliseconds mymaster 60000
sentinel failover-timeout mymaster 180000
sentinel parallel-syncs mymaster 1
sentinel notification-script
第一行port指定sentinel端口。
第二行monitor配置指示 Sentinel 去监视一个名为 myredis 的主redis实例。Sentinel的配置文件中不必说明此主实例属下的从实例,因为Sentinel实例可以通过询问主实例来获得所有从实例的信息。
行末2表示将这个主实例判断为失效至少需要2个 Sentinel 进程的同意,只要同意 Sentinel 的数量不达标,自动failover就不会执行。
down-after-milliseconds 选项指定了 Sentinel 认为Redis实例已经失效所需的毫秒数。当实例超过该时间没有返回PING,或者直接返回错误, 那么 Sentinel 将这个实例标记为主观下线(subjectively down,简称 SDOWN )。
failover-timeout表示如果在该时间(ms)内未能完成failover操作,则认为该failover失败。
parallel-syncs如果全部从实例一起对新的主实例进行同步, 那么就可能会造成所有从Redis实例在短时间内全部不可用的情况出现。可以通过将这个值设为 1 来保证每次只有一个slave处于不能处理命令请求的状态。
notification-script指定sentinel检测到该监控的redis实例指向的实例异常时,调用的报警脚本。该配置项可选。
启动Sentinel:
Sentinel只是一个运行在特殊模式下的 Redis实例, 你可以在启动一个普通 Redis实例时通过给定 –sentinel 选项来启动 Redis Sentinel 实例。如:
redis-server /path/to/sentinel.conf –sentinel
当然也可以运行Redis自带的redis-sentinel,如:
redis-sentinel /path/to/sentinel.conf

Sentinel集群:
1.和其他集群不同,你无须设置其他Sentinel的地址,Sentinel进程可以通过发布与订阅来自动发现正在监视相同主实例的其他Sentinel。当一个 Sentinel 发现一个新的 Sentinel 时,它会将新的 Sentinel 添加到一个列表中,这个列表保存了 Sentinel 已知的,监视同一个主服务器的所有其他Sentinel。
2.Sentinel集群中的Sentinel不会再同一时刻并发去failover同一个master,第一个进行failover的Sentinel如果失败了(上文配置的failover-timeout),另外一个才会重新进行failover,以此类推。
3.当Sentinel将一个slave选举为master并发送SLAVE OF NO ONE后,即使其它的slave还没针对新master重新配置自己,failover也被认为是成功了。
4.上述过度过程中,若此时重启old master,则redis集群将处于无master状态,此时只能手动修改配置文件,然后重新启动集群.
5.Master-Slave切换后,Sentinel会改写master,slave和sentinel的conf配置文件。
6.一旦一个Sentinel成功地对一个master进行了failover,它将会把关于master的最新配置通过广播形式通知其它sentinel,其它的Sentinel则更新对应master的配置。

例子:
启动redis:

/etc/redis/redis-m.conf
daemonize yes
pidfile /var/run/redis/redis-server-m.pid
port 6379
loglevel notice
logfile /var/log/redis/redis-server-m.log
databases 16

disable snapshot

save “”
dir /app/redis-m
appendonly yes
appendfilename “appendonly.aof”

not to be a slave

slaveof no one

/etc/redis/redis-s1.conf
daemonize yes
pidfile /var/run/redis/redis-server-s1.pid
port 6380
loglevel warning
logfile /var/log/redis/redis-server-s1.log
databases 16

disable snapshot

save “”
dir /app/redis-s1
appendonly yes
appendfilename “appendonly.aof”

to be a slave

slaveof 127.0.0.1 6379

/etc/redis/redis-s2.conf
daemonize yes
pidfile /var/run/redis/redis-server-s2.pid
port 6381
loglevel warning
logfile /var/log/redis/redis-server-s2.log
databases 16

disable snapshot,enable AOF

save “”
dir /app/redis-s2
appendonly yes
appendfilename “appendonly.aof”

to be a slave

slaveof 127.0.0.1 6379
查看进程实例:

ps -ef | grep redis
root 17560 1 0 09:48 ? 00:00:00 redis-server *:6379
root 17572 1 0 09:48 ? 00:00:00 redis-server *:6380
root 17609 1 0 09:49 ? 00:00:00 redis-server *:6381

redis-cli
127.0.0.1:6379> info replication

Replication

role:master
connected_slaves:2
slave0:ip=127.0.0.1,port=6380,state=online,offset=547,lag=0
slave1:ip=127.0.0.1,port=6381,state=online,offset=547,lag=1
master_repl_offset:547
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:2
repl_backlog_histlen:546
启动sentinel:

sentinel1.conf
port 26379
sentinel monitor myredis 127.0.0.1 6379 2
sentinel down-after-milliseconds myredis 60000
sentinel failover-timeout myredis 180000
sentinel parallel-syncs myredis 1
sentinel notification-script myredis /etc/redis/log-issues.sh

sentinel2.conf
port 26380
sentinel monitor myredis 127.0.0.1 6379 2
sentinel down-after-milliseconds myredis 60000
sentinel failover-timeout myredis 180000
sentinel parallel-syncs myredis 1
sentinel notification-script myredis /etc/redis/log-issues.sh

log-issues.sh

!/bin/bash

echo “master failovered at date” > /root/redis_issues.log

——-启动——–
nohup redis-sentinel /etc/redis/sentinel1.conf
nohup redis-sentinel /etc/redis/sentinel2.conf
连接:

127.0.0.1:26379> sentinel masters
1) 1) “name”
2) “myredis”
3) “ip”
4) “127.0.0.1”
5) “port”
6) “6379”
7) “runid”
8) “a88ffd6548e333f3ac895cf1b890ef32a527dd66”
……
37) “parallel-syncs”
38) “1”
39) “notification-script”
40) “/etc/redis/log-issues.sh”
127.0.0.1:26379> sentinel slaves myredis
1) 1) “name”
2) “127.0.0.1:6381”
3) “ip”
4) “127.0.0.1”
5) “port”
6) “6381”
……
2) 1) “name”
2) “127.0.0.1:6380”
3) “ip”
4) “127.0.0.1”
5) “port”
6) “6380”
sentinel reset : 重置所有名字和给定模式 pattern 相匹配的主服务器。 pattern 参数是一个 Glob 风格的模式。 重置操作清除该sentinel的所保存的所有状态信息,并进行一次重新的发现过程。

127.0.0.1:26379> sentinel reset myredis
(integer) 1
sentinel failover :进行一次主动的failover。即在不询问其他 Sentinel 意见的情况下, 强制开始一次自动故障迁移 。发起故障转移的 Sentinel 会向其他 Sentinel 发送一个新的配置,其他 Sentinel 会根据这个配置进行相应的更新。

127.0.0.1:26379> sentinel failover myredis
OK
master切换到了localhost:6381上:

127.0.0.1:26379> sentinel get-master-addr-by-name myredis
1) “127.0.0.1”
2) “6381”

redis-cli中

redis-cli
127.0.0.1:6379> info replication

Replication

role:slave
master_host:127.0.0.1
master_port:6381
master_link_status:up
客户端:
sentinel 的 failover 过程对客户端是透明的,以Java Jedis为例:

public class RedisSentinelClient {

/**
 * @param args
 */
public static void main(String[] args) {
    Set sentinels = new HashSet();
    sentinels.add(new HostAndPort("172.30.37.73", 26379).toString());
    sentinels.add(new HostAndPort("172.30.37.73", 26380).toString());
    sentinels.add(new HostAndPort("172.30.37.73", 26381).toString());
    JedisSentinelPool sentinelPool = new JedisSentinelPool("myredis", sentinels);
    System.out.println("Current master: " + sentinelPool.getCurrentHostMaster().toString());

    Jedis master = sentinelPool.getResource();
    master.set("username","tom");
    sentinelPool.returnResource(master);

    Jedis master2 = sentinelPool.getResource();
    String value = master2.get("username");
    System.out.println("username: " + value);
    master2.close();
    sentinelPool.destroy();
}

}
cluster:
1.一个 Redis 集群包含 16384 个哈希槽(hash slot),数据库中的每个键都属于这 16384 个哈希槽的其中一个,集群中的每个节点负责处理一部分哈希槽。 例如一个集群有三个节点,其中:
节点 A 负责处理 0 号至 5500 号哈希槽。
节点 B 负责处理 5501 号至 11000 号哈希槽。
节点 C 负责处理 11001 号至 16384 号哈希槽。
这种将哈希槽分布到不同节点的做法使得用户可以很容易地向集群中添加或者删除节点。例如:
如果用户将新节点 D 添加到集群中, 那么集群只需要将节点 A 、B 、 C 中的某些槽移动到节点 D 就可以了。
如果用户要从集群中移除节点 A , 那么集群只需要将节点 A 中的所有哈希槽移动到节点 B 和节点 C , 然后再移除空白(不包含任何哈希槽)的节点 A 就可以了。
2.Redis 集群对节点使用了主从复制功能: 集群中的每个节点都有 1 个至 N 个复制品(replica), 其中一个复制品为主节点(master), 而其余的 N-1 个复制品为从节点(slave)。
3.Redis 集群的节点间通过Gossip协议通信。

命令:

//集群(cluster)
CLUSTER INFO 打印集群的信息
CLUSTER NODES 列出集群当前已知的所有节点(node),以及这些节点的相关信息。
//节点(node)
CLUSTER MEET 将 ip 和 port 所指定的节点添加到集群当中,让它成为集群的一份子。
CLUSTER FORGET 从集群中移除 node_id 指定的节点。
CLUSTER REPLICATE 将当前节点设置为 node_id 指定的节点的从节点。
CLUSTER SAVECONFIG 将节点的配置文件保存到硬盘里面。
//槽(slot)
CLUSTER ADDSLOTS [slot …] 将一个或多个槽(slot)指派(assign)给当前节点。
CLUSTER DELSLOTS [slot …] 移除一个或多个槽对当前节点的指派。
CLUSTER FLUSHSLOTS 移除指派给当前节点的所有槽,让当前节点变成一个没有指派任何槽的节点。
CLUSTER SETSLOT NODE 将槽 slot 指派给 node_id 指定的节点,如果槽已经指派给另一个节点,那么先让另一个节点删除该槽>,然后再进行指派。
CLUSTER SETSLOT MIGRATING 将本节点的槽 slot 迁移到 node_id 指定的节点中。
CLUSTER SETSLOT IMPORTING 从 node_id 指定的节点中导入槽 slot 到本节点。
CLUSTER SETSLOT STABLE 取消对槽 slot 的导入(import)或者迁移(migrate)。
//键 (key)
CLUSTER KEYSLOT 计算键 key 应该被放置在哪个槽上。
CLUSTER COUNTKEYSINSLOT 返回槽 slot 目前包含的键值对数量。
CLUSTER GETKEYSINSLOT 返回 count 个 slot 槽中的键。
启动集群:
Redis Cluster如果数据冗余是1的话,至少要3个Master和3个Slave

192.168.XXX.XXX:7000
192.168.XXX.XXX:7001
192.168.XXX.XXX:7002
192.168.XXX.XXX:7003
192.168.XXX.XXX:7004
192.168.XXX.XXX:7005
配置文件:

bind 192.168.XXX.XXX //不能绑定到192.168.XXX.XXX或localhost,否则指导客户端重定向时会报”Connection refused”的错误。
port 7000
daemonize yes //后台运行
cluster-enabled yes //开启Cluster
cluster-require-full-coverage no //默认是yes,只要有结点宕机导致16384个槽没全被覆盖,整个集群就全部停止服务,改为no。
cluster-config-file nodes_7000.conf //集群配置文件,这个配置文件不是要我们去配的,而是Redis运行时保存配置的文件,所以我们也不可以修改这个文件。
cluster-node-timeout 5000 //超时多久则认为它宕机了。
appendonly yes
logfile ./redis_7000.log
启动各节点:redis-server redis_700X.conf
安装基于ruby的集群工具:

yum install ruby rubygems -y
wget https://rubygems.org/downloads/redis-3.2.1.gem
gem install -l redis-3.2.1.gem
cp redis-3.2.1/src/redis-trib.rb /usr/local/bin/redis-trib //复制集群管理程序到/usr/local/bin
创建集群:

redis-trib create –replicas 1 127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005
–replicas 1 表示我们希望为集群中的每个主节点创建一个从节点,以上命令的意思就是让 redis-trib 程序创建一个包含三个主节点和三个从节点的集群。

测试:

$ redis-cli -c -p 7000
redis 127.0.0.1:7000> set foo bar
-> Redirected to slot [12182] located at 127.0.0.1:7002
OK
redis 127.0.0.1:7002> set hello world
-> Redirected to slot [866] located at 127.0.0.1:7000
OK
redis 127.0.0.1:7000> get foo
-> Redirected to slot [12182] located at 127.0.0.1:7002
“bar”
redis 127.0.0.1:7000> get hello
-> Redirected to slot [866] located at 127.0.0.1:7000
“world”
值被放到了相应节点的Hash槽中,redis-cli不断在700X节点之前重定向跳转。如果启动时不加-c选项的话,就能看到以错误形式显示出的MOVED重定向消息。

重新分片:
重分片基本上就是从部分节点移动哈希槽到另外一部分节点上去,像创建集群一样也是通过使用 redis-trib 工具来完成。

添加新节点:
现在按照相同方法启动了两个新实例7010,7011。其中7010为主,7011为从。

//添加主节点
redis-trib.rb add-node 192.168.1.100:7010 192.168.1.100:7000
//查看节点信息,7010被成功添加
redis-cli -c -h 192.168.1.100 -p 7000 cluster nodes


0d1f9c979684e0bffc8230c7bb6c7c0d37d8a5a9 192.168.1.100:7010 master - 0 1442452249525 0 connected


//添加从节点
redis-trib.rb add-node –slave –master-id 0d1f9c979684e0bffc8230c7bb6c7c0d37d8a5a9 192.168.1.100:7011 192.168.1.100:7000
迁移Slot:

redis-trib.rb reshard 192.168.1.100:7000 //下面是主要过程

How many slots do you want to move (from 1 to 16384)? 1000 //设置slot数1000
What is the receiving node ID? 03ccad2ba5dd1e062464bc7590400441fafb63f2 //新节点node id
Please enter all the source node IDs.
Type ‘all’ to use all the nodes as source nodes for the hash slots.
Type ‘done’ once you entered all the source nodes IDs.
Source node #1:all //表示全部节点重新洗牌
Do you want to proceed with the proposed reshard plan (yes/no)? yes //确认重新分
删除节点:
如果删除的是主节点,她有slot,需要先去掉分配的slot,然后在删除主节点

redis-trib.rb reshard 192.168.10.219:6378 //取消分配的slot,下面是主要过程

How many slots do you want to move (from 1 to 16384)? 1000 //被删除master的所有slot数量
What is the receiving node ID? 5d8ef5a7fbd72ac586bef04fa6de8a88c0671052 //接收6378节点slot的master
Please enter all the source node IDs.
Type ‘all’ to use all the nodes as source nodes for the hash slots.
Type ‘done’ once you entered all the source nodes IDs.
Source node #1:03ccad2ba5dd1e062464bc7590400441fafb63f2 //被删除master的node-id
Source node #2:done
Do you want to proceed with the proposed reshard plan (yes/no)? yes //取消slot后,reshard
//现在节点上已经没有slot

redis-trib.rb del-node 192.168.10.219:6378 ‘03ccad2ba5dd1e062464bc7590400441fafb63f2’

Jedis客户端:

Set jedisClusterNodes = new HashSet();
//Jedis Cluster will attempt to discover cluster nodes automatically
jedisClusterNodes.add(new HostAndPort(“127.0.0.1”, 7379));
JedisCluster jc = new JedisCluster(jedisClusterNodes);
jc.set(“foo”, “bar”);
String value = jc.get(“foo”);
要点:
Sentinel是一种自动failover的解决方案。Cluster是一种分片的方案,自带failover,使用Cluster时不需要再用Sentinel。
Sentinel:
1.Sentinel的作用是将主从切换自动化。
2.Sentinel本身也支持集群,用Sentinel集群来监控redis集群。
3.Sentinel集群自身也需要多数机制。(避免单点问题,至少需要三个)
4.Sentinel只是一个运行在特殊模式下的 Redis实例。

通过给定 –sentinel 选项来启动 Redis Sentinel 实例。如:
redis-server /path/to/sentinel.conf –sentinel
当然也可以运行Redis自带的redis-sentinel,如:
redis-sentinel /path/to/sentinel.conf
在默认情况下,Sentinel 使用TCP端口26379。 可以使用 redis-cli 进行通讯 redis-cli -p 26379。
4.Sentinel进程可以通过发布与订阅来自动发现正在监视相同主实例的其他Sentinel,只需监控相同主实例无须设置其他Sentinel的地址。

配置文件conf中

sentinel monitor myredis 127.0.0.1 6379 2
5.Sentinel 的 failover 过程对代码客户端是透明的。

你可能感兴趣的:(Redis)