zoukankan      html  css  js  c++  java
  • 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)资源隔离性比较差,容易出现相互影响的情况。

    ------------------------------------------------------------------
    -----------------------------------------------------------
    ---------------------------------------------
    朦胧的夜 留笔~~
  • 相关阅读:
    (转载)教你在PHP中使用全局变量
    (转载)遍历memcache中已缓存的key
    (转载)PHP_Memcache函数详解
    PHP去除空白字符
    (转载)用PHP正则表达式清除字符串的空白
    (转载)PHP静态方法
    (转载)PHP 动态生成表格
    (转载)PHP strtotime函数详解
    (转载)URL与URI的区别
    ldap集成confluence
  • 原文地址:https://www.cnblogs.com/liconglong/p/14327430.html
Copyright © 2011-2022 走看看