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: 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)配置:
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 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 地址。修改如下:
    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 哨兵集群有所帮助。如有任何问题,欢迎留言讨论!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/947455.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

数据结构:时间复杂度和空间复杂度

我们知道代码和代码之间算法的不同,一定影响了代码的执行效率,那么我们该如何评判算法的好坏呢?这就涉及到了我们算法效率的分析了。 📖一、算法效率 所谓算法效率的分析分为两种:第一种时间效率,又称时间…

《Vue3实战教程》39:Vue3无障碍访问

如果您有疑问,请观看视频教程《Vue3实战教程》 无障碍访问​ Web 无障碍访问 (也称为 a11y) 是指创建可供任何人使用的网站的做法——无论是身患某种障碍、通过慢速的网络连接访问、使用老旧或损坏的硬件,还是仅处于某种不方便的环境。例如,…

GESP2024年6月认证C++五级( 第三部分编程题(1)黑白格)

参考程序&#xff08;二维前缀和&#xff09; #include <iostream> #include <vector> #include <algorithm> using namespace std;int main() {int n, m, k;cin >> n >> m >> k;// 输入网格图vector<vector<int>> grid(n, v…

二、SQL语言,《数据库系统概念》,原书第7版

文章目录 一、概览SQL语言1.1 SQL 语言概述1.1.1 SQL语言的提出和发展1.1.2 SQL 语言的功能概述 1.2 利用SQL语言建立数据库1.2.1 示例1.2.2 SQL-DDL1.2.2.1 CREATE DATABASE1.2.2.2 CREATE TABLE 1.2.3 SQL-DML1.2.3.1 INSERT INTO 1.3 用SQL 语言进行简单查询1.3.1 单表查询 …

js按日期按数量进行倒序排序,然后再新增一个字段,给这个字段赋值 10 到1

效果如下图&#xff1a; 实现思路&#xff1a; 汇总数据&#xff1a;使用 reduce 方法遍历原始数据数组&#xff0c;将相同日期的数据进行合并&#xff0c;并计算每个日期的总和。创建日期映射&#xff1a;创建一个映射 dateMap&#xff0c;存储每个日期的对象列表。排序并添加…

用uniapp写一个播放视频首页页面代码

效果如下图所示 首页有导航栏&#xff0c;搜索框&#xff0c;和视频列表&#xff0c; 导航栏如下图 搜索框如下图 视频列表如下图 文件目录 视频首页页面代码如下 <template> <view class"video-home"> <!-- 搜索栏 --> <view class…

【three.js】光源

光源 光源特点 当使用MeshLambertMaterial材质时&#xff0c;会受到光线的影响&#xff0c; 我们代码里面如果没有设置光线&#xff0c;则使用MeshLambertMaterial材质修饰的模型不可见&#xff0c;这个时候&#xff0c;我们添加光线后&#xff0c;便可以看见。 环境光 定义&a…

U8G2库使用案例(stm32)

U8G2官网&#xff1a; 自己移植的U8g2库&#xff0c;OLED库超好用&#xff0c;自己封装了用户层不需要再去查资料使用&#xff0c;注释写的很多很详细&#xff0c;有示例上手就会&#xff0c;初始化也很简单 个人移植的U8g2库&#xff1a; 超简单的stm32 U8g2移植 大家可以自…

Linux 上安装 PostgreSQL

文章目录 前言一、安装PostgreSQL二、修改数据库默认数据存储目录 1.自定义数据存放目录2.修改自定义服务3.初始化数据库4.运行数据库 三、配置数据库信息 四、权限 异常处理 前言 提示&#xff1a;本次博客是centos7.9安装PostgreSQL12版本 名称 版本 Centos 7.9 postg…

HTML——56.表单发送

<!DOCTYPE html> <html><head><meta charset"UTF-8"><title>表单发送</title></head><body><!--注意&#xff1a;1.表单接收程序&#xff0c;放在服务器环境中(也就是这里的www文件目录中)2.表单发送地址&#x…

logback之pattern详解以及源码分析

目录 &#xff08;一&#xff09;pattern关键字介绍 &#xff08;二&#xff09;源码分析 &#xff08;一&#xff09;pattern关键字介绍 %d或%date&#xff1a;表示日期&#xff0c;可配置格式化%d{yyyy-MM-dd HH:mm:ss} %r或%relative&#xff1a;也是日期&#xff0c;不过…

vLLM结构化输出(Guided Decoding)

简介 vLLM 的结构化输出特性是通过“引导式解码”&#xff08;Guided Decoding&#xff09;实现的&#xff0c;这一功能允许模型在生成文本时遵循特定的格式约束&#xff0c;例如 JSON 模式或正则表达式&#xff0c;从而确保生成的内容符合预期的结构化要求。 后端引擎 启动…

CM3/CM4时钟系统

CM3/4时钟系统 1. CM3时钟系统1.1 输入时钟源------------------A1.2 锁相环PLL------------------B1.3 系统时钟SYSCLK--------C/D/E/F/G 2. CM4时钟系统2.1 输入时钟源------------------A2.2 锁相环PLL------------------B2.3 系统时钟SYSCLK--------C/D/E2.4 时钟信号输出M…

RabbitMQ实现生产者消费者

一.启动MQ 注意管理员身份进入cmd才行,我这里是在本地安装的MQ,推荐使用虚拟机安装 二.思路 官方解释RabbitMQ结构: 自我理解RabbitMQ结构: 其实RabbitMQ的服务器就像邮局一样,我们的生产者和消费者对于这个服务器来说都是消费者,因为服务器都可以向两者发送消息 环境准备 …

MySQL--》如何在SQL中巧妙运用函数与约束,优化数据处理与验证?

目录 函数使用 字符串函数 数值函数 日期函数 流程函数 约束 外键约束 约束规则 函数使用 函数是指一段可以直接被另一段程序调用的程序或代码&#xff0c;在mysql当中有许多常见的内置函数&#xff0c;接下来开始对这些内置函数及其作用进行简单的讲解和使用&#xf…

OpenLinkSaas使用手册-待办事项和通知中心

在OpenLinkSaas工作台上&#xff0c;你可以查看待办事项和未读通知。 待办事项 目前待办事项支持: 个人待办项目待办:在项目中指派给你的任务/缺陷Git待办:在Git仓库中指标给你的Issue,目前只有在AtomGit和Gitee账号登录时才支持。 通知中心 通知中心支持Git通知和邮件通知两种…

【Unity】 HTFramework框架(五十八)【进阶篇】资源及代码热更新实战演示(Deployment + HybridCLR)

更新日期&#xff1a;2025年1月2日。 Github源码&#xff1a;[点我获取源码] 索引 资源及代码热更新实战演示运行演示Demo1.克隆项目工程2.更新子模块3.打开项目4.打开入口场景5.设置远端资源服务器地址6.导入HybridCLR7.初始化HybridCLR8.发布项目9.部署资源版本10.运行Exe11.…

路由基本配置实验

路由器用于实现不同类型网络之间的互联。 路由器转发ip分组的基础是路由表。 路由表中的路由项分为直连路由项、静态路由项和动态路由项。 通过配置路由器接口的ip地址和子网掩码自动生成直连路由项。 通过手工配置创建静态路由项。 热备份路由器协议允许将由多个路由器组…

CTFshow—远程命令执行

29-35 Web29 代码利用正则匹配过滤了flag&#xff0c;后面加了/i所以不区分大小写。 可以利用通配符绕过 匹配任何字符串&#xff0f;文本&#xff0c;包括空字符串&#xff1b;*代表任意字符&#xff08;0个或多个&#xff09; ls file * ? 匹配任何一个字符&#xff08;不…

idea 的 springboot项目spring-boot-devtools 自动编译 配置热部署

1&#xff0c;设置一 2&#xff0c;设置二 设置二&#xff08;旧版本&#xff09; CtrlShiftAlt/ 点击弹出框中Registry... 引入&#xff08;如果报错&#xff0c;换不同的版本&#xff09; <dependency><groupId>org.springframework.boot</groupId><a…