• 6.Redis之主从复制原理


    0.主从复制原理

      当建立主从关系时,slave配置slaveof host  port. slave服务器会向主服务器发送一个sync命令,master 接受并fork一个进行来执行bgsave命令。该命令生成一个RDB文件并且全量发送个slave服务器,slave服务器接受并载入RDB文件,同时,主服务器将缓冲区的命令以增量的方式发送给从服务器,最终是从服务器的数据状态和主服务器保持一致。

      注意:当slave第一次slaveof master时,master会生成一个RDB文件,然后把这个RDB文件传输给slave,但是当master如果有新的数据写入时,这时新的数据会直接发送给slave服务器。。。

    RDB的工作原理

      当redis生成dump.rdb文件时,工作过程如下:

    • redis主进程fork一个子进程
    • fork出来的子进程将内存的数据集dump到临时的RDB中
    • 当子进程对临时的RDB文件写入完毕,redis用新的RDB文件代替旧的RDB文件。  

    AOF的工作原理

      AOF:append only file。每当redis执行一个改变数据集的命令时,这个命令都会被追加到AOF文件的末尾。当redis重新启动时,程序可以通过AOF文件恢复数据。

    1.主从复制过程

      在从节点执行slaveof命令后,复制过程边开始运作,redis的主从复制大致上分为6个过程:

      1)保存主节点(master)的信息

        执行slaveof后从节点只保存主节点的地址信息便直接返回了,这时建立复制流程还没有开始

      2)从节点(slave)内部通过每秒运行的定时任务维护复制相关逻辑,当定时任务发现存在新的主节点后,会尝试与该节点建立网络连接,从节点建立一个socket 套接字,如果从节点无法建立连接,定时任务会无限重试直到连接成功或者执行slaveof no one取消复制

      3)发送ping命令。

        连接建立成功后从节点发送ping请求进行首次通信,ping请求主要目的如下:

      • 检测主从之间网络套接字是否可用
      • 检测主节点当前是否可接受处理命令

        如果发送ping命令后,从节点没有收到主节点的pong回复或者超时,比如网络超时或者主节点正在阻塞无法响应命令,从节点会断开复制连接,下次定时任务会发起重试

      4)权限验证。如果主节点设置了requirepass参数,则需要密码验证,从节点必须配置masterauth参数保证与主节点相同密码才能通过验证;如果验证失败复制将终止,从节点重新发起复制流程。

      5)同步数据集。主从复制连接正常通信后,对于首次建立复制的场景,主节点会把持有的数据全部发送给从节点,这部分操作是耗时最长的步骤

      6)命令持续复制,当主节点把当前的数据同步给从节点后,便完成了复制的建立流程。接下来主节点会持续地把写命令发送个从节点,保证主从数据一致性。      

      总结

      1)保存主节点信息-->2)主从建立socket连接--->3)发送ping命令--->4)权限验证--->5)同步数据集--->6)命令持续复制  

    2.数据同步

      Redis在2.8以及以上的版本使用的是psync命令完成主从数据同步,同步过程分为:全量复制和部分复制

    • 全量复制:一般用于初次复制场景,Redis早期支持的复制功能只有全量复制,它会把主节点全部数据一次性发送给从节点,当数据量较大时,会对从节点和网络造成很大的开销。
    • 部分复制:用于处理在主从复制中因网络闪断等原因造成的数据丢失场景,当从节点再次连上主节点后,如果条件允许,主节点会补发丢失数据给从节点。因为补发的数据远远小于全量数据,可以有效避免全量复制的过高开销。

      psync命令运行需要以下组件支持

    • 主从节点各自复制偏移量
    • 主节点复制积压缓冲区
    • 主节点运行id

      2.1 复制偏移量

    • 参与复制的主从节点都会维护自身复制偏移量。主节点在处理完写入命令后,会把命令的字节长度做累加记录,统计信息在info replication的master_repl_offset指标中。
    • 从节点(slave)每秒钟上报自身的复制偏移量给主节点,因此主节点也会保存从节点的复制偏移量
    127.0.0.1:6379> info replication
    # Replication
    role:master
    connected_slaves:1
    slave0:ip=127.0.0.1,port=6380,state=online,offset=24766,lag=0   ##这里是从节点的偏移量
    master_failover_state:no-failover
    master_replid:7b0e995ff19d40cdc37247fe4e1700509f87801e
    master_replid2:0000000000000000000000000000000000000000
    master_repl_offset:24766                                        ##这里是主节点的偏移量
    • 从节点在接受到主节点发送的命令后,也会累加记录自身的偏移量。统计信息在info replication中的slave_repl_offset指标中
    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:6
    master_sync_in_progress:0
    slave_read_repl_offset:25200
    slave_repl_offset:25200   ##从节点的偏移量
    slave_priority:100
    slave_read_only:1
    replica_announced:1
    connected_slaves:0
    master_failover_state:no-failover
    master_replid:7b0e995ff19d40cdc37247fe4e1700509f87801e
    master_replid2:0000000000000000000000000000000000000000
    master_repl_offset:25200
    second_repl_offset:-1
    repl_backlog_active:1
    repl_backlog_size:1048576
    repl_backlog_first_byte_offset:1
    repl_backlog_histlen:25200

      2.2.复制积压缓冲区

      复制积压缓冲区是保存在主节点上的一个固定长度的队列,默认大小为1MB,当主节点有连接的从节点(slave)时被创建,这时主节点(master)响应写命令时,不但会把命令发送给从节点,还会写入复制积压缓冲区中。

      由于缓冲区本质上是先进先出的定长队列,所以能实现保存最近已复制数据的功能,用于部分复制和复制命令丢失的数据补救,复制缓冲区相关统计信息保存在主节点的info replication中:  

    role:master   ##这里是主节点
    repl_backlog_active:1     ##开启复制缓冲区
    repl_backlog_size:1048576     ##缓冲区最大长度
    repl_backlog_first_byte_offset:1     ##起始偏移量,计算当前缓冲区可用范围
    repl_backlog_histlen:25242      ##已保存数据的有效长度

      根据统计指标,可算出复制积压缓冲区内的可用偏移量范围:[repl_backlog_first_byte_offset,repl_backlog_first_byte_offset+repl_backlog_histlen]

      2.3 主节点运行id

      每个Redis节点启动后都会动态分配一个40位的十六进制字符串作为运行id,运行id的主要作用是用来唯一识别Redis节点,比如从节点保存主节点的运行id识别自己正在复制的是那个主节点。如果只使用ip+port的方式识别主节点,那么主节点重启变更了整体数据集(如替换RDB/AOF)文件,从节点再基于偏移量复制数据将是不安全的,因此当当运行id变化后从节点将做全量复制。可以运行info server 命令查看当前节点运行的id

    127.0.0.1:6379> info server
    # Server
    redis_version:6.2.6
    redis_git_sha1:00000000
    redis_git_dirty:0
    redis_build_id:dbb063e6f0357f98
    redis_mode:standalone
    os:Linux 3.10.0-862.el7.x86_64 x86_64
    arch_bits:64
    multiplexing_api:epoll
    atomicvar_api:atomic-builtin
    gcc_version:4.8.5
    process_id:1998
    process_supervised:no
    run_id:3385736efb4c28615a6a4a38a301210fbbdf0e1c   ##运行的id
    tcp_port:6379
    server_time_usec:1647114012450275
    uptime_in_seconds:21871
    uptime_in_days:0
    hz:10
    configured_hz:10
    lru_clock:2946844
    executable:/data/6379/redis-server
    config_file:/data/6379/redis.conf
    io_threads_active:0

      这里需要注意的是redis关闭在启动后,运行id会随之改变,可以通过命令: redis-cli -p 端口号 info server |grep run_id 进行查看

      如何在不改变运行id的情况下重启呢?

      当需要调优一些内存相关配置,例如hash-max-ziplist-value等,这些配置需要redis重新加载才能优化已存在的数据,这时可以用debug reload命令重新加载RDB并保持运行的id发生不变,从而避免不必要的全量复制。

    [root@redis 6380]# redis-cli  -p 6380 debug reload         ##注意这里的debug reload使用
    OK

    debug reload 命令会阻塞当前redis节点主线程,阻塞期间会生成本地RDB快照并清空数据之后再加载RDB文件,因此对于大数据量的主节点和无法容忍阻塞的应用场景,谨慎使用。1

     3.心跳

       主从节点在建立复制后,它们之间维护着长连接并彼此发送心跳命令:

      1)主从节点彼此都有心跳检测机制,各自模拟成对方的客户端进行通信,通过client list 命令查看复制相关客户端信息,主节点的连接状态为flags=M,从节点连接状态为Flags-S

      2)  主节点默认每个10秒对从节点发送ping命令,判断从节点的存活性和连接状态。可通过参数repl-ping-slave-perios控制发送频率。

      3)从节点在主线程中每隔1s发送replconf ack {offset}命令,给主节点上报自身当前的复制偏移量。replconf命令主要作用如下:

    • 实时检测主从节点网络状态
    • 上报自身复制偏移量,检查复制数据是否丢失,如果从节点数据丢失,再从主节点的复制缓冲区中拉取丢失数据
    • 实现保证从节点的数量和延迟性功能,通过min-slave-to-write,min-slaves-max-lag参数配置定义。

      主节点根据replconf命令判断从节点超时时间,体现在info replication统计中的lag信息中,lag表示与从节点最后一次通信延迟的秒数,正常延迟应该在0和1之间,如果超过repl-timeout配置的值(默认60秒),则判定从节点下线并断开复制客户端连接,即使主节点判定从节点下线后,如果从节点重新恢复,心跳检测会继续进行。

    4.异步复制

      主节点不但复制数据读写,还负责把写命令同步给从节点,写命令的发送过程是异步完成,也就是说主节点自身处理完写命令后直接返回给客户端,并不等待从节点复制完成

      由于主从复制过程是异步的,就会造成从节点的数据相对主节点存在延迟。具体延迟多少字节,这里可以在主节点执行info replicatioin命令查看相关指标获得。如下: 

    slave0:ip=127.0.0.1,port=6380,state=online,offset=938,lag=1
    master_repl_offset:938

      在统计信息中可以看到从节点slave0信息,分别记录了从节点的ip和port,从节点的状态,offset表示当前从节点的复制偏移量,master_repl_offset表示当前主节点的复制偏移量,两者的差值就是当前从节点复制延迟量,Redis的复制速度取决于主从之间网络环境,repl_disable_tcp_nodelay,命令处理速度等,正常情况下,延迟在1秒以内。

      

    RDB文件状态监控

      其中跟RDB文件状态监控相关的参数:

    • rdb_changes_since_last_save:表明上次RDB保存以后改变的key次数
    • rdb_bgsave_in_progress:表示当前是否进行bgsave操作。是为1
    • rdb_last_save_time :上次保存RDB文件的时间戳
    • rdb_last_bgsave_time_sec:上次保存的耗时
    • rdb_last_bgsave_status:上次保存的状态
    • rdb_current_bgsave_time_sec:目前保存RDB文件已花费的时间

    AOF文件状态监控

      其中跟AOF文件状态监控相关的参数

    • aof_enable  aof文件是否启用
    • aof_rewrite_in_progress   表示当前是否在进行写入aof文件操作
    • aof_rewrite_scheduled
    • aof_last_rewrite_time_sec 上次写入的时间戳
    • aof_current_rewrite_time_sec : -1
    • aof_last_bgrewrite_status:ok 上次重写状态
    • aof_last_write_status:ok   上次写入状态 

      参数:rdb_last_bgsave_time_sec:0  注意一下这个参数,这个值表示上次bgsave命令执行的时间,在磁盘io定量的情况下,redis占用的内存越大,这个值也就越大。通常该参数的时间取决于两个因素:

      1.Redis占用的内存大小

      2.磁盘的写入速度

     参数:rdb_last_bgsave_time_sec:85 这个标识表示我们上次保存dump RDB文件的时间。这个耗时受限于上面提到的两个因素。

       当redis处于rdb_bgsave_in_progress状态时,通过vmstat命令查看性能,得到wa值偏高,也就是说cpu在等待io的请求完成,因此可以看到bgsave对于IO的性能影响比较大。

     那么该如何解决这个问题呢?

     通过的设计思路就是利用replication机制来解决:即master不开启RDB和AOF日志,来保证master的读写性能。而slave则开启rdb和aof来进行持久化,保证数据的持久性。

    灾难恢复

      灾难恢复是指当我们的master挂掉了之后,这时我们需要先做的步骤如下:

      1.首先停掉从库的复制关系,slaveof no one

      2.重试重启主库,看看数据有没有丢失,如果有丢失的话,需要把从库的数据文件拷贝到主库中,然后再启动主库

      3.当主库启动完毕之后,看看主从数据是否一致,如果是一致的话,那么我们就可以在去从库中开启对主库的复制:slaveof  host:port

          

          

      

        

      

      

              

  • 相关阅读:
    lcn 分布式事务协调者集群原理
    springboot 监控 Actuator
    springboot 配置文件说明
    docker 安装jenkins
    docker 搭建maven 私服
    docker 安装 gitlab
    docker 安装软件
    docker 部署 java 项目
    mybatis 中between and用法
    vue-router history 模式 iis 配置
  • 原文地址:https://www.cnblogs.com/zmc60/p/16041068.html
Copyright © 2020-2023  润新知