redis主从&哨兵&集群

一、主从复制

  1、主从同步介绍

    通过主从复制,可以避免出现单点故障,即使主redis宕机,从服务器仍然可以提供服务;

    主redis中的数据和从redis中的数据保持实时同步,当主redis写入数据时,通过主从复制机制会复制到两个从redis中;

    只有一个主redis,可以有多个从redis,一个redis既可以是主redis也可以是从redis

    redis主从复制不会阻塞master,在同步数据时,master可以继续处理客户端的请求

  2、实现原理

    redis的主从同步分为全量同步和增量同步,只有在redis第一次启动时,会使用全量同步,对于断线重连的场景,有可能是全量同步也有可能是增量同步,这要看master的runid是否一致,其余场景都是增量同步。

    全量同步:全量同步分为三个阶段,同步快照阶段、同步写缓冲阶段、同步增量阶段

      同步快照阶段:master创建并发送快照给slave,slave载入并解析快照。master同时将此阶段所产生的写命令存储到缓存区

      同步写缓冲阶段:master向slave同步存储在缓存区的写命令

      同步增量阶段:master向slave同步写操作命令。

    增量同步:redis增量同步指的是slave完成初始化后开始正常工作,master发生的写操作同步到slave的过程。通常情况下,master的每一个写命令都会向slave发送一个写命令,然后slave接收并执行。

  3、搭建主从

    主节点配置无需变化,从节点设置主节点的ip和端口

    4.0之前使用slaveof  IP port

slaveof 8.131.245.53 6379

    4.0之后使用replicaof IP port

repllicaof 8.131.245.53 6379

  按照上述配置,主从就搭建完毕,先启动主节点,后启动从节点,可以在主节点做一些写入操作,同时在从节点查看。从节点不能写入数据。

  连接从节点:

./bin/redis-cli -p 6380

  主从的缺点就是如果主节点宕机,没有办法对master进行动态选举。哨兵模式对此做了完善。

二、哨兵

  Sentinel(哨兵)进程用于监控redis集群中master主服务器的状态,在master发生故障时,可以动态的选举master,从而实现master和slave的切换,进而保证系统的高可用。

  Sentinel已经集成在redis2.6及后续的版本中了,并在2.8版本稳定。

  哨兵模式主要的作用就是:监控及节点故障判断、哨兵leader的选举、自动故障迁移

  哨兵的作用主要是:监控、提醒、自动故障迁移

    监控:哨兵会不断的检查master和slave是否运作正常

    提醒:当被监控的某个redis节点出现问题时,哨兵可以通过API向管理员或者其他应用程序发送通知

    自动故障迁移:当一个master不能正常工作时,哨兵会开始一次自动故障迁移操作。

  1、哨兵监控及节点故障判定  

    哨兵的监控总共有3个任务:获取主从拓扑图的info命令、监控其他节点的PING-PONG机制命令、向其他哨兵发送监控主节点状态的消息

      监控master的info命令:每个哨兵节点会以每10秒一次的频率向主节点和从节点发送info命令,从而获取redis主从的拓扑图,哨兵配置时只配置对主节点的监控即可,通过对主节点发送info命令,获取从节点的信息,当有新的从节点加入时,可以立马感知。

      监控其他节点的PING-PONG机制命令:哨兵会以1秒一次的频率向master、slave、sentinel节点发送一次ping命令做一次心跳检测,这个是哨兵判断节点是否正常的重要依据。

      向其他哨兵发送监控master状态消息:每个哨兵每2秒会向redis数据节点的指定频道上发送其对于master节点的监控状态以及当前哨兵的相关信息,同时每个哨兵也会订阅该频道,用来了解其他哨兵节点的信息及对主节点的判断,其实就是通过消息的publish和subscribe来完成的。

    

    故障判断主要是有SDOWN(主观下线)和ODOWN(客观下线)区分

    (1)每一个哨兵以每秒一次的频率向整个集群中的master和slave以及其他的哨兵发送一个PING请求。

    (2)如果一个实例距最后一次有效回复PING命令的时间超过了down-after-milliseconds选项所设置的值,则这个实例会被哨兵标记为主观下线(SDOWN)

    (3)如果master节点被标记为SDOWN,此时该哨兵会使用sentinel is-masterdown-by-addr指令来寻求其他哨兵对master的判断

    (4)当有足够数量的哨兵在时间范围内确认了master已经处于SDOWN状态,那么master的状态会变为ODOWN

    (5)一般情况下,哨兵会以10秒一次的频率向master和slave发送info命令,如果当master被标记为ODOWN后,哨兵向已下线master节点的所有从节点发送info命令的频率改为一秒一次。

    (6)若没有足够的哨兵统一master下线,master的ODOWN状态会被移除,若master向哨兵重新发送了PING命令的返回,那么master上的ODOWN状态也会被移除。

  2、哨兵leader的选举过程

    当master被标记为ODOWN后,就需要哨兵对主从进行故障迁移,那么哨兵也是一个集群,到底使用哪一个哨兵来进行故障迁移呢,那么就涉及到了哨兵leader的选举过程,并由最终选举出来的哨兵leader来进行故障迁移。

    哨兵leader的选举主要分为三步:

    (1)每个在线的哨兵都有可能称为leader,当一个哨兵确认master下线后,他会向其他哨兵发送is-master-down-by-addr命令,征求判断并要求自己成为leader

    (2)当其他哨兵收到该请求后,可以拒绝或者同意它成为领导者

    (3)如果该哨兵发现自己在选举的票数大于半数,该哨兵将成为leader,如果没有超过,则继续选举

  3、自动故障迁移

    自动故障迁移可以分为master选择和配置文件修改

      master选择:

      (1)获取原master下所有的slave并过滤掉主观下线的节点

      (2)选择slave-prioruty(权重)最高的节点,如果有则该节点成为master,如果没有则继续其他策略(这个权重是人为设置的,因此不常用)

      (3)选择出复制偏移量最大的节点(通俗地讲就是复制master数据最多的节点,因为复制的越多,数据就越完整),如果有就返回该节点成为master,如果没有,就继续其他策略

      (4)选择run_id最小的节点

      配置文件修改:

      (1)通过slaveof no one命令,让选出来的从节点变更为主节点,并通过slaveof命令让其他从节点成为新master的从节点

      (2)当已下线的主节点重新上线时,sentinel会向其发送slave命令,让其成为新master的slave

      (3)当客户端试图连接一个已经失效的master时,集群也会返回一个新的master地址,从而使集群可以使用新的master替换失效的master

      (4)master和slave切换后,master、slave、sentinel的配置文件都会发生变更

  4、哨兵配置

    哨兵也可以有多个,这里的配置模拟一主两从三哨兵,主从服务器已经在主从同步时配置过,那么这里直接配置哨兵。

    直接修改sentinal.conf文件

#关闭保护模式
protected-mode no
#哨兵的端口
port 26379
#设置监控的主节点ip及端口,2代表超过两个哨兵确认master为SDOWN时,会将master节点状态改为ODOWN
sentinel monitor mymaster 127.0.0.1 6379 2
#开启守护线程(可以后台运行)
daemonize yes

  启动哨兵(src目录下的命令,这里是将src下的执行脚本copy到了bin目录)

./bin/redis-sentinel sentinel.conf

  然后使用相同的操作配置另外两个哨兵。

  启动后,kill掉master后,就可以发现有一个slave变更为master,因为slave是不可以操作写命令的,但是变更为master后,就可以了

127.0.0.1:6380> set s2 v2
(error) READONLY You can't write against a read only replica.
127.0.0.1:6380> set s2 v2
OK

  然后再来看一下master、slave和sentinal的配置文件变化,可以发现由slave变更为master节点的redis.conf配置文件中,已经新增了replicaof配置,配置的值为新的master,另外一个slave的redis.conf文件,可以发现replicaof配置的master已经切换为了新的master,哨兵的配置文件sentinal.conf中monitor监控也已经调整为新的master

  5、主从复制+哨兵高可用

  

 该种模式和哨兵模式的区别主要是有一个VIP(虚拟IP),在master宕机时,除了选举新的master外,还会通过哨兵中的client-reconfig-script脚本配置的内容,去动态修改VIP(虚拟IP)。

 那么该种模式还是有很大的缺点:例如主从切换过程中会丢失数据,redis只能单点写,不能水平扩容。

三、集群(redisCluster)

  集群模式是所有的redis节点使用ping-pong机制彼此互联,内部使用二进制协议优化传输速度和贷款。同时节点的fail状态是通过集群中超半数的节点检测失效时才会生效。

  客户端与redis节点直连,不需要中间proxy层,客户端不需要连接集群所有节点,连接集群中的任何一个可用节点即可。

  rediscluster把所有的物理节点映射到[0-16383]slot上,cluster负责维护node、slot、value

  redis集群内部设置了16384个槽,当需要在redis中放一个KV数据时,redis会先对key使用crc16算法计算出来一个结果,然后把结果与16384取余,这样每个key都会映射到一个编号在0-16383之间的hash槽,redis会根据节点数量大致均匀将hash槽映射到不同的节点。

  1、redis-cluster投票:容错

  (1)节点失效判断:集群中的所有master参与投票,如果半数以上的master节点与其中一个master节点通讯超过(cluster-node-timeout),则认为该节点失效

  (2)集群失效判断:如果集群任意master挂掉,且当前master没有slave,则集群进入fail状态;如果集群的半数以上master挂掉,无论是否有slave,集群进入fail状态。 

  2、cluster集群搭建

    (1)redia集群至少需要3个master,每个master至少需要一个slave,因此就需要创建6个redis实例,每个实例的配置文件,需要开启集群模式。

#由于是在一台机器上开了6个不同的端口,因此需要调整端口
port 8001
#开启集群模式
cluster-enable yes

    (2)配置完毕后,启动所有实例

./bin/redis-server etc/redis.conf

    (3)创建集群

./bin/redis-cli --cluster create 127.0.0.1:8001 127.0.0.1:8002 127.0.0.1:8003 127.0.0.1:8004 127.0.0.1:8005 127.0.0.1:8006 --cluster-replicas 1


>>> Performing hash slots allocation on 6 nodes... Master[0] -> Slots 0 - 5460 Master[1] -> Slots 5461 - 10922 Master[2] -> Slots 10923 - 16383 Adding replica 127.0.0.1:8005 to 127.0.0.1:8001 Adding replica 127.0.0.1:8006 to 127.0.0.1:8002 Adding replica 127.0.0.1:8004 to 127.0.0.1:8003 >>> Trying to optimize slaves allocation for anti-affinity [WARNING] Some slaves are in the same host as their master M: 093eee16ce08b26aee60132c185160fe84c016ea 127.0.0.1:8001 slots:[0-5460] (5461 slots) master M: 41ce50f8ae9bf5a4320fea3c681c42130b60238c 127.0.0.1:8002 slots:[5461-10922] (5462 slots) master M: e1a4be3556e3333abafe5cf8fb2163d95f3dcd6d 127.0.0.1:8003 slots:[10923-16383] (5461 slots) master S: 8ce7a8c5983f5aa3b1c18ded2e1c90d8ab18c0a4 127.0.0.1:8004 replicates 41ce50f8ae9bf5a4320fea3c681c42130b60238c S: b4e1fb1f1dd38a65041670525217d591242beb5f 127.0.0.1:8005 replicates e1a4be3556e3333abafe5cf8fb2163d95f3dcd6d S: ca81e8da8461253f5f301fd6a5943917a77e3070 127.0.0.1:8006 replicates 093eee16ce08b26aee60132c185160fe84c016ea Can I set the above configuration? (type 'yes' to accept): yes >>> Nodes configuration updated >>> Assign a different config epoch to each node >>> Sending CLUSTER MEET messages to join the cluster Waiting for the cluster to join ..... >>> Performing Cluster Check (using node 127.0.0.1:8001) M: 093eee16ce08b26aee60132c185160fe84c016ea 127.0.0.1:8001 slots:[0-5460] (5461 slots) master 1 additional replica(s) S: b4e1fb1f1dd38a65041670525217d591242beb5f 127.0.0.1:8005 slots: (0 slots) slave replicates e1a4be3556e3333abafe5cf8fb2163d95f3dcd6d M: e1a4be3556e3333abafe5cf8fb2163d95f3dcd6d 127.0.0.1:8003 slots:[10923-16383] (5461 slots) master 1 additional replica(s) M: 41ce50f8ae9bf5a4320fea3c681c42130b60238c 127.0.0.1:8002 slots:[5461-10922] (5462 slots) master 1 additional replica(s) S: 8ce7a8c5983f5aa3b1c18ded2e1c90d8ab18c0a4 127.0.0.1:8004 slots: (0 slots) slave replicates 41ce50f8ae9bf5a4320fea3c681c42130b60238c S: ca81e8da8461253f5f301fd6a5943917a77e3070 127.0.0.1:8006 slots: (0 slots) slave replicates 093eee16ce08b26aee60132c185160fe84c016ea [OK] All nodes agree about slots configuration. >>> Check for open slots... >>> Check slots coverage... [OK] All 16384 slots covered.

  至此,集群搭建完毕。

    (4)连接集群

./bin/redis-cli -h 127.0.0.1 -p 8001 -c

    (5)查看集群信息

127.0.0.1:8001> cluster info

cluster_state:ok
cluster_slots_assigned:16384
cluster_slots_ok:16384
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:6
cluster_size:3
cluster_current_epoch:6
cluster_my_epoch:1
cluster_stats_messages_ping_sent:300
cluster_stats_messages_pong_sent:310
cluster_stats_messages_sent:610
cluster_stats_messages_ping_received:305
cluster_stats_messages_pong_received:300
cluster_stats_messages_meet_received:5
cluster_stats_messages_received:610

    (6)查看集群下节点

127.0.0.1:8001> cluster nodes

093eee16ce08b26aee60132c185160fe84c016ea 127.0.0.1:8001@18001 myself,master - 0 1611651086000 1 connected 0-5460
b4e1fb1f1dd38a65041670525217d591242beb5f 127.0.0.1:8005@18005 slave e1a4be3556e3333abafe5cf8fb2163d95f3dcd6d 0 1611651088080 5 connected
e1a4be3556e3333abafe5cf8fb2163d95f3dcd6d 127.0.0.1:8003@18003 master - 0 1611651088000 3 connected 10923-16383
41ce50f8ae9bf5a4320fea3c681c42130b60238c 127.0.0.1:8002@18002 master - 0 1611651087000 2 connected 5461-10922
8ce7a8c5983f5aa3b1c18ded2e1c90d8ab18c0a4 127.0.0.1:8004@18004 slave 41ce50f8ae9bf5a4320fea3c681c42130b60238c 0 1611651087000 4 connected
ca81e8da8461253f5f301fd6a5943917a77e3070 127.0.0.1:8006@18006 slave 093eee16ce08b26aee60132c185160fe84c016ea 0 1611651089083 6 connected

  说明:

    这里创建集群时,用的是127.0.0.1,但是如果想使用JAVA程序连接时,是不能这么创建的,这样创建的话,如果JAVA程序和redis集群不在一台服务器上,是不能够连接集群的(项目启动没问题,但是使用时就会报错),但是如果使用实际的本机ip创建集群有可能报错

./bin/redis-cli --cluster create 8.131.245.53:8001 8.131.245.53:8002 8.131.245.53:8003 8.131.245.53:8004 8.131.245.53:8005 8.131.245.53:8006 --cluster-replicas 1
[ERR] Node 8.131.245.53:8001 is not empty. Either the node already knows other nodes (check with CLUSTER NODES) or contains some key in database 0.

    可以看下:https://www.cnblogs.com/liconglong/p/14358096.html

 3、总结

   集群的优点:

    (1)无需哨兵监控,如果master挂了,redis cluster内部自动将slave切换为master;

    (2)可以水平扩容

    (3)支持自动化迁移,如果某一个slave挂了,同时其master只有这一个slave,那么会从其他master下平移一个多余的slave到该master下。

   集群的缺点:

    (1)批量操作是个坑

    (2)资源隔离性比较差,容易出现相互影响的情况。

------------------------------------------------------------------
-----------------------------------------------------------
---------------------------------------------
朦胧的夜 留笔~~
原文地址:https://www.cnblogs.com/liconglong/p/14327430.html