当前位置: 首页 > news >正文

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 文件的配置内容:

version: "3"networks:redis-replication:driver: bridgeipam:config:- subnet: 172.25.0.0/24services:master:image: rediscontainer_name: redis-masterports:- "6371:6379"volumes:- "./master/redis.conf:/etc/redis.conf"- "./master/data:/data"command: ["redis-server", "/etc/redis.conf"]restart: alwaysnetworks:redis-replication:ipv4_address: 172.25.0.101slave1:image: rediscontainer_name: redis-slave-1ports:- "6372:6379"volumes:- "./slave1/redis.conf:/etc/redis.conf"- "./slave1/data:/data"command: ["redis-server", "/etc/redis.conf"]restart: alwaysnetworks:redis-replication:ipv4_address: 172.25.0.102slave2:image: rediscontainer_name: redis-slave-2ports:- "6373:6379"volumes:- "./slave2/redis.conf:/etc/redis.conf"- "./slave2/data:/data"command: ["redis-server", "/etc/redis.conf"]restart: alwaysnetworks:redis-replication:ipv4_address: 172.25.0.103sentinel1:image: rediscontainer_name: redis-sentinel-1ports:- "26380:26379"volumes:- "./sentinel1/sentinel.conf:/etc/sentinel.conf"command: ["/bin/bash", "-c", "cp /etc/sentinel.conf /sentinel.conf && redis-sentinel /sentinel.conf"]restart: alwaysnetworks:redis-replication:ipv4_address: 172.25.0.201sentinel2:image: rediscontainer_name: redis-sentinel-2ports:- "26381:26379"volumes:- "./sentinel2/sentinel.conf:/etc/sentinel.conf"command: ["/bin/bash", "-c", "cp /etc/sentinel.conf /sentinel.conf && redis-sentinel /sentinel.conf"]restart: alwaysnetworks:redis-replication:ipv4_address: 172.25.0.202sentinel3:image: rediscontainer_name: redis-sentinel-3ports:- "26382:26379"volumes:- "./sentinel3/sentinel.conf:/etc/sentinel.conf"command: ["/bin/bash", "-c", "cp /etc/sentinel.conf /sentinel.conf && redis-sentinel /sentinel.conf"]restart: alwaysnetworks: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)配置:
port 6379
protected-mode no
slave-serve-stale-data yes
replicaof no one
appendonly yes
  1. 从节点(Slave)配置(2个slave配置文件一致):
port 6379
bind 0.0.0.0
protected-mode no
replicaof 172.25.0.101 6379
appendonly yes
dir /data
  1. 哨兵(Sentinel)配置(3个sentinel配置文件一致):
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。

四、启动服务

docker-compose up -d

启动容器

docker-compose ps

在这里插入图片描述

四、遇到的问题

连接哨兵集群的代码:

package mainimport ("context""fmt""log""time""github.com/go-redis/redis/v8"
)var rdb *redis.Clientfunc 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 地址。修改如下:
    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 哨兵集群有所帮助。如有任何问题,欢迎留言讨论!

http://www.lryc.cn/news/516157.html

相关文章:

  • 【网页自动化】篡改猴入门教程
  • 【顶刊TPAMI 2025】多头编码(MHE)之极限分类 Part 4:MHE表示能力
  • Github - unexpected disconnect while reading sideband packet
  • Ubuntu 环境安装 之 RabbitMQ 快速入手
  • UE5中实现右键开镜效果
  • Apache HTTPD 换行解析漏洞(CVE-2017-15715)
  • Excel重新踩坑5:二级下拉列表制作;★数据透视表;
  • 力扣--35.搜索插入位置
  • C# 设计模式(行为型模式):模板方法模式
  • Leetcode打卡:设计一个ATM机器
  • 【TCP】SYN、ACK、FIN、RST、PSH、URG的全称
  • 【OceanBase】使用 Superset 连接 OceanBase 数据库并进行数据可视化分析
  • 【通识安全】应急救护常识23则
  • C语言:cJSON将struct结构体与JSON互相转换
  • 在Linux中,如何查看和修改网络接口配置?
  • 使用深度学习来实现图像超分辨率 综述!
  • 基于深度学习的视觉检测小项目(六) 项目的信号和变量的规划
  • 【Android项目学习】3. MVVMHabit
  • 在Linux中,如何配置负载均衡器以分配网络流量?
  • 手机投屏到电视的3种选择:无线本地投屏,无线远程投屏,AirPlay投屏
  • MySQL关联关系理论与实践
  • 多模态论文笔记——U-ViT(国内版DiT)
  • 在 IntelliJ IDEA 中开发 GPT 自动补全插件
  • 7. C语言 运算符详解
  • Java四大常用JSON解析性能对比:Hutool、Fastjson2、Gson与Jackson测试
  • Qt 5.14.2 学习记录 —— 일 新项目
  • uni-app:实现普通选择器,时间选择器,日期选择器,多列选择器
  • Unity3D仿星露谷物语开发17之空库存栏UI
  • QT------模型/视图
  • Git - 记录一次由于少输入了一个命令导致的更改丢失