一、Redis主从复制

  一)理论知识讲解

  1、实现主从复制

  1. 从 Redis 2.8 开始,使用异步复制。
  2. 一个主服务器可以有多个从服务器。
  3. 从服务器也可以有自己的从服务器。
  4. 复制功能不会阻塞主服务器。
  5. 可以通过复制功能来让主服务器免于执行持久化操作,由从服务器去执行持久化操作即可

  2、全量复制(redis2.8以前)

    1、全量复制的流程

  

redis主从复制及哨兵sentinel_Redis

    2、全量复制开销
  • bgsave时间
  • RDB文件网络传输时间
  • 从节点清空数据时间
  • 从节点加载RDB时间
  • 可能的AOF重写时间:RDB加载完毕后,若开启了AOF参数,会进行AOF重写,以保证AOF是最新的状态
    3、全量复制的问题

  master与slave之间的网络发生了抖动,这段时间的数据就会丢失

  2、Redis部分复制(Redis2.8之后添加的功能)

    1、部署复制的流程

  

redis主从复制及哨兵sentinel_服务器_02

    2、部分复制解决了全量复制的网络抖动导致数据丢失的问题

  master在写的时候,会写一份复制缓冲区的命令;

  1. 当网络抖动结束后,slave会发送pysnc {offset} {runId}告知自己目前偏移量(数据所处的位置)
  2. 当master收到slave的偏移量后,看是否在buffer中,若在返回给slave一个CONTINUE,随后发送slave缺失数据到相应的slave

  (buffer默认是1M,为了保证数据的完整性,可以配置大一些)

  4、故障处理

  没有设置自动转移,只能自己手工操作处理

  架构图,如下

  

redis主从复制及哨兵sentinel_主从复制_03

    1、slave宕机

  slave宕机如图

  

redis主从复制及哨兵sentinel_Redis_04

   手动解决

  

redis主从复制及哨兵sentinel_服务器_05

 

    2、mater宕机

   

redis主从复制及哨兵sentinel_服务器_06

   手动解决

  

redis主从复制及哨兵sentinel_服务器_07

  4、优化架构,解决主从复制故障转移问题

  

redis主从复制及哨兵sentinel_Redis_08

  5、开发与运维中的问题

    1、问题汇总
  1. 读写分离
  2. 主从配置不一致
  3. 规避全量复制
  4. 规避复制风暴
    2、读写分离

  

redis主从复制及哨兵sentinel_服务器_09

  1. 读写分离:读流量分摊到从节点
  2. 可能遇到的问题
  • 复制数据延迟:读写数据不一致
  • 惰性删除  主节点处理读取命令时,自动检测键的时间,如果超时自动删除
  • 定时删除   在内部循环,定期查看键有没有过期,如果过期自动删除,之后同步给从节点
  • 从节点故障
    3、配置不一致
  1. maxmemory设置不一致:丢失数据(避免此问题,通过配置管理工具标准化安装、配置)
  2. 数据结构优化参数(利润比hash-max-ziplist-entries):内存不一致
    4、规避全量复制
  1. 第一次全量复制
  • 第一次不可避免
  • 操作时间:小主节点、低峰时操作
  1. 节点运行ID不匹配
  • 主节点重启(运行ID变化)
  • 故障转移:例如哨兵或者集群
  1. 复制积压缓冲区不足
  • 网络中断,部分复制无法满足
  • 增大复制缓冲配置rel_backlog_size,网络"增强" 规避复制风暴(计算每分钟可以写入多少字节 * 故障处理分钟数)
    5、规避复制风暴

  详情见连接:​​javascript:void(0)​

  什么是复制风暴?举例:我们master重启,其master下的所有slave检测到RunID发生变化,导致所有从节点向主节点做全量复制。尽管redis对这个问题做了优化,即只生成一份RDB文件,但需要多次传输,仍然开销很大。

  1. 单主节点复制风暴      太多从节点
  2. 单机复制风暴    机柜

  二)redis主从复制实战

  1、redis主从架构

   

redis主从复制及哨兵sentinel_主从复制_10

  当数据量变得庞大的时候,读写分离还是很有必要的。同时避免一个redis服务宕机,导致应用宕机的情况,我们启用sentinel(哨兵)服务,实现主从切换的功能。redis提供了一个master,多个slave的服务。

         准备三个redis服务,依次命名文件夹子master,slave1,slave2.这里为在测试机上,不干扰原来的redis服务,我们master使用6000端口。

  2、修改Redis主从的配置

  注意:配置文件的位置,根据实际情况更改

    1、配置详解
slaveof 192.168.1.1 6379
slave-read-only 只读模式
masterauth <password> 主服务器设置密码后需要填写密码
min-slaves-to-write <number of slaves>
从服务器不少于,才允许写入
min-slaves-max-lag <number of seconds>
从服务器延迟不大于
CONFIG set slave-read-only yes
Config set masterauth root
INFO replication
SLAVEOF NO ONE 升级至MASTER
    2、master修改配置
port 6000
requirepass 123456
    3、slave1修改配置
port 6001
slaveof 127.0.0.1 6000
masterauth 123456
requirepass 123456
    4、slave2修改配置
port 6002
slaveof 127.0.0.1 6000
masterauth 123456
requirepass 123456

  requirepass:是认证密码,应该之后要作主从切换,所以建议所有的密码都一致。masterauth是从机对主机验证时,所需的密码(即主机的requirepass)。

   3、启动主机

  注意:配置文件的位置,根据实际情况更改

    1、启动master
redis-server redis.conf
    2、启动slave
redis-server redis1.conf
redis-server redis2.conf
    3、查看启动后进程和端口
ps -ef |grep redis
ss -lutnp

  4、验证主从复制

    1、master
# redis-cli -h 127.0.0.1 -p 6000
127.0.0.1:6000> auth 123456
OK
127.0.0.1:6000> set test chenqm
OK
    2、slave1
# redis-cli -h 127.0.0.1 -p 6001
127.0.0.1:6001> auth 123456
OK
127.0.0.1:6001> get test
"chenqm"
    3、slave2
# redis-cli -h 127.0.0.1 -p 6002
127.0.0.1:6001> auth 123456
OK
127.0.0.1:6001> get test
"chenqm"

  可以看到主机执行写命令,从机能同步主机的值,主从复制,读写分离就实现了。

二、Redis主从复制哨兵sentinel模式(主从切换)

  一)redis哨兵sentinel概述

  万一主机挂了怎么办,这是个麻烦事情,所以redis提供了一个sentinel(哨兵),以此来实现主从切换的功能,类似与zookeeper。

  注意:配置文件的位置,根据实际情况更改

  启动三个哨兵:建议配置节点个数是基数(>=3)

  哨兵sentinel官网链接:https://redis.io/topics/sentinel

  1、Sentinel的基本知识

  1. 您需要至少三个Sentinel实例才能实现可靠的部署。
  2. 三个Sentinel实例应放置在相信独立失败的计算机或虚拟机中。例如,不同的物理服务器或虚拟机在不同的可用区域上执行。
  3. 由于Redis使用异步复制,Sentinel + Redis分布式系统不能保证在故障期间保留已确认的写入。然而,有些方法可以部署Sentinel,使窗口可以丢失局限于某些时刻的写入,而另外还有其他安全性较低的部署方式。
  4. 您的客户需要支持Sentinel。受欢迎的客户端库支持Sentinel,但不是全部。
  5. 如果您不在开发环境中进行不定期测试,或者在生产环境中可以更好地进行测试(如果可行),那么就没有安全的HA设置。你可能有一个错误的配置,只有当它太迟了(凌晨3点,当你的主站停止工作时)才会显现出来。
  6. Sentinel,Docker或其他形式的网络地址转换或端口映射应该小心:Docker执行端口重新映射,打破其他Sentinel进程的Sentinel自动发现以及主服务器的从属列表。有关更多信息,请查看本文后面有关Sentinel和Docker的部分。

  2、三个定时任务

    1、没10秒每个sentinel对master和slave执行info
  • 发现slave
  • 确认主从关系
    2、每2秒每个sentinel通过master节点的channel交换信息(pub/sub)
  • 通过_sentinel_:hello频道交互
  • 交互对节点的“看法”和自身信息
    3、每1秒每个sentinel对其他sentinel和redis执行ping
  • 心跳检测,失败判定依据

  二)Redis哨兵(sentinel)实现主从切换部署

   1、配置 三个sentinel进程

  master的sentinel.conf 

port 26279
sentinel auth-pass mymaster 123456

  slave1的sentinel.conf 

port 26379
sentinel auth-pass mymaster 123456

  slave2的sentinel.conf 

port 26479
sentinel auth-pass mymaster 123456

  2、启动sentinel服务(到对应的目录执行相应的命令)

  启动方式一:

  如果您使用的是​​redis-sentinel​​​可执行文件(或者如果您的可执行文件具有该名称的符号链接​​redis-server​​),则可以使用以下命令行运行Sentinel:

redis-sentinel /path/to/sentinel.conf

  启动方式二:

redis-server sentinel.conf --sentinel

  查看日志

[7014] 11 Jan 19:42:30.918 # +monitor master mymaster 127.0.0.1 6000 quorum 2
[7014] 11 Jan 19:42:30.925 * +slave slave 127.0.0.1:6001 127.0.0.1 6002 @ mymaster 127.0.0.1 6000

  从对应的日志观察到,一个master服务,两个slave服务。

   3、验证

    1、 直接验证:哨兵

  新开一个命令行窗口进入redis的src目录,用redis-cli工具登录其中一个哨兵

redis-cli -p 26379

  连接成功后运行如下命令

sentinel master mymaster
    2、故障验证:master宕机
ps -ef|grep [r]edis
kill -9 PID

  查看日志

[7014] 11 Jan 19:43:41.463 # +sdown master mymaster 127.0.0.1 6000
[7014] 11 Jan 19:46:42.379 # +switch-master mymaster 127.0.0.1 6000 127.0.0.1 6001

  master切换了,当6000端口的这个服务重启的时候,他会变成6001端口服务的slave。

  因为sentinel在切换master的时候,把对应的sentinel.conf和redis.conf文件的配置修改。

  期间我们还需要关注的一个问题:sentinel服务本身也不是万能的,也会宕机,所以我们还得部署sentinel集群,象我这样多启动几个sentinel。

  注意这个配置:

sentinel monitor mymaster 127.0.0.1 6000 2   //这个后面的数字2,是指当有两个及以上的sentinel服务检测到master宕机,才会去执行主从切换的功能。

  三)故障切换过程

  1、主观下线和客观下线  

  sentinel monitor <masterName> <ip> <port> <quorum>

sentinel monitor mymaster 127.0.0.1 6000 2   //这个后面的数字2,是指当有两个及以上的sentinel服务检测到master宕机,才会去执行主从切换的功能。 建议配置值:节点数/2+1

  sentinel down-after-milliseconds <masterName> <timeout>

sentinel down-after-milliseconds master 30000 #slave探测主节点正常返回结果的超时时间

  主观下线:每个sentinel节点对Redis节点失败的“偏见”

  客观下线:所有sentinel节点对Redis节点失败“达成共识”(超过quorum个统一)

  sentinel is-master-down-by-addr 问其他sentinel节点,是否同意master下线

  2、领导者选举

  原因:仅需要一个sentinel节点完成故障转移

  选举:通过sentinel is-master-down-by-addr命令都希望成为领导者

  1. 每个做主观下线的sentinel节点向其他sentinel节点发送命令,要求将它设置为领导者
  2. 收到命令的sentinel节点若没有同意过其他sentinel节点发送的命令,那么将同意该请求,否则拒绝
  3. 若该sentinel节点发现自己的票数已经超过sentinel集合半数且超过querum,那么它将成为领导者
  4. 若此过程有多个sentinel节点成为了领导者,那么将等待一段时间重新进行选举

  

redis主从复制及哨兵sentinel_主从复制_11

   3、故障转移(sentinel领导者节点完成)

  1. 从slave节点中选出一个“合适的”节点作为新的master节点
  2. 对上面的slave节点执行slaveof no one命令让其成为master节点
  3. 向剩余的slave节点发送命令,让它们成为新master节点的slave节点,复制规则和parallel-syncs参数有关(parallel-syncs设置的数据,根据新master的系统资源进行配置,设置为1是顺序执行RDB文件和buffer的发送)
  4. 更新对原来master节点配置为slave,并保持着对其“关注”,当其恢复后命令它去复制新的master节点

  4、选择“合适的”slave节点(需要另外配置)

  1. 选择slave-priority(slave节点优先级)最高的slave节点,若存在则返回,不存在则继续(默认不配置)
  2. 选择复制偏移量最大的slave节点(复制的最完整),若存在则返回,不存在则继续
  3. 选择runId最小的slave节点

  四)客户端接入

  1、客户端接入原理

 

  2、客户端接入流程

  1. sentinel地址集合
  2. masterName
  3. 不是代理模式

  3、各种语言接入sentinel

    1、java接入sentinel

  java接入sentinel​

    2、python接入sentinel

  python接入sentinel​

    3、php接入sentinel

  php接入sentinel​

  五)常见的开发运维问题

  1、节点运维

    1、何时需要节点下线
  1. 机器下线:例如过保等情况
  2. 机器性能不足:例如CPU、内存、磁盘、网络等
  3. 节点自身故障:例如服务不稳定等
    2、节点下线

  主节点下线

#只有一个故障转移的过程
sentinel failover <masterName>

  

redis主从复制及哨兵sentinel_redis_12

  从节点下线

  临时下线(暂时关闭)还是永久下线,例如是否做一些请理工作(RDB、AOF等)。要考虑读写分离的情况

  sentinel节点下线(同上)

     3、节点上线

  主节点:sentinel failover进行替换

  从节点:slaveof即可,sentinel节点可以感知

  sentinel节点:参考其他sentinel节点启动即可

  2、常见的开发问题:高可用读写分离

  

redis主从复制及哨兵sentinel_Redis_13