第 5 篇:「集群的记忆与裁判」—— GCS 全局控制服务解剖

第 5 篇:「集群的记忆与裁判」—— GCS 全局控制服务解剖

阅读本文你将了解:

  1. GCS 的全部状态就是 6 张表src/ray/gcs/gcs_table_storage.h:200),持久化就是把这 6 张表换一个 StoreClient 后端——没有第二种机制。
  2. 官方说的三种存储在源码里是 StorageType 枚举:IN_MEMORY / REDIS_PERSIST / ROCKSDB_PERSISTsrc/ray/gcs/gcs_server.h:130),默认 gcs_storage="memory"src/ray/common/ray_config_def.h:488)→ 默认不容错。
  3. 官方文档列的「GCS 恢复期间不可用清单」(actor / placement group / 资源管理 / 节点注册 / worker 创建),逐条对应 GCS 里的 manager 对象,因为恢复期它们还没被 Initialize
  4. Task 与 Actor 的调度路径完全不同:Task 由本地 Raylet 调度(第 4 篇),Actor 由 GCS 主动向 Raylet 租 workersrc/ray/gcs/actor/gcs_actor_scheduler.h:238)。
  5. GCS 自己也持有一份 ClusterResourceSchedulersrc/ray/gcs/gcs_server.h:268)——但不是用来调度 task,而是给 PlacementGroup 做全局装箱。
  6. GCS 向全集群广播变更用的是**长轮询(long-poll)**而非流式 gRPC(src/ray/gcs/pubsub_handler.h:47)。

5.0 一句话定性

GCS(Global Control Service)是 Ray 集群的唯一权威元数据仓库 + 少量全局决策的裁判。它不做数据面(对象传输不经过它),也不调度普通任务;它负责的是"谁活着、谁在哪、谁该被重建"这一类必须全局一致、且必须能持久化的信息。

理解 GCS 有一个极简的心智模型:

GCS = 6 张表 + 一堆围绕表工作的 manager + 一个把变更广播出去的 pubsub。

5.1 架构视角(Architect):GCS 管什么、不管什么

官方文档对 GCS 的定义(fault_tolerance/gcs.html):

The Global Control Service, or GCS, manages cluster-level metadata. It also provides a handful of cluster-level operations including actor, placement groups and node management.

拆成"管"与"不管":

GCS 管(必须全局一致)GCS 不管(数据面 / 本地决策)
节点注册与存活判定对象存储与传输(Plasma / ObjectManager)
Actor 注册表与重建普通 Task 的调度(本地 Raylet 决策)
PlacementGroup 创建与装箱任务参数拉取(PullManager)
集群资源视图(近似、异步)引用计数(各 worker 的 ReferenceCounter)
Job / Worker / Task 事件元数据对象溢写(LocalObjectManager)

这个分工直接决定了 Ray 的可用性特征:GCS 挂掉不会让正在跑的任务停止(官方明确说 running Ray tasks and actors remain alive, and any existing objects stay available),但会让任何需要"改元数据"的操作停摆——新建 actor、新加节点、新创 placement group 都不行。

反过来,这也解释了一个常见误解:Ray 集群"没崩"不代表健康,可能只是 GCS 在恢复中。

5.2 GcsServer 的成员地图

GcsServersrc/ray/gcs/gcs_server.h:99)是整个控制面的容器。它的成员声明顺序有一条硬约束,写在源码注释里(:255-256):

NOTE: the declaration order for data members must follow the dependency structure between them.

因为 C++ 析构顺序是声明的逆序,声明顺序错了就会在析构时出现"依赖对象已销毁"的悬空访问。所以我们可以从成员声明顺序直接读出依赖关系:268-330):
在这里插入图片描述

两类成员值得单独点名:

  • cluster_resource_scheduler_:268:GCS 自己也有一份集群资源调度器,但不用于调度 task,而是给 PlacementGroup 做全局装箱决策(§5.10)。
  • ray_syncer_:295InitRaySyncer():165):这回答了第 4 篇留下的悬念——各 Raylet 的集群资源视图靠它同步收敛(§5.7)。

5.3 状态模型:6 张表就是 GCS 的全部记忆

GcsTableStoragesrc/ray/gcs/gcs_table_storage.h:200)的构造函数(:202)一目了然:

访问器键 → 值用途
job_table_JobTable():214JobID → JobTableDataJob 元数据
actor_table_ActorTable():219ActorID → ActorTableDataActor 注册表(谁在哪、什么状态)
actor_task_spec_table_ActorTaskSpecTable():224ActorID → TaskSpecActor 重建的凭据(保存创建参数)
placement_group_table_PlacementGroupTable():229PlacementGroupID → PG 数据PG 状态
node_table_NodeTable():234NodeID → GcsNodeInfo节点清单
worker_table_WorkerTable():239WorkerID → WorkerTableDataWorker 清单

底层统一是 std::shared_ptr<StoreClient> store_client_:250)——这就是持久化后端的抽象点
在这里插入图片描述

关键结论:GCS 没有任何"隐藏状态"。所有元数据都在这 6 张表里,持久化 = 换后端,恢复 = 从后端把表读回来。这就是为什么官方说恢复后 “it loads all the data back from the backing store and resumes regular functions”

actor_task_spec_table_ 尤其值得注意:它保存的是 Actor 的创建参数(TaskSpec)。Actor 能在其所在节点宕机后被重建,靠的就是这张表。

5.4 三种存储后端:官方说法 ↔ 源码落点

StorageType 枚举(src/ray/gcs/gcs_server.h:130)与配套常量(:137-139逐字对应官方的环境变量取值:

官方 RAY_gcs_storage 取值源码常量枚举
memory(默认)kInMemoryStorage:137IN_MEMORY = 1
rediskRedisStorage:138REDIS_PERSIST = 2
rocksdbkRocksDbStorage:139ROCKSDB_PERSIST = 3

配置项在 GetStorageType():237)里读出,默认值全部对得上官方文档:

官方参数源码默认值
RAY_gcs_storagegcs_storagesrc/ray/common/ray_config_def.h:488"memory"
RAY_gcs_storage_pathgcs_storage_path:492""(rocksdb 模式必填)
RAY_gcs_rocksdb_io_pool_sizegcs_rocksdb_io_pool_size:5014
RAY_gcs_rocksdb_strand_bucketsgcs_rocksdb_strand_buckets:50864
RAY_gcs_rpc_server_reconnect_timeout_sgcs_rpc_server_reconnect_timeout_s:54960

官方文档还提到 RocksDB 是 single-writer(同一时刻只能有一个 GCS 打开该路径),以及 I/O 走独立线程池避免阻塞 GCS 事件循环——后者对应的正是 gcs_rocksdb_io_pool_size(默认 4)。

关于 strand_buckets=64 的含义,源码注释(:508 附近)与官方一致:按键哈希分桶,同桶串行、异桶并发,在保序与并发之间取平衡。

5.5 GCS 容错:官方"不可用清单"的源码解释

官方文档列出 GCS 恢复期间不可用的功能:

Actor creation, deletion and reconstruction. / Placement group creation, deletion and reconstruction. / Resource management. / Worker node registration. / Worker process creation.

这五条逐条对应 GcsServer 的 manager 初始化方法——因为恢复期这些对象要么还没构建、要么还没 Initialize

官方"不可用"对应初始化方法位置
Actor 创建/删除/重建InitGcsActorManagersrc/ray/gcs/gcs_server.h:178
PlacementGroup 创建/删除/重建InitGcsPlacementGroupManager:183
资源管理InitGcsResourceManager:162
Worker 节点注册InitGcsNodeManager:152
Worker 进程创建InitGcsWorkerManager:198

而"正在跑的 task/actor 不受影响",源码层面的原因是:它们的执行完全在本地 Raylet + CoreWorker 上,只在需要改元数据时才联系 GCS。

另一条容易忽略的官方说明,源码里也有对应:

If a raylet can’t reconnect for more than 60 seconds, that raylet exits and the corresponding node fails.

这个 60 秒就是 gcs_rpc_server_reconnect_timeout_ssrc/ray/common/ray_config_def.h:549)。这是生产上非常关键的一个旋钮:GCS 恢复时间超过它,整个集群会连锁性地"节点自杀"。在 GCS 恢复较慢的环境(大集群、RocksDB 数据量大)里,应适当调大。

5.6 节点管理:注册、心跳与失败判定

节点生命周期由 GcsNodeManagersrc/ray/gcs/gcs_node_manager.h)与健康检查协作完成:

方法行号作用
HandleRegisterNode:71节点注册(写入 node_table_ 并广播)
HandleUnregisterNode:76主动注销
HandleDrainNode:84节点排水(优雅下线)
HandleGetAllNodeInfo:89查询全量节点
HandleGetAllNodeAddressAndLiveness:94查询地址与存活
HandleCheckAlive:112存活探测
OnNodeFailure:122节点失败处理
IsNodeDead / IsNodeAlive:146 / :152存活状态查询
UpdateAliveNode:232更新存活节点集合

事件通知用监听器模式:AddNodeAddedListener:196)/ AddNodeRemovedListener:184)/ AddNodeDrainingListener:208)。这是 GCS 内部解耦的关键——节点状态一变,资源管理器、Actor 管理器、PG 管理器都能收到通知(它们各自的 OnNodeDeadsrc/ray/gcs/gcs_resource_manager.h:102src/ray/gcs/actor/gcs_actor_manager.h:176src/ray/gcs/gcs_placement_group_manager.h:155)。

健康检查是独立机制GcsHealthCheckManager):AddNode:74)注册节点通道,MarkNodeHealthy:92)标记健康,FailNode:109)判定失败。它不依赖心跳,而是主动探测——这意味着节点失败有两条检测路径(心跳超时 + 主动探测失败),互为兜底。

在这里插入图片描述

5.7 集群资源视图如何收敛:回答第 4 篇的悬念

第 4 篇留了一个问题:各 Raylet 各自持有一份异步收敛的集群资源视图,那这份视图到底怎么同步?答案在 GCS 侧。

两条互补的通道:

  1. RaySyncer(src/ray/gcs/gcs_server.h:295 / InitRaySyncer() :165:专门负责在 Raylet 与 GCS 之间同步资源视图消息。GCS 侧的消费入口是 GcsResourceManager::ConsumeSyncMessagesrc/ray/gcs/gcs_resource_manager.h:66)。
  2. Raylet 心跳上报:第 4 篇讲过的 FillResourceUsagesrc/ray/raylet/scheduling/cluster_lease_manager.h:124)随心跳带上 resource_loadresource_load_by_shape;GCS 侧对应 UpdateResourceLoadssrc/ray/gcs/gcs_resource_manager.h:150)、UpdateNodeResourceUsage:127)、UpdateFromResourceView:136)。

GCS 侧的集群资源账本由 GcsResourceManager 维护,对外提供查询接口:HandleGetAllAvailableResources:71)、HandleGetAllTotalResources:78)、HandleGetAllResourceUsage:90)。

还有一条反向链路:InitGcsResourceLoadPullersrc/ray/gcs/gcs_server.h:209)与 resource_load_puller_:273)——GCS 会主动拉取各 Raylet 的负载,而不是只被动接收心跳。拉取与上报并行,是为了让 autoscaler 拿到更及时的数据(gcs_autoscaler_state_manager_:272)。

收敛性质:GCS 的集群资源视图同样是近似值(接收有延迟、拉取有周期)。所以第 4 篇说的 spillback 机制,本质上是在补偿"GCS 视图 + 本地视图都不精确"这一事实——去中心化调度 + 最终一致视图 + spillback 兜底,三者是一套完整设计。

5.8 pubsub:GCS 如何把变更推给全集群

GCS 的状态变更要通知到所有 Raylet 与 CoreWorker,机制是 pubsub。入口在 src/ray/gcs/pubsub_handler.h

组件行号职责
HandleGcsPublish:43发布消息
HandleGcsSubscriberPoll:47长轮询拉取
HandleGcsSubscriberCommandBatch:51批量订阅/取消
sender_to_subscribers_:57发送者 → 订阅者集合
ControlPlanePubSubHandler:62控制面频道(actor/job/node 变更)
ObservabilityPubSubHandler:95可观测频道(日志、错误、Dashboard 资源 JSON)

GCS 里有两个独立的 publisher(src/ray/gcs/gcs_server.h:275/:277):

  • gcs_publisher_:控制面,承载"必须可靠送达"的元数据变更
  • observability_publisher_:可观测数据,允许丢弃(日志丢了不影响正确性)

这个拆分很关键:控制面与可观测面物理隔离,避免 Dashboard 日志洪峰把关键元数据通知挤掉。

值得注意的是实现选型:注释(:60-61)写明是 “long-poll subscribe”,而不是 gRPC streaming。长轮询的好处是穿透代理友好、实现简单、断线重连逻辑朴素可靠;代价是通知有额外一轮 RTT 延迟。对于"节点加入/Actor 状态变更"这种低频但关键的事件,这是合理的取舍。

5.9 Actor:调度权在 GCS 手里(与 Task 完全不同)

这是本篇最重要、也最容易被误解的一点。

第 2 篇讲过 Task 的路径:f.remote() → 本地 Raylet → 本地决策或 spillback。Task 的调度权在 Raylet。

Actor 不是。Actor 创建请求先到 GCS,由 GCS 向 Raylet 租 worker

步骤方法位置
注册 Actor(写表)HandleRegisterActorsrc/ray/gcs/actor/gcs_actor_manager.h:122
创建 ActorHandleCreateActor:131
调度 pending actorsSchedulePendingActors:166
调度单个 actorGcsActorScheduler::Schedulesrc/ray/gcs/actor/gcs_actor_scheduler.h:136
向指定节点租 workerLeaseWorkerFromNode:238
租约被授予HandleWorkerLeaseGrantedReply:275
租约被拒绝(重试)HandleWorkerLeaseRejectedReply:281
在 worker 上创建 actorCreateActorOnWorker:300
创建成功/失败OnActorCreationSuccess / OnActorSchedulingFailedsrc/ray/gcs/actor/gcs_actor_manager.h:214 / :203

为什么 Actor 要 GCS 调度? 因为 Actor 是有状态且需要全局唯一的实体:

  • 它的位置一旦确定,所有调用方都得知道去哪找它(需要写进 actor_table_
  • 它可能需要被重建(节点宕机后)——只有持有元数据的 GCS 能做这件事
  • detached actor 的生命周期与 owner 解耦,需要 GCS 托管(PollOwnerForActorRefDeleted:302

这也解释了官方"GCS 恢复期间 Actor 创建/删除/重建不可用"——Actor 的调度权就在 GCS,GCS 不在,Actor 就生不出来

反过来,Task 无状态、可 spillback、位置不需要被记住,所以完全下放给 Raylet 是合理的。Ray 把调度权按"状态是否需要被记住"来切分,这是理解其架构的一条主线。

Actor 相关的其它 GCS 入口:HandleGetActorInfo:135)、HandleGetNamedActorInfo:139,具名 actor)、HandleListNamedActors:143)、HandleKillActorViaGcs:151)、HandleReportActorOutOfScope:155)、RestartActor:339)、DestroyActor:317)、HandleRestartActorForLineageReconstruction:126,lineage 重建入口,第 6 篇详述)。

5.10 PlacementGroup:GCS 用自己的调度器做全局装箱

PlacementGroup(PG)是"预留一组资源"的原语,其调度同样在 GCS:

方法行号作用
HandleCreatePlacementGroupsrc/ray/gcs/gcs_placement_group_manager.h:76创建 PG
RegisterPlacementGroup:115注册(写表)
SchedulePendingPlacementGroups:121调度待定 PG
OnPlacementGroupCreationSuccess / Failed:144 / :136结果回调
HandleWaitPlacementGroupUntilReady:95等待就绪
RemovePlacementGroup:148移除
OnNodeDead / OnNodeAdd:155 / :161节点变化响应
CleanPlacementGroupIfNeededWhenJobDead:183Job 死亡清理
CleanPlacementGroupIfNeededWhenActorDead:199Actor 死亡清理

调度执行者是 gcs_placement_group_scheduler_src/ray/gcs/gcs_server.h:284),它依赖 raylet_client_pool_(源码注释明确写了这个依赖)。

而它做决策时用的工具,就是 GcsServer 自己那份 cluster_resource_scheduler_src/ray/gcs/gcs_server.h:268)——GCS 侧的这份调度器是为 PG 的"全局装箱(bundle packing)"服务的,与 Raylet 那份(第 4 篇)用途不同。

PG 的装箱结果还要回写资源账本:GcsResourceManager::UpdatePlacementGroupLoadsrc/ray/gcs/gcs_resource_manager.h:144)。

一句话总结 PG 与 Actor 的差异:Actor 是"找一个节点放一个实体",PG 是"在集群里划一块地"——后者天然需要全局视角,所以只能由 GCS 做。

5.11 GCS 与外界的通信:gRPC 与客户端池

GCS 对外暴露 gRPC 服务,端口与线程数来自 GcsServerConfigsrc/ray/gcs/gcs_server.h:60-76):

字段行号说明
grpc_server_port / grpc_server_thread_num:60 / :61服务端口与线程数
redis_address / redis_port / redis_username / redis_password:65-66 / :63-64Redis 后端连接信息
enable_redis_ssl / retry_redis:67 / :68Redis 安全与重试
raylet_config_list:74下发给 Raylet 的配置列表

对外调用则通过客户端池(:264-267):raylet_client_pool_worker_client_pool_,以及专用于拉取负载的 resource_load_pull_raylet_client_pool_

RPC 线程数可调:gcs_server_rpc_server_thread_numsrc/ray/common/ray_config_def.h:453)与 gcs_server_rpc_client_thread_num:459)。大集群(数百节点)里 GCS 的 RPC 线程常常是隐性瓶颈,如果观察到 GCS CPU 打满但吞吐上不去,先看这两个值。

存储写入还有一个批量上限:maximum_gcs_storage_operation_batch_size:444,默认 1000)——控制单次批量写存储的条数,避免大事务拖垮后端。

5.12 GCS 启动时序

GcsServer::Start()src/ray/gcs/gcs_server.h:107)→ DoStart():149)内部按依赖顺序初始化各 manager。注释(:95-98)明确了生命周期:

1. Gcs server contains a lot of data member, gcs server outlives all of them.
2. Gcs table storage and all gcs managers share a lifetime, that starts from a DoStart call to Stop.

初始化方法清单(:152-230)本身就是一张启动流程图:

InitGcsNodeManager(:152) → InitGcsHealthCheckManager(:155) → InitIOContextMonitor(:159)
→ InitGcsResourceManager(:162) → InitRaySyncer(:165) → InitClusterResourceScheduler(:168)
→ InitGcsJobManager(:171) → InitGcsActorManager(:178) → InitGcsPlacementGroupManager(:183)
→ InitGcsWorkerManager(:198) → InitGcsTaskManager(:201) → InitGcsAutoscalerStateManager(:206)
→ InitGcsResourceLoadPuller(:209) → InitUsageStatsClient(:212)
→ InitKVManager(:215) → InitKVService(:218) → InitFunctionManager(:221)
→ InitPubSubHandler(:224) → InitRuntimeEnvManager(:227) → InitMetricsExporter(:230)
→ InstallEventListeners(:233)

其中 InitIOContextMonitor:159)与成员 io_context_monitor_thread_:330)值得一提:它在一个独立线程上探测 GCS 的 io_context 是否卡死,并把结果反馈到 gRPC health check(SERVING / NOT_SERVING)。这是 GCS 的"自我心跳"——GCS 进程还在但事件循环卡住时,外部能感知到。

还有 GetOrGenerateClusterId:249):从存储里读 cluster id,读不到就生成并持久化,且要求幂等。这也是为什么 kv_manager_:288)要在存储层就绪后才能初始化。

5.13 Job、Task 事件与内部 KV

除核心三件套(节点/Actor/PG)外,GCS 还托管若干元数据服务:

  • Jobgcs_job_manager_src/ray/gcs/gcs_server.h:289),表为 job_table_
  • Task 事件gcs_task_manager_:309),配 task_events_reported/dropped/stored 三个 metric(初始化处 :201-203)——注意有 dropped 计数,说明任务事件允许丢弃(可观测数据,非关键路径)
  • 内部 KVkv_manager_:288),接口 InternalKVInterfacesrc/ray/gcs/gcs_kv_manager.h:34),实现 GcsInternalKVManager:103)。用于 RuntimeEnv URI 存储、cluster id 持久化等
  • RuntimeEnvruntime_env_manager_src/ray/gcs/gcs_server.h:287)与 runtime_env_handler_:303
  • 函数管理function_manager_:285InitFunctionManager :221

5.14 生产实践(Production)

必须知道的三件事

  1. 默认不容错gcs_storage 默认 "memory"src/ray/common/ray_config_def.h:488)。生产集群如果没显式配置,GCS 一挂整个集群就废。这是 Ray 部署里最常见的高可用缺口。
  2. 恢复期节点会自杀:Raylet 重连 GCS 超过 gcs_rpc_server_reconnect_timeout_s(默认 60s)就退出。大集群 + RocksDB 恢复慢时,务必调大这个阈值,否则会出现"GCS 恢复了但节点全没了"。
  3. RocksDB 是单写者:同一存储路径同一时刻只能有一个 GCS 打开。绝不能在两个集群间共享同一个 RAY_gcs_storage_path

后端选型(对齐官方表格)

维度External RedisEmbedded RocksDB
额外组件需要 HA Redis无(本地持久化卷)
存活条件Redis 存活持久卷存活且能重新挂载
平台全平台仅 Linux
成熟度正式支持(KubeRay + Ray Serve)Alpha
源码REDIS_PERSISTsrc/ray/gcs/gcs_server.h:133ROCKSDB_PERSIST:134

观测清单

看什么说明
task_events_dropped 计数持续增长说明 GCS 处理不过来,任务事件在被丢弃
GCS RPC 线程gcs_server_rpc_server_thread_num:453)打满 → GCS 成为瓶颈
HandleGetAllResourceUsage 延迟GCS 侧资源视图落后于实际,会导致调度误判
PlacementGroup 创建延迟InitGcsPlacementGroupManager 处注册了 latency histogram(src/ray/gcs/gcs_server.h:188-189
GCS 事件循环io_context_monitor_thread_:330)→ gRPC health 状态
Actor 调度失败OnActorSchedulingFailedsrc/ray/gcs/actor/gcs_actor_manager.h:203)是排查 actor 起不来的第一入口

典型故障排查

  1. 新节点加不进集群HandleRegisterNodesrc/ray/gcs/gcs_node_manager.h:71)是否被 GCS 接收;GCS 是否在恢复期;gcs_rpc_server_reconnect_timeout_s 是否过小。
  2. Actor 创建卡住 → 走 GCS 路径:SchedulePendingActorssrc/ray/gcs/actor/gcs_actor_manager.h:166)→ LeaseWorkerFromNodesrc/ray/gcs/actor/gcs_actor_scheduler.h:238)→ 是否被 HandleWorkerLeaseRejectedReply:281)反复拒绝(通常是资源不足或 RuntimeEnv 起不来)。
  3. 具名 Actor 找不到HandleGetNamedActorInfosrc/ray/gcs/actor/gcs_actor_manager.h:139),注意 namespace 隔离。
  4. GCS 重启后状态丢失 → 确认 gcs_storage 不是 memory;Redis 模式下确认 RAY_REDIS_ADDRESS 生效。
  5. PG 一直 pendingSchedulePendingPlacementGroupssrc/ray/gcs/gcs_placement_group_manager.h:121);装箱失败通常是资源碎片或策略过严(第 7 篇详述)。

5.15 进阶(Advanced):GCS 为什么不做调度,以及与同类系统的对比

为什么 GCS 不调度普通 Task

从第 4 篇与本篇的对比可以反推出设计意图:

  • Task 的量级是百万级,若每个都要问 GCS,GCS 立刻成为瓶颈
  • Task 无状态、可 spillback,位置不需要被记住 → 不需要全局一致
  • Actor/PG 的量级是万级以下,且位置/状态必须全局可见 → 必须走 GCS

判据是"状态是否需要被全局记住",而不是"重要不重要"。这是一条可以迁移到其它系统设计上的经验。

与同类"集群元数据服务"对比

维度Ray GCSKubernetes (etcd + apiserver)ZooKeeperHDFS NameNode
状态模型6 张 KV 表通用 KV + 对象模型层次化 znode文件系统元数据树
一致性单点权威(可选持久化)Raft 强一致Zab 强一致单点 + JournalNode
高可用Redis/RocksDB 持久化重启多副本 Raft多副本HA(JournalNode + ZKFC)
参与调度(Actor / PG)是(scheduler 读 apiserver)
故障时数据面继续运行已运行 Pod 继续视业务而定读写中断

GCS 最大的特点是单点 + 可选持久化,而不是 Raft 多副本。它用"数据面不受影响 + 快速重启恢复"来替代强一致多副本的复杂度。这个取舍在 AI 负载场景下是合理的(任务失败可重试、重算代价低于维护强一致的开销),但对控制面可用性要求极高的场景(如长期运行的在线服务)就需要 KubeRay 的 GCS FT 方案来补强

5.16 小结与下篇预告

本篇把 GCS 拆成了五层:状态层(6 张表 / 3 种后端)、管理层(节点/资源/Actor/PG/Job/Task 各 manager)、同步层(RaySyncer + 心跳 + 负载拉取)、通知层(控制面 / 可观测面双 pubsub,长轮询)、服务层(gRPC + 客户端池 + 健康自监测)。

三条最值得记住的结论:

  1. GCS 的全部记忆就是 6 张表src/ray/gcs/gcs_table_storage.h:200),持久化只是换 StoreClient——没有第二种机制,也意味着恢复期所有依赖表的 manager 都不可用。
  2. 调度权按"状态是否需被记住"切分:Task 归 Raylet,Actor 与 PlacementGroup 归 GCS(src/ray/gcs/actor/gcs_actor_scheduler.h:238 / src/ray/gcs/gcs_placement_group_manager.h:121)。
  3. 默认配置下 GCS 不容错gcs_storage="memory"src/ray/common/ray_config_def.h:488),且恢复超时会导致节点连锁退出(gcs_rpc_server_reconnect_timeout_s=60:549)——这是生产部署最容易踩的坑。

下一篇(06 容错与 Lineage)将沿着本篇埋下的三条线索展开:actor_task_spec_table_src/ray/gcs/gcs_table_storage.h:224)保存的创建参数如何支撑 Actor 重建HandleRestartActorForLineageReconstructionsrc/ray/gcs/actor/gcs_actor_manager.h:126)如何触发 lineage 重建、以及对象侧的 src/ray/core_worker/object_recovery_manager.h:108src/ray/core_worker/reference_counter.h:159 如何与 GCS 协作完成容错闭环。

关键源码事实:

  • GcsServersrc/ray/gcs/gcs_server.h:99Start/Stop :107/:110DoStart :149StorageType :130;存储常量 :137-139;成员声明顺序约束 :255-256
  • 初始化方法族:InitGcsNodeManager :152InitGcsHealthCheckManager :155InitGcsResourceManager :162InitRaySyncer :165InitGcsActorManager :178InitGcsPlacementGroupManager :183InitGcsWorkerManager :198InitGcsTaskManager :201InitGcsResourceLoadPuller :209InitKVManager :215InitPubSubHandler :224
  • 核心成员:cluster_resource_scheduler_ :268gcs_table_storage_ :269gcs_resource_manager_ :271resource_load_puller_ :273gcs_publisher_ :275gcs_node_manager_ :279gcs_actor_manager_ :282gcs_placement_group_scheduler_ :284kv_manager_ :288ray_syncer_ :295gcs_task_manager_ :309io_context_monitor_thread_ :330
  • 6 张表:src/ray/gcs/gcs_table_storage.h:200(访问器 :214/:219/:224/:229/:234/:239
  • 节点管理:src/ray/gcs/gcs_node_manager.h:71/:112/:122/:184/:196;健康检查 src/ray/gcs/gcs_health_check_manager.h:74/:92/:109
  • 资源视图:src/ray/gcs/gcs_resource_manager.h:66/:127/:136/:150
  • Actor:src/ray/gcs/actor/gcs_actor_manager.h:122/:166/:203/:214/:339;调度器 src/ray/gcs/actor/gcs_actor_scheduler.h:136/:238/:275/:281/:300
  • PlacementGroup:src/ray/gcs/gcs_placement_group_manager.h:76/:121/:144/:155
  • pubsub:src/ray/gcs/pubsub_handler.h:43/:47/:62/:95
  • 配置:src/ray/common/ray_config_def.h:444/:453/:459/:488/:492/:501/:508/:549
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

头茬韭菜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值