Redis-Cluster模式设计[二]
# 2. Ambari 中的 Redis 高可用设计元素
Ambari 对 Redis 集群的高可用运维做了系统性的集成,通过自动化脚本与节点反亲和策略,实现主从分离、分布式容错和集群弹性扩缩容。下面结合表格、代码和设计要点进行逐步拆解。
# 2.1 主从组件的分割与布局
Redis 的高可用核心,在于 Master 与 Slave 角色的合理分布。Ambari 通过自动化分配策略,确保主从节点物理隔离,极大提升集群容灾能力。
# 2.1.1 节点分布表
节点名称 | 角色 | 端口 | 哈希槽分配 | 职责 | 数据复制关系 |
---|---|---|---|---|---|
Node 1 | Master 1 | 6379 | 0-5461 | 负责哈希槽 0-5461 数据 | 复制到 Slave 3 (Node 3) |
Node 1 | Slave 1 | 6380 | 5462-10922 | 复制 Master 2 (Node 2) 数据 | |
Node 2 | Master 2 | 6379 | 5462-10922 | 负责哈希槽 5462-10922 数据 | 复制到 Slave 1 (Node 1) |
Node 2 | Slave 2 | 6380 | 10923-16383 | 复制 Master 3 (Node 3) 数据 | |
Node 3 | Master 3 | 6379 | 10923-16383 | 负责哈希槽 10923-16383 数据 | 复制到 Slave 2 (Node 2) |
Node 3 | Slave 3 | 6380 | 0-5461 | 复制 Master 1 (Node 1) 数据 |
笔记
Master 和 Slave 通过交叉分布,互为容灾,消除了单节点故障的隐患 高可用。
# 2.1.2 反亲和性设计
在集群自动化部署时,Ambari 内部会调用如 get_assigned_master
方法,确保 Slave 节点总是绑定到不同的物理主机上,避免“同命运”故障:
def get_assigned_master(self, params):
master_hosts = params.redis_master_hosts
Logger.info("Available Master nodes: {0}".format(master_hosts))
current_slave_index = int(params.redis_port) % len(master_hosts)
assigned_master_index = (current_slave_index + 1) % len(master_hosts)
assigned_master = master_hosts[assigned_master_index]
Logger.info(format("Assigning Slave on port {params.redis_port} to Master {assigned_master}"))
return assigned_master
2
3
4
5
6
7
8
9
10
提示
这种主从跨机绑定方式,有效规避了主从同物理节点带来的整体失效风险,确保了每一次故障切换的独立性和安全性。
# 2.2 主从组件的启动与管理
Ambari 将 Redis Master 和 Slave 的生命周期管理彻底解耦,分别以独立脚本完成配置、启动、监控和故障恢复,方便按需维护和弹性扩展。
# 2.2.1 Redis Master 的启动逻辑
def start(self, env):
import params
self.configure(env)
Logger.info(format("Starting Redis Master on port {redis_port}"))
Execute(format(
"{client_bin}/redis-server /etc/redis/redis.conf --cluster-config-file /etc/redis/cluster_master.conf --pidfile {master_redis_pid_file}"),
user=params.redis_user)
2
3
4
5
6
7
笔记
Master 主要承担数据处理和哈希槽分配,不参与 Slave 的生命周期管理。
# 2.2.2 Redis Slave 的启动逻辑
def start(self, env):
import params
self.configure(env)
slave_port = int(params.redis_port) + 1
Logger.info(format("Starting Redis Slave on port {slave_port}"))
Execute(format(
"{client_bin}/redis-server /etc/redis/redis.conf --port {slave_port} --cluster-config-file /etc/redis/cluster_slave.conf --pidfile {slave_redis_pid_file}"),
user=params.redis_user)
self.initialize_or_expand_cluster(params)
2
3
4
5
6
7
8
9
10
11
12
- Slave 启动后,会根据当前集群状态自动决定是初始化集群,还是扩容加入现有主节点。
# 2.2.3 集群初始化与扩展逻辑
initialize_or_expand_cluster
方法根据集群现状动态决策,自动化处理 Master 初始化和 Slave 加入:
def initialize_or_expand_cluster(self, params):
retries = 5
retry_delay = 10
for attempt in range(retries):
code, output = shell.call(
format("{client_bin}/redis-cli -p {params.redis_port} -a {redis_password} cluster nodes"),
user=params.redis_user)
if code == 0 and len(output.splitlines()) > 1:
Logger.info("Cluster is already initialized. Proceeding with slave addition.")
self.add_slave_to_master(params)
return
elif len(output.splitlines()) == 1:
Logger.info("Cluster is not initialized. Initializing Redis Cluster with master nodes and assigning slots.")
self.initialize_cluster_and_assign_slots(params)
return
else:
Logger.warning("Cluster is not initialized (attempt {}/{}).".format(attempt + 1, retries))
time.sleep(retry_delay)
Logger.error("Cluster could not be initialized after retries.")
raise Exception("Cluster in an inconsistent state.")
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
注意
集群状态判断与自动化容错,极大减少了人工运维成本,同时也避免了节点状态“悬空”或孤岛问题。
# 2.3 动态扩展与缩容
# 2.3.1 动态扩展
扩容时,只需新启动 Master/Slave 角色节点,Slave 通过 add_slave_to_master
方法智能挂载到合适主节点,无需手动分配:
def add_slave_to_master(self, params):
slave_port = int(params.redis_port) + 1
master_host = self.get_assigned_master(params)
if self.is_slave_already_in_cluster(params, slave_port):
Logger.info(format("Redis Slave {params.hostname}:{slave_port} is already part of the cluster, skipping addition."))
return
Execute(format(
"{client_bin}/redis-cli --cluster add-node {params.hostname}:{slave_port} {master_host}:{params.redis_port} --cluster-slave -a {redis_password}"),
user=params.redis_user)
Logger.info("Slave node added to the cluster as a replica of master {master_host}. No need to rebalance slots.")
2
3
4
5
6
7
8
9
10
11
12
13
提示
动态扩容过程全自动,无需重启业务,对线上服务“无感知”热扩容。
# 2.3.2 动态缩容
缩容则结合 Redis reshard
工具,先迁移哈希槽再下线节点,保证业务平滑、数据均衡,不影响整体读写可用性。