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 哨兵集群有所帮助。如有任何问题,欢迎留言讨论!

相关推荐
虎头金猫2 天前
4K 视频总卡在公网带宽?用 N1 + OpenList 把网盘播放链路重新理顺
运维·服务器·网络·python·容器·beautifulsoup·pandas
分布式存储与RustFS2 天前
MinIO 官方 Docker 镜像被移除:依赖它的项目该怎么办
docker·云原生·devops·对象存储·minio·分布式存储
IT大白鼠2 天前
Redis 系列 · 第 01 篇——认知入门:Redis 是什么
redis·nosql
彧azz2 天前
Linux 环境下 Redis 学习总结:数据类型、持久化、锁、事务、主从与缓存问题
linux·redis·笔记·学习·面试
玉&心2 天前
通过Arthas在线诊断K8S中的内存及JVM等使用情况
docker·k8s·arthas
xing-xing2 天前
Docker容器中Nginx站点根目录网页配置访问
nginx·docker
赵文宇(温玉)2 天前
CoreDNS的hosts插件的缺行配置导致k8s集群异常
容器·kubernetes·rancher
guo_wen_qiang2 天前
上传本地镜像到harbor中
docker·容器·持续部署
羑悻的小杀马特2 天前
Dockerfile 全景指南:从入门编写dockerfile到生产环境镜像优化实战,一步步带你从啃透制作指令到镜像制作落地!
docker·dockerfile·镜像制作
BianHuanShiZhe2 天前
docker常见命令
docker