美文网首页
redis主从+哨兵实现高可用

redis主从+哨兵实现高可用

作者: 昵称已被使用_ | 来源:发表于2021-03-02 20:04 被阅读0次

    前言

    Redis高可用常见的方式有两种:

    • 主从复制(Replication-Sentinel模式),至少需要3台服务器,1个Master节点,2个Slave节点,3个Sentinel节点,当有2个Sentinel认为Master挂了,则把其中1个Slave调整为Master
    • Redis集群(Redis-Cluster模式)Slave节点,至少需要6台服务器,即3个Master节点,每个Master至少都有1个Slave节点
    • 本文主要介绍redis主从+哨兵实现高可用
    • 我这里先准备3台服务器,安装目录为/www/server/redis
    IP地址              redis版本(其他版本操作方式一致)
    192.168.88.5(主)  redis 6.0.10
    192.168.88.6(从)  redis 6.0.10
    192.168.88.7(从)  redis 6.0.10
    

    建议先通读本文后在实操

    安装redis

    ...略

    配置防火墙

    # 查看防火墙状态
    systemctl status firewalld 
    
    # 启用防火墙
    systemctl start firewalld
    
    # 停用防火墙
    systemctl stop firewalld
    
    # 设置开机时启用防火墙
    systemctl enable firewalld.service
    
    # 设置开机时不启用防火墙
    systemctl disable firewalld.service
    
    # 防火墙开放6379端口
    firewall-cmd --zone=public --add-port=6379/tcp --permanent
    # 防火墙开放26379端口
    firewall-cmd --zone=public --add-port=26379/tcp --permanent
    # 重启防火墙使配置生效
    systemctl restart firewalld
    

    建议先关闭防火墙

    配置主从

    • 连接某台服务器做主节点,我这里使用192.168.88.5做主节点
    # 进入redis安装目录
    cd /www/server/redis
    
    # 备份配置文件
    mv redis.conf bak_redis.conf
    
    # 创建新的配置文件
    vim redis.conf
    
    • 编辑配置文件内容,内容如下,其中带注释的配置需要你评估是否要修改,其余配置是redis 6.0.10的默认配置内容
    requirepass 123123  # redis密码,不需要则删除该行
    masterauth 123123  # 不需要密码则删除该行,哨兵模式需要用到
    bind 0.0.0.0 # 所有ip可以访问redis
    port 6379 # 端口
    logfile /www/server/redis/logs/redis.log # 新建目录和日志文件
    
    pidfile var/run/redis.pid
    dir ./
    dbfilename "dump.rdb"
    protected-mode yes
    
    maxclients 10000
    
    tcp-backlog 511
    
    timeout 0
    
    tcp-keepalive 300
    
    daemonize yes
    
    supervised no
    
    loglevel notice
    
    databases 16
    
    always-show-logo yes
    
    save 900 1
    save 300 10
    save 60 10000
    
    stop-writes-on-bgsave-error yes
    
    rdbcompression yes
    
    rdbchecksum yes
    
    replica-serve-stale-data yes
    
    replica-read-only yes
    
    repl-diskless-sync no
    
    repl-diskless-sync-delay 5
    
    repl-disable-tcp-nodelay no
    
    replica-priority 100
    
    lazyfree-lazy-eviction no
    lazyfree-lazy-expire no
    lazyfree-lazy-server-del no
    replica-lazy-flush no
    
    appendonly no
    
    appendfilename "appendonly.aof"
    
    appendfsync everysec
    
    no-appendfsync-on-rewrite no
    
    auto-aof-rewrite-percentage 100
    auto-aof-rewrite-min-size 64mb
    
    aof-load-truncated yes
    
    aof-use-rdb-preamble yes
    
    lua-time-limit 5000
    
    slowlog-log-slower-than 10000
    
    slowlog-max-len 128
    latency-monitor-threshold 0
    notify-keyspace-events ""
    
    hash-max-ziplist-entries 512
    hash-max-ziplist-value 64
    
    list-max-ziplist-size -2
    
    list-compress-depth 0
    
    set-max-intset-entries 512
    
    zset-max-ziplist-entries 128
    zset-max-ziplist-value 64
    
    hll-sparse-max-bytes 3000
    
    stream-node-max-bytes 4kb
    stream-node-max-entries 100
    
    activerehashing yes
    
    client-output-buffer-limit normal 0 0 0
    client-output-buffer-limit replica 256mb 64mb 60
    client-output-buffer-limit pubsub 32mb 8mb 60
    
    hz 10
    
    dynamic-hz yes
    
    aof-rewrite-incremental-fsync yes
    
    rdb-save-incremental-fsync yes
    
    
    • 重复以上步骤配置从节点服务器,从节点的redis.conf,只需额外添加如下内容
    replicaof 192.168.88.5 6379  # 主节点的ip+端口,如果你的redis版本小于5.0,则把replicaof改为slaveof
    
    • 分别启动配置好的三个redis节点
    # 启动redis
    ./src/redis-server ./redis.conf
    
    • 查看主从配置结果
    # -a 指定密码连接redis
    ./src/redis-cli -a 123123
    
    # 查看主从关系
    info Replication
    
    • 如下可以看到当前role是master以及从节点的ip和端口等信息
    [root@localhost ~]# cd /www/server/redis
    [root@localhost redis]# ./src/redis-cli -a 123123
    Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
    127.0.0.1:6379> info Replication
    # Replication
    role:master
    connected_slaves:2
    slave0:ip=192.168.88.6,port=6379,state=online,offset=1688303,lag=0
    slave1:ip=192.168.88.7,port=6379,state=online,offset=1688303,lag=0
    master_replid:f035e75692e9f119d2c095fd4c79e606146b4c4f
    master_replid2:bbd9b99985d844bc3e4031de95e9601b7d0513db
    master_repl_offset:1688303
    second_repl_offset:1653771
    repl_backlog_active:1
    repl_backlog_size:1048576
    repl_backlog_first_byte_offset:639728
    repl_backlog_histlen:1048576
    

    配置哨兵

    • 所有哨兵配置文件是一样的,所以每台服务器重复以下操作
    # 进入redis安装目录
    cd /www/server/redis
    
    # 备份配置文件
    mv sentinel.conf bak_sentinel.conf
    
    # 创建新的配置文件
    vim sentinel.conf
    
    • 编辑配置文件内容,内容如下
    bind 0.0.0.0
    port 26379
    daemonize yes
    pidfile /var/run/redis-sentinel.pid
    logfile /www/server/redis/logs/sentinel.log #  新建目录和日志文件
    dir ./
    sentinel deny-scripts-reconfig yes
    sentinel monitor mymaster 192.168.88.5 6379 2 # 配置主节点的ip和端口,2表示当有2个哨兵认为master失效,master才算真正失效
    sentinel auth-pass mymaster 123123 # 访问密码
    sentinel down-after-milliseconds mymaster 5000
    sentinel failover-timeout mymaster 15000
    
    • 分别启动配置好的三个哨兵节点
    # 启动redis
    ./src/redis-sentinel ./sentinel.conf
    
    • 查看哨兵配置结果
    # -p 指定哨兵端口连接redis sentinel
    ./src/redis-cli -p 26379
    
    # 使用哨兵查看master信息
    sentinel master mymaster
    
    # 使用哨兵查看slaves信息
    sentinel slaves mymaster
    

    验证哨兵自动故障转移

    • 连接Master节点服务器,当前这里是192.168.88.5
    • kill掉Master节点,注意不是kill哨兵
    • 通过哨兵查看新的master,./src/redis-cli -p 26379, 如下发现新的Master节点为192.168.88.6
    [root@localhost redis]# ps -ef | grep redis
    redis     17087      1  0 01:28 ?        00:00:00 /www/server/redis/src/redis-server 0.0.0.0:6379
    root      17244      1  1 01:28 ?        00:00:01 /www/server/redis/src/redis-sentinel 0.0.0.0:26379 [sentinel]
    root      17499   2227  0 01:30 pts/0    00:00:00 grep --color=auto redis
    [root@localhost redis]# kill -9 17087
    [root@localhost redis]# ./src/redis-cli -p 26379
    127.0.0.1:26379> sentinel master mymaster
     1) "name"
     2) "mymaster"
     3) "ip"
     4) "192.168.88.6"
     5) "port"
     6) "6379"
    

    也可以查看哨兵日志文件tailf ./logs/sentinel.log

    应用高可用配置

    当哨兵发现Master节点挂掉,会自动把其中一个Slave节点选举为Master节点,这个时候Master节点的ip就变了,所以当前我们还没有实现高可用,以下有两种方式处理ip变化

    方式一:应用配置多个哨兵,通过哨兵获取真实的Master节点

    • 如下是spingboot应用集成redis哨兵的配置方式,代码层面不需要改动
    spring:
      redis:
        password: 123123
        sentinel:
          master: mymaster
          nodes: 192.168.88.5:26379,192.168.88.6:26379,192.168.88.7:26379
    
    • 其他应用可能涉及到代码改造,请自行查找相关文档

    方式二:VIP方式,当哨兵发现故障,把新的Master对应的ip到绑定虚拟ip上

    注:VIP方式需要使用ROOT权限,若安全管理要求不允许使用ROOT则只能使用第一种方式

    1. 连接Master节点对应的服务器,手动给Master添加虚拟ip
    # 查看网卡类型,即将用到,我这里是ens32,Centos6及以下默认为eth0
    ls /etc/sysconfig/network-scripts | grep ifcfg-
    
    # 这里我设置的虚拟ip是192.168.88.88
    /sbin/ip addr add 192.168.88.88 dev ens32
    sbin/arping -q -c 3 -U 192.168.88.88 -I ens32
    
    # 查看虚拟ip是否设置成功
    ip addr
    
    # 测试,使用虚拟ip连接redis
    /www/server/redis/src/redis-cli -h 192.168.88.88 -a 123123
    
    1. 分别给三台服务器创建脚本
    # 创建脚本文件
    touch /scripts/notify_master.sh
    # 分配可执行权限
    chmod +x /scripts/notify_master.sh
    # 编辑文件
    vim /scripts/notify_master.sh
    
    1. 编辑脚本内容如下,注意LOCAL_IP每台服务器都不一样,也就是每台服务器的这个配置文件都不一样
    #!/bin/bash
    MASTER_IP=$6  #哨兵调用该脚本会传6个参数,第6个参数是新主redis的ip地址
    LOCAL_IP='192.168.88.5'  #本机ip,注意每个服务器都不一样
    VIP='192.168.88.88' #虚拟ip 
    NETMASK='24'
    INTERFACE='ens32' #网卡类型
    if [ ${MASTER_IP} = ${LOCAL_IP} ];then
        /sbin/ip  addr  add ${VIP}/${NETMASK}  dev ${INTERFACE}  #将VIP绑定到该服务器上
        /sbin/arping -q -c 3 -U ${VIP} -I ${INTERFACE}
        exit 0
    else
       /sbin/ip  addr del  ${VIP}/${NETMASK}  dev ${INTERFACE}   #将VIP从该服务器上删除
       exit 0
    fi
    exit 1  #如果返回1,sentinel会一直执行这个脚本
    

    注1:使用命令/scripts/notify_master.sh 1 1 1 1 1 192.168.88.5添加虚拟ip,验证脚本是否可以正常执行,其中192.168.88.5为本机ip, 因为脚本是获取$6(第6个参数),这里的 1 1 1 1 1是参数填充
    注2:当哨兵选举新的Master后,会调用上面脚本,当${MASTER_IP}等于${LOCAL_IP}会给当前服务器添加虚拟ip,否则删除虚拟ip

    1. 编辑每个哨兵配置文件sentinel.conf,最后一行添加如下内容
    sentinel client-reconfig-script mymaster /scripts/notify_master.sh
    
    1. 停止所有哨兵服务,然后重启所有哨兵
    2. 停止Master节点,查看虚拟ip是否绑定到新Master对应的服务器上
    # 每台服务器分别执行ip addr查看那台服务器绑定了虚拟ip
    ip addr | grep 88
    
    1. 最后,应用通过虚拟ip连接redis即可

    使用chkconfig设置开机启动

    设置哨兵开机启动

    • 创建脚本
    cd /etc/rc.d/init.d
    vim redis-sentinel
    
    • 编辑脚本内容
    #!/bin/sh
    #chkconfig: 2345 80 90
    #description: Redis Sentinel Service
    REDISPORT=26379
    REDISPATH=/www/server/redis #注意修改为你的redis安装目录
    EXEC=${REDISPATH}/src/redis-sentinel
    CLIEXEC=${REDISPATH}/src/redis-cli
    CONF="${REDISPATH}/sentinel.conf"
    PIDFILE=/var/run/redis-sentinel.pid #注意修改为你的哨兵pid文件
    case "$1" in
      start)
        if [ -f $PIDFILE ]
        then
            echo "$PIDFILE exists, process is already running or crashed"
        else
            echo "Starting Redis sentinel..."
            $EXEC $CONF
        fi
        ;;
      stop)
        if [ ! -f $PIDFILE ]
        then
            echo "$PIDFILE does not exist, process is not running"
        else
            PID=$(cat $PIDFILE)
            echo "Stopping ..."
            $CLIEXEC -p $REDISPORT shutdown
            while [ -x /proc/${PID} ]
            do
              echo "Waiting for Redis-sentinel to shutdown ..."
              sleep 1
            done
            echo "Redis-sentinel stopped"
        fi
        ;;
      *)
        echo "Please use start or stop as first argument"
        ;;
    esac
    
    
    • 设置开机启动
    # 给脚本添加可执行权限
    chmod +x redis-sentinel
    
    # 验证脚本能否关闭哨兵服务
    ./redis-sentinel stop
    
    # 验证脚本能否启动哨兵服务
    ./redis-sentinel start
    
    # 把哨兵添加到chkconfig列表中
    chkconfig --add redis-sentinel
    
    # 设置哨兵服务开机启动
    chkconfig redis-sentinel on
    

    设置redis开机启动

    • 创建脚本
    cd /etc/rc.d/init.d
    vim redis
    
    • 编辑脚本内容
    #!/bin/sh
    # chkconfig: 2345 56 26
    # description: Redis Service
    
    ### BEGIN INIT INFO
    # Provides:          Redis
    # Required-Start:    $all
    # Required-Stop:     $all
    # Default-Start:     2 3 4 5
    # Default-Stop:      0 1 6
    # Short-Description: starts Redis
    # Description:       starts the BT-Web
    ### END INIT INFO
    
    # Simple Redis init.d script conceived to work on Linux systems
    # as it does use of the /proc filesystem.
    
    REDISPATH=/www/server/redis #注意修改为你的redis安装目录
    PIDFILE=/www/server/redis/redis.pid #注意修改为你的redis pid文件
    CONF="${REDISPATH}/redis.conf"
    REDISPORT=$(cat $CONF |grep port|grep -v '#'|awk '{print $2}')
    REDISPASS=$(cat $CONF |grep requirepass|grep -v '#'|awk '{print $2}')
    REDISHOST=$(cat $CONF |grep bind|grep -v '#'|awk '{print $2}')
    if [ "$REDISPASS" != "" ];then
        REDISPASS=" -a $REDISPASS"
    fi
    if [ -f "${REDISPATH}/start.pl" ];then
        STARPORT=$(cat ${REDISPATH}/start.pl)
    else
        STARPORT="6379"
    fi
    EXEC=${REDISPATH}/src/redis-server
    CLIEXEC="${REDISPATH}/src/redis-cli -h ${REDISHOST} -p ${REDISPORT}${REDISPASS}"
    echo "${REDISPATH}/src/redis-cli -h ${REDISHOST} -p ${REDISPORT}${REDISPASS}"
    
    redis_start(){
        if [ -f "${REDISPATH}/redis.pid" ]; then
            ps -p $(cat ${PIDFILE}) > /dev/null 2>&1
            if [ $? -ne "0" ]; then
                rm -f ${PIDFILE}
            else
                echo "redis is running! ($(cat ${PIDFILE}))"
                exit 0
            fi
        fi
        echo "Starting redis server..."
        sudo -u redis $EXEC $CONF
        echo ${REDIS_PORT} > ${REDISPATH}/start.pl
        echo "Starting redis success!"
    }
    redis_status(){
        if [ -f "${REDISPATH}/redis.pid" ]; then
            ps -p $(cat ${PIDFILE}) > /dev/null 2>&1
            if [ $? -ne "0" ]; then
                echo "Redis is not running, buy pid file is exits ${PIDFILE}"
                exit 1
            else
                echo "redis is running! ($(cat ${PIDFILE}))"
                exit 0
            fi
        else
            echo "redis is stopped"
            exit 0
        fi
    }
    redis_stop(){
        echo "Stopping ..."
        $CLIEXEC shutdown
        sleep 1
        pkill -9 redis-server
        rm -f ${PIDFILE}
        echo "Redis stopped"
    }
    
    case "$1" in
        start)
            redis_start
            ;;
        stop)
            redis_stop
            ;;
        status)
            redis_status
            ;;
        restart|reload)
            redis_stop
            sleep 0.3
            redis_start
            ;;
        *)
            echo "Please use start or stop as first argument"
            ;;
    esac
    
    
    • 设置开机启动
    # 给脚本添加可执行权限
    chmod +x redis
    
    # 验证脚本能否关闭redis
    ./redis stop
    
    # 验证脚本能否启动redis
    ./redis start
    
    # 把redis添加到chkconfig列表中
    chkconfig --add redis
    
    # 设置redis服务开机启动
    chkconfig redis on
    

    其他

    # 查看所有chklist中服务
    chkconfig --list
    
    # 关闭xxx开机启动
    chkconfig xxx off
    
    # 把xxx从chkconfig列表中删除
    chkconfig --del xxx
    

    最后

    • 至此已经实现redis高可用
    • 参考1:Redis高可用技术解决方案
    • 参考2:redis主从+哨兵+vip实现高可用
    • 补充1:本文在做redis高可用时,经常会依次操作每台服务器执行相同的命令,重复操作显然效率低,这里推荐-linux自动化运维工具ansible,批量操作多台服务器执行命令
    • 补充2:服务器使用WinSCP传输文件效率低下,如你使用Xshell命令行工具,可以使用如下方式实现文件上传与下载
      # 安装lrzsz
      yum -y install lrzsz
      rz # 上传
      sz fileName # 下载,fileName是你要下载的文件名
      

    安全管理要求

    在对服务器安全要求比较严格的情况下,需要考虑以下几点

    1. redis的安装及操作不能使用root权限
    2. redis不能使用默认端口
    3. 配置文件不能使用bind 0.0.0.0,必须制定ip
    4. 密码必须不能使用弱密码

    相关文章

      网友评论

          本文标题:redis主从+哨兵实现高可用

          本文链接:https://www.haomeiwen.com/subject/rsbxqltx.html