Docker实现

  1.第一步:搭建redis集群专用的docker网络

    

docker network create net-redis --subnet 172.23.0.0/16
# --subnet 它定义了网络内部容器可以使用的 IP 地址范围。

   2.第二步:构建redis.conf文件

  

#!/bin/bash

for port in $(seq 1 6);do
    mkdir -p /mydata/redis/node-${port}/conf
    touch /mydata/redis/node-${port}/conf/redis.conf
    cat << TTT > /mydata/redis/node-${port}/conf/redis.conf
port 6379 
bind 0.0.0.0
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
cluster-announce-ip 172.23.0.1${port}
cluster-announce-port 6379
cluster-announce-bus-port 16379
appendonly yes
TTT
done

  配置解释

  

port 6379:

含义: 指定 Redis 实例监听的端口号。
作用: 客户端通过这个端口连接到 Redis 服务器。
默认值: 6379
bind 0.0.0.0:

含义: 指定 Redis 实例监听的网络接口地址。
作用:
0.0.0.0 表示监听所有可用的网络接口。这意味着 Redis 实例可以接受来自任何 IP 地址的连接请求。 注意:在生产环境中,通常不建议使用 0.0.0.0,因为它会增加安全风险。 建议绑定到特定的内网 IP 地址。
默认值: 127.0.0.1 (只允许本地连接)
cluster-enabled yes:

含义: 启用 Redis 集群模式。
作用: 将 Redis 实例配置为集群模式的节点。
默认值: no (禁用集群模式)
cluster-config-file nodes.conf:

含义: 指定集群配置文件名。
作用: Redis 集群使用此文件来存储集群的配置信息,例如节点信息、槽位分配等。 此文件由 Redis 自动维护,不应手动修改。
默认值: 无 (如果没有启用集群模式,则不需要配置此项)
cluster-node-timeout 5000:

含义: 指定集群节点超时时间,单位为毫秒。
作用: 如果一个节点在指定的时间内没有收到来自其他节点的 ping 消息,则认为该节点已失效。
默认值: 15000 (15 秒)
cluster-announce-ip 172.23.0.1${port}:

含义: 指定集群节点对外公布的 IP 地址。
作用: 告知集群中的其他节点,本节点的IP地址是什么。
重点: 172.23.0.1${port}是一个模板字符串。 ${port}会被实际的端口号替换。所以,如果port变量是 6379,那么最终的地址会是 172.23.0.16379。 这几乎肯定是一个错误配置! 端口号不应该直接附加在IP地址后面。正确的配置应该是独立的设置端口。这个配置会导致节点无法正确加入集群。
cluster-announce-port 6379:

含义: 指定集群节点对外公布的客户端连接端口。
作用: 告知集群中的其他节点,本节点用于客户端连接的端口号。
默认值: 与 port 配置相同
cluster-announce-bus-port 16379:

含义: 指定集群节点间通信的总线端口。
作用: 集群节点之间使用此端口进行数据同步、故障转移等操作。 此端口通常是客户端连接端口 + 10000。
默认值: 与 port 配置的端口号 + 10000。
appendonly yes:

含义: 启用 AOF (Append Only File) 持久化。
作用: 将每个写命令追加到 AOF 文件中,以保证数据的持久性。 即使 Redis 服务器崩溃,也可以通过 AOF 文件恢复数据。
默认值: no (禁用 AOF 持久化)
总结和注意事项:

安全性: bind 0.0.0.0 在生产环境中存在安全风险,应该绑定到特定的内网 IP 地址。
cluster-announce-ip: cluster-announce-ip 172.23.0.1${port} 绝对是错误的。${port}会被直接追加到IP地址后,生成一个无效的地址。正确的配置方式是不使用模板字符串,直接指定一个有效的IP地址,或者使用环境变量替换,但要确保替换后的结果是有效的IP地址。 cluster-announce-ip的作用非常重要,它告诉其他节点如何连接到当前节点。
端口: 确保客户端连接端口 (cluster-announce-port) 和集群总线端口 (cluster-announce-bus-port) 没有被防火墙阻止。
持久化: appendonly yes 启用 AOF 持久化可以保证数据的持久性,但会影响性能。 可以根据实际需求选择 AOF 或 RDB 持久化方式,或者同时启用两种持久化方式。

  第三步:启动容器

#!/bin/bash

for port in $(seq 1 6); do
docker run -p 637${port}:6379 -p 1637${port}:16379 --name redis-${port} -v /mydata/redis/node-${port}/data:/data -v /mydata/redis/node-${port}/conf/redis.conf:/etc/redis/redis.conf -d --net net-redis --ip 172.23.0.1${port} redis redis-server /etc/redis/redis.conf
done
echo "Redis docker generated successfully."

  第四步:进入到任意一个容器内,进入该容器的redis客户端中执行创建集群的命令

  

docker exec -it redis-1 /bin/bash

redis-cli --cluster create 172.23.0.11:6379 172.23.0.12:6379 172.23.0.13:6379 172.23.0.14:6379 172.23.0.15:6379 172.23.0.16:6379  --cluster-replicas 1


# 参数解释
  • --cluster-replicas 1 参数告诉 redis-cli 在创建集群时,为每个主节点创建一个副本节点。

由于你提供了 6 个节点,redis-cli 会自动将它们组织成 3 个主节点和 3 个副本节点。 具体分配是:

  1. 172.23.0.11:6379 是主节点, 172.23.0.12:6379 是它的副本。
  2. 172.23.0.13:6379 是主节点, 172.23.0.14:6379 是它的副本。
  3. 172.23.0.15:6379 是主节点, 172.23.0.16:6379 是它的副本。

redis-cli 会尽可能地均匀分配槽给各个主节点。 副本节点不存储任何槽的分配信息,它们只是简单地复制主节点的数据。

总结:

--cluster-replicas 参数控制着集群中主节点和副本节点的比例。 如果你设置 --cluster-replicas 0,那么就不会创建任何副本节点,所有节点都将成为主节点。

如果你的目标是创建更多的主节点而不是副本,你需要使用不同的节点组合来创建集群,或者直接手动添加节点到现有的集群。 请注意,redis集群节点数量最好是奇数,避免脑裂。

  步骤成功的图片

   如何查看节点角色:

  

redis-cli -h 172.23.0.11 -p 6379 cluster nodes

 

  至此三主三从的redis节点搭建完毕

常见疑问点:

一.单主多从和多主多从的区别

多主多从的 Redis 集群架构相比于单主多从的架构,主要优势体现在以下几个方面:

1. 扩展性(Scalability):

  • 水平扩展: 多主架构允许通过增加主节点来水平扩展集群的容量。 单主架构的写入性能受到单个主节点的限制,而多主架构可以将写入负载分散到多个主节点上,从而提高整体写入吞吐量。
  • 更高的吞吐量: 更多的节点参与数据处理,显著提高读写吞吐量。

2. 性能(Performance):

  • 写入性能: 如上所述,多主架构可以分散写入负载,提高整体写入性能。
  • 并发处理能力: 多主架构能够并发处理更多的客户端请求,降低延迟。

3. 高可用性(High Availability):

  • 更强的容错能力: 如果一个主节点宕机,只有其负责的槽会受到影响,其他主节点仍然可以继续提供服务。 单主架构中,如果主节点宕机,整个集群的写入服务都会中断,直到故障转移完成。
  • 更快的故障恢复: 多主架构中,每个主节点只需要处理一部分槽的故障转移,因此故障恢复速度更快。

4. 资源利用率(Resource Utilization):

  • 更均衡的资源利用: 多主架构可以将负载分散到多个节点上,从而更均衡地利用集群中的资源。 单主架构中,主节点的负载较高,而副本节点的负载较低。

总结:

  • 多主多从的 Redis 集群更适合需要高扩展性、高性能和高可用性的场景。 它可以处理更大的数据量,支持更高的并发访问,并且具有更强的容错能力。
  • 单主多从的 Redis 架构更适合读多写少的场景,或者数据量较小,对扩展性和可用性要求不高的场景。 它的配置和管理相对简单。

更详细的对比:

特性单主多从多主多从
扩展性 有限,受单个主节点限制 高,可以通过增加主节点水平扩展
性能 读性能好,写性能受主节点限制 读写性能均好,可以分散写入负载
可用性 主节点宕机影响所有写入服务,故障转移时间长 主节点宕机只影响部分槽,故障转移时间短
资源利用率 主节点负载高,从节点负载低 资源利用更均衡
复杂性 简单 相对复杂
适用场景 读多写少,数据量小,对扩展性和可用性要求不高 高并发,大数据量,对扩展性和可用性要求高

选择建议:

在选择 Redis 架构时,需要根据实际业务需求进行权衡。 如果你的业务需要处理大量的数据和高并发的访问,并且对可用性有很高的要求,那么 Redis 集群(多主多从)是更好的选择。 如果你的业务数据量较小,并发访问量不高,并且可以容忍一定的故障恢复时间,那么单主多从的 Redis 架构可能更适合你

 二、多住多从有哨兵机制吗?

没有。 Redis 集群(多主多从)本身就内置了故障检测和自动故障转移机制,不需要额外的哨兵(Sentinel)。

原因:

  • 集群节点间的 Gossip 协议: Redis 集群使用 Gossip 协议进行节点间的通信,每个节点都会定期与其他节点交换信息,包括节点的状态、角色、负责的槽等。 通过这种方式,集群中的每个节点都能了解集群的整体状态。
  • 内置的故障检测机制: 每个节点都会定期 ping 其他节点,如果一个节点在一定时间内没有收到另一个节点的回复,它会将该节点标记为 PFAIL(Possible Fail,可能失效)。 如果集群中有足够多的节点都认为该节点失效,该节点会被标记为 FAIL(Fail,失效)。
  • 自动故障转移: 当一个主节点被标记为 FAIL 时,其副本节点会参与故障转移的投票过程。 得票数最多的副本节点会被提升为新的主节点,并接管原主节点负责的槽。 这个过程是自动进行的,不需要人工干预。

与哨兵的区别:

  • 哨兵: 是独立的进程,用于监控 Redis 主节点的健康状态,并在主节点宕机时自动进行故障转移。
  • Redis 集群: 故障检测和故障转移机制内置在集群节点中,不需要额外的进程。

总结:

Redis 集群自带故障检测和自动故障转移功能,已经提供了高可用性,所以不需要再使用哨兵。 两者是互斥的。 你要么使用 Redis 集群,要么使用哨兵来监控 Redis 主从复制架构。 同时使用 Redis 集群和哨兵是多余的,而且可能会导致冲突。

为什么不需要哨兵?

Redis 集群的设计目标之一就是提供高可用性,而其内置的故障检测和自动故障转移机制已经能够很好地满足这一需求。 使用哨兵会增加系统的复杂性,并且可能会引入额外的故障点。 因此,Redis 集群的设计者选择将故障检测和故障转移机制集成到集群节点中,从而简化了系统的架构。

注意:

如果你在使用 Redis 集群,并且之前配置了哨兵,应该移除哨兵配置,以避免冲突。

三、多主多从应该如何查询数据呢?

在多主多从的 Redis 集群中查询数据,你需要一个客户端能够感知 Redis 集群拓扑,并能够根据 Key 自动路由到正确的主节点上。 你不需要手动去查找数据位于哪个主节点。

以下是几种常见的查询数据的方式和原理:

1. 使用支持集群的客户端:

这是最推荐也是最常见的方式。 大部分主流编程语言的 Redis 客户端都提供了对 Redis 集群的支持。 这些客户端能够自动地进行如下操作:

  • 集群拓扑发现: 客户端会连接到集群中的一个或多个节点,然后通过 CLUSTER NODES 命令获取整个集群的拓扑信息,包括每个节点的地址、角色、负责的槽等。
  • Key 的哈希槽计算: 客户端会根据你要查询的 Key 使用一定的哈希算法(默认为 CRC16)计算出 Key 对应的哈希槽(Slot)。 Redis 集群将整个 Key 空间划分为 16384 个哈希槽。
  • 路由到正确的节点: 客户端会根据 Key 的哈希槽,找到负责该槽的主节点,然后将查询请求发送到该节点。
  • 重定向处理 (MOVED 和 ASK): 如果客户端发送请求到错误的节点,Redis 节点会返回 MOVED 或 ASK 错误。
    • MOVED 表示 Key 的哈希槽已经迁移到另一个节点,客户端会更新其拓扑信息,然后将请求发送到新的节点。
    • ASK 表示 Key 的哈希槽正在迁移到另一个节点,客户端会先向目标节点发送 ASKING 命令,然后将请求发送到目标节点。

示例 (Python with redis-py-cluster):

from rediscluster import RedisCluster

# 集群的启动节点
startup_nodes = [{"host": "127.0.0.1", "port": "7000"},
                 {"host": "127.0.0.1", "port": "7001"},
                 {"host": "127.0.0.1", "port": "7002"}]

# 创建集群客户端
rc = RedisCluster(startup_nodes=startup_nodes, decode_responses=True)

# 设置键值对
rc.set("mykey", "myvalue")

# 获取键值对
value = rc.get("mykey")
print(value)  # 输出: myvalue

 

在这个例子中,你只需要指定集群的启动节点,客户端会自动发现整个集群的拓扑,并根据 Key "mykey" 找到负责该 Key 的主节点,然后执行 set 和 get 操作。 你不需要关心 Key 位于哪个主节点。

2. 手动计算哈希槽并连接到对应的节点 (不推荐):

这种方式非常麻烦,不推荐使用。 你需要手动计算 Key 的哈希槽,然后根据集群的拓扑信息找到负责该槽的主节点,最后连接到该节点并执行查询。 这种方式容易出错,而且需要手动处理重定向等问题。

具体步骤如下:

  1. 获取集群拓扑: 使用 CLUSTER NODES 命令连接到集群中的一个节点,获取集群的拓扑信息。
  2. 计算哈希槽: 使用 CRC16 算法计算 Key 的哈希值,然后对 16384 取模,得到 Key 的哈希槽。 slot = crc16(key) % 16384
  3. 找到对应的节点: 根据哈希槽,从集群拓扑信息中找到负责该槽的主节点。
  4. 连接到节点并查询: 连接到该主节点,并执行查询操作。
  5. 处理重定向: 如果收到 MOVED 或 ASK 错误,需要更新拓扑信息,并按照错误信息中的指示重定向到新的节点。

为什么不推荐手动计算哈希槽?

  • 复杂性: 手动计算哈希槽和处理重定向逻辑非常复杂,容易出错。
  • 维护困难: 集群拓扑可能会动态变化,手动维护拓扑信息非常困难。
  • 性能损失: 手动计算哈希槽和处理重定向逻辑会带来额外的性能开销。

总结:

使用支持集群的客户端是查询 Redis 集群数据的最佳方式。 客户端会自动处理集群拓扑发现、Key 的哈希槽计算、路由和重定向等问题,你只需要像使用单机 Redis 一样使用客户端即可。 避免手动计算哈希槽和连接到对应的节点,因为这会增加复杂性和维护成本。

 

posted on 2025-03-22 12:47  輪滑少年  阅读(187)  评论(0)    收藏  举报