zoukankan      html  css  js  c++  java
  • Redis从出门到高可用--Redis复制原理与优化

    Redis从出门到高可用–Redis复制原理与优化

    单机有什么问题?
    1、单机故障;
    2、单机容量有瓶颈
    3、单机有QPS瓶颈
    
    主从复制:主机数据更新后根据配置和策略,自动同步到备机的master/slaver机制,Master以写为主,Slave以读为主。
    
    1、一个master可以有多个slave;
    2、一个slaver只能有一个master;
    3、数据流向是单向的,master到slave;
    
    主从复制两种实现方式:
    1、slaveof命令
    
            取消复制:slavof no one
    2、配置
        slaveof ip port
        slave-read-only yes  :实现读写分离
    
    
        两种方式比较:
    
        方式                    slaveof             配置
        优点                   无需配置           统一配置
        缺点                   不便于管理          需要重启
    
    
    
    实验演示:
    修改配置文件:端口分别为6379(master),6380(slave)
    分别启动两个redis实例:
    
    1
    2
    3
    4
    6379.conf

    [root@localhost config]# redis-server redis6279.conf
    [root@localhost config]# redis-cli
    1
    2
    3
    4
    6380.conf

    [root@localhost config]# redis-server redis6380.conf
    [root@localhost config]# redis-cli -p 6380
    设置6380为6379的slave:
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    127.0.0.1:6380> slaveof 127.0.0.1 6379
    OK
    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:5
    master_sync_in_progress:0
    slave_repl_offset:29
    slave_priority:100
    slave_read_only:1
    connected_slaves:0
    master_repl_offset:0
    repl_backlog_active:0
    repl_backlog_size:1048576
    repl_backlog_first_byte_offset:0
    repl_backlog_histlen:0
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    127.0.0.1:6379> info replication
    # Replication
    role:master
    connected_slaves:1
    slave0:ip=127.0.0.1,port=6380,state=online,offset=43,lag=1
    master_repl_offset:43
    repl_backlog_active:1
    repl_backlog_size:1048576
    repl_backlog_first_byte_offset:2
    repl_backlog_histlen:42
    在6379上执行set操作:
    
    1
    2
    3
    4
    127.0.0.1:6379> set k1 1 
    OK
    127.0.0.1:6379> set k2 2
    OK
    在6380上执行get操作:
    
    1
    2
    127.0.0.1:6380> get k1
    "1"

    二、复制的原理

    redis全量复制的原理是,首先将master本身的RDB文件同步给slave,而在同步期间,master写入的命令也会记录下来(master内部
    有一个复制缓冲区,会记录同步时master新增的写入),当slave将RDB加载完后,会通过偏移量的对比将这期间master写入的值同步给slave。
    

    三、全量复制和部分复制

    在介绍全量复制和部分复制和之前,先介run_id和偏移量offset
    
    run_id:
    
    1
    2
    3
    4
    [root@localhost config]# redis-cli -p 6379 info server | grep run
    run_id:9e4f78c64e71ec4201aa5bda334a10f8ccde2aaa
    [root@localhost config]# redis-cli -p 6380 info server | grep run
    run_id:c38b9cc14a2c050dd047ae395d23735f72f9105a
    偏移量offset:
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    slave0:ip=127.0.0.1,port=6380,state=online,offset=1424,lag=1
    master_repl_offset:1424
    repl_backlog_active:1
    repl_backlog_size:1048576
    repl_backlog_first_byte_offset:2
    repl_backlog_histlen:1423
    [root@localhost config]# redis-cli -p 6379 info replication
    # Replication
    role:master
    connected_slaves:1
    slave0:ip=127.0.0.1,port=6380,state=online,offset=1438,lag=0
    master_repl_offset:1438
    repl_backlog_active:1
    repl_backlog_size:1048576
    repl_backlog_first_byte_offset:2
    repl_backlog_histlen:1437
    [root@localhost config]# redis-cli -p 6379 set k3 3
    OK
    [root@localhost config]# redis-cli -p 6379 info replication
    # Replication
    role:master
    connected_slaves:1
    slave0:ip=127.0.0.1,port=6380,state=online,offset=1480,lag=1
    master_repl_offset:1480
    repl_backlog_active:1
    repl_backlog_size:1048576
    repl_backlog_first_byte_offset:2
    repl_backlog_histlen:1479
    [root@localhost config]#
    复制过程:
    
    
    全量复制:
    

    image

    全量复制要求 大专栏  Redis从出门到高可用--Redis复制原理与优化将master的数据同步到slave,同时也要将master新增的数据同步到slave。
    1、psync ? 1:第一个参数是runId,第二个参数偏移量,由于第一次同步,slave不知道master的runId和自己的偏移量,所有以?和-1代替,告诉master节点是第一次同步;
    2、master接收到1的指令后,知道slave需要进行全量复制,所以将自己的runId和偏移量offset发送给slave
    3、save masterInfo : salve保存master的基本信息;
    4、master执行bgsave 异步生成RDB文件;
    
    为将将全量数据复制到slave,并且在生成RDB到RDDB文件传输完成过程中新增的数据也传输,master开启子进程来将dataset写入rdb文件(步骤4),同时将子进程完成之
    前接收到的写命令缓存到复制缓冲区,即send buffer。
    5、master 执行send RDB将master生成的RDB文件传给slave;
    6、将复制缓冲区buffer中的增量数据发给slave;
    7、清除老数据(slave挂一个新的master时会清除老数据);
    8、slave加载RDB文件和buffer数据;
    
    
    全量复制开销:
    1、master执行bgsave命令的开销;
    2、RDB文件网络传输时间;
    3、slave节点清除数据的时间;
    4、从节点加载RED的时间;
    5、可能的AOF重写时间(在slave加载RED文件时);
    
    
    增量复制(部分复制):
    值得注意的是,当slave跟master的连接断开时,slave可以自动的重新连接master,在redis2.8版本之前,每当slave进程挂掉重新连
    接master的时候都会开始新的一轮全量复制。如果master同时接收到多个slave的同步请求,则master只需要备份一次RDB文件。
    上面提到,slave和master断开了、当slave和master重新连接上之后需要全量复制,这个策略是很不友好的,从Redis2.8开始,Redis提供了增量复制的机制:
    
    master除了备份RDB文件之外还会维护者一个环形队列(复制缓冲区,默认大小1M),以及环形队列的写索引和slave同步的全局offset,环形队列用于存储最新
    的操作数据,当slave和maste断开重连之后,会把slave维护的offset,也就是上一次同步到哪里的这个值告诉master,同时会告诉master上次和
    当前slave连接的master的runid,满足下面两个条件,Redis不会全量复制:
    1、slave传递的run id和master的run id一致;
    2、master在环形队列上可以找到对呀offset的值。
    

    image

    1、在slave复制master过程中连接断开;
    2、主服务器端为复制流维护一个内存缓冲区(in-memory backlog)。主从服务器都维护一个复制偏移量(replication offset)和master run id 
    3、slave重写连接
    4、slave发送自己的runId和offset;
    5、假如主从服务器的两个master run id相同,并且指定的偏移量在内存缓冲,复制就会从上次中断的点开始继续。
    

    区中还有效

    四、故障处理

    主从结构–故障转移

    slave宕机
    当其中某一个slave发生故障,此时可以将故障机的客户端重新连接到其他的slave上;
    
    master宕机
    当master发生故障,首先。master客户端断开与master服务的连接,即执行slaveof no one,然后重新选一个master,其他客户端重新连接到新的master;
    
    但是在实际的生成中,每一秒都是很重要,所以重新连接肯定不是好的选择,即,主从复制其实并没有真正的解决redis高可用问题。
    

    五、开发运维常见问题

    1、读写分离
    读流量分摊到从节点
    
    问题:
    复制数据延迟:由于对master的写的数据复制到slave需要时间,或者slave发生阻塞;
    读写分离时,master会异步的将数据复制到slave,如果这是slave发生阻塞,则会延迟master数据的写命令,造成数据不一致的情况
    
    
    解决方法:可以对slave的偏移量值进行监控,如果发现某台slave的偏移量有问题,则将数据读取操作切换到master,但本身这个监控开销比较高,所以关于这个问题,大部分的情况是可以直接使用而不去考虑的
    
    
    读到过期数据:我们知道redis在删除过期key的时候,是有两种策略,第一种是懒惰型策略,即只有当redis操作这个key的时候,发现这个key过期,就会把这个key删除
    。第二种是定期采样一些key进行删除。
    针对上面说的两种过期策略,会有个问题,即如果我们过期key的数量非常多,而采样速度根本比不上过期key的生成速度时会造成
    很多过期数据没有删除,但在redis里master和slave达成一种协议,slave是不能处理数据的(即不能删除数据)而我们的客户端没
    有及时读到到过期数据,并将master将key删除的命令同步给slave,就会导致slave读到过期的数据(这个问题已经在redis3.2版本
    中解决)
    
    从节点故障,如何将从节点进行迁移;
    
    2、主从配置不一致
    这个问题一般很少见,但如果有,就会发生很多诡异的问题
    
    1、例如maxmemory不一致,这个会导致数据的丢失;
    原因:例如master配置4G,slave配置2G,这个时候主从复制可以成功,但,如果在进行某一次全量复制的时候,slave拿到master的
    RDB加载数据时发现自身的2G内存不够用,这时就会触发slave的maxmemory策略,将数据进行淘汰。更可怕的是,在高可用的集群环
    境下,如果我们将这台slave升级成master的时候,就会发现数据已经丢失了
    
    2、数据结构优化参数不一致(例如hash-max-ziplist-entries):这个就会导致内存不一致
    原因:例如在master上对这个参数进行了优化,而在slave没有配置,就会造成主从节点内存不一致的诡异问题。
    
    3、规避全量复制
    1、第一次全量复制:
    当我们某一台slave第一次去挂到master上时,是不可避免要进行一次全量复制的,那么,我们如何去想办法降低开销呢?
    方案1:小主节点,例如我们把redis分成2G一个节点,这样一来,会加速RDB的生成和同步,同时还可以降低我们fork子进程的开销(
    master会fork一个子进程来生成同步需要的RDB文件,而fork是要拷贝内存快的,如果主节点内存太大,fork的开销就大)。
    
    方案2:既然第一次不可以避免,那我们可以选在集群低峰的时间(凌晨)进行slave的挂载。
    
    2.节点RunID不匹配
    例如我们主节点重启(RunID发生变化),对于slave来说,它会保存之前master节点的RunID,如果它发现了此时master的RunID发生
    变化,那它会认为这是master过来的数据可能是不安全的,就会采取一次全量复制
    解决办法:对于这类问题,我们只有是做一些故障转移的手段,例如master发生故障宕掉,我们选举一台slave晋升为master(哨兵或集群)
    
    3.复制积压缓冲区不足
    master生成RDB同步到slave,slave加载RDB这段时间里,master的所有写命令都会保存到一个复制缓冲队列里(如果主从直接网络抖
    动,进行部分复制也是走这个逻辑),待slave加载完RDB后,拿offset的值到这个队列里判断,如果在这个队列中,则把这个队列从
    offset到末尾全部同步过来,这个队列的默认值为1M。而如果发现offset不在这个队列,就会产生全量复制。
    解决办法:增大复制缓冲区的配置 rel_backlog_size 默认1M,我们可以设置大一些,从而来加大我们offset的命中率。
    这个值,我们可以假设,一般我们网络故障时间一般是分钟级别,那我们可以根据我们当前的QPS来算一下每分钟可以写入多少字节,再乘以我们可能发生故障的分钟就可以得到我们这个理想的值。
    
    4、规避复制风暴
    什么是复制风暴?举例:我们master重启,其master下的所有slave检测到RunID发生变化,导致所有从节点向主节点做全量复制。尽
    管redis对这个问题做了优化,即只生成一份RDB文件,但需要多次传输,仍然开销很大。
    
    1.单主节点复制风暴:主节点重启,多从节点全量复制
    解决:更换复制拓扑如下图:
    

    image

    (1).我们将原来master与slave中间加一个或多个slave,再在slave上加若干个slave,这样可以分担所有slave对master复制的压力。
    (这种架构还是有问题:读写分离的时候,slave1也发生了故障,怎么去处理?)
    (2).如果只是实现高可用,而不做读写分离,那当master宕机,直接晋升一台slave即可。
    
    
    
    2.单机器复制风暴:机器宕机后的大量全量复制,如下图:
    

    image

    当machine-A这个机器宕机重启,会导致该机器所有master下的所有slave同时产生复制。(灾难)
    (1).主节点分散多机器(将master分散到不同机器上部署)
    
    (2).还有我们可以采用高可用手段(slave晋升master)就不会有类似问题了。
    
  • 相关阅读:
    JavaScript 核心参考 Arguments 对象
    readonly 和 disable的区别
    Asp.net 页面导航的几种方法与比较(转)
    CSS float clear 使用
    PHP时区列表
    Jquery 父窗口中移进移出鼠标到Iframe: 移进显示更多内容, 移出隐藏部分内容
    Mysql 查看进程SQL
    好用的弹出对话框 artDialog
    In Cache 算法
    live 绑定事件会触发多次
  • 原文地址:https://www.cnblogs.com/lijianming180/p/12099817.html
Copyright © 2011-2022 走看看