CentOS上部署Redis及其哨兵(Sentinel)模式

架构:说明我这里是伪集群的,redis 在同一台机器,Sentinel 只有一个,也存在单点故障问题

只能当作开发环境使用,要满足生产至少是下面这种架构

javascript 复制代码
+-------------------+      +-------------------+      +-------------------+
|  Sentinel 1       |      |  Sentinel 2       |      |  Sentinel 3       |
|  (Monitoring)     |<---->|  (Monitoring)     |<---->|  (Monitoring)     |
+-------------------+      +-------------------+      +-------------------+
        |                          |                          |
        v                          v                          v
+-------------------+      +-------------------+      +-------------------+
|  Redis Master     |<---->|  Redis Slave 1    |<---->|  Redis Slave 2    |
|  (Port: 6379)     |      |  (Port: 6380)     |      |  (Port: 6381)     |
+-------------------+      +-------------------+      +-------------------+

安装Shell 脚本:

记得赋予可执行权限:chmod +x redis_sentinel_manager.sh

javascript 复制代码
#!/bin/bash

# =============================================================================
# Script Name: redis_sentinel_manager.sh
# Version: v1.4 (Enhanced stop function using ps/kill)
# Description: A script to install and manage Redis Sentinel mode on CentOS 7/8
# Author: ldj
# Creation Date: 2025-07-31
# =============================================================================

# 全局变量
REDIS_VERSION="7.0.14"
REDIS_PORT1=6379
REDIS_PORT2=6380
REDIS_PORT3=6381
SENTINEL_PORT=26379
REDIS_DIR="/usr/local/redis"
DATA_DIR="/var/lib/redis"
LOG_DIR="/var/log/redis"
REDIS_PASSWORD="redis123456"  # 建议设置强密码

# 检查权限
if [ "$(id -u)" -ne 0 ]; then
    echo "请使用root权限运行此脚本"
    exit 1
fi

# 显示使用说明
usage() {
    echo "使用方法:"
    echo "$0 <install|uninstall|start|stop>"
    echo ""
    echo "功能说明:"
    echo "  install   - 安装Redis哨兵模式"
    echo "  uninstall - 卸载Redis及相关文件"
    echo "  start     - 启动Redis服务"
    echo "  stop      - 停止Redis服务"
}

# 检查Redis实例和Sentinel是否正在运行
check_running() {
    if pgrep -f "redis-server" > /dev/null; then
        echo "[$(date +'%Y-%m-%d %H:%M:%S')] 发现Redis实例正在运行,请先停止所有Redis实例和服务后再进行安装。"
        exit 1
    fi

    if pgrep -f "redis-sentinel" > /dev/null; then
        echo "[$(date +'%Y-%m-%d %H:%M:%S')] 发现Sentinel正在运行,请先停止Sentinel服务后再进行安装。"
        exit 1
    fi
}

# 安装函数
install() {
    echo "[$(date +'%Y-%m-%d %H:%M:%S')] 开始安装Redis哨兵模式..."

    # 检查是否有正在运行的Redis实例或Sentinel
    check_running

    # 创建目录
    mkdir -p $REDIS_DIR $DATA_DIR $LOG_DIR
    mkdir -p $DATA_DIR/$REDIS_PORT1
    mkdir -p $DATA_DIR/$REDIS_PORT2
    mkdir -p $DATA_DIR/$REDIS_PORT3
    mkdir -p $DATA_DIR/sentinel

    # 安装依赖
    echo "[$(date +'%Y-%m-%d %H:%M:%S')] 安装编译依赖..."
    yum install -y wget gcc make tcl || { echo "安装依赖失败"; exit 1; }

    # 下载编译Redis
    cd $REDIS_DIR || { echo "无法进入目录 $REDIS_DIR"; exit 1; }
    echo "[$(date +'%Y-%m-%d %H:%M:%S')] 下载Redis $REDIS_VERSION..."
    wget https://download.redis.io/releases/redis-$REDIS_VERSION.tar.gz || { echo "下载Redis失败"; exit 1; }
    tar xzf redis-$REDIS_VERSION.tar.gz || { echo "解压Redis失败"; exit 1; }
    cd redis-$REDIS_VERSION || { echo "无法进入Redis源码目录"; exit 1; }

    # 编译 (在源码根目录)
    echo "[$(date +'%Y-%m-%d %H:%M:%S')] 编译Redis..."
    make || { echo "编译Redis失败"; exit 1; }

    # ========== 关键修复:正确安装所有二进制文件 ==========
    # 直接在 src 目录执行 make install,这是标准做法
    echo "[$(date +'%Y-%m-%d %H:%M:%S')] 安装Redis二进制文件 (server, cli, sentinel)..."
    cd src || { echo "无法进入 src 目录"; exit 1; }
    make install || { echo "安装二进制文件失败"; exit 1; }

    # 验证 redis-sentinel 是否安装成功
    if ! command -v redis-sentinel &> /dev/null; then
        echo "致命错误: redis-sentinel 安装失败,未找到可执行文件。"
        exit 1
    fi
    echo "[$(date +'%Y-%m-%d %H:%M:%S')] redis-sentinel 安装验证通过。"
    # ============================================================

    # 可选:运行测试 (在源码根目录)
    echo "[$(date +'%Y-%m-%d %H:%M:%S')] 运行测试验证安装..."
    cd .. # 回到源码根目录
    make test || echo "[$(date +'%Y-%m-%d %H:%M:%S')] 测试运行完成 (可能存在非致命错误,但核心功能应正常)。"

    # ==================== 关键修改:配置并启动 Redis 实例 (注意顺序!) ====================

    echo "[$(date +'%Y-%m-%d %H:%M:%S')] 配置并启动 Redis 实例..."

    # --- 步骤 1: 配置并启动 主节点 (REDIS_PORT1) ---
    echo "[$(date +'%Y-%m-%d %H:%M:%S')] 配置主节点 (端口: $REDIS_PORT1)..."
    cat <<EOF > $REDIS_DIR/redis-$REDIS_PORT1.conf
port $REDIS_PORT1
bind 0.0.0.0
dir $DATA_DIR/$REDIS_PORT1
pidfile /var/run/redis-$REDIS_PORT1.pid
logfile "$LOG_DIR/redis-$REDIS_PORT1.log"
daemonize yes
appendonly yes
requirepass $REDIS_PASSWORD
masterauth $REDIS_PASSWORD
EOF

    # 启动主节点
    redis-server $REDIS_DIR/redis-$REDIS_PORT1.conf || { echo "启动主节点 $REDIS_PORT1 失败"; exit 1; }
    echo "[$(date +'%Y-%m-%d %H:%M:%S')] 主节点 (端口: $REDIS_PORT1) 已启动。"

    # --- 步骤 2: 配置并启动 从节点 (REDIS_PORT2 和 REDIS_PORT3) ---
    for PORT in $REDIS_PORT2 $REDIS_PORT3; do
        echo "[$(date +'%Y-%m-%d %H:%M:%S')] 配置从节点 (端口: $PORT)..."
        cat <<EOF > $REDIS_DIR/redis-$PORT.conf
port $PORT
bind 127.0.0.1
dir $DATA_DIR/$PORT
pidfile /var/run/redis-$PORT.pid
logfile "$LOG_DIR/redis-$PORT.log"
daemonize yes
appendonly yes
requirepass $REDIS_PASSWORD
masterauth $REDIS_PASSWORD
replicaof 127.0.0.1 $REDIS_PORT1
EOF
    done

    # 启动从节点
    sleep 2 # 给主节点一点时间完全启动
    for PORT in $REDIS_PORT2 $REDIS_PORT3; do
        redis-server $REDIS_DIR/redis-$PORT.conf || { echo "启动从节点 $PORT 失败"; exit 1; }
        echo "[$(date +'%Y-%m-%d %H:%M:%S')] 从节点 (端口: $PORT) 已启动。"
    done

    # --- 步骤 3: 配置并启动 Sentinel ---
    echo "[$(date +'%Y-%m-%d %H:%M:%S')] 配置Sentinel..."
    cat <<EOF > $REDIS_DIR/sentinel.conf
port $SENTINEL_PORT
daemonize yes
pidfile /var/run/redis-sentinel.pid
logfile "$LOG_DIR/sentinel.log"
dir $DATA_DIR/sentinel

sentinel monitor mymaster 127.0.0.1 $REDIS_PORT1 2
sentinel down-after-milliseconds mymaster 5000
sentinel failover-timeout mymaster 15000
sentinel parallel-syncs mymaster 1
sentinel auth-pass mymaster $REDIS_PASSWORD
EOF

    # 启动Sentinel
    echo "[$(date +'%Y-%m-%d %H:%M:%S')] 启动Sentinel..."
    redis-sentinel $REDIS_DIR/sentinel.conf || { echo "启动Sentinel失败"; exit 1; }
    echo "[$(date +'%Y-%m-%d %H:%M:%S')] Sentinel 已启动。"

    # 防火墙配置 (略,保持不变)
    echo "[$(date +'%Y-%m-%d %H:%M:%S')] 配置防火墙规则..."
    if systemctl is-active --quiet firewalld; then
        firewall-cmd --permanent --add-port=$REDIS_PORT1/tcp
        firewall-cmd --permanent --add-port=$REDIS_PORT2/tcp
        firewall-cmd --permanent --add-port=$REDIS_PORT3/tcp
        firewall-cmd --permanent --add-port=$SENTINEL_PORT/tcp
        firewall-cmd --reload && echo "[$(date +'%Y-%m-%d %H:%M:%S')] 防火墙规则已配置。"
    else
        echo "[$(date +'%Y-%m-%d %H:%M:%S')] 防火墙服务(firewalld)未运行,跳过防火墙配置。"
    fi

    echo "[$(date +'%Y-%m-%d %H:%M:%S')] 安装完成!"
    echo "请使用 'redis-cli -p $SENTINEL_PORT' 连接 Sentinel 并检查状态。"
    echo "例如: redis-cli -p $SENTINEL_PORT -a $REDIS_PASSWORD"
    echo "在 Sentinel CLI 中执行: SENTINEL masters"
}

# 卸载函数
uninstall() {
    echo "[$(date +'%Y-%m-%d %H:%M:%S')] 卸载Redis及相关文件..."
    # 停止服务
    stop
    # 删除文件
    rm -rf $REDIS_DIR $DATA_DIR $LOG_DIR
    echo "[$(date +'%Y-%m-%d %H:%M:%S')] 卸载完成!"
}

# 启动函数
start() {
    echo "[$(date +'%Y-%m-%d %H:%M:%S')] 启动Redis服务..."
    for PORT in $REDIS_PORT1 $REDIS_PORT2 $REDIS_PORT3; do
        redis-server $REDIS_DIR/redis-$PORT.conf || { echo "启动Redis实例 $PORT 失败"; exit 1; }
    done
    redis-sentinel $REDIS_DIR/sentinel.conf || { echo "启动Sentinel失败"; exit 1; }
    echo "[$(date +'%Y-%m-%d %H:%M:%S')] Redis服务已启动。"
}

# 停止函数
stop() {
    echo "[$(date +'%Y-%m-%d %H:%M:%S')] 停止Redis服务..."
    # 逐个杀死 Redis 实例
    for PORT in $REDIS_PORT1 $REDIS_PORT2 $REDIS_PORT3; do
        # 查找进程
        pids=$(ps aux | grep -E "redis-server.*127.0.0.1:$PORT|redis-server.*:$PORT" | grep -v grep | awk '{print $2}')
        if [ ! -z "$pids" ]; then
            echo "正在强制停止端口 $PORT 的 Redis 实例 (PID: $pids)..."
            # 直接发送 SIGKILL (-9),强制终止
            kill -9 $pids
        else
            echo "端口 $PORT 的 Redis 实例未找到。"
        fi
    done

    # 停止 Sentinel
    sentinel_pids=$(ps aux | grep "redis-sentinel" | grep -v grep | awk '{print $2}')
    if [ ! -z "$sentinel_pids" ]; then
        echo "正在强制停止 Sentinel (PID: $sentinel_pids)..."
        # 直接发送 SIGKILL (-9),强制终止
        kill -9 $sentinel_pids
    else
        echo "Sentinel 实例未找到。"
    fi
    echo "[$(date +'%Y-%m-%d %H:%M:%S')] Redis服务已停止。"
}

# 根据参数执行操作
case $1 in
    install)
        install
        ;;
    uninstall)
        uninstall
        ;;
    start)
        start
        ;;
    stop)
        stop
        ;;
    *)
        usage
        exit 1
        ;;
esac

重新运行: ./redis_sentinel_manager.sh install

验证:

第一步:确认进程都在跑

javascript 复制代码
ps -ef | grep redis
  • 3 个 Redis 实例(1 主 2 从)起来了。
  • 1 个 Sentinel 也起来了。 ✅ 服务启动成功!

第二步:连上 Sentinel,问它"主节点是谁?"

javascript 复制代码
redis-cli -p 26379
javascript 复制代码
SENTINEL get-master-addr-by-name mymaster

这说明:

  • Sentinel 正在监控一个叫 mymaster 的主节点。
  • 当前主节点是 127.0.0.1:6379。 ✅ 哨兵在正常工作!

第三步:写个数据,看能不能读到(功能测试)

1.连主节点写数据:

javascript 复制代码
redis-cli -p 6379

> AUTH redis123456
> SET name ldj
> exit

2.连从节点读数据:

javascript 复制代码
redis-cli -p 6380
> AUTH redis123456
> GET name

如果返回 "ldj",说明主从数据同步正常

补充:

部署方式(生产推荐)

方法 工具 说明
1. 容器化部署(推荐) Docker + Docker Compose / Kubernetes 用容器封装 Redis 和 Sentinel,配置集中管理,启动快,环境一致
2. 配置管理工具 Ansible / SaltStack / Puppet 编写 Playbook,一键在多台机器部署,保证配置一致性
3. 云服务商托管 阿里云 Redis / AWS ElastiCache / Azure Cache 完全托管,自动故障转移、备份、监控,最省心

补充:使用docker-compose 安装

redis-docker-compose.yml

javascript 复制代码
version: '3.8'

services:
  redis-master:
    image: redis:6.0
    container_name: redis-master
    command: ["redis-server", "/usr/local/etc/redis/redis.conf"]
    volumes:
      - ./redis-master.conf:/usr/local/etc/redis/redis.conf
      - redis-data-master:/data
    networks:
      - redis-net
    ports:
      - "6379:6379"

  redis-slave-1:
    image: redis:6.0
    container_name: redis-slave-1
    command: ["redis-server", "/usr/local/etc/redis/redis.conf"]
    volumes:
      - ./redis-slave-1.conf:/usr/local/etc/redis/redis.conf
      - redis-data-slave-1:/data
    networks:
      - redis-net
    ports:
      - "6380:6379"
    depends_on:
      - redis-master

  redis-slave-2:
    image: redis:6.0
    container_name: redis-slave-2
    command: ["redis-server", "/usr/local/etc/redis/redis.conf"]
    volumes:
      - ./redis-slave-2.conf:/usr/local/etc/redis/redis.conf
      - redis-data-slave-2:/data
    networks:
      - redis-net
    ports:
      - "6381:6379"
    depends_on:
      - redis-master

  sentinel-1:
    image: redis:6.0
    container_name: sentinel-1
    command: ["redis-sentinel", "/usr/local/etc/redis/sentinel.conf"]
    volumes:
      - ./sentinel-1.conf:/usr/local/etc/redis/sentinel.conf
    networks:
      - redis-net
    ports:
      - "26379:26379"
    depends_on:
      - redis-master

  sentinel-2:
    image: redis:6.0
    container_name: sentinel-2
    command: ["redis-sentinel", "/usr/local/etc/redis/sentinel.conf"]
    volumes:
      - ./sentinel-2.conf:/usr/local/etc/redis/sentinel.conf
    networks:
      - redis-net
    ports:
      - "26380:26379"
    depends_on:
      - redis-master

  sentinel-3:
    image: redis:6.0
    container_name: sentinel-3
    command: ["redis-sentinel", "/usr/local/etc/redis/sentinel.conf"]
    volumes:
      - ./sentinel-3.conf:/usr/local/etc/redis/sentinel.conf
    networks:
      - redis-net
    ports:
      - "26381:26379"
    depends_on:
      - redis-master

volumes:
  redis-data-master:
  redis-data-slave-1:
  redis-data-slave-2:

networks:
  redis-net:
    driver: bridge

配置文件示例

redis-master.conf

javascript 复制代码
port 6379
bind 0.0.0.0
protected-mode yes
appendonly yes
requirepass yourStrongPassword!
masterauth yourStrongPassword!

redis-slave-1.confredis-slave-2.confyunx

javascript 复制代码
port 6379
bind 0.0.0.0
protected-mode yes
appendonly yes
requirepass yourStrongPassword!
masterauth yourStrongPassword!
slaveof redis-master 6379

运行:

javascript 复制代码
docker-compose -f redis-docker-compose.yml up -d
相关推荐
曹牧31 分钟前
Oracle数据库中,将JSON字符串转换为多行数据
数据库·oracle·json
被摘下的星星1 小时前
MySQL count()函数的用法
数据库·mysql
末央&1 小时前
【天机论坛】项目环境搭建和数据库设计
java·数据库
徒 花1 小时前
数据库知识复习07
数据库·作业
素玥1 小时前
实训5 python连接mysql数据库
数据库·python·mysql
jnrjian1 小时前
text index 查看index column index定义 index 刷新频率 index视图
数据库·oracle
瀚高PG实验室2 小时前
审计策略修改
网络·数据库·瀚高数据库
言慢行善2 小时前
sqlserver模糊查询问题
java·数据库·sqlserver
韶博雅2 小时前
emcc24ai
开发语言·数据库·python
有想法的py工程师2 小时前
PostgreSQL 分区表排序优化:Append Sort 优化为 Merge Append
大数据·数据库·postgresql