redis主从复制数据延迟解决方案

有些话、适合烂在心里 提交于 2020-08-05 18:13:56

在 redis 主从复制模式下可能会出现 slave 延迟导致读写不一致的问题。 解决办法有2种

1. 修改从几点参数配置

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

  1. 如果slave-serve-stale-data设置为yes(默认设置),从库会继续响应客户端的请求。

  2. 如果slave-serve-stale-data设置为no,除去INFO和SLAVOF命令之外的任何请求都会返回一个错误”SYNC with master in progress”。

2. 编写外部监控程序

将主从模式更换为哨兵模式则无需自己去做监控

对于无法容忍大量延迟场景,可以编写外部监控程序监听主从节点的复制偏移量,当延迟较大时触发报警或者通知客户端避免读取延迟过高的从节点。

编写监控程序,然后定时执行

<?php
/**
 * [监控 redis 主从复制偏移量:当监控到延迟高的节点时,移除延迟高的从节点, 即动态修改读写分离配置信息。(可以添加触发报警机制)]
 *      [在做主从复制时推荐使用 redis 的哨兵模式,则无需自己去监控,哨兵模式能自己监控并切换主从]
 *
 * @Author  leeprince:2020-05-05 10:29
 */

define('IS_DEBUG', false);
define('MAX_OFFSET', 10);
$redis = new Redis();
$redis->connect("127.0.0.1", 63790);
$redis->auth("leeprince");

$info         = $redis->info('replication');
$slaveNum     = $info['connected_slaves'];
$masterOffest = $info['master_repl_offset'];

echo "+++++++++++++++++++++++定时开始+++++++++++++++++++++++\r\n";

$invalidSlave = []; // 要移除的从节点
for ($i = 0; $i < $slaveNum; $i++) {
    $slaveKey    = "slave{$i}";
    $slaveInfo   = $info[$slaveKey];
    $slaveInfo   = explode(',', $slaveInfo);

    $slaveHost   = explode('=', $slaveInfo[0])[1];
    $slavePort   = explode('=', $slaveInfo[1])[1];
    $slaveState  = explode('=', $slaveInfo[2])[1];
    $slaveOffset = explode('=', $slaveInfo[3])[1];

    $offset = $masterOffest - $slaveOffset;
    if ($offset > MAX_OFFSET || $slaveState != 'online') {
        $readHostMap = include_once "./hostMap.php";
        $slaveString = "tcp://{$slaveHost}:{$slavePort}";
        $invalidSlave[] = $readHostMap[$slaveString];
        var_dump("当前从节点为高延迟--{$slaveString}");
    }
}

if (empty($invalidSlave)) {
    if (IS_DEBUG) {
        echo "========================================\r\n";
        var_dump($info);
        echo "========================================\r\n";
    }
    var_dump('不存在需要移除的从节点');
    exit(0);
}

// redis 动态配置文件
$confPath = './config.php';
include $confPath;


if (IS_DEBUG) {
    echo "========================================\r\n";
    var_dump($info);
    var_dump($replication);
    echo "========================================\r\n";
}

$isHaveChange = false; // 是否需要修改配置。考虑上一次可能已经移除了该从节点
foreach ($replication as $key => &$value) {
    if (in_array($value, $invalidSlave)) {
        $isHaveChange = true;
        var_dump("需要移除的从节点存在当前配置中--{$value}");
        unset($replication[$key]);
    }
}

if ($isHaveChange) {
    $content = "<?php \n\$replication = ".var_export($replication, true).";";
    file_put_contents($confPath, $content);
    var_dump('已修改配置文件--', $content);
} else {
    var_dump('无需修改配置文件');
}
exit(0);

完整的代码:包含 linux 定时器与 swoole 毫秒级定时器版本
https://github.com/leeprince/docker/tree/master/redis/monitor

在从节点种模拟网络延迟步骤

$ apt update

$ apt install -y iproute2

$ ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
2: tunl0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN group default qlen 1000
    link/ipip 0.0.0.0 brd 0.0.0.0
3: ip6tnl0@NONE: <NOARP> mtu 1452 qdisc noop state DOWN group default qlen 1000
    link/tunnel6 :: brd ::
15: eth0@if16: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc netem state UP group default qlen 1000
    link/ether 02:42:ac:12:00:04 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 172.18.0.4/16 brd 172.18.255.255 scope global eth0
       valid_lft forever preferred_lft forever

# 设置模拟网络延迟 5 秒。 删除设置:tc qdisc del dev eth0 root netem delay 5000ms
$ tc qdisc add dev eth0 root netem delay 5000ms

运行结果:

attachments-2020-08-3n3EIqe25f2a69871f5ef.png
 

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!