Redis搭建哨兵模式一主两从三哨兵

Redis搭建哨兵模式一主两从三哨兵

目录

Redis搭建哨兵模式一主两从三哨兵

一、Redis哨兵模式

[1. 哨兵模式原理:](#1. 哨兵模式原理:)

[2. 哨兵的作用:](#2. 哨兵的作用:)

3.哨兵的结构

4.故障转移机制

故障转移过程如下:

主节点的选举条件:

二、节点规划

三、实施部署

1.关闭防火墙安全内核机制,所有节点全部执行

2.分别修改主机名

3.修改所有节点hosts文件

4.主从部署

5.修改Master节点配置文件

6.修改slave1和slave2两个从节点

8.哨兵部署

9.启动哨兵模式所有节点都要启动

10.在master查看哨兵信息

总结


一、Redis哨兵模式

哨兵的核心功能:在主从复制的基础上,哨兵引入了主节点的自动故障转移

1. 哨兵模式原理:

哨兵:是一个分布式系统,用于对主从结构中的每台服务器进行监控,当出现故障时通过投票机制选择新的Master。所以整个运行哨兵的集群的数量不得少于3个节点。

2. 哨兵的作用:

监控:哨兵会不断地检查主节点和从节点是否运作正常。

自动故障转移:当主节点不能正常工作时,哨兵会开始自动故障转移操作,他会将失效主节点的其中一个从节点升级为新的主节点,并让其他从节点改为复制新的主节点。

通知提醒:哨兵可以将故障转移的结果发送给客户端

3.哨兵的结构

哨兵节点:哨兵系统由一个或多个哨兵节点组成,哨兵节点就是特殊的redis节点,不存储数据

数据节点:主节点和从节点都是数据节点

注意:

哨兵的启动依赖主从模式,所以须把主从模式安装好的情况下再去做哨兵模式,所有节点上都需要部署哨兵模式,哨兵模式会监控所有的Redis工作节点是否正常

4.故障转移机制

由哨兵节点定期监控主节点是否出现了故障,每个哨兵节点每隔1秒会向主节点、从节点及其它哨兵节点发送一次ping命令做一次心跳检测。 如果主节点在一定时间范围内不回复或者是回复一个错误消息,那么这个哨兵就会认为这个主节点主观下线了(单方面的),当超过半数哨兵节点认为该主节点下线了,这样就客观下线了。 此时哨兵节点会通过Raft算法〈选举算法)实现选举机制共同选举出一个哨兵节点为leader,来负责处理主节点的故障转移和通知。

故障转移过程如下:

1.将某一个从节点升级为新的主节点,让其它从节点指向新的主节点;

2.若原主节点恢复也变成从节点,并指向新的主节点

3.通知客户端主节点已经更换

主节点的选举条件:

1.过滤掉不健康的(已下线的),没有回复哨兵ping响应的丛节点

2.选择配置文件中从节点优先级最高的(replication-priority,默认值为100)

3.选择复制偏移量最大的,也就是复制最完整的从节点。

二、节点规划

|--------|-----------|-------------|-----|----|-----|--------------------|
| 节点 | 服务器 | IP | CPU | 内存 | 磁盘 | 版本 |
| master | Almalinux | 10.0.20.176 | 8 | 16 | 150 | redis-7.4.2.tar.gz |
| slave1 | Almalinux | 10.0.20.177 | 8 | 16 | 150 | redis-7.4.2.tar.gz |
| slave2 | Almalinux | 10.0.20.178 | 8 | 16 | 150 | redis-7.4.2.tar.gz |

三、实施部署

1.关闭防火墙安全内核机制,所有节点全部执行

复制代码
[root@localhost ~]# systemctl stop firewalld
[root@localhost ~]# setenforce 0

2.分别修改主机名

复制代码
[root@localhost ~]# hostnamectl set-hostname master && bash    #10.0.20.176
[root@localhost ~]# hostnamectl set-hostname slave1 && bash     #10.0.20.177
[root@localhost ~]# hostnamectl set-hostname slave2 && bash     #10.0.20.178

3.修改所有节点hosts文件

复制代码
[root@master ~]#  cat >>/etc/hosts<< EOF
10.0.20.176 master
10.0.20.177 slave1
10.0.20.178 slave2
EOF

4.主从部署

所有节点源码编译安装redis(也可以使用下方一键安装脚本)

将源码包上传至/usr/local/src路径下

bash 复制代码
#!/bin/bash

# ====== 配置变量 ======
REDIS_VERSION="7.4.2"
REDIS_PORT="63790"
REDIS_USER="redis"
REDIS_GROUP="redis"
REDIS_HOME="/usr/local/redis"
REDIS_DATA_DIR="/var/lib/redis"
REDIS_LOG_DIR="/var/log/redis"
REDIS_RUN_DIR="/var/run/redis"

# ====== 颜色输出函数 ======
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color

log_info() {
    echo -e "${GREEN}[INFO]${NC} $(date '+%Y-%m-%d %H:%M:%S') - $1"
}

log_warning() {
    echo -e "${YELLOW}[WARNING]${NC} $(date '+%Y-%m-%d %H:%M:%S') - $1"
}

log_error() {
    echo -e "${RED}[ERROR]${NC} $(date '+%Y-%m-%d %H:%M:%S') - $1" >&2
}

# ====== 检查并安装依赖 ======
install_dependencies() {
    log_info "开始安装依赖包..."
    
    # 检查并安装tar
    if ! command -v tar &> /dev/null; then
        yum -y install tar
        log_info "已安装tar"
    else
        log_info "tar已安装"
    fi
    
    # 检查并安装gcc
    if ! command -v gcc &> /dev/null; then
        yum -y install gcc
        log_info "已安装gcc"
    else
        log_info "gcc已安装"
    fi
    
    # 检查gcc是否安装成功
    if ! command -v gcc &> /dev/null; then
        log_error "GCC安装失败,请检查YUM源配置"
        exit 1
    fi
}

# ====== 配置系统参数 ======
configure_system() {
    log_info "配置系统参数..."
    
    # 配置内存过度分配
    if ! grep -q "vm.overcommit_memory = 1" /etc/sysctl.conf; then
        echo "vm.overcommit_memory = 1" >> /etc/sysctl.conf
        sysctl -p
        log_info "已配置内存过度分配策略"
    fi
    
    # 配置透明大页 (需要重启生效)
    if [ ! -f /etc/rc.d/rc.local ]; then
        echo '#!/bin/bash' > /etc/rc.d/rc.local
    fi
    chmod +x /etc/rc.d/rc.local
    
    if ! grep -q "transparent_hugepage" /etc/rc.d/rc.local; then
        echo 'echo never > /sys/kernel/mm/transparent_hugepage/enabled' >> /etc/rc.d/rc.local
        log_info "已配置透明大页禁用(重启后生效)"
    fi
}

# ====== 创建Redis用户和组 ======
create_redis_user() {
    log_info "创建Redis用户和组..."
    
    if ! getent group ${REDIS_GROUP} > /dev/null; then
        groupadd -r ${REDIS_GROUP}
        log_info "已创建Redis组: ${REDIS_GROUP}"
    fi
    
    if ! id -u ${REDIS_USER} > /dev/null 2>&1; then
        useradd -r -g ${REDIS_GROUP} -s /sbin/nologin ${REDIS_USER}
        log_info "已创建Redis用户: ${REDIS_USER}"
    fi
}

# ====== 安装Redis ======
install_redis() {
    log_info "开始安装Redis ${REDIS_VERSION}..."
    
    # 检查Redis源码包是否存在
    if [ ! -f "/usr/local/src/redis-${REDIS_VERSION}.tar.gz" ]; then
        log_error "Redis源码包不存在: /usr/local/src/redis-${REDIS_VERSION}.tar.gz"
        exit 1
    fi
    
    # 解压Redis源码
    tar -zxf "/usr/local/src/redis-${REDIS_VERSION}.tar.gz" -C /usr/local
    if [ $? -ne 0 ]; then
        log_error "解压Redis源码包失败"
        exit 1
    fi
    
    # 重命名目录
    mv "/usr/local/redis-${REDIS_VERSION}" "${REDIS_HOME}"
    
    # 编译安装Redis
    cd "${REDIS_HOME}"
    make MALLOC=libc
    if [ $? -ne 0 ]; then
        log_error "Redis编译失败"
        exit 1
    fi
    
    cd "${REDIS_HOME}/src"
    make install PREFIX="${REDIS_HOME}"
    if [ $? -ne 0 ]; then
        log_error "Redis安装失败"
        exit 1
    fi
    
    log_info "Redis ${REDIS_VERSION} 安装成功"
}

# ====== 配置Redis ======
configure_redis() {
    log_info "配置Redis..."
    
    # 创建数据和日志目录
    mkdir -p ${REDIS_DATA_DIR} ${REDIS_LOG_DIR} ${REDIS_RUN_DIR}
    chown -R ${REDIS_USER}:${REDIS_GROUP} ${REDIS_DATA_DIR} ${REDIS_LOG_DIR} ${REDIS_RUN_DIR}
    chmod -R 755 ${REDIS_DATA_DIR} ${REDIS_LOG_DIR} ${REDIS_RUN_DIR}
    
    # 修改Redis配置文件
    if [ -f "${REDIS_HOME}/redis.conf" ]; then
        # 备份原始配置文件
        cp "${REDIS_HOME}/redis.conf" "${REDIS_HOME}/redis.conf.bak"
        
        # 应用配置修改
        sed -i 's/^bind 127.0.0.1/bind 0.0.0.0/g' "${REDIS_HOME}/redis.conf"   # 开放对外链接
        sed -i 's/daemonize no/daemonize yes/' "${REDIS_HOME}/redis.conf"      # 守护进程方式启动
        sed -i 's/protected-mode yes/protected-mode no/' "${REDIS_HOME}/redis.conf"   # 开放外部访问
        sed -i "s/port 6379/port ${REDIS_PORT}/" "${REDIS_HOME}/redis.conf"    # 修改端口号
        
        # 添加额外配置
        echo "dir ${REDIS_DATA_DIR}" >> "${REDIS_HOME}/redis.conf"
        echo "logfile ${REDIS_LOG_DIR}/redis.log" >> "${REDIS_HOME}/redis.conf"
        echo "pidfile ${REDIS_RUN_DIR}/redis.pid" >> "${REDIS_HOME}/redis.conf"
        
        # 设置配置文件权限
        chown ${REDIS_USER}:${REDIS_GROUP} "${REDIS_HOME}/redis.conf"
        chmod 644 "${REDIS_HOME}/redis.conf"
        
        log_info "Redis配置已完成"
    else
        log_error "Redis配置文件不存在: ${REDIS_HOME}/redis.conf"
        exit 1
    fi
}

# ====== 创建Systemd服务 ======
create_systemd_service() {
    log_info "创建Systemd服务..."
    
    cat > /etc/systemd/system/redis.service << EOF
[Unit]
Description=Redis In-Memory Data Store
Documentation=https://redis.io/documentation
After=network.target

[Service]
Type=forking
User=${REDIS_USER}
Group=${REDIS_GROUP}
PIDFile=${REDIS_RUN_DIR}/redis.pid
ExecStart=${REDIS_HOME}/bin/redis-server ${REDIS_HOME}/redis.conf
ExecStop=${REDIS_HOME}/bin/redis-cli -h 127.0.0.1 -p ${REDIS_PORT} shutdown
Restart=always
RestartSec=3
LimitNOFILE=65535
RuntimeDirectory=redis
RuntimeDirectoryMode=0755
PrivateTmp=true

[Install]
WantedBy=multi-user.target
EOF
    
    # 重新加载Systemd配置
    systemctl daemon-reload
    log_info "Systemd服务已创建"
}

# ====== 创建符号链接 ======
create_symlinks() {
    log_info "创建符号链接..."
    
    ln -sf "${REDIS_HOME}/bin/redis-cli" /usr/local/sbin/redis-cli
    ln -sf "${REDIS_HOME}/bin/redis-server" /usr/local/sbin/redis-server
    
    # 添加到PATH环境变量
    if ! grep -q "${REDIS_HOME}/bin" /etc/profile; then
        echo "export PATH=\${PATH}:${REDIS_HOME}/bin" >> /etc/profile
        source /etc/profile
    fi
    
    log_info "符号链接已创建"
}

# ====== 配置防火墙 ======
configure_firewall() {
    log_info "配置防火墙..."
    
    if systemctl is-active --quiet firewalld; then
        firewall-cmd --permanent --add-port=${REDIS_PORT}/tcp
        firewall-cmd --reload
        log_info "已放行TCP ${REDIS_PORT}端口"
    else
        log_warning "firewalld未运行,跳过端口放行"
    fi
}

# ====== 启动Redis服务 ======
start_redis_service() {
    log_info "启动Redis服务..."
    
    # 设置目录权限
    chown -R ${REDIS_USER}:${REDIS_GROUP} ${REDIS_HOME}
    
    # 启动并启用服务
    systemctl start redis
    systemctl enable redis
    
    # 检查服务状态
    sleep 2  # 等待服务启动
    if systemctl is-active --quiet redis; then
        log_info "Redis服务启动成功"
        systemctl status redis --no-pager
    else
        log_error "Redis服务启动失败"
        journalctl -u redis --since "1 minute ago" --no-pager
        exit 1
    fi
}

# ====== 安装后提示 ======
post_install_info() {
    echo ""
    log_info "========== Redis 安装完成 =========="
    log_info "版本: Redis ${REDIS_VERSION}"
    log_info "端口: ${REDIS_PORT}"
    log_info "配置文件: ${REDIS_HOME}/redis.conf"
    log_info "数据目录: ${REDIS_DATA_DIR}"
    log_info "日志文件: ${REDIS_LOG_DIR}/redis.log"
    log_info "管理命令:"
    log_info "  启动: systemctl start redis"
    log_info "  停止: systemctl stop redis"
    log_info "  状态: systemctl status redis"
    log_info "  连接: redis-cli -p ${REDIS_PORT}"
    echo ""
    log_warning "注意: 当前配置未设置密码,生产环境请设置requirepass"
    log_warning "      修改配置文件: ${REDIS_HOME}/redis.conf"
    log_warning "      取消注释: # requirepass foobared 并设置强密码"
    echo ""
}

# ====== 主执行流程 ======
main() {
    log_info "开始Redis安装流程"
    
    # 检查root权限
    if [ "$(id -u)" != "0" ]; then
        log_error "此脚本必须使用root权限运行"
        exit 1
    fi
    
    # 执行安装步骤
    install_dependencies
    configure_system
    create_redis_user
    install_redis
    configure_redis
    create_systemd_service
    create_symlinks
    configure_firewall
    start_redis_service
    post_install_info
    
    log_info "Redis安装完成"
}

# 执行主函数
main "$@"

执行流程:

bash 复制代码
[root@master ~]# touch install_redis.sh       #创建脚本文件&&脚本插入进去
[root@master ~]# chmod +x install_redis.sh    #给予执行权限
[root@master ~]# ./install_redis.sh           #执行

预计输出

5.修改Master节点配置文件

bash 复制代码
[root@master ~]# cp /usr/local/redis/redis.conf redis.conf.bak     #备份(好习惯)
[root@master ~]# vi /usr/local/redis/redis.conf
bind 0.0.0.0                 #88行,注释掉bind项,或修改0.0.0.0默认监听所有端口
daemonize yes               #310行,开启守护进程
logfile /var/log/redis/redis.log   #356行,指定日志文件目录
dir /var/lib/redis              #516行,指定工作目录
# requirepass 密码           #1050行,指定redis登录密码,可不设置
#重启redis
[root@master redis]# systemctl restart redis

6.修改slave1和slave2两个从节点

bash 复制代码
[root@slave1 ~]# cp /usr/local/redis/redis.conf redis.conf.bak
[root@slave1 ~]# vi /usr/local/redis/redis.conf
bind 0.0.0.0                 #88行,注释掉bind项,或修改0.0.0.0默认监听所有端口
daemonize yes               #310行,开启守护进程
logfile /var/log/redis/redis.log   #356行,指定日志文件目录
dir /var/lib/redis              #516行,指定工作目录
replicaof 10.0.20.176 63790     #539行,指定主节点的ip和端口

#重启slave1节点和slave2节点redis服务
[root@slave1 ~]# systemctl restart redis
[root@slave2 ~]# systemctl restart redis

7.验证主从效果

bash 复制代码
[root@master redis]# tail -f /var/log/redis/redis.log
[root@master redis]# redis-cli -p 63790    #登录redis
127.0.0.1:63790> info replication         #查看
127.0.0.1:63790> set k1 1               #在主库创建文件在从库查看
OK
127.0.0.1:63790> get k1                 #存在
"1"
127.0.0.1:63790> 

在master上动态查看日志:

在master上验证从节点

8.哨兵部署

bash 复制代码
[root@master ~]# cd /usr/local/redis
[root@master redis]# ll

修改哨兵模式的配置文件(所有节点操作)

bash 复制代码
[root@master ~]# cp /usr/local/redis/sentinel.conf sentinel.conf.bak  #备份

protected-mode no             #6行,关闭保护模式
port 26379                    #10行,哨兵默认端口号
daemonize yes                 #15行,开启后台运行
logfile /var/log/redis/sentinel.log   #34行,指定日志目录
dir /var/lib/redis                 #73行,数据文件

#92行,改变master节点地址,指定哨兵节点监控10.0.20.176:63790这个主节点
sentinel monitor mymaster 10.0.20.176 63790 2

#133行,可以修改时间,判定服务器down掉的时间周期,默认30000毫秒(30秒)
sentinel down-after-milliseconds mymaster 30000

#233行,故障切换时间,故障节点的最大超时时间为180000(180秒)
sentinel failover-timeout mymaster 180000

9.启动哨兵模式所有节点都要启动

#注意:先启动主节点,在启从节点

bash 复制代码
[root@master redis]# /usr/local/redis/src/redis-sentinel sentinel.conf &
[1]13569
[root@slave1 redis]# /usr/local/redis/src/redis-sentinel sentinel.conf &
[1] 13496
[root@slave2 redis]# /usr/local/redis/src/redis-sentinel sentinel.conf &
[1] 13754

10.在master查看哨兵信息

所有节点都可以查看哨兵info sentinel

bash 复制代码
[root@master redis]# redis-cli -p 26379 info Sentinel

11.验证哨兵,模拟故障

bash 复制代码
[root@master redis]# ps -ef |grep redis
[root@master redis]# systemctl stop redis
[root@master redis]# tail -f /var/log/redis/sentinel.log

在Slave1上查看是否转换成功

bash 复制代码
[root@slave1 redis]#  redis-cli -p 26379 INFO Sentinel

在slave2上查看是否转换成功

bash 复制代码
[root@slave2 redis]#  redis-cli -p 26379 INFO Sentinel

当原来的master修复后会做为slave从新加入

bash 复制代码
[root@master redis]# redis-cli -p 26379
127.0.0.1:26379> info

将权重值调成默认方便下次选举

总结

哨兵系统中的主从节点,与普通的主从节点并没有什么区别,故障发现和转移是由哨兵来控制和完成的。

哨兵节点本质上是Redis节点.

每个哨兵节点,只需要配置监控主节点,便可以自动发现其他的哨兵节点和从节点.

在哨兵节点启动和故障转移阶段,各个节点的配置文件会被重写(Config Rewrite)。

故障转移分三步

1.从下线的主服务的所有从服务里面挑选一个从服务, 将其转成主服务

2.已下线主服务的所有从服务改为复制新的主服务 挑选出新的主服务之后,领头sentinel 向原主服务的从服务发送 slaveof 新主服务 的命令,复制新master。

3.将已下线的主服务设置成新的主服务的从服务, 当其回复正常时,复制新的主服务,变成新的主服务的从服务 当已下线的服务重新上线时,sentinel会向其发送slaveof命令, 让其成为新主的从。

bash 复制代码
查看[root@master redis-5.0.9]下的master节点信息
sentinel master imooc-master

查看[root@master redis-5.0.9]下的slaves节点信息
sentinel slaves imooc-master

欢迎一起交流

相关推荐
给力学长4 小时前
洗衣店小程序的设计与实现
java·数据库·vue.js·小程序·node.js
倔强的石头_4 小时前
【Linux指南】Linux 环境下 Git 从 0 到 1:手把手带你玩转版本控制
linux
大白的编程日记.4 小时前
【MySQL】初识数据库基础
数据库·mysql
澡点睡觉4 小时前
【golang长途旅行第36站】golang操作Redis
开发语言·redis·golang
zzz100664 小时前
shell编程 函数、数组与正则表达式
linux·运维·服务器
杰克崔5 小时前
文件页的预取逻辑
linux·运维·服务器
bobz9655 小时前
falco
linux
wdfk_prog5 小时前
[Linux]学习笔记系列 -- mm/slub.c SLUB内存分配器(The SLUB Allocator) 现代内核对象缓存的核心
java·linux·运维·c语言·笔记·学习·缓存
tongsound5 小时前
linx top 指令使用
linux