天天看点

Redis主从模式的实现

  前面说到了redis在单机的模式下是可以数据持久化的,但是不可以解决单点失败的问题,当单台redis服务器出现问题时,就可能会造成数据的丢失;想要解决这个问题的话我们可以使用Redis的主从模式这也是Redis集群最简单的实现方式,这篇文章我就来简单部署一个Redis主从架构,我准备了3台ubuntu1804的主机,IP地址分别为10.0.0.{100,101,102},主机名分别为redis-master,redis-slave1,redis-slave2。

1、安装Redis

  这里我就使用脚本来安装Redis了。

root@redis-master:~# vim install_redis.sh
#!/bin/bash

SRC_DIR=/usr/local/src
COLOR="echo -e \\033[01;31m"
END='\033[0m'
CPUS=`lscpu | awk '/^CPU\(s\)/{print $2}'`

URL='https://download.redis.io/releases/'
VERSION=redis-6.2.7
PASSWORD=wm521314
INSTALL_DIR=/apps/redis


install() {
    #下载依赖包
    apt -y install make gcc libjemalloc-dev || { ${COLOR}"安装软件包失败,请检查网络配置"${END}; exit; }
    
    #开始下载redis源码包并解压包
    cd ${SRC_DIR}
    wget ${URL}${VERSION}.tar.gz || { ${COLOR}"Redis源码下载失败"${END}; exit; }
    tar xf ${VERSION}.tar.gz
    
    #解压后的源码包里面自带Makefile文件,直接编译安装即可
    cd ${VERSION}
    make -j ${CPUS} PREFIX=${INSTALL_DIR} install && ${COLOR}"Redis编译安装完成"${END} || { ${COLOR}"Redis编译安装失败"${END}; exit; }
    
    #创建软链接
    ln -s ${INSTALL_DIR}/bin/redis-* /usr/bin/
    
    #创建后期需要的目录
    mkdir -p ${INSTALL_DIR}/{etc,log,data,run}
    
    #这准备配置文件并修改默认的配置
    cp redis.conf ${INSTALL_DIR}/etc/
    sed -i -e 's/bind 127.0.0.1.*/bind 0.0.0.0/' -e "/# requirepass/a requirepass ${PASSWORD}" -e "/^dir .*/c dir ${INSTALL_DIR}/data/" -e "/logfile .*/c logfile ${INSTALL_DIR}/log/redis-6379.log" -e "/^pidfile .*/c pidfile ${INSTALL_DIR}/run/redis_6379.pid" ${INSTALL_DIR}/etc/redis.conf

    #判断是否有redis用户,没有就创建一个
    if id redis &> /dev/null ;then
        ${COLOR}"Redis用户已经存在"${END}
    else
        useradd -r -s /sbin/nologin redis
        ${COLOR}"Redis用户创建成功"${END}
    fi

    #修改目录的权限
    chown -R redis.redis ${INSTALL_DIR}
    
    #修改内核参数
    cat >> /etc/sysctl.conf <<-EOF
net.core.somaxconn = 20480
vm.overcommit_memory = 1
EOF

    #准备service文件
    cat > /lib/systemd/system/redis.service <<-EOF
[Unit]
Description=Redis persistent key-value database
After=network.target

[Service]
ExecStart=${INSTALL_DIR}/bin/redis-server ${INSTALL_DIR}/etc/redis.conf --supervised systemd
ExecStop=/bin/kill -s QUIT \$MAINPID
#Type=notify                                                                                                                                                                                                    
User=redis
Group=redis
RuntimeDirectory=redis
RuntimeDirectoryMode=0755

[Install]
WantedBy=multi-user.target
EOF
    
    #重新加载一下服务并设置redis开机自启动并立即启动
    systemctl daemon-reload
    systemctl enable --now redis &> /dev/null && ${COLOR}"Redis服务启动成功,Redis信息如下:"${END} || { ${COLOR}"Redis服务启动失败"${END};exit; }
    sleep 1
    redis-cli -a ${PASSWORD} INFO Server 2> /dev/null
}

install
root@redis-master:~# bash -n install_redis.sh
root@redis-master:~# bash install_redis.sh
           
Redis主从模式的实现

2、Redis主从复制

  Redis的主从模式是可以实现Redis的数据跨主机备份,在配置主从的时候,从节点是需要开启数据持久化并设置和主节点同样的连接密码。

Redis主从模式的实现

2.1、默认redis状态

  在默认的情况下,三台刚安装的redis主机都是单机模式的master角色。

Redis主从模式的实现
Redis主从模式的实现
Redis主从模式的实现

2.2、实现Redis主从复制

  实现Redis的主从复制是有两种方式的,一种你可以通过命令行来配置,这样配置的话是临时生效,命令行配置的话重启Redis服务就没有用了,但是同步过来的数据还是会保留的;另一种就是修改redis的配置文件来使其生效,这样的话即使重启redis服务主从的关系还在的。

2.2.1、命令行配置

2.2.1.1、准备测试的数据
Redis主从模式的实现
2.2.1.2、使用命令行启用主从
Redis主从模式的实现
Redis主从模式的实现
Redis主从模式的实现
2.2.1.3、在master节点查看主从状态

  这时回到主节点查看主从的状态时,这时会发现自己还是master,但是发现下面多了两个slave,可以看到两个slave的相关信息。

Redis主从模式的实现
2.2.1.4、查看相关日志信息
Redis主从模式的实现
Redis主从模式的实现
2.2.1.5、查看连接状态
Redis主从模式的实现
Redis主从模式的实现
Redis主从模式的实现

这时候你在master节点上写入数据时,两个slave节点是可以把数据同步过来的。

Redis主从模式的实现
Redis主从模式的实现
Redis主从模式的实现

这是在从节点测试一下是否可以写入数据,从下图可以看出是没有写入key的操作的,只能进行读的操作。

Redis主从模式的实现
2.2.1.6、取消主从同步

  我们是可以通过从节点执行replicaof no one命令即可取消主从复制,修改完后角色会变成master,并且之前同步的数据是不会丢的。

Redis主从模式的实现

  由于是通过命令行来实现的主从复制,当从节点重启Redis服务后就会失效了,这和使用命令行取消主从是一样的,不过之前的数据还是在的。

Redis主从模式的实现

2.2.2、修改配置文件

  我们在前面使用了命令行实现了主从复制,命令行配置是有缺陷的,当从节点的redis服务重启后就失效了;为了解决这个缺陷我们可以将命令行配置的内容加到配置文件中,在重启一下redis服务让其读取配置文件。

Redis主从模式的实现
Redis主从模式的实现

添加数据查看是否同步可以参考前面使用命令行配置那个的步骤是一样的,这里我就不演示了。

3、主从复制故障与恢复

3.1、从节点故障与恢复

  当从节点出现故障时,只需将Redis客户端指向其他的从节点就可以了,并不会对整体的架构的读操作进行太大的影响,即使所有的从节点出现故障,也可以直接访问主节点进行读的操作;不过一般从节点出现故障后,除了一些特殊情况一般都会尽快的修复好,从而减轻其他节点的工作负载。

Redis主从模式的实现

3.2、主节点故障与恢复

3.2.1、主节点故障

Redis主从模式的实现
Redis主从模式的实现

3.2.2、提升新的主节点

  当我们的主节点故障时,我们可以将一个从节点提升为新的主节点,在将另一个从节点指向到新的主节点,这里我就直接使用命令行修改配置了。

Redis主从模式的实现
Redis主从模式的实现

3.2.3、原主节点恢复正常

  当原来的主节点修复好了后,把Redis服务起来后会发现恢复到了单机的状态,并且只有之前的数据。

Redis主从模式的实现

  如果现在想要将原的主节点变成现有的主从架构的从节点,这样的话就可以将新的主节点(slave1)的数据同步过来了;但是想要保持之前的原节点不变的话,就需要将现在的主从架构中的节点都指向原节点,并且刚刚新增的key也就会丢失;这里我们可以保持原先的master节点为主节点为例,这里可以把slave2设置成原master节点的从节点,我们也是可以直接把现在新主节点(slave1)设置成原master节点的从节点,这样的话就形成了级联复制,这样的话slave可以不用修改配置,这样的话slave2是从slave1来同步数据,而slave1从master节点同步数据。

Redis主从模式的实现
Redis主从模式的实现

4、主从复制的优化

4.1、主从复制过程

  Redis主从复制可以分为全量同步和增量同步。

4.1.1、全量复制的过程

Redis主从模式的实现

  第一次都是需要主从同步是全量同步的,主从同步可以让从节点到主节点进行同步数据,而且从节点也可以有从节点,也就是前面演示的级联复制的架构;

  Redis的主从同步是非阻塞的,master节点收到从服务器的psync(在2.8版本之前是SYNC)命令,会fork一个子进程在后台执行bgsave命令,并将新写入的数据先写入到一个缓冲区中,bgsave执行完成之后,再将生成的RDB文件发送给slave节点,然后master节点再将缓冲区的内容以redis协议格式再全部发送给slave节点,slave节点先删除旧数据,slave节点将收到后的RDB文件载入自己的内存,再加载所有收到缓冲区的内容,从而这样一次完整的数据同步。

  Redis全量复制一般发生在Slave首次初始化阶段,这时Slave需要将Master上的所有数据都复制一份。

4.1.2、增量复制的过程

Redis主从模式的实现

  在全量同步之后再次需要同步时,从服务器只要发送当前的offset位置(等同于MySQL的binlog的位置)给主服务器,然后主服务器根据相应的位置将之后的数据(包括写在缓冲区的积压数据)发送给从服务器,再次将其保存到从节点内存即可。

4.1.3、主从同步完整过程

  1. 从服务器连接主服务器,发送PSYNC命令。
  2. 当主服务器接收到PSYNC命令后,开始执行BGSAVE命令生成RDB快照文件并使用缓冲区记录此后执行的所有写命令。
  3. 当主服务器BGSAVE执行完后,向所有从服务器发送RDB快照文件,并在发送期间继续记录被执行的写命令。
  4. 从服务器收到快照文件后丢弃所有旧数据,载入收到的快照至内存。
  5. 主服务器快照发送完毕后,开始向从服务器发送缓冲区中的写命令。
  6. 从服务器完成对快照的载入,开始接收命令请求,并执行来自主服务器缓冲区的写命令。
  7. 后期同步会先发送自己slave_repl_offset位置,只同步新增加的数据,不再全量同步。
Redis主从模式的实现

4.2、主从复制的主要事项

4.2.1、避免全量复制

  • 第一次的全量复制是没法避免的,后续的全量复制是可以利用小主节点(内存小),尽量在业务低峰时进行全量复制;
  • 在主节点重启后会发现运行的ID发生了变化,可能会触发全量复制,可以利用故障转移,例如哨兵或者集群的方式,而从节点重启的话是不会导致全量复制的;
  • 当复制积压缓冲区不足时,主节点生成的新数据大与缓冲区的大小,从节点恢复和主节点连接后,这样会导致全量复制,这个是可以修改repl-backlog-size的值来解决,将其值调大。

4.2.2、避免复制的风暴

  单主节点复制的风暴:当主节点重启后,多个从节点会同时从主节点复制数据,这样的话是会带来复制风暴,解决方式可以更换复制的架构,比如可以使用级联复制的架构。

Redis主从模式的实现

  单机器多实例的复制风暴:当服务器出现宕机时,后面有修复了,这样的话就会进行大量的全量复制,并引发复制风暴,解决的方法是主节点分散多机器。

Redis主从模式的实现

4.3、主从复制优化配置

repl-diskless-sync no # 是否使用无盘同步RDB文件,默认为no,no为不使用无盘,需要将RDB文件保存到磁盘后再发送给slave,yes为支持无盘,支持无盘就是RDB文件不需要保存至本地磁盘,而且直接通过socket文件发送给slave

repl-diskless-sync-delay 5 #diskless时复制的服务器等待的延迟时间

repl-ping-slave-period 10 #slave端向server端发送ping的时间间隔,默认为10秒

repl-timeout 60 #设置主从ping连接超时时间,超过此值无法连接,master_link_status显示为down,并记录错误日志

repl-disable-tcp-nodelay no #是否启用TCP_NODELAY,如设置成yes,则redis会合并小的TCP包从而节省带宽, 但会增加同步延迟(40ms),造成master与slave数据不一致,假如设置成no,则redis master会立即发送同步数据,没有延迟,yes关注网络性能,no关注redis服务中的数据一致性

repl-backlog-size 1mb #master的写入数据缓冲区,用于记录自上一次同步后到下一次同步过程中间的写入命令,计算公式:repl-backlog-size = 允许从节点最大中断时长 * 主实例offset每秒写入量,比如master每秒最大写入64mb,最大允许60秒,那么就要设置为64mb*60秒=3840MB(3.8G),建议此值是设置的足够大

repl-backlog-ttl 3600 #如果一段时间后没有slave连接到master,则backlog size的内存将会被释放。如果值为0则 表示永远不释放这部份内存。

slave-priority 100 #slave端的优先级设置,值是一个整数,数字越小表示优先级越高。当master故障时将会按照优先级来选择slave端进行恢复,如果值设置为0,则表示该slave永远不会被选择。

min-replicas-to-write 1 #设置一个master的可用slave不能少于多少个,否则master无法执行写

min-slaves-max-lag 20 #设置至少有上面数量的slave延迟时间都大于多少秒时,master不接收写操作(拒绝写入)
           

5、常见主从复制故障

5.1、master密码不对

5.2、redis版本不一致

5.3、无法远程连接

5.4、配置不一致

  1. 当主从节点的maxmemory不一致,主节点的内存大雨从节点的内存时,这样就可能会出现主从复制丢失数据的情况。
  2. 主从节点的rename-command命令不一致,例如在主节点定义了flushall,flushdb,而在从节点上没有定义,这样的话在主节点执行flushall或者flushdb的话,在从节点的数据是没有同步的。

继续阅读