Skip to content

Routing in Distributed Systems

分布式系统中的路由

question

分布式系统中的路由有谁来负责?客户端还是服务端?

answer

两种方式都存在,要看具体系统的设计选择

客户端路由 client-side routing

客户端自己决定请求发到哪个节点,例如

  • 通过一致性哈希(Consistent Hashing)或某种分片规则定位到具体节点
  • 通常客户端会缓存一份集群拓扑信息或元数据

代表系统:

  • Cassandra
  • Riak
  • Kafka Producer(可以自己决定发送到哪个 partition)

优点:

  • 请求路径短,直接到目标节点
  • 减少跳转、中间层压力

缺点:

  • 客户端实现复杂,要感知集群拓扑变化
  • 拓扑变化(比如扩容)可能导致客户端缓存失效,需要有刷新机制

服务端路由 server-side routing

客户端只连接某个入口节点(称为 router、coordinator、proxy 等),再由这个节点在集群内部路由转发。

代表系统:

  • MongoDB(mongos)
  • TiDB(SQL 层接入)
  • HBase(通过 RegionServer)
  • Elasticsearch(coordinating node)

优点:

  • 客户端简单,不需要关心数据分布
  • 系统可以集中处理元数据、负载均衡

缺点:

  • 增加一跳,可能引入性能瓶颈
  • 入口节点成为潜在的热点或单点故障点(需高可用设计)

对比例子

Kafka(客户端路由):

Kafka 的 producer 会从 broker 获取元数据,然后根据 topic 的 partition 和 key 做 hash,直接发送消息到对应的 broker。这样中间没有 proxy,性能高。

MongoDB(服务端路由):

MongoDB 分片集群中,客户端连接 mongos,而不是直接连接 shard。mongos 是查询协调器,接收请求后根据 chunk 的分布信息,分发请求到对应 shard 上。

Redis Cluster

数据分片

  • Redis Cluster 将整个 key 空间划分为 16384 个 slot(称为 哈希槽)。
  • 每个 key 通过 CRC16(key) % 16384得到其 slot 编号。
  • 每个节点负责其中的一部分 slot。

路由流程(客户端侧):

  1. 客户端第一次连接时,会从任意一个 Redis 节点获取集群拓扑信息(即所有 slot 分布在哪些节点)。
  2. 计算 slot:发送命令时,客户端根据 key 计算它属于哪个 slot。
  3. 选择节点:根据 slot 到节点的映射,直接将命令发送到对应的节点。

如果客户端路由错了(比如映射信息过期),Redis 节点会返回:

  • -MOVED:告诉客户端该 slot 已经迁移到其他节点,客户端需更新 slot 映射表。
  • -ASK:表示 slot 正在迁移过程中,客户端暂时重定向到新节点(但不更新本地映射)。

客户端需要支持这类重试和 slot 映射更新逻辑。

Redis Cluster 节点如何管理 slot?

Redis Cluster 将 16384 个 slot 显式分配给集群中的节点。每个节点会维护一份 slot -> 节点 的映射信息,并参与集群协议,确保这个映射在整个集群中是一致的。

一、slot 是怎么分配给节点的?{id="slot_1"}

在 Redis Cluster 启动或扩容时,管理员手动(或使用工具如 redis-cli --cluster create)将 slot 分配给节点。比如:

  • 节点 A:0 ~ 5460
  • 节点 B:5461 ~ 10922
  • 节点 C:10923 ~ 16383

Redis 每个主节点(master)会维护自己负责的 slot 范围,并在 CLUSTER SLOTS、CLUSTER NODES 等命令中向外暴露这些信息。

二、slot 元数据存储在哪?

每个 Redis 节点内部维护一张哈希表:

1
2
3
struct clusterNode {
  int slots[16384]; // 每个节点记录自己负责哪些 slot
}

此外,每个节点还记录所有其他节点的 IP、端口、角色(master/slave)、健康状态等集群元数据。

三、节点之间如何同步 slot 信息?

Redis Cluster 节点通过 gossip 协议(定期交换心跳包和元数据)相互同步 cluster 状态,包括:

  • 每个节点负责的 slot 范围
  • 节点是否宕机
  • 主从关系是否发生切换

slot 是否在迁移(migrating/importing)

这些信息帮助节点共同维持整个集群的一致视图。

四、slot 迁移是怎么进行的?(Re-sharding)

当你想把部分 slot 从节点 A 移动到节点 B:

  1. 设置状态标志:

  2. A 设置 slot 为 migrating

  3. B 设置该 slot 为 importing

  4. 通过 CLUSTER SETSLOT 命令通知集群 slot 状态变化

  5. 搬迁数据:

  6. 客户端或管理员使用 redis-cli --cluster reshard 工具

  7. 将指定 slot 上的 key 从 A 拉到 B,通常用 MIGRATE 命令实现

  8. 完成后 slot 属于 B,更新集群状态

客户端这时会收到 ASK 响应,提示临时重定向请求到目标节点。

五、如何查看 slot 分布?

1
2
3
4
5
# 查看 slot -> 节点映射
redis-cli -c -h 任意节点 cluster slots

# 查看节点视图(包含每个节点管理的slot)
redis-cli -c -h 任意节点 cluster nodes

总结对比

方式 特点 代表系统
客户端路由 高性能、需要客户端维护路由信息 Cassandra、Kafka、Couchbase
服务端路由(代理) 简化客户端逻辑、可集中控制负载,但增加中间跳转 MongoDB、TiDB、HBase、ES