Redis主从复制进阶常见问题及解决方案

redis主从复制进阶常见问题解决如:读写分离、数据延迟、主从配置不一致、规避全量复制、规避复制风暴等

1、读写分离
2、数据延迟
3、主从配置不一致
4、规避全量复制
5、规避复制风暴

1、读写分离读流量分摊到从节点。

这是个非常好的特性,如果一个业务只需要读数据,那么我们只需要连一台 slave 从机读数据。

image.png

虽然读写有优势,能够让读这部分分配给各个 slave 从机,如果不够,直接加 slave 机器就好了。但是也会出现以下问题。

2.复制数据延迟。

可能会出现slave延迟导致读写不一致等问题,当然你也可以使用监控偏移量offset,如果 offset 超出范围就切换到master上,逻辑切换,而具体延迟少,可以通过info replication的offset指标进行排查。对于无法容忍大量延迟场景,可以编写外部监控程序监听主从节点的复制偏移量,当延迟较大时触发报警或者通知客户端避免读取延迟过高的从节点

//监控从服务器复制延迟问题
//用C扩展的redis才行
//include_once "vendor/autoload.php";   插件不支持info
//The command 'INFO' is not allowed in replication
$redis = new Redis(); // Predis\Client($sentinels,$options);
$redis->connect("192.168.1.5",6379);
$redis->auth("123456");
swoole_timer_tick(1000, function () use ($redis){
    $replication = $redis->info("replication");
    $slaveCount = $replication["connected_slaves"];
    $ipArray=[];
    for ($i=0; $i<$slaveCount; $i++){
        //主服务的offset
        $masterOffset = $replication["master_repl_offset"];
        $slaveStr = explode(",",$replication["slave".$i]);
        //offset
        $slaveOffset = (int)explode("=",$slaveStr[3])[1];
        //从机ip地址
        $slaveIp = explode("=", $slaveStr[0])[1];
        //从机端口
        $slavePort = explode("=", $slaveStr[1])[1];
        //拼接主从复制下redis连接地址在配制文件中
        //['tcp://192.168.1.5?alias=master', 'tcp://192.168.1.6?alias=slave']
        if(($masterOffset - $slaveOffset) < 10){
            $ipArray[] = 'tcp://'.$slaveIp.'?alias=slave-'.$i;
        }
    }
    array_unshift($ipArray,'tcp://192.168.1.5?alias=master');
    file_put_contents("config.php","<?php \n\$sentinels=".var_export($ipArray,true).";");
   // var_dump($replication['master_repl_offset']);
});

同时从节点的slave-serve-stale-data参数也与此有关,它控制这种情况下从节点的表现当从库同主机失去连接或者复制正在进行,从机库有两种运行方式:

1) 如果slave-serve-stale-data设置为yes(默认设置),从库会继续响应客户端的请求。 
2) 如果slave-serve-stale-data设置为no,除去INFO和SLAVOF命令之外的任何请求都会返回一个错误”SYNC with master in progress”。

接下下用工具模拟网络延迟:

例子:模拟网络延迟

docker run --privileged -itd -v /usr/docker/test/slave02:/usrsrc/redis --name redis-slave2 --net redis-network -p 6381:6379 --ip192.168.1.8 redis

--privileged Docker容器将拥有访问主机所有设备的权限通过linux下的控流工具,模拟网络延迟,用代码模拟下,因为对于网络的操作属于特殊权限所以需要添加--privileged参数

centos:  yum install iproute
alpine:  apk add install iproute2

进入到容器之后配置延迟5s

tc  qdisc  add   dev  eth0  root  netem  delay 5000ms
tc  qdisc  del  dev  eth0  root netem delay 5000ms

一台主服务,3台从服务,结果offset>10的slave结点服务被抛弃

复制数据延迟监控

3、异步复制导致数据丢失

因为master->slave的复制是异步,所以可能有部分还没来得及复制到slave就宕机了,此时这些部分数据就丢失了。

怎么解决?(请记住只能降低到可控范围,没办法做到100%不丢失)

#最少有多少台slave机器才能写入
min-slaves-to-write 1  
#从节点最大延迟时间,延迟小于min-slaves-max-lag秒的slave才认为是健康的slave
min-slaves-max-lag  10

要求至少有1个slave,数据复制和同步的延迟不能超过10秒

如果说一旦所有的slave,数据复制和同步的延迟都超过了10秒钟,那么这个时候,master就不会再接收任何请求了

有了min-slaves-max-lag这个配置,就可以确保说,一旦slave复制数据和ack延时太长,就认为可能master宕机后损失的数据太多了,那么就拒绝写请求,这样可以把master宕机时由于部分数据未同步到slave导致的数据丢失降低到可控范围内

如何选择,要不要读写分离?

没有最合适的方案,只有最合适的场景,读写分离需要业务可以容忍一定程度的数据不一致,适合读多写少的业务场景,读写分离,是为了什么,主要是因为要建立一主多从的架构,才能横向任意扩展slave node去支撑更大的读吞吐量。

4、从节点故障问题

对于从节点的故障问题,需要在客户端维护一个可用从节点可用列表,当从节点故障时,立刻切换到其他从节点或主节点,之后讲解redis Cluster 或哨兵时候可以解决这个问题

5、配置不一致

主机和从机不同,经常导致主机和从机的配置不同,并带来问题。

数据丢失:主机和从机有时候会发生配置不一致的情况,例如maxmemory不一致,如果主机配置maxmemory为8G,从机 slave 设置为4G,这个时候是可以用的,而且还不会报错。但是如果要做高可用,让从节点变成主节点的时候,就会发现数据已经丢失了,而且无法挽回。

6、规避全量复制

全量复制指的是当 slave 从机断掉并重启后,runid 产生变化而导致需要在 master 主机里拷贝全部数据。这种拷贝全部数据的过程非常耗资源。

全量复制是不可避免的,例如第一次的全量复制是不可避免的,这时我们需要选择小主节点,且maxmemory值不要过大,这样就会比较快。同时选择在低峰值的时候做全量复制。

造成全量复制的原因

1. 是主从机的运行runid不匹配。解释一下,主节点如果重启,runid将会发生变化。如果从节点监控到runid不是同一个,它就会认为你的节点不安全。当发生故障转移的时候,如果主节点发生故障,那么从机就会变成主节点。我们会在后面讲解哨兵和集群。
2. 复制缓冲区空间不足,比如默认值1M,可以部分复制。但如果缓存区不够大的话,首先需要网络中断,部分复制就无法满足。其次需要增大复制缓冲区配置(repl-backlog-size),对网络的缓冲增强。参考之前的说明。

怎么解决?

在一些场景下,可能希望对主节点进行重启,例如主节点内存碎片率过高,或者希望调整一些只能在启动时调整的参数。如果使用普通的手段重启主节点,会使得runid发生变化,可能导致不必要的全量复制。

为了解决这个问题,Redis提供了debug reload的重启方式:重启后,主节点的runid和offset都不受影响,避免了全量复制。

7、单机器的复制风暴   

1、当一个主机下面挂了很多个slave从机的时候,主机master挂了,这时master主机重启后,因为 runid 发生了变化,所有的slave从机都要做一次全量复制。这将引起单节点和单机器的复制风暴,开销会非常大。

解决:

可以采用树状结构降低多个从节点对主节点的消耗
从节点采用树状树非常有用,网络开销交给位于中间层的从节点,而不必消耗顶层的主节点。但是这种树状结构也带来了运维的复杂性,增加了手动和自动处理故障转移的难度

2、由于Redis的单线程架构,通常单台机器会部署多个Redis实例。当一台机器(machine)上同时部署多个主节点(master)时,如果每个master主机只有一台slave从机,那么当机器宕机以后,会产生大量全量复制。这种情况是非常危险的情况,带宽马上会被占用,会导致不可用。

解决:

1、应该把主节点尽量分散在多台机器上,避免在单台机器上部署过多的主节点。
2、当主节点所在机器故障后提供故障转移机制,避免机器恢复后进行密集的全量复制

主从配置参数参考 

###########从库##############   
#设置该数据库为其他数据库的从数据库   
slaveof <masterip> <masterport>  
 
#主从复制中,设置连接master服务器的密码(前提master启用了认证)   
masterauth <master-password>  

slave-serve-stale-data yes   
# 当从库同主库失去连接或者复制正在进行,从库有两种运行方式:   
# 1) 如果slave-serve-stale-data设置为yes(默认设置),从库会继续相应客户端的请求   
# 2) 如果slave-serve-stale-data设置为no,除了INFO和SLAVOF命令之外的任何请求都会返回一个错误"SYNC with master in progress"  

#当主库发生宕机时候,哨兵会选择优先级最高的一个称为主库,从库优先级配置默认100,数值越小优先级越高  
slave-priority 100  

#从节点是否只读;默认yes只读,为了保持数据一致性,应保持默认  
slave-read-only yes 

########主库配置##############  
#在slave和master同步后(发送psync/sync),后续的同步是否设置成TCP_NODELAY假如设置成yes,则redis会合并小的TCP包从而节省带宽,但会增加同步延迟(40ms),造成master与slave数据不一致假如设置成no,则redis master会立即发送同步数据,没有延迟  
#前者关注性能,后者关注一致性  
repl-disable-tcp-nodelay no  

#从库会按照一个时间间隔向主库发送PING命令来判断主服务器是否在线,默认是10秒  
repl-ping-slave-period 10  

#复制积压缓冲区大小设置  
repl-backlog-size 1mb  

#master没有slave一段时间会释放复制缓冲区的内存,repl-backlog-ttl用来设置该时间长度。单位为秒。  
repl-backlog-ttl 3600  

#redis提供了可以让master停止写入的方式,如果配置了min-slaves-to-write,健康的slave的个数小于N,mater就禁止写入。master最少得有多少个健康的slave存活才能执行写命令。这个配置虽然不能保证N个slave都一定能接收到master的写操作,但是能避免没有足够健康的slave的时候,master不能写入来避免数据丢失。设置为0是关闭该功能。  
min-slaves-to-write 3  
min-slaves-max-lag 10



猜您喜欢
    1条评论
    • tadalista vs cialis 回复

      Have you ever considered about including a little bit more than just your articles? I mean, what you say is valuable and everything. However imagine if you added some great graphics or video clips to give your posts more, "pop"! Your content is excellent but with images and videos, this website could undeniably be one of the greatest in its field. Amazing blog!