Docker 环境中搭建 Redis 哨兵模式集群的步骤与问题解决

在 Docker 环境中搭建 Redis 哨兵模式集群的步骤与问题解决

在 Redis 高可用架构中,哨兵模式(Sentinel)是确保 Redis 集群在出现故障时自动切换主节点的一种机制。通过使用 Redis 哨兵,我们可以实现 Redis 集群的监控、故障检测和自动故障转移。在本篇文章中,我将带大家了解如何在 Docker 环境中搭建一个 Redis 哨兵模式集群,并解决在连接时遇到的一些问题。

一、准备工作
  1. Docker 环境

    首先确保你的机器已经安装并配置了 Docker 和 Docker Compose。

  2. 网络配置

    我们将创建一个 Docker 网络,用于 Redis 集群中的容器间通信。在 Docker Compose 配置文件中,我们使用了 bridge 网络模式,并且为容器分配了静态 IP 地址,以确保容器间的稳定连接。

二、Docker Compose 配置文件

我们将通过 Docker Compose 部署 Redis 集群。以下是 docker-compose.yml 文件的配置内容:

yaml 复制代码
version: "3"

networks:
  redis-replication:
    driver: bridge
    ipam:
      config:
        - subnet: 172.25.0.0/24

services:
  master:
    image: redis
    container_name: redis-master
    ports:
      - "6371:6379"
    volumes:
      - "./master/redis.conf:/etc/redis.conf"
      - "./master/data:/data"
    command: ["redis-server", "/etc/redis.conf"]
    restart: always
    networks:
      redis-replication:
        ipv4_address: 172.25.0.101

  slave1:
    image: redis
    container_name: redis-slave-1
    ports:
      - "6372:6379"
    volumes:
      - "./slave1/redis.conf:/etc/redis.conf"
      - "./slave1/data:/data"
    command: ["redis-server", "/etc/redis.conf"]
    restart: always
    networks:
      redis-replication:
        ipv4_address: 172.25.0.102

  slave2:
    image: redis
    container_name: redis-slave-2
    ports:
      - "6373:6379"
    volumes:
      - "./slave2/redis.conf:/etc/redis.conf"
      - "./slave2/data:/data"
    command: ["redis-server", "/etc/redis.conf"]
    restart: always
    networks:
      redis-replication:
        ipv4_address: 172.25.0.103

  sentinel1:
    image: redis
    container_name: redis-sentinel-1
    ports:
      - "26380:26379"
    volumes:
      - "./sentinel1/sentinel.conf:/etc/sentinel.conf"
    command: ["/bin/bash", "-c", "cp /etc/sentinel.conf /sentinel.conf && redis-sentinel /sentinel.conf"]
    restart: always
    networks:
      redis-replication:
        ipv4_address: 172.25.0.201

  sentinel2:
    image: redis
    container_name: redis-sentinel-2
    ports:
      - "26381:26379"
    volumes:
      - "./sentinel2/sentinel.conf:/etc/sentinel.conf"
    command: ["/bin/bash", "-c", "cp /etc/sentinel.conf /sentinel.conf && redis-sentinel /sentinel.conf"]
    restart: always
    networks:
      redis-replication:
        ipv4_address: 172.25.0.202

  sentinel3:
    image: redis
    container_name: redis-sentinel-3
    ports:
      - "26382:26379"
    volumes:
      - "./sentinel3/sentinel.conf:/etc/sentinel.conf"
    command: ["/bin/bash", "-c", "cp /etc/sentinel.conf /sentinel.conf && redis-sentinel /sentinel.conf"]
    restart: always
    networks:
      redis-replication:
        ipv4_address: 172.25.0.203

在这个配置文件中,我们部署了:

1 个 Redis 主节点(master)。

2 个 Redis 从节点(slave1 和 slave2)。

3 个 Redis 哨兵节点(sentinel1、sentinel2、sentinel3)。

每个 Redis 容器都有单独的配置文件,并通过 volumes 映射到宿主机。我们使用了 Docker 的 bridge 网络模式,并为每个容器分配了静态 IP 地址,确保容器之间能够稳定通信。

三、Redis 配置文件

配置文件目录结构如下:

redis-sentinel-cluster/
├── docker-compose.yml
├── master/
│   └── redis.conf             
├── slave1/
│   └── redis.conf             # Redis 从节点配置文件
├── slave2/
│   └── redis.conf             # Redis 从节点配置文件
├── sentinel1/
│   └── sentinel.conf          # Redis Sentinel 配置文件
├── sentinel2/
│   └── sentinel.conf          # Redis Sentinel 配置文件
├── sentinel3/
│   └── sentinel.conf          # Redis Sentinel 配置文件
└── data/                       # 数据目录,用于持久化 Redis 数据

每个 Redis 节点都需要配置相应的配置文件,以下是关键配置内容:

  1. 主节点(Master)配置:
bash 复制代码
port 6379
protected-mode no
slave-serve-stale-data yes
replicaof no one
appendonly yes
  1. 从节点(Slave)配置(2个slave配置文件一致):
bash 复制代码
port 6379
bind 0.0.0.0
protected-mode no
replicaof 172.25.0.101 6379
appendonly yes
dir /data
  1. 哨兵(Sentinel)配置(3个sentinel配置文件一致):
bash 复制代码
sentinel monitor mymaster 10.28.145.144 6371 2
sentinel parallel-syncs mymaster 1
sentinel down-after-milliseconds mymaster 30000
sentinel failover-timeout mymaster 180000

注意:在哨兵的配置中,我们指定了主节点的 IP 地址为 10.28.145.144(即本机地址)以及映射的端口 6371。

四、启动服务

bash 复制代码
docker-compose up -d
bash 复制代码
docker-compose ps

四、遇到的问题

连接哨兵集群的代码:

go 复制代码
package main

import (
	"context"
	"fmt"

	"log"
	"time"

	"github.com/go-redis/redis/v8"
)

var rdb *redis.Client

func main() {
	// 定义 Redis 哨兵集群的地址
	sentinelAddrs := []string{
		"127.0.0.1:26380",
		"127.0.0.1:26381",
		"127.0.0.1:26382",
	}

	// 配置 Redis 哨兵模式连接
	options := &redis.FailoverOptions{
		MasterName:    "mymaster",    // 设定主节点名字
		SentinelAddrs: sentinelAddrs, // 哨兵地址
		Password:      "",            // 设置密码(如果有)
		DB:            0,             // 数据库索引
	}

	// 创建 Redis 客户端
	rdb = redis.NewFailoverClient(options)

	// 测试连接
	ctx, cancel := context.WithTimeout(context.Background(), 25*time.Second)
	defer cancel()

	_, err := rdb.Ping(ctx).Result()
	if err != nil {
		log.Fatalf("无法连接到 Redis 哨兵集群: %v", err)
	}

	fmt.Println("成功连接到 Redis 哨兵集群")

	// 执行其他 Redis 操作
	setAndGet(ctx)
}

func setAndGet(ctx context.Context) {
	// 示例:设置键值对并获取
	err := rdb.Set(ctx, "mykey", "Hello Redis!", 0).Err()
	if err != nil {
		log.Fatalf("无法设置键值对: %v", err)
	}

	val, err := rdb.Get(ctx, "mykey").Result()
	if err != nil {
		log.Fatalf("无法获取键值对: %v", err)
	}

	fmt.Printf("获取的值: %s\n", val)
}

在进行 Redis 哨兵集群连接时,遇到了以下问题:

  1. 问题描述:
    在尝试通过 Go 语言客户端连接 Redis 哨兵集群时,报错信息为:

    redis: 2025/01/03 09:58:07 sentinel.go:700: sentinel: discovered new sentinel="172.25.0.202:26379" for master="mymaster"
    redis: 2025/01/03 09:58:07 sentinel.go:700: sentinel: discovered new sentinel="172.25.0.203:26379" for master="mymaster"
    redis: 2025/01/03 09:58:07 sentinel.go:661: sentinel: new master="mymaster" addr="172.25.0.101:6379"
    2025/01/03 09:58:32 无法连接到 Redis 哨兵集群: context deadline exceeded

经过分析,发现错误是由于 Go 客户端连接 Redis 哨兵集群时,Redis 哨兵返回的主节点地址是 Docker 内部的 IP 地址(例如:172.25.0.101:6379),而 Go 客户端无法直接连接该地址。

  1. 原因分析:
    由于容器内的 IP 地址在宿主机和外部环境中不可访问,因此客户端无法通过这些 IP 地址与 Redis 集群进行通信。为了确保 Redis 哨兵能够返回宿主机可以访问的 IP 地址,我们需要在 Redis 配置和 Sentinel 配置中做一些调整。

五、问题解决方案

为了解决以上问题,我们需要确保 Redis 哨兵返回正确的主节点 IP 地址。以下是解决方案:

  1. 修改 Sentinel 配置:
    在 Sentinel 的配置中,将主节点的 IP 地址改为宿主机的 IP 地址。修改如下:

    bash 复制代码
    sentinel monitor mymaster 10.28.145.144 6371 2

这样,Redis 哨兵就会将主节点的地址返回为宿主机的 IP 地址,从而使客户端能够正确连接到 Redis 集群。

注意:此处只是临时解决方案,如果这样强制写死,虽然能正常访问,但哨兵集群发生故障迁移时,仍然会出现这个问题,最终解决方案待更新。

六、总结

通过 Docker 部署 Redis 哨兵集群,可以轻松实现 Redis 的高可用性。然而,在容器化环境下,尤其是 Docker 桥接网络模式中,我们需要特别注意容器之间的通信和外部访问。在本文中,我们分析了在连接 Redis 哨兵集群时遇到的网络问题,并给出了有效的解决方案。通过调整 Sentinel 配置,将主节点的 IP 地址设置为宿主机的 IP 地址,解决了客户端无法连接 Redis 集群的问题。最终,我们成功实现了 Docker 环境下 Redis 哨兵模式集群的高可用部署。希望本文对你在 Docker 环境下搭建 Redis 哨兵集群有所帮助。如有任何问题,欢迎留言讨论!

相关推荐
希忘auto4 小时前
详解Redis在Centos上的安装
redis·centos
Bright16684 小时前
centos9安装k8s集群
云原生·容器·kubernetes
!!!5255 小时前
华为云镜像加速器
docker·容器·华为云
xidianjiapei0016 小时前
Kubernetes的Ingress 资源是什么?
云原生·容器·kubernetes
sszdzq8 小时前
Docker
运维·docker·容器
dmy8 小时前
docker 快速构建开发环境
后端·docker·容器
逻各斯9 小时前
redis中的Lua脚本,redis的事务机制
java·redis·lua
土豆沒加9 小时前
K8S的Dashboard登录及验证
云原生·容器·kubernetes
终端行者11 小时前
kubernetes1.28部署mysql5.7主从同步,使用Nfs制作持久卷存储,适用于centos7/9操作系统,
数据库·容器·kubernetes
2401_8979300611 小时前
linux系统如何配置host.docker.internal
linux·docker·eureka