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

发布于:2025-08-02 ⋅ 阅读:(13) ⋅ 点赞:(0)

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

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

+-------------------+      +-------------------+      +-------------------+
|  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

 

#!/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

验证:

 第一步:确认进程都在跑

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

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

redis-cli -p 26379
SENTINEL get-master-addr-by-name mymaster

这说明:

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

 

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

1.连主节点写数据:

redis-cli -p 6379

> AUTH redis123456
> SET name ldj
> exit

2.连从节点读数据: 

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

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

port 6379
bind 0.0.0.0
protected-mode yes
appendonly yes
requirepass yourStrongPassword!
masterauth yourStrongPassword!

redis-slave-1.conf 和 redis-slave-2.confyunx

port 6379
bind 0.0.0.0
protected-mode yes
appendonly yes
requirepass yourStrongPassword!
masterauth yourStrongPassword!
slaveof redis-master 6379

运行:

docker-compose -f redis-docker-compose.yml up -d