一:主从模式Windows下搭建

1:基本介绍

  主从复制中一个 主节点(master)可以拥有多个 从节点(slave)但是一个slave只能对应一个master。这样,当某个slave宕机是不会影响其它slave的读取和master的读取和写入;但是之前宕机的slave重新启动服务后,数据会从自动master上同步过来(前提是在配置文件上配置的主从复制,若是通过命令的方式设置的主从复制,不管哪一台宕机重启后会都会变为一个普通的单机的Redis,默认都是master)在主从模式下,只有一个主节点可以写和读,而从节点只能读,所以通常主节点负责写,从节点负责读(因为读取的操作最频繁)。但是,当唯一的master挂了以后,虽然不影响slave的读操作,但影响当前主从复制Redis服务的写操作,需要将master重启后,redis才重新对外提供写服务(前提是配置文件配置的主从复制)

2:主从复制优缺点

优点:
    ①:支持主从复制,主机(Master)会自动将数据同步到从机(Slave),可以进行读写分离
    ②:为了分载Master的读操作压力,Slave服务器可以为客户端提供只读操作的服务,写服务仍然必须由Master来完成
    ③:Slave同样可以接受其它Slaves的连接和同步请求,这样可以有效的分载Master的同步压力。
    ④:Master Server是以非阻塞的方式为Slaves提供服务。所以在Master-Slave同步期间,客户端仍然可以提交查询或修改请求。
    ⑤:Slave Server同样是以非阻塞的方式完成数据同步。在同步期间,如果有客户端提交查询请求,Redis则返回同步之前的数据
缺点:
    ①:Redis不具备自动容错和恢复功能,主机和从机的宕机都会导致前端部分读写请求失败,需要等待机器重启或者手动切换前端的IP才能恢复。
    ②:主机宕机,宕机前有部分数据未能及时同步到从机,切换IP后还会引入数据不一致的问题,降低了系统的可用性。
    ③:Redis较难支持在线扩容,在集群容量达到上限时在线扩容会变得很复杂。

3:配置主从模式

为了方便在 windows 下操作主从复制(Linux和这里Windows操作基本一致后,都是解压后复制三个出来)
注:要是不会Redis下如何搭建单据Redis请参考 Redis基本操作 环境: Redis:解压三份Redis应用(这里我以6.2.5为例) 解压后的文件夹: redis6379 用来配置主机Master redis6380 用来配置从机Slave① redis6381 用来配置从机Slave② 修改redis6379、redis6380、redis6381下的Redis配置 注:Redis配置文件在Windows下一般为 "redis.windows.conf" 注:Redis配置文件在Windows下一般为 "redis.conf"

①:redis6379主节点(Master)配置文件修改

Redis中的各种配置不明白的请参考 ”“
进入redis6379主节点Master文件夹下修改基本配置
①:指定Redis主节点端口(端口不可冲突)
    port:6379
②:指定新的PID文件路径 (windows下没有)
    pidfile /var/run/redis_6379.pid
③:日志文件位置,当指定为 "空字符串" 为标准输出。如 redis 以守护进程运行,日志将会输出到 "/dev/null"
    logfile "redisLog_6379.log"
④:RDB持久化快照的的文件名
    dbfilename dump6379.rdb
⑤:设置redis连接密码
    requirepass 1234
⑥:保护模式,默认开启,拒绝外部访问,建议关闭 -- 设置为:no
    protected-mode yes

②:redis6380从节点(Slave①)配置文件修改

进入redis6380从节点Slave①文件夹下修改基本配置
①:指定Redis主节点端口(端口不可冲突)
    port:6380
②:指定新的PID文件路径 (windows下没有)
    pidfile /var/run/redis_6380.pid
③:日志文件位置,当指定为 "空字符串" 为标准输出。如 redis 以守护进程运行,日志将会输出到 "/dev/null"
    logfile "redisLog_6380.log"
④:RDB持久化快照的的文件名
    dbfilename dump6380.rdb
⑤:设置redis连接密码
    requirepass 1234
⑥:保护模式,默认开启,拒绝外部访问,建议关闭 -- 设置为:no
    protected-mode yes

配置主Master地址
①:主从复制,使用replicaof来指明出Master主节点地址 ,默认关闭
    replicaof 127.0.0.1 6379
②:如果Master需要密码认证,则在这里设置,默认不设置
    masterauth 1234

③:redis6381从节点(Slave②)配置文件修改

进入redis6381从节点Slave②文件夹下修改基本配置
①:指定Redis主节点端口(端口不可冲突)
    port:6381
②:指定新的PID文件路径 (windows下没有)
    pidfile /var/run/redis_6381.pid
③:日志文件位置,当指定为 "空字符串" 为标准输出。如 redis 以守护进程运行,日志将会输出到 "/dev/null"
    logfile "redisLog_6381.log"
④:RDB持久化快照的的文件名
    dbfilename dump6381.rdb
⑤:设置redis连接密码
    requirepass 1234
⑥:保护模式,默认开启,拒绝外部访问,建议关闭 -- 设置为:no
    protected-mode yes

配置主Master地址
①:主从复制,使用replicaof来指明出Master主节点地址 ,默认关闭
    replicaof 127.0.0.1 6379
②:如果Master需要密码认证,则在这里设置,默认不设置
    masterauth 1234

4:启动主从模式

开始三个Redis服务端
注:配置文件和服务放在一个目录下

创建bat脚本文件:redis服务启动.bat
    @echo off
    rem 设置我们redis目录位置 开启Redis服务端
    set redis_home=C:\Users\xiaof\Desktop\redis
    start cmd /k "cd /d  %redis_home%\redis6379 && redis-server.exe redis.windows.conf"
    start cmd /k "cd /d  %redis_home%\redis6380 && redis-server.exe redis.windows.conf"
    start cmd /k "cd /d  %redis_home%\redis6381 && redis-server.exe redis.windows.conf"
    exit

创建bat脚本文件:redis客户端启动.bat
    @echo off
    rem 设置我们redis目录位置 开启Redis客户端
    set redis_home=C:\Users\xiaof\Desktop\redis
    start cmd /k "cd /d  %redis_home%\redis6379 && redis-cli.exe -h 127.0.0.1 -p 6379 -a 1234"
    start cmd /k "cd /d  %redis_home%\redis6380 && redis-cli.exe -h 127.0.0.1 -p 6380 -a 1234"
    start cmd /k "cd /d  %redis_home%\redis6381 && redis-cli.exe -h 127.0.0.1 -p 6381 -a 1234"
    exit
创建bat脚本文件:redis服务端客户端关闭.bat
@echo off
start cmd /k "taskkill /f /t /im redis-server.exe && taskkill /f /t /im cmd.exe"
exit

5:测试主从复制

  到这我们就算成功搭建了主从复制了,在主机上使用set命令也会同步到其它从机,但是从机上不会有写命令

info replication属性说明:
    role
        当前Redis服务器角色(会有Master和slave)
    connected_slaves
        当前Redis服务器下连接的从机数
    slave(N)
        从机的连接状态信息 state=online 代表状态在线
    master_failover_state
        主节点的故障转移状态,可选值如下:
            no-failover:当前没有正在协调中的故障转移。
            waiting-for-sync:主节点正在等待副本来获取它的副本数据偏移值。
            failover-in-progress:主节点已经降级了,并试图将所有权移交给目标副本。
    master_replid
        每次重启redis产生一个40位的ID,用于主从复制.识别增量的一个标识
    master_host、master_port
        连接主节点的IP+端口号
    master_link_status
        连接主节点的状态 up代表连接 down代表未连接

Master主机配置查看:
    127.0.0.1:6379> info replication
    # Replication
    role:master
    connected_slaves:2
    slave0:ip=127.0.0.1,port=6381,state=online,offset=438,lag=0
    slave1:ip=127.0.0.1,port=6380,state=online,offset=438,lag=0
    master_failover_state:no-failover
    master_replid:e96c06dc1ffde9d13cb7791bdfba36dd26b89794
    master_replid2:0000000000000000000000000000000000000000
    master_repl_offset:438
    second_repl_offset:-1
    repl_backlog_active:1
    repl_backlog_size:1048576
    repl_backlog_first_byte_offset:1
    repl_backlog_histlen:438

Slave从机配置查看:
    127.0.0.1:6380> info replication
    # Replication
    role:slave
    master_host:127.0.0.1
    master_port:6379
    master_link_status:up
    master_last_io_seconds_ago:11
    master_sync_in_progress:0
    slave_repl_offset:410
    slave_priority:100
    slave_read_only:1
    replica_announced:1
    connected_slaves:0
    master_failover_state:no-failover
    master_replid:e96c06dc1ffde9d13cb7791bdfba36dd26b89794
    master_replid2:0000000000000000000000000000000000000000
    master_repl_offset:410
    second_repl_offset:-1
    repl_backlog_active:1
    repl_backlog_size:1048576
    repl_backlog_first_byte_offset:1
    repl_backlog_histlen:410

主从连接状态查看

6:使用命令方式配置主从复制

  不推荐使用此方式配置主从,只可用于测试,因为这种方式的配置主从不会持久化,每次关闭再启动就会变为一个单机

  用上边配置文件搭建案例来说,关闭Redis服务后注释主机和从机的配置文件配置的 replicaof、masterauth、requirepass  

  这时候利用脚本启动的Redis服务都是单机的Master主机

这时候我们可以看出Master原来的主节点里没有任何从机,下面我将6380、6381设置为从机
127.0.0.1:6379> info replication # Replication role:master connected_slaves:0 master_failover_state:no-failover master_replid:a0b02f9a1a0e6a2b24c90a19a7d9c2e5e1f2c96c master_replid2:0000000000000000000000000000000000000000 master_repl_offset:0 second_repl_offset:-1 repl_backlog_active:0 repl_backlog_size:1048576 repl_backlog_first_byte_offset:0 repl_backlog_histlen:0
把Redis6380设置为从节点Slave①:
    127.0.0.1:6380> slaveof 127.0.0.1 6379
把Redis6381设置为从节点Slave②:
    127.0.0.1:6381> slaveof 127.0.0.1 6379

这时候就设置好主从了 6379为Master主节点;6380、6381为Slave从节点
若其中一台从机想断开和主机连接则执行:slaveof no one
若主节点宕机则不影响从机的读取,但是缺少主节点就代表没有写功能
若从机宕机后重启则之前配置为从机的配置被初始化,启动后默认为单个主机

7:简单介绍主从复制原理

全量同步:一般发生在Slave连接主机后初始化阶段,这时Slave需要将Master上的所有数据都复制一份
    ①:从服务器连接到主服务器,首先发送一个SYNC命令;
    ②:主服务器接收到SYNC命名后,主服务器开始执行 bgsave 命令生成RDB文件并使用缓冲区记录此后执行的所有写命令;
    ③:主服务器 bgsave 命令执行完后,向所有从服务器发送快照文件,并在发送期间继续记录主服务器被执行的写命令;
    ④:从服务器收到快照文件后丢弃所有旧数据,载入收到的快照;
    ⑤:主服务器快照发送完毕后开始向从服务器发送缓冲区中的写命令;
    ⑥:从服务器完成对快照的载入,开始接收命令请求,并执行来自主服务器缓冲区的写命令;
    完成上面几个步骤后就完成了从服务器数据初始化的所有操作,从服务器此时可以接收来自用户的读请求。
    
增量同步:Redis增量复制是指Slave初始化后开始正常工作时主服务器发生的写操作同步到从服务器的过程。
    增量复制的过程主要是主服务器每执行一个写命令就会向从服务器发送相同的写命令,从服务器接收并执行收到的写命令。

二:主从复制Linux下搭建

  通过上面的在Windows下的搭建操作,这里我就不多啰嗦了,直接上手操作搭建

  若连在Linux如何搭建单机Redis不怎么熟悉的请参考:Redis入门及环境搭建

具体搭建完主从复制是这个样子的:

如果想按照我这个目录快速搭建主从复制可以直接复制下面代码:

具体步骤:
①:把 redis-6.2.6.tar.gz 压缩包放到home目录下解压
    rz -y
    tar -zxvf redis-6.2.6.tar.gz 
②:解压后进入redis目录里进行编译安装,
    cd redis-6.2.6/
    make && make PREFIX=/home/redis6379 install
③:复制成三份(主从复制 6379主,6380、6381从)
    cp -r redis6379 redis6380
    cp -r redis6379 redis6381
④:为每个redis创建配置文件目录和拷贝redis配置文件
    mkdir /home/redis6379/conf
    mkdir /home/redis6380/conf
    mkdir /home/redis6381/conf
    cp /home/redis-6.2.6/redis.conf /home/redis6379/conf/redis6379.conf
    cp /home/redis-6.2.6/redis.conf /home/redis6380/conf/redis6380.conf
    cp /home/redis-6.2.6/redis.conf /home/redis6381/conf/redis6381.conf
⑤:去编辑每个Redis目录下的 redis63*.conf 配置文件
    具体参考上面Windows下搭建主从复制的第3小节文件配置

⑥:编写启动脚本:startRedis.sh和stopRedis.sh
cd /home/
cat > startRedis.sh <<EOF
#!/bin/sh
/home/redis6379/bin/redis-server /home/redis6379/conf/redis6379.conf  2>&1 &
/home/redis6380/bin/redis-server /home/redis6380/conf/redis6380.conf  2>&1 &
/home/redis6381/bin/redis-server /home/redis6381/conf/redis6381.conf  2>&1 &
echo "redis is start"
EOF
cat > stopRedis.sh <<EOF
#!/bin/sh
#stop redis
ps -ef|grep redis |grep -v grep|awk '{print }'|xargs kill 
echo "redis is stop"
EOF
chmod 744 startRedis.sh stopRedis.sh 

接下来就是启动测试了,测试就按照上面测试即可,启动则启动下那个命令即可!

Redis客户端启动:
    /home/redis6379/bin/redis-cli -h 127.0.0.1 -p 6379 -a 1234
    /home/redis6380/bin/redis-cli -h 127.0.0.1 -p 6380 -a 1234
    /home/redis6381/bin/redis-cli -h 127.0.0.1 -p 6381 -a 1234
然后通过:info replication 命令来查看具体主从服务

通过 tail -f xxx.conf 来实时刷新日志查看

三:哨兵模式Linux下搭建

1:基本介绍

  介绍了主从复制后,我们知道slave成为master的从节点后,一旦master主节点宕机,我们可以选择一个正常的slave成为新的主节点,其它从节点再去连接这个新的主节点,实现手动的故障恢复。但是,人工干预效率低、易出错,并且故障感知滞后,不具备生产实用性。一个能够自动感知系统故障、自动故障转移的可靠组件,肯定是生产环境中最需要的。为此,Redis官方提供一个高可用的解决方案----哨兵(Sentinel),使用它可以搭建一个即使无人干预也能抵抗某些类型失败的高可用的Redis分布式系统。
  哨兵是Redis的一种运行模式,它专注于对Redis实例(主节点、从节点)运行状态的监控,并能够在主节点发生故障时通过一系列的机制实现选主及主从切换,实现故障转移,确保整个Redis系统的可用性。

Redis Sentinel官方文档
Redis官方中说明了Redis哨兵具备如下几个功能:
    监控(Monitoring):
        持续监控Redis主节点、从节点是否处于预期的工作状态。
    通知(Notification):
        哨兵可以把Redis实例的运行故障信息通过API通知监控系统或者其他应用程序。
    自动故障恢复(Automatic failover):
        当主节点运行故障时,哨兵会启动自动故障恢复流程:某个从节点会升级为主节点,其它从节点会使用新的主节点进行主从复制,
        通知客户端使用新的主节点进行。
    配置中心(Configuration provider):
        哨兵可以作为客户端服务发现的授权源,客户端连接到哨兵请求给定服务的Redis主节点地址。如果发生故障转移,哨兵会通知新的地址。
        这里要注意:哨兵并不是Redis代理,只是为客户端提供了Redis主从节点的地址信息。
Sentinel的分布式特性:
    Redis Sentinel是一个分布式系统,它被设计为基于一套配置,并在多个哨兵实例的配合下工作。多实例共同协作有以下优势:
        ①:主节点的系统故障是在多个实例共同认可的情况下完成的,大大降低了误报的概率。
        ②:即使不是所有的哨兵实例都正常运行哨兵集群也能正常工作(除非哨兵实例全宕机),这大大增加了系统的稳定性和健壮性。

2:哨兵模式的作用

  哨兵服务(sentinel)通过发送命令让Redis服务器(主服务器和从服务器)返回当前运行状态;当哨兵监测到master宕机后,哨兵服务会自动将Slave切换成Master ,然后通过发布订阅模式通知其他的从服务器,修改配置文件,让它们切换主机;然而一个哨兵进程服务对Redis服务器进行监控,也可能会出现宕机问题,为此,我们可以使用多个哨兵进行监控。各个哨兵之间还会进行监控,这样就形成了多哨兵模式,就算一个哨兵进程宕机,后面的哨兵还能继续工作

优点:
    哨兵模式是基于主从模式的,所有主从的优点,哨兵模式都具有
    主从可以自动切换,系统更健壮,可用性更高
缺点:
    Redis较难支持在线扩容,在集群容量达到上限时在线扩容会变得很复杂

3:故障切换过程

  假设Master服务器宕机,哨兵A先检测到这个结果,并不会马上进行failover(故障转移)过程,仅仅是哨兵A主观上认为Master服务器不可用,这个现象成为主观下线(不能肯定是Master宕机了)。当后面的哨兵B,哨兵C,哨兵D....也检测到Master服务器不可用,并且随着多个哨兵服务主观认为Master宕机且主观认为的数量达到一定值时,那么哨兵之间就会进行一次投票,投票的结果由一个哨兵发起,进行failover(故障转移)操作。切换成功后,就会通过发布订阅模式,让各个哨兵把自己监控的从服务器实现切换主机,这个过程称为客观下线(Master确实是宕机了)。这样对于客户端而言,一切都是透明的。

4:哨兵模式的工作方式

①:每个Sentinel(哨兵)进程以每秒钟一次的频率向整个集群中的主服务器(Master)、从服务器(Slave)、哨兵(Sentinel)进程
  发送一个PING命令。 ②:如果一个实例(instance)距离最后一次有效回复PING命令的时间超过 down-after-milliseconds 选项所指定的值(默认30秒),
  这个实例会被Sentinel进程标记为主观下线(SDOWN) ③:如果一个Master被标记为主观下线(SDOWN),则正在监视这个Master的所有 Sentinel进程要以每秒一次的频率确认Master
  是否的确进入了主观下线状态 ④:当有足够数量的Sentinel进程(大于等于配置文件指定的值)在指定的时间范围内确认Master进入了主观下线状态(SDOWN),
  则主Master会被标记为客观下线(ODOWN) ⑤:在一般情况下, 每个Sentinel进程会以每10秒一次的频率向集群中的所有Master主服务器、Slave从服务器发送INFO命令,
  目的是发现slave结点,确定主从关系。 ⑥:当Master被Sentinel进程标记为客观下线(ODOWN)时,Sentinel进程向下线的Master的所有Slave发送INFO命令的频率会从
  10秒一次改为每秒一次。 ⑦:若没有足够数量的Sentinel进程同意Master下线,Master的客观下线状态就会被移除。若之前被标记的Master重新又向Sentinel进程
  发送PING命令返回有效回复,Master主服务器的主观下线状态就会被移除。

5:搭建哨兵模式

哨兵模式是基于主从复制模式之上的,所以自己得准备一个基本的一主二从的主从模式环境
注:这里主从搭建完全使用第二小节的:主从复制Linux下搭建里的目录配置
这里哨兵模式我使用多哨兵模式(都在127.0.0.1机器里):
    ./redisSentinel26379      此文件夹下存放哨兵A 端口:26379
    ./redisSentinel26380      此文件夹下存放哨兵B 端口:26380
    ./redisSentinel26381      此文件夹下存放哨兵C 端口:26381

①:创建文件夹专门存放哨兵模式
    mkdir /home/sentinel
②:拷贝3份Redis程序当哨兵程序并复制哨兵配置文件(这里我直接拷贝6379原主从复制主机)
    cp -r /home/redis6379 /home/sentinel/redisSentinel26379
    cp -r /home/redis6379 /home/sentinel/redisSentinel26380
    cp -r /home/redis6379 /home/sentinel/redisSentinel26381
    rm -rf /home/sentinel/redisSentinel26379/conf/*
    rm -rf /home/sentinel/redisSentinel26380/conf/*
    rm -rf /home/sentinel/redisSentinel26381/conf/*
    cp /home/redis-6.2.6/sentinel.conf /home/sentinel/redisSentinel26379/conf/sentinel26379.conf
    cp /home/redis-6.2.6/sentinel.conf /home/sentinel/redisSentinel26380/conf/sentinel26380.conf
    cp /home/redis-6.2.6/sentinel.conf /home/sentinel/redisSentinel26381/conf/sentinel26381.conf
③:编写哨兵启动脚本
cd /home/sentinel
cat > startRedisSentinel.sh << EOF
#!/bin/sh
/home/sentinel/redisSentinel26379/bin/redis-sentinel /home/sentinel/redisSentinel26379/conf/sentinel26379.conf 2>&1 &
/home/sentinel/redisSentinel26380/bin/redis-sentinel /home/sentinel/redisSentinel26380/conf/sentinel26380.conf 2>&1 &
/home/sentinel/redisSentinel26381/bin/redis-sentinel /home/sentinel/redisSentinel26381/conf/sentinel26381.conf 2>&1 &
echo "redis sentinel is start"
EOF
chmod 744 startRedisSentinel.sh 

6:更改配置文件

注:每个哨兵的配置文件都必须一致,处理端口和日志文件存在差别,其它一样都监控某一台主机
①:保护模式,默认开启,拒绝外部访问,建议关闭 -- 设置为:no protected-mode no ②:指定新的PID文件路径 (windows下没有) pidfile /var/run/redis-sentinel26379.pid ③:日志文件位置 logfile "./redisSentinelLog26379.log" ④:工作目录(存储运行时的文件) dir /home/sentinel ⑤:配置监听的主服务器,这里 sentinel monitor 代表监控
-- mymaster代表服务器名称,可以自定义 -- 127.0.0.1 6379代表监控的主服务器IP和端口 -- 2代表只有两个或者两个以上的哨兵认为主服务器不可用的时候,才会做故障转移操作 sentinel monitor mymaster 127.0.0.1 6379 2 ⑥:定义连接Master服务的密码(搭建的主从服务密码必须一致,要不然有问题) -- mymaster服务名称(和上面对应) 1234 为密码 sentinel auth-pass mymaster 1234

7:启动哨兵测试

  注:必须先启动主从复制机器,确认没问题后再次启动多哨兵机器

  执行之前脚本启动:./startRedisSentinel.sh

启动哨兵日志打印:

启动26379、26380、26381三台哨兵服务(以26379日志来说,三个日志一样)
~# oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
~# Redis version=6.2.6, bits=64, commit=00000000, modified=0, pid=9099, just started
~# Configuration loaded
~* Increased maximum number of open files to 10032 (it was originally set to 1024).
~* monotonic clock: POSIX clock_gettime
~* Running mode=sentinel, port=26379.
~# WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
~# Sentinel ID is ae12e9902494e32aa77172ad7900dafb83b29ea4
~# +monitor master mymaster 127.0.0.1 6379 quorum 2
~* +slave slave 127.0.0.1:6380 127.0.0.1 6380 @ mymaster 127.0.0.1 6379
~* +slave slave 127.0.0.1:6381 127.0.0.1 6381 @ mymaster 127.0.0.1 6379
~* +sentinel sentinel dbeba218078a3400c04c0fb2247861be0167e2b8 127.0.0.1 26381 @ mymaster 127.0.0.1 6379
~* +sentinel sentinel 335d08176477f79734a60420f0b1890303c9aec1 127.0.0.1 26380 @ mymaster 127.0.0.1 6379

使用客户端连接哨兵服务:

  /home/sentinel/redisSentinel26379/bin/redis-cli  -h  127.0.0.1  -p  26379

哨兵基本命令:
    ping
        回复PONG.
    sentinel masters 
        显示被监控的所有master以及它们的状态
    sentinel master <master name> 
        显示指定被监控的master的信息和状态;如我们设置的名称为mymaster
    sentinel slaves <master name> 
        显示指定master的所有slave以及它们的状态
    sentinel get-master-addr-by-name <master name> 
        返回指定master的ip和端口,如果正在进行failover或者failover已经完成,
        将会显示被提升为master的slave的ip和端口。
    sentinel reset <pattern> 
        重置名字匹配该正则表达式的所有的master的状态信息,清楚其之前的状态信息,以及slaves信息
    sentinel failover <master name> 
        强制sentinel执行failover,并且不需要得到其他sentinel的同意。
        但是failover后会将最新的配置发送给其他sentinel。

主机宕机模拟:

  强行杀死主节点6379服务器后的30秒,哨兵就会进行主节点选举

哨兵26379日志打印:
~# +sdown master mymaster 127.0.0.1 6379
~# +odown master mymaster 127.0.0.1 6379 #quorum 2/2
~# +new-epoch 1
~# +try-failover master mymaster 127.0.0.1 6379
~# +vote-for-leader ae12e9902494e32aa77172ad7900dafb83b29ea4 1
~# dbeba218078a3400c04c0fb2247861be0167e2b8 voted for ae12e9902494e32aa77172ad7900dafb83b29ea4 1
~# 335d08176477f79734a60420f0b1890303c9aec1 voted for ae12e9902494e32aa77172ad7900dafb83b29ea4 1
~# +elected-leader master mymaster 127.0.0.1 6379
~# +failover-state-select-slave master mymaster 127.0.0.1 6379
~# +selected-slave slave 127.0.0.1:6380 127.0.0.1 6380 @ mymaster 127.0.0.1 6379
~* +failover-state-send-slaveof-noone slave 127.0.0.1:6380 127.0.0.1 6380 @ mymaster 127.0.0.1 6379
~* +failover-state-wait-promotion slave 127.0.0.1:6380 127.0.0.1 6380 @ mymaster 127.0.0.1 6379
~# +promoted-slave slave 127.0.0.1:6380 127.0.0.1 6380 @ mymaster 127.0.0.1 6379
~# +failover-state-reconf-slaves master mymaster 127.0.0.1 6379
~* +slave-reconf-sent slave 127.0.0.1:6381 127.0.0.1 6381 @ mymaster 127.0.0.1 6379
~* +slave-reconf-inprog slave 127.0.0.1:6381 127.0.0.1 6381 @ mymaster 127.0.0.1 6379
~* +slave-reconf-done slave 127.0.0.1:6381 127.0.0.1 6381 @ mymaster 127.0.0.1 6379
~# -odown master mymaster 127.0.0.1 6379
~# +failover-end master mymaster 127.0.0.1 6379
~# +switch-master mymaster 127.0.0.1 6379 127.0.0.1 6380
~* +slave slave 127.0.0.1:6381 127.0.0.1 6381 @ mymaster 127.0.0.1 6380
~* +slave slave 127.0.0.1:6379 127.0.0.1 6379 @ mymaster 127.0.0.1 6380
~# +sdown slave 127.0.0.1:6379 127.0.0.1 6379 @ mymaster 127.0.0.1 6380
哨兵26380、26381日志打印(两个一样)
~# +sdown master mymaster 127.0.0.1 6379
~# +new-epoch 1
~# +vote-for-leader ae12e9902494e32aa77172ad7900dafb83b29ea4 1
~# +odown master mymaster 127.0.0.1 6379 #quorum 3/2
~# Next failover delay: I will not start a failover before Fri Jan 14 01:16:10 2022
~# +config-update-from sentinel ae12e9902494e32aa77172ad7900dafb83b29ea4 127.0.0.1 26379 @ mymaster 127.0.0.1 6379
~# +switch-master mymaster 127.0.0.1 6379 127.0.0.1 6380
~* +slave slave 127.0.0.1:6381 127.0.0.1 6381 @ mymaster 127.0.0.1 6380
~* +slave slave 127.0.0.1:6379 127.0.0.1 6379 @ mymaster 127.0.0.1 6380
~# +sdown slave 127.0.0.1:6379 127.0.0.1 6379 @ mymaster 127.0.0.1 6380

  通过上面的日志可以看出6379宕机了,但是通过哨兵选举6380切换为主机,并把它从机设置连接为6380为主机

原主机宕机后上线模拟:

命令切换到home目录/home/redis6379/bin/redis-server  /home/redis6379/conf/redis6379.conf  2>&1  &

但是启动6379后日志拼命打印如下日志,并发现连不上哨兵选举的主机(在Redis服务器有密码的情况下)
~* Retrying with SYNC...
~# MASTER aborted replication with an error: NOAUTH Authentication required.
~* Reconnecting to MASTER 127.0.0.1:6381 after failure
~* MASTER <-> REPLICA sync started
~* Non blocking connect for SYNC fired the event.
~* Master replied to PING, replication can continue...
~* (Non critical) Master does not understand REPLCONF listening-port: -NOAUTH Authentication required.
~* (Non critical) Master does not understand REPLCONF capa: -NOAUTH Authentication required.
~* Partial resynchronization not possible (no cached master)
~# Unexpected reply to PSYNC from master: -NOAUTH Authentication required.
这时候就得杀死6379 Redis服务后进行简单配置,在redis6379.conf内找到 masterauth配置主机密码
    masterauth 1234
    这个配置在主从复制时就可以配置密码
哨兵26380日志打印:
~# -sdown slave 127.0.0.1:6379 127.0.0.1 6379 @ mymaster 127.0.0.1 6380
~* +convert-to-slave slave 127.0.0.1:6379 127.0.0.1 6379 @ mymaster 127.0.0.1 6380
~# +sdown slave 127.0.0.1:6379 127.0.0.1 6379 @ mymaster 127.0.0.1 6380
~* +reboot slave 127.0.0.1:6379 127.0.0.1 6379 @ mymaster 127.0.0.1 6380
~# -sdown slave 127.0.0.1:6379 127.0.0.1 6379 @ mymaster 127.0.0.1 6380
哨兵26379、26381日志打印(两个一样)
~# -sdown slave 127.0.0.1:6379 127.0.0.1 6379 @ mymaster 127.0.0.1 6380
~# +sdown slave 127.0.0.1:6379 127.0.0.1 6379 @ mymaster 127.0.0.1 6380
~* +reboot slave 127.0.0.1:6379 127.0.0.1 6379 @ mymaster 127.0.0.1 6380
~# -sdown slave 127.0.0.1:6379 127.0.0.1 6379 @ mymaster 127.0.0.1 6380

这时6379的Redis服务就会被当为从机来指向6380哨兵选举的Redis主机上

8:哨兵日志输出状态说明

@ 
    字符之后的内容用于指定主服务器,这些内容是可选的,它们仅在@字符之前的内容指定的
    实例不是主服务器时使用
+slave
    一个新的从服务器已经被Sentinel识别并关联。
+sdown
    给定的实例现在处于主观下线状态。
-sdown
    给定的实例已经不再处于主观下线状态。
+odown
    给定的实例现在处于客观下线状态。
-odown
    给定的实例已经不再处于客观下线状态。
+new-epoch
    当前的纪元(epoch)已经被更新。
+try-failover
    一个新的故障迁移操作正在执行中,等待被大多数 Sentinel 选中(waiting to be
     elected by the majority)
+reset-master
    主服务器已被重置
+monitor    
    主节点已被监视器监控
+failover-state-reconf-slaves
    故障转移状态切换到了 reconf-slaves 状态。
+failover-detected
    另一个 Sentinel 开始了一次故障转移操作,或者一个从服务器转换成了主服务器。
+slave-reconf-sent
    领头(leader)的 Sentinel 向实例发送了 [SLAVEOF](/commands/slaveof.html) 命令,
    为实例设置新的主服务器。
+slave-reconf-inprog
    实例正在将自己设置为指定主服务器的从服务器,但相应的同步过程仍未完成。
+slave-reconf-done
    从服务器已经成功完成对新主服务器的同步。
-dup-sentinel
    对给定主服务器进行监视的一个或多个 Sentinel 已经因为重复出现而被移除 —— 当Sentinel实
    例重启的时候,就会出现这种情况。
+sentinel
    一个监视给定主服务器的新 Sentinel 已经被识别并添加。
+elected-leader
    赢得指定纪元的选举,可以进行故障迁移操作了。
+failover-state-select-slave
    故障转移操作现在处于 select-slave 状态 —— Sentinel 正在寻找可以升级为主服务器的从服务器。
no-good-slave
    Sentinel 操作未能找到适合进行升级的从服务器。Sentinel 会在一段时间之后再次尝试寻找合适的
    从服务器来进行升级,又或者直接放弃执行故障转移操作。
selected-slave
    Sentinel 顺利找到适合进行升级的从服务器。
failover-state-send-slaveof-noone
    Sentinel 正在将指定的从服务器升级为主服务器,等待升级功能完成。
failover-end-for-timeout
    故障转移因为超时而中止,不过最终所有从服务器都会开始复制新的主服务器
    (slaves will eventually be configured to replicate with the new master anyway)
failover-end
    故障转移操作顺利完成。所有从服务器都开始复制新的主服务器了。
+switch-master
    配置变更,主服务器的 IP 和地址已经改变。 这是绝大多数外部用户都关心的信息。
+tilt
    进入 tilt 模式。
-tilt
    退出 tilt 模式。

四:集群模式Linux下搭建(重点)

  Redis 是我们目前大规模使用的缓存中间件,由于它强大高效而又便捷的功能,得到了广泛的使用。单节点的Redis已经就达到了很高的性能,为了提高可用性我们用主从复制到哨兵再到更强大的Redis集群。

  Redis集群(Redis Cluster)Redis 3.0开始引入的一个分布式存储系统;Redis集群是一个可以在多个Redis节点之间进行数据共享的设施(installation),不过Redis集群不支持那些需要同时处理多个键的Redis命令(如:mset,hmset...), 因为执行这些命令需要在多个Redis节点之间移动数据,并且在高负载的情况下,这些命令将降低Redis集群的性能,并导致不可预测的错误。

下面我将详细介绍Redis集群,主从和哨兵的搭建只是便于理解集群的演变,本节适用3.0~6.0的Redis版本

1:Redis集群介绍

Redis集群通过分区(partition)来提供一定程度的可用性(availability);
即使集群中有一部分节点失效或者无法进行通讯, 集群也可以继续处理命令请求。 Redis集群提供了以下两个好处: 将数据自动切分(split)到多个节点的能力,这就是下面说的数据分片。 当集群中的一部分节点失效或者无法进行通讯时,仍然可以继续处理命令请求的能力。

2:数据分片

  Redis集群没有使用一致性hash(consistency hashing), 而是引入了哈希槽的概念,使用哈希槽来实现数据分片(sharding);一个Redis集群包含16384个哈希槽(hash slot),数据库中的每个键计算后都会在这16384个哈希槽的其中一个槽位上;集群中槽位计算使用公式CRC16(key) % 16384来计算键key属于哪个槽里, 其中 CRC16(key) 语句用于计算键key的CRC16校验和。

集群中的每个节点负责处理一部分哈希槽。举个例子,一个集群中存在三个Master主节点,那么它最多可以有三个哈希槽, 其中:

  节点 A 负责处理 0 号至 5460 号哈希槽。        [5461个槽点]
  节点 B 负责处理 5461 号至 10922 号哈希槽。     [5462个槽点]
  节点 C 负责处理 10923 号至 16383 号哈希槽。   [5461个槽点]
这种将哈希槽分布到不同节点的做法使得用户可以很容易地向集群中添加或者删除节点。
  因为添加一个集群Master节点我只需要把前三个Master节点上的槽位里的槽点提出来部分分给新添加上来的Master节点上的槽位里;删除也差不多,只需要提前把待删除的主节点Master上的槽点全部提取出来分给其它Master节点上的槽位里,再删除主节点Master

  这时我要添加一个key键比如说:设置一个key,叫MyName的key  == > set MyName antLaddie

  按照Redis Cluster的哈希槽算法,CRC16('MyName') = 45121;45121 % 16384 = 12353 那么这个key就被分配到了节点C上;同样的,当我连接(A,B,C)的任意一个节点想获取MyName这个key,都会转到节点C上;如果用户将新节点 D 添加到集群中,那么集群只需要将节点 A 、B 、C 中的部分槽移动到节点 D 就可以了。增加一个D节点的结果可能如下(把ABC槽点分部分给D):

  节点A覆盖1365-5460
  节点B覆盖6827-10922
  节点C覆盖12288-16383
  节点D覆盖0-1364,5461-6826,10923-1228
  与此类似, 如果用户要从集群中移除节点 A , 那么集群只需要将节点 A 中的所有哈希槽移动到节点 B 和节点 C ,然后再移除空白(不包含任何哈希槽)的节点 A 就可以了,因为将一个哈希槽从一个节点移动到另一个节点不会造成节点阻塞, 所以无论是添加新节点还是移除已存在节点,又或者改变某个节点包含的哈希槽数量, 都不会造成集群下线。

3:集群主从复制模型

  为了使集群在一部分节点下线或者无法与集群的大多数(majority)节点进行通讯的情况下, 仍然可以正常运作, Redis集群对节点使用了主从复制功能;集群中的每个节点都有 1 个至 N 个复制品(replica), 其中一个复制品为主节点(master), 而其余的 N-1 个复制品为从节点(slave)。在之前列举的节点A 、B 、C的例子中,如果节点 B 下线了(没有从节点), 那么集群将无法正常运行, 因为集群找不到节点来处理 5461 号至 10922号的哈希槽位。另一方面, 假如在创建集群的时候(或者至少在节点 B 下线之前), 我们为主节点 B 添加了从节点 B1 , 那么当主节点 B 下线的时候,集群就会将 B1 设置为新的主节点, 并让它代替下线的主节点 B , 继续处理 5461 号至 10922 号的哈希槽, 这样集群就不会因为主节点 B 的下线而无法正常运作了。不过如果节点 B 和 B1 都下线的话, Redis 集群还是会停止运作

  总的来说,当某个负责指定插槽槽位的主节点(Master)下线了,并且负责这个槽位内的主从模型范围内里找不到替代主节点的从机后,整个集群将会置为不可用的状态;但是可以通过 cluster-require-full-coverage no 来关闭这限制,表示除下线的槽位不可以,其余槽位可正常写入和读取

4:Redis一致性保证

Redis并不能保证数据的强一致性. 这意味这在实际中集群在特定的条件下可能会丢失写操作
第一个原因是因为集群是用了异步复制. 写操作过程:   ①:客户端向主节点B写入一条命令.   ②:主节点B向客户端回复命令状态(成功还是失败).   ③:主节点将写操作复制给当前主从复制下的从节点 B1、B2、B3... 主节点对命令的复制工作发生在返回命令状态回复之后,因为如果每次处理命令请求都需要等待复制操作完成的话,那么主节点处理命令请求的速度
将极大地降低;我们必须在性能和一致性之间做出权衡。注意:Redis集群可能会在将来提供同步写的方法。 第二原因是Redis集群可能会丢失命令的情况是集群出现了网络分区并且一个客户端与至少包括一个主节点在内的少数实例被孤立:   假设集群包含A、B、C、A1、B1、C1六个节点,其中 A、B、C 为主节点, A1、B1、C1 为A,B,C的从节点,还有一个客户端 Z1 假设
集群中发生网络分区,那么集群可能会分为两方,大部分的一方包含节点 A、C、A1、B1、C1 ,小部分的一方则包含节点 B 和客户端 Z1。 Z1仍然能够向主节点B中写入, 如果网络分区发生时间较短,那么集群将会继续正常运作,如果分区的时间足够让大部分的一方将B1选举为新的
master,那么Z1写入B中得数据便丢失了. 注意,在网络分裂出现期间,客户端 Z1 可以向主节点 B 发送写命令的最大时间是有限制的,
这一时间限制称为节点超时时间(node timeout),是 Redis 集群的一个重要的配置选项

5:Redis集群搭建准备

  搭建Redis集群至少需要准备3个主Master节点和3个从Slave节点,总共6个节点才能搭建一套Redis集群,因为6台机器成本太大,所以换成伪集群在一台机器上部署;这里我将介绍 redis3.0~6.0 两种方式搭建集群

注:若不是工作需求直接使用5.0+版本,直接使用官方自带的redis-cli -c 来操作集群,不需要在下载Ruby脚本啥的

①:节点说明
    127.0.0.1:8001[Master主节点]              127.0.0.1:8004 [Slave从节点]
    127.0.0.1:8002[Master主节点]              127.0.0.1:8005 [Slave从节点]
    127.0.0.1:8003[Master主节点]              127.0.0.1:8006 [Slave从节点]
    127.0.0.1:8007 [后面用来测试扩容]
    127.0.0.1:8008 [后面用来测试扩容]
    127.0.0.1:8009 [后面用来测试扩容]
    127.0.0.1:8010 [后面用来测试扩容]
②:搭建基本环境及BaseRedis(就是一个单机版Redis)
    cd /home
    yum -y install cpp binutils glibc glibc-kernheaders glibc-common glibc-devel gcc make gcc-c++ libstdc++-devel tcl
    # 通过 rz -y 上传Redis压缩包 redis-3.2.9.tar.gz 或 redis-6.2.6.tar.gz
    tar -zxvf redis-3.2.9.tar.gz
    cd redis-3.2.9/
    mkdir -p /usr/local/redisCluster/redisBase/bin
    make && make PREFIX=/usr/local/redisCluster/redisBase install
    # 到这我们就有一个基本的Redis程序了,可以用这个redisBase里的命令来搭配不同配置文件批量启动集群
    # 批量集群节点文件夹创建
    mkdir -p /usr/local/redisCluster/redis8001  /usr/local/redisCluster/redis8001/etc
    mkdir -p /usr/local/redisCluster/redis8002  /usr/local/redisCluster/redis8002/etc
    mkdir -p /usr/local/redisCluster/redis8003  /usr/local/redisCluster/redis8003/etc
    mkdir -p /usr/local/redisCluster/redis8004  /usr/local/redisCluster/redis8004/etc
    mkdir -p /usr/local/redisCluster/redis8005  /usr/local/redisCluster/redis8005/etc
    mkdir -p /usr/local/redisCluster/redis8006  /usr/local/redisCluster/redis8006/etc
    mkdir -p /usr/local/redisCluster/redis8007  /usr/local/redisCluster/redis8007/etc
    mkdir -p /usr/local/redisCluster/redis8008  /usr/local/redisCluster/redis8008/etc
    mkdir -p /usr/local/redisCluster/redis8009  /usr/local/redisCluster/redis8009/etc
    mkdir -p /usr/local/redisCluster/redis8010  /usr/local/redisCluster/redis8010/etc
    # 为每个节点文件夹里面放一个Redis配置文件
    cp /home/redis-3.2.9/redis.conf /usr/local/redisCluster/redis8001/etc/redisNodes_8001.conf
    cp /home/redis-3.2.9/redis.conf /usr/local/redisCluster/redis8002/etc/redisNodes_8002.conf
    cp /home/redis-3.2.9/redis.conf /usr/local/redisCluster/redis8003/etc/redisNodes_8003.conf
    cp /home/redis-3.2.9/redis.conf /usr/local/redisCluster/redis8004/etc/redisNodes_8004.conf
    cp /home/redis-3.2.9/redis.conf /usr/local/redisCluster/redis8005/etc/redisNodes_8005.conf
    cp /home/redis-3.2.9/redis.conf /usr/local/redisCluster/redis8006/etc/redisNodes_8006.conf
    cp /home/redis-3.2.9/redis.conf /usr/local/redisCluster/redis8007/etc/redisNodes_8007.conf
    cp /home/redis-3.2.9/redis.conf /usr/local/redisCluster/redis8008/etc/redisNodes_8008.conf
    cp /home/redis-3.2.9/redis.conf /usr/local/redisCluster/redis8009/etc/redisNodes_8009.conf
    cp /home/redis-3.2.9/redis.conf /usr/local/redisCluster/redis8010/etc/redisNodes_8010.conf

基本文件创建准备

  基本的文件创建好,我们就要修改每个节点的配置文件了,然后和一键启动脚本即可

①:修改每个节点下的配置文件,如下示例,其它文件只需要套用此配置,把8001批量替换800*
    具体替换的vim命令 :%s/源字符串/目标字符串/g
# 端口号
    port 8001
# 设置外部任何IP都可以连接,或者设置指定IP连接 用 "-" 分割
  bind 0.0.0.0 或 *   新版本设置:bind * -::* # 后台启动 daemonize yes # 指定数据文件存放发位置,必须指定不同的目录位置,不然会丢失运行的一些数据,比如日志,持久化文件等 dir /usr/local/redisCluster/redis8001 # 指定新的PID进程文件路径 (windows下没有)当 daemonize yes为守护进程时必须设置 pidfile /var/run/redisNodes_8001.pid # 日志文件名称 logfile "/usr/local/redisCluster/redis8001/redisNodes_8001.log" # RDB持久化快照的的文件名 dbfilename dumpNodes_8001.rdb # 开启aof 注同时开启AOF和RDB时当Redis重启时,会优先使用AOF文件来还原数据集,若考虑性能则可以关闭aof appendonly yes # aof文件路径 appendfilename "appendonly_8001.aof" # 是否开启集群(必须开启) cluster-enabled yes #集群节点配置文件 cluster-config-file nodes-8001.conf # 集群连接超时时间 cluster-node-timeout 5000 ②:创建Redis集群启动脚本 RedisClusterStart.sh 这里的 8007 8008 8009 8010虽然启动,但是不使用,后面扩容使用 cat > RedisClusterStart.sh << EOF #!/bin/sh /usr/local/redisCluster/redisBase/bin/redis-server /usr/local/redisCluster/redis8001/etc/redisNodes_8001.conf /usr/local/redisCluster/redisBase/bin/redis-server /usr/local/redisCluster/redis8002/etc/redisNodes_8002.conf /usr/local/redisCluster/redisBase/bin/redis-server /usr/local/redisCluster/redis8003/etc/redisNodes_8003.conf /usr/local/redisCluster/redisBase/bin/redis-server /usr/local/redisCluster/redis8004/etc/redisNodes_8004.conf /usr/local/redisCluster/redisBase/bin/redis-server /usr/local/redisCluster/redis8005/etc/redisNodes_8005.conf /usr/local/redisCluster/redisBase/bin/redis-server /usr/local/redisCluster/redis8006/etc/redisNodes_8006.conf /usr/local/redisCluster/redisBase/bin/redis-server /usr/local/redisCluster/redis8007/etc/redisNodes_8007.conf /usr/local/redisCluster/redisBase/bin/redis-server /usr/local/redisCluster/redis8008/etc/redisNodes_8008.conf /usr/local/redisCluster/redisBase/bin/redis-server /usr/local/redisCluster/redis8009/etc/redisNodes_8009.conf /usr/local/redisCluster/redisBase/bin/redis-server /usr/local/redisCluster/redis8010/etc/redisNodes_8010.conf echo "redis is start" EOF chmod 744 RedisClusterStart.sh

  这时我们就把10个节点的Redis启动了,此时的Redis都是以集群模式启动了,只是现在没有让它们之间集群关联

6:Redis集群关联(原生)

集群的搭建可以分为四步:
    ①:启动节点:将节点以集群模式启动,此时节点是独立的,并没有建立联系;[上一小节已启动]
    ②:节点握手:让独立的节点连成一个网络;
    ③:分配槽:将16384个槽分配给主节点;
    ④:指定主从关系:为从节点指定主节点。
注:这里我只使用 8001 ~ 8006 其中 8001 ~ 8003为Master主节点,要分配槽的,8004 ~ 8006 为Slave从节点

1:节点握手

  我们上面的10个节点启动以后是相互独立的,并不知道其它节点的存在;需要进行节点握手,将独立的节点组成一个网络。节点握手使用 cluster meet {ip} {port} 命令实现,例如在8001节点中执行 cluster meet 10.200.157.126 8002可以完成8001节点和8002节点的握手;注意ip使用的是局域网ip而不是 localhost 或127.0.0.1,是为了其他机器上的节点或客户端也可以访问。可使用cluster nodes查看

以集群模式连接8001节点:(这里一定要加 -c 以集群模式启动)
    /usr/local/redisCluster/redisBase/bin/redis-cli -c -h 10.200.157.126 -p 8001
查看当前节点:(此时8001就单独一个节点集群)
  10.200.157.126:8001> cluster nodes
  3a00331cad40d52e5755c22699668574e090fa7e :8001 myself,master - 0 0 0 connected

在 8001 节点下使用Cluster meet 命令把所有节点加入到集群,完成节点握手:
    cluster meet 10.200.157.126 8002
    cluster meet 10.200.157.126 8003
    cluster meet 10.200.157.126 8004
    cluster meet 10.200.157.126 8005
    cluster meet 10.200.157.126 8006

2:分配槽

  在Redis集群中,借助槽实现数据分区。集群有16384个槽,槽是数据管理和迁移的基本单位。当数据库中的16384个槽都分配了节点时,集群处于上线状态(ok);如果有任意一个槽没有分配节点,则集群处于下线状态(fail)。cluster info命令可以查看集群状态,分配槽之前状态为fail;

未分配完(或未分配)槽点:
    10.200.157.126:8001> cluster info
    cluster_state:fail          【集群状态fail失败 ok 成功】
    cluster_slots_assigned:0    【当前整个集群分配的插槽点数,未到16384是无法启动的】
通过redis_cli客户端命令为 8001 ~ 8003 分配插槽 【每个节上的插槽随便分配点数,这里我就平均分配】
/usr/local/redisCluster/redisBase/bin/redis-cli -p 8001 cluster addslots {0..5460}
/usr/local/redisCluster/redisBase/bin/redis-cli -p 8002 cluster addslots {5461..10922}
/usr/local/redisCluster/redisBase/bin/redis-cli -p 8003 cluster addslots {10923..16383}
分配完槽点显示正常:
    10.200.157.126:8001> cluster info
    cluster_state:ok
    cluster_slots_assigned:16384

3:指定主从关系

  集群中指定主从关系就不再使用slaveof命令了,而是使用 cluster replicate 命令;参数使用节点ID

从分配插槽时就已经确定了主节点Master了,因为只有主节点才可以分配插槽,下面我将从机连接到主机上
    Master 8001  --> Slave 8004
    Master 8002  --> Slave 8005
    Master 8003  --> Slave 8006
随便进入一个集群节点查询当前的全部集群ID,用来分配主从关系,这里我就进入8001节点查看
开始分配主从:
cd /usr/local/redisCluster/redisBase/bin/
./redis-cli -p 8004 cluster replicate 3a00331cad40d52e5755c22699668574e090fa7e
./redis-cli -p 8005 cluster replicate 72cfe73954d8dc94f3ba0a3910885fccf1a26aba
./redis-cli -p 8006 cluster replicate 372db80734eaf94f4edeab82ab3b8e5ba4bc40d6
测试:
10.200.157.126:8001> set name zhangsan   -> Redirected to slot [5798] located at 10.200.157.126:8002 
OK
【↑↑ 此时计算出name属于5798槽点,所以在8002,这是自动切换到8002节点保存】 10.200.157.126:8002> set age 22 -> Redirected to slot [741] located at 10.200.157.126:8001 
OK
【↑↑ 此时计算出age属于741槽点,所以在8001,这是自动切换到8001节点保存】

7:Redis集群关联(Ruby脚本搭建 Redis-trib)

  Redis-trib命令详解(引用别人文章)

  除了使用原生的方式,我们还可以使用Ruby脚本来搭建集群,不过在搭建前需要下载依赖ruby和rubygems;下载完我们就可以通过redis-trib.rb的Ruby脚本文件实现自动化的集群搭建

①:下载依赖ruby和rubygems:yum -y install ruby rubygems
②:安装redis和ruby的接口:gem install redis
Redis5.0.0以上版本就不推荐使用此方式了,因为有更好的 redis-cli 方式

当你出现了这种情况就需要按照如下步骤解决:
》》[root@MiWiFi-IR1200G-srv redisCluster]# gem install redis
》》Fetching: redis-4.5.1.gem (100%)
》》ERROR:  Error installing redis:
》》    redis requires Ruby version >= 2.4.0.  【说的是需要2.4及2.4以上的Ruby版本】

解决方案:
①:安装curl
    yum install curl
②:安装rvm
    curl -L get.rvm.io | bash -s stable
    这时候可能会出现问题:
        curl: (7) Failed connect to raw.githubusercontent.com:443; 拒绝连接
    我们需要修改hosts文件:sudo vim /etc/hosts
    然后把 199.232.28.133 raw.githubusercontent.com 复制加到hosts文件的最后一行
    然后再执行 curl -L get.rvm.io | bash -s stable
③:刷新rvm文件
    source /usr/local/rvm/scripts/rvm
⑤:查看rvm库中已知的ruby版本
    rvm list known
⑥:安装一个ruby版本
    rvm install 2.6.3
⑦:使用一个ruby版本 并设置为默认版本
    rvm use 2.6.3
    ruby --version
⑧:卸载一个已知版本
    rvm remove 2.0.0
⑨:安装最初出问题的命令
    [root@MiWiFi-IR1200G-srv redisCluster]# gem install redis
    Fetching redis-4.5.1.gem
    Successfully installed redis-4.5.1
    Parsing documentation for redis-4.5.1
    Installing ri documentation for redis-4.5.1
    Done installing documentation for redis after 0 seconds
    1 gem installed

解决安装Ruby版本问题

此时此刻我们就可以使用 redis-trib.rb 来搭建集群了
把我们之前解压编译的redis里的 redis-trib.rb 文件拷贝到我们的redisBase基本命令文件夹里
cp /home/redis-3.2.9/src/redis-trib.rb /usr/local/redisCluster/redisBase/bin/
## 注不要出现空格
/usr/local/redisCluster/redisBase/bin/redis-trib.rb create --replicas 1 10.200.157.126:8001 10.200.157.126:8002 10.200.157.126:8003 10.200.157.126:8004 10.200.157.126:8005 10.200.157.126:8006
说明:
    create:这表示我们希望创建一个新的集群
    --replicas 1:代表比例,就是主节点数/从节点数比例
        1:代表 1/1=1  说明1Master 1Slave 假设20个Redis节点就代表集群里存在10个主从,每个Master下面存在1个Slave
        0.5:代表 1/2  说明1Master 2Slave 假设15个Redis节点就代表集群里存在5个主从,每个Master下面存在2个Slave
    集群的创建是按照顺序来的,比如 1 那么上面的例子就是前3为Master,后3为Slave,和前面一一对应
   搭建成功记得测试哟!

8:Redis集群关联(redis-cli官方工具搭建)

  若Redis是5.0以上版本,那么搭建Redis集群就简单多了,我们可以直接使用redis-cli就可以快速进行集群搭建;
  注:Redis5.0以下使用上面介绍的方法redis-trib.rb

[root@MiWiFi-IR1200G-srv redisCluster]# cd /usr/local/redisCluster/redisBase/bin/
[root@MiWiFi-IR1200G-srv bin]# ./redis-cli --cluster create --cluster-replicas 1 192.168.31.51:8001 192.168.31.51:8002 192.168.31.51:8003 192.168.31.51:8004 192.168.31.51:8005 192.168.31.51:8006
基本参数介绍:
    --cluster
        指定是用于创建集群环境
    --cluster-replicas
        用于指定主节点上从节点数,1代表1主1从,2代表1主2从;
        注:主机必须大于等于三台,那设置2从机就代表至少准备9台节点,三个1主2从
    -a
        若存在密码则通过这个设置(前提得一样)
    {IP}:{端口}... 
        代表哪些集群组成集群

我们也可以使用:./redis-cli --cluster check 127.0.0.1:8001 查看集群状态

9:Redis集群的基本连接及节点下线

  这里我们就使用官方自带的 redis-cli 来连接集群,但是注意的是必须加上 -c 参数,代表我们是以集群方式连接,这里我就以8001来进行测试

# 连接 8001 主节点端口(因为连接从节点Slave无法写操作,所以不连那个测试)
[root@MiWiFi-IR1200G-srv bin]# ./redis-cli -c -h 127.0.0.1 -p 8001
127.0.0.1:8001> set name zhangsan
-> Redirected to slot [5798] located at 192.168.31.51:8002
OK
【↑↑ 此时计算出name属于5798槽点,所以在8002,这是自动切换到8002节点保存】
192.168.31.51:8002> set age 22
-> Redirected to slot [741] located at 192.168.31.51:8001
OK
【↑↑ 此时计算出age属于741槽点,所以在8001,这是自动切换到8001节点保存】
192.168.31.51:8001> keys *
1) "age"
【↑↑ 此时在8001插槽里,所以在只能查询到8001槽点下的全部数据】
192.168.31.51:8001> set height 180
-> Redirected to slot [8223] located at 192.168.31.51:8002
OK
【↑↑ 此时计算出height属于8223槽点,所以在8002,这是自动切换到8002节点保存】
192.168.31.51:8002> keys *
1) "height"
2) "name"
【↑↑ 此时在8001插槽里,所以在只能查询到8001槽点下的全部数据】
192.168.31.51:8002> get age
-> Redirected to slot [741] located at 192.168.31.51:8001
"22"
【↑↑ 计算age键在8001下,所以跳转过去取值】
192.168.31.51:8001> get name
-> Redirected to slot [5798] located at 192.168.31.51:8002
"zhangsan"
【↑↑ 计算age键在8002下,所以跳转过去取值】
192.168.31.51:8002>
【↑↑ 最终在8002节点下】

测试8001的这个Master主节点宕机

  案例中我们集群是三个主节点Master[8001~8003]和三个从节点[8004~8006];这时候我把8001宕机,那么8004从机会顶上来的当主机

①:使用kill强行杀死一个8001节点的RedisCluster
②:使用redis-trib.rb的检查命令来查看当前集群的状态(注:必须连接一个在线的主或从节点)
[root@MiWiFi-IR1200G-srv bin]# /usr/local/redisCluster/redisBase/bin/redis-trib.rb check 127.0.0.1:8006
>>> Performing Cluster Check (using node 127.0.0.1:8006)
S: 9b868e59ccf602258d079339aa51d7335d637e8d 127.0.0.1:8006
   slots: (0 slots) slave
   replicates 0a8967caa61cc159a99d409ebe61a73c7ade16cf
S: 2293234155950a91541f1a3a64884a89fce6c469 192.168.31.51:8005
   slots: (0 slots) slave
   replicates 51ede3997f64d139fb66810df132c67fc1fffe2f
M: 51ede3997f64d139fb66810df132c67fc1fffe2f 192.168.31.51:8002
   slots:5461-10922 (5462 slots) master
   1 additional replica(s)
M: 0a8967caa61cc159a99d409ebe61a73c7ade16cf 192.168.31.51:8003
   slots:10923-16383 (5461 slots) master
   1 additional replica(s)
M: e7f4ae2d2a7f7c48b37b4273de572405caec9f91 192.168.31.51:8004
   slots:0-5460 (5461 slots) master
   0 additional replica(s)
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
开头的S代表Slave M代表Master   8001下线后发现8004主动担起主节点的重任
注:若没有 redis-trib.rb 的可以使用 redis-cli 程序来连接查看状态
/usr/local/redisCluster/redisBase/bin/redis-cli -c -h 127.0.0.1 -p 8006
127.0.0.1:8006>cluster nodes

测试8001的这个主节点上线

①:使用8001的配置文件来启动8001节点
[root@MiWiFi-IR1200G-srv bin]# cd /usr/local/redisCluster/redisBase/bin/
[root@MiWiFi-IR1200G-srv bin]# ./redis-server /usr/local/redisCluster/redis8001/etc/redisNodes_8001.conf
②:检查集群状况
[root@MiWiFi-IR1200G-srv bin]# /usr/local/redisCluster/redisBase/bin/redis-trib.rb check 127.0.0.1:8006
>>> Performing Cluster Check (using node 127.0.0.1:8006)
S: 9b868e59ccf602258d079339aa51d7335d637e8d 127.0.0.1:8006
   slots: (0 slots) slave
   replicates 0a8967caa61cc159a99d409ebe61a73c7ade16cf
S: 2293234155950a91541f1a3a64884a89fce6c469 192.168.31.51:8005
   slots: (0 slots) slave
   replicates 51ede3997f64d139fb66810df132c67fc1fffe2f
M: 51ede3997f64d139fb66810df132c67fc1fffe2f 192.168.31.51:8002
   slots:5461-10922 (5462 slots) master
   1 additional replica(s)
M: 0a8967caa61cc159a99d409ebe61a73c7ade16cf 192.168.31.51:8003
   slots:10923-16383 (5461 slots) master
   1 additional replica(s)
S: 3b5a75e7f60745a59864aa4600e454be49b5d240 192.168.31.51:8001
   slots: (0 slots) slave
   replicates e7f4ae2d2a7f7c48b37b4273de572405caec9f91
M: e7f4ae2d2a7f7c48b37b4273de572405caec9f91 192.168.31.51:8004
   slots:0-5460 (5461 slots) master
   1 additional replica(s)
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
此时8001节点上线时只能当个从机了,因为8004节点之前谋权篡位了,只有等8004下线后8001才会成为主节点

测试8004主节点和8001从节点这一个小的主从全部宕机

  通过ps -ef | grep redis 查看进程并使用 kill 关闭了8001和8004两个节点,此时按照默认配置,此集群是无法正常使用的了,这时只能让人为参与,启动宕机的机器;或者把宕机的那一部分插槽转移到其它好的主节点上,这样集群就会存在两个主节点了;

  这是我们就需要把8001、8004给重启一下,这里我为了方便,直接把全部Redis进程杀死并重新执行脚本

# 杀死Redis全部进程
kill -9 `ps -ef | grep redis | grep -v grep | awk '{print $2}'`
# 启动脚本启动全部Redis(包括)
/usr/local/redisCluster/RedisClusterStart.sh

从下面开始我将介绍redis-trib方式(3.0 >= redis <5.0)和redis-cli(redis >= 5.0)两种方式来操作集群;推荐使用redis-cli

老版本使用redis-trib方式,新版本使用redis-cli(推荐)

10:集群增加主节点(redis-trib方式)

  我们可以看出之前我一直启动着8007~8010这四台机器,就是用来后面的扩容做准备,这时我将8007加入到集群中并设置主节点Master;我们可以通过redis-trib的add node指令加入节点

# 使用redis-trib.rb的add-node指令
# redis-trib.rb add-node {待加入集群的IP:端口} {已存在集群中的任意节点IP:端口}
[root@localhost redisCluster]# cd /usr/local/redisCluster/redisBase/bin/
[root@localhost bin]# ./redis-trib.rb add-node 10.200.157.141:8007 10.200.157.141:8001

此时此刻我们已经把主节点加入到集群了,这时加入的8007Master是一个(slots: (0 slots) master);所以要想使用就必先分配插槽,
从8001~8003里面随便分一点给8007;分配使用redis-trib.rb的reshard指令重新分片; 注:这个IP和端口连接任意的都可以,只要能进入集群 [root@localhost bin]# ./redis-trib.rb reshard 10.200.157.141:8005 How many slots do you want to move (from 1 to 16384)? 4096 【回车】 (提示我们要移动多少个插槽(从1到16384);我们可以均匀分配 16384/4=4096所以我们就填写4096,若均匀下来存在小数我们就取个整就行)
(建议分配尽量均匀,相差太大可能会有问题(相差几十都还行),这是我的小建议,出了那问题老麻烦了)
What is the receiving node ID? d9859d6acf261106cd1c8d5d7ce47c0425250dff 【回车】 (提示我们把这4096个插槽点分给那个MasterID ) 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 【回车】 (提示我们redis-trib.rb会向你询问重新分片的源节点(source node), 也即是说要从哪个节点中取出 4096 个哈希槽,并将这些槽移动 到8007节点上面。如果我们不打算从特定的节点上取出指定数量的哈希槽, 那么可以向 redis-trib输入all,这样的话, 集群中的所有主节点 都会成为源节点, redis-trib.rb将从各个源节点中各取出一部分哈希槽,凑够4096个, 然后移动到7006节点上) Do you want to proceed with the proposed reshard plan (yes/no)? yes 【回车】 (是否要继续提议的重新分片计划)

11:集群增加主节点(redis-cli方式)

这里我需要添加一个8007节点,默认添加就为主节点Master
[root@MiWiFi-IR1200G-srv bin]# ./redis-cli --cluster add-node 192.168.31.51:8007 192.168.31.51:8002
    add-node {待添加IP}:{待添加端口} {已存在IP}:{已存在端口}

分配插槽给8007【平均分配】
[root@MiWiFi-IR1200G-srv bin]# ./redis-cli --cluster rebalance --cluster-threshold 1 --cluster-use-empty-masters 192.168.31.51:8007

分配【手动分配】

./redis-cli --cluster reshard --cluster-from all --cluster-to {需要分配槽点的ID} --cluster-slots {分配的槽点} --cluster-yes 127.0.0.1:8001

12:集群增加从节点(redis-trib方式)

  增加一个8008节点来作为8007主节点的从机

和添加主节点一样,但是加上 --slave 就代表添加的是从节点;
注:但是这里未指定添加到哪台主节点下,只是配置了个10.200.157.141:8001让其加入到某个集群
这时redis-trib.rb就会将8008从节点添加到从节点较少的主节点Master上(这里显然就添加到8007Master上)
[root@localhost bin]# cd /usr/local/redisCluster/redisBase/bin/
[root@localhost bin]# ./redis-trib.rb add-node --slave 10.200.157.141:8008 10.200.157.141:8001
但是话说回来,我不想让redis-trib来分配从节点到任意一个主节点下,我要自己手动指定到主节点Master下,
这里我准备将8009未分配到集群的节点分配给8003主节点下
这里的 --master-id  代表指定的主节点node id
[root@localhost bin]# cd /usr/local/redisCluster/redisBase/bin/
[root@localhost bin]# ./redis-trib.rb add-node --slave --master-id aec1bb289da5fed2159ccb3217d2aec03ba47709 10.200.157.141:8009 10.200.157.141:8002

13:集群增加从节点(redis-cli方式)

这里我就把8008添加到8007节点下(8007就是刚刚我们添加的主节点)
[root@MiWiFi-IR1200G-srv bin]# ./redis-cli --cluster add-node --cluster-slave --cluster-master-id a669b1cb86c103eb08e527fc6ff6a489f7fb2904 192.168.31.51:8009 192.168.31.51:8003
    --cluster-slave:加入的是从节点
    --cluster-master-id:后面设置要连接谁当主节点;这里设置ID

14:集群移除一个主节点(redis-trib方式)

  我现在的需求时移除8007主节点,但移除主节点前,我们必须先把当前待移除的8007主节点里的全部插槽移除出去,也就是要重新分片

这里我就把8007里的全部插槽移出去,移动到8003主节点上
这里的 del-node 指令代表移除节点;d9859d6acf261106cd1c8d5d7ce47c0425250dff代表移除的8007节点ID
[root@localhost bin]# cd /usr/local/redisCluster/redisBase/bin/
[root@localhost bin]# ./redis-trib.rb del-node 10.200.157.141:8002 d9859d6acf261106cd1c8d5d7ce47c0425250dff
>>> Removing node d9859d6acf261106cd1c8d5d7ce47c0425250dff from cluster 10.200.157.141:8002
[ERR] Node 10.200.157.141:8007 is not empty! Reshard data away and try again.
    【报错 >>> 从集群 10.200.157.141:8002 中删除节点 d9859d6acf261106cd1c8d5d7ce47c0425250dff】
    【报错[ERR] 节点 10.200.157.141:8007 不为空(就是8007节点里存在插槽)! 重新分片数据,然后重试。】
# 重新分片 注:这个IP和端口连接任意的都可以,只要能进入集群
[root@localhost bin]# ./redis-trib.rb reshard 10.200.157.141:8002
    How many slots do you want to move (from 1 to 16384)? 4096
    (这里我就移动4096个插槽点)
    What is the receiving node ID? aec1bb289da5fed2159ccb3217d2aec03ba47709
    (把这4096个插槽点移动到谁的主节点上,这里我移动到8003主节点上)
    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:d9859d6acf261106cd1c8d5d7ce47c0425250dff
    Source node #2:done
    (说的是我要从哪个主节点ID里分配这4096个插槽点,若设置all的话就会平均每个都抽出来一点插槽)
    (但这我明确指出从8007节点里移动插槽到8003;;done结束设置)
    Do you want to proceed with the proposed reshard plan (yes/no)? yes 【回车】

15:集群移除一个主/从节点(redis-cli方式)

删除节点和上面一节逻辑一样
①:对当前集群进行重新分片,把待删除的主机上的全部插槽移动到其它主节点下
    ./redis-cli --cluster reshard {集群内任意IP}:{集群内任意端口}
    ==>具体的参考上面和 ./redis-trib.rb reshard 10.200.157.141:8002 一样
②:删除节点(这里删除主节点和从节点命令一样)
    ./redis-cli --cluster del-node {集群内任意IP}:{集群内任意端口} {待删除的ID}

16:集群移除一个从节点(redis-trib方式)

我现在要移除8009从节点,因为它是从节点也没有插槽,所以直接移除
[root@localhost bin]# ./redis-trib.rb del-node 10.200.157.141:8002 7aab013e8257fce39bdcd36cad9320cd4265ef21
>>> Removing node 7aab013e8257fce39bdcd36cad9320cd4265ef21 from cluster 10.200.157.141:8002
>>> Sending CLUSTER FORGET messages to the cluster...
>>> SHUTDOWN the node.

.