OceanBase源码解读:RootService总控入口 ob_root_service.cpp

如果把 OceanBase 集群比作一艘船,RootService(RS)就是驾驶舱,而 rootserver/ob_root_service.cpp 里的 ObRootService 类则是驾驶舱里的总控台。它运行在 RS Leader 节点,负责集群成员管理、租户与资源池调度、DDL 路由、心跳租约、升级、系统包加载等全局事务。与 observer 内其它子系统按租户实例化不同,RS 相关逻辑是集群级别的单例,必须在正确的时间以正确的顺序把 Server 管理、Zone 管理、Unit 管理、DDL 服务、均衡器、检查器等一系列模块装配起来。本文聚焦这个总控入口,看 OceanBase 如何用一套状态机驱动整个集群的启停与运维。

核心数据结构

ObRootService 类汇集了 RS 所需的全部子系统,关键成员如下:

class ObRootService {
  bool inited_;                          // 是否完成 init()
  bool server_refreshed_;
  ObAddr self_addr_;                     // 本机地址
  ObServerConfig *config_;               // 集群配置
  ObSrvRpcProxy rpc_proxy_;              // 对外 RPC 代理
  ObCommonRpcProxy common_proxy_;        // 通用 RPC 代理
  ObMySQLProxy sql_proxy_;               // SQL 执行代理
  ObMultiVersionSchemaService *schema_service_;  // 多版本 schema 服务
  ObLSTableOperator *lst_operator_;      // 日志流位置表操作器
  ObServerManager server_manager_;       // OBServer 成员管理
  ObHeartbeatChecker hb_checker_;        // 心跳检查器
  ObServerChecker server_checker_;       // Server 状态检查器
  ObZoneManager zone_manager_;           // Zone 管理
  ObZoneStorageManager zone_storage_manager_;
  ObDDLService ddl_service_;             // DDL 服务
  ObTenantDDLService tenant_ddl_service_;
  ObUnitManager unit_manager_;           // Unit 资源管理
  ObRootBalancer root_balancer_;         // 负载均衡
  ObRootInspection root_inspection_;     // RS 巡检
  ObUpgradeExecutor upgrade_executor_;   // 升级执行器
  ObLSTableOperator *lst_operator_;      // 日志流位置表
  common::ObLatch bootstrap_lock_;       // 引导锁
  share::ObRsStatus rs_status_;          // RS 状态机
  int64_t fail_count_;                   // 启动失败计数
  ...
};

其中 ObServerManager 维护所有 OBServer 的存活状态与版本;ObUnitManager 负责资源单元(CPU/内存/磁盘)的分配与迁移;ObDDLServicetenant_ddl_service_ 分别处理系统租户和普通租户的 schema 变更;ObLSTableOperator 提供日志流位置信息,是 RS 高可用与副本定位的基础;rs_status_ 则驱动 RS 自身的生命周期状态机。

生命周期三阶段

init:装配依赖,但不激活

init() 是 RS 的真实初始化入口。它按”先本地队列与元数据,再 Server/Zone/Unit,最后 DDL 与检查器”的顺序依次初始化 20 多个子系统。所有 RPC 代理在此阶段保持 inactive,避免未就绪的 RS 提前对外暴露服务:

int ObRootService::init(ObServerConfig &config, ObConfigManager &config_mgr,
                        ObSrvRpcProxy &srv_rpc_proxy, ObCommonRpcProxy &common_proxy,
                        ObAddr &self, ObMySQLProxy &sql_proxy,
                        observer::ObRestoreCtx &restore_ctx, ObRsMgr &rs_mgr,
                        ObMultiVersionSchemaService *schema_service,
                        ObLSTableOperator &lst_operator)
{
  // 参数校验:地址合法、schema_service 非空
  if (inited_) { ret = OB_INIT_TWICE; }
  else if (!self.is_valid()) { ret = OB_INVALID_ARGUMENT; }
  else if (NULL == schema_service) { ret = OB_INVALID_ARGUMENT; }
  else {
    config_ = &config; config_mgr_ = &config_mgr;
    rpc_proxy_ = srv_rpc_proxy; common_proxy_ = common_proxy;
    const bool rpc_active = false;       // init 阶段不激活 RPC
    common_proxy_.active(rpc_active);
    rpc_proxy_.active(rpc_active);
    self_addr_ = self; restore_ctx_ = &restore_ctx;
    sql_proxy_.assign(sql_proxy); sql_proxy_.set_inactive();
    // oracle 代理也设为 inactive
    rs_mgr_ = &rs_mgr;
    addr_agent_ = &rs_mgr.get_addr_agent();
    schema_service_ = schema_service;
    lst_operator_ = &lst_operator;
  }
  // 子系统初始化:任务队列、Zone、Server、DDL、Unit、均衡、巡检...
  if (FAILEDx(task_queue_.init(...))) { ... }
  else if (OB_FAIL(zone_manager_.init(sql_proxy_))) { ... }
  else if (OB_FAIL(server_manager_.init(...))) { ... }
  else if (OB_FAIL(ddl_service_.init(...))) { ... }
  else if (OB_FAIL(tenant_ddl_service_.init(...))) { ... }
  else if (OB_FAIL(unit_manager_.init(...))) { ... }
  else if (OB_FAIL(root_balancer_.init(...))) { ... }
  else if (OB_FAIL(root_inspection_.init(...))) { ... }
  else if (OB_FAIL(upgrade_executor_.init(...))) { ... }
  ...
  if (OB_SUCC(ret)) { inited_ = true; }
  return ret;
}

瀑布式错误处理让失败位置一目了然;任意子系统初始化失败都会打印 DBA 级日志,便于运维快速定位。

start_service:从 Leader 开始对外服务

start_service() 只有在当前节点是 RS Leader 时才执行。它把 rs_status_ 从 INIT 推到 STARTING,激活 RPC 与 SQL 代理,启动心跳检查器与异步任务队列,注册 LS 表回调,并调度后续定时任务:

int ObRootService::start_service()
{
  start_service_time_ = ObTimeUtility::current_time();
  if (!inited_) { ret = OB_NOT_INIT; }
  else if (OB_FAIL(rs_status_.set_rs_status(status::STARTING))) { ... }
  else if (!ObRootServiceRoleChecker::is_rootserver()) { ret = OB_NOT_MASTER; }
  else {
    sql_proxy_.set_active(); oracle_sql_proxy_.set_active();
    const bool rpc_active = true;
    common_proxy_.active(rpc_active); rpc_proxy_.active(rpc_active);
    tenant_ddl_service_.restart();
    server_manager_.reset(); zone_manager_.reset();
    if (OB_FAIL(hb_checker_.start())) { ... }
    else if (OB_FAIL(task_queue_.start())) { ... }
    else if (OB_FAIL(inspect_task_queue_.start())) { ... }
    else if (OB_FAIL(TG_START(lib::TGDefIDs::GlobalCtxTimer))) { ... }
    else if (OB_FAIL(global_ctx_task_.schedule(...))) { ... }
    else if (OB_FAIL(lst_operator_->set_callback_for_rs(rs_list_change_cb_))) { ... }
    else if (OB_TMP_FAIL(update_inmemory_ls_table_())) { /* 加速启动,忽略 */ }
    if (FAILEDx(rs_status_.set_rs_status(status::IN_SERVICE))) { ... }
    else if (OB_FAIL(schedule_refresh_server_timer_task(0))) { ... }
    else if (OB_FAIL(schedule_restart_timer_task(0))) { ... }
  }
  if (OB_FAIL(ret)) {
    update_fail_count(ret);
    rs_status_.set_rs_status(status::STOPPING);
    stop_service();   // 启动失败自动回滚
  }
  return ret;
}

这里有两个关键设计:一是 ObRootServiceRoleChecker 保证只有 Leader 才进入 IN_SERVICE,避免脑裂;二是启动失败时自动回滚到 STOPPING 并调用 stop_service(),防止半启动状态对外提供服务。

stop_service:优雅停机与状态重置

stop_service() 是 RS 的停机入口,先停线程,再等待结束,最后把状态重置为 INIT,为后续重新启动或销毁做准备:

int ObRootService::stop_service()
{
  if (OB_FAIL(stop())) { LOG_WARN(...); }
  else { wait(); }
  if (FAILEDx(rs_status_.set_rs_status(status::INIT))) { ... }
  return ret;
}

集群启动:execute_bootstrap

execute_bootstrap() 是集群首次启动时的”开机向导”,串联起系统租户、日志流、Unit 与系统包的创建:

int ObRootService::execute_bootstrap(const obrpc::ObBootstrapArg &arg)
{
  const ObServerInfoList &server_list = arg.server_list_;
  if (server_list.count() <= 0) { ret = OB_INVALID_ARGUMENT; }
  else {
    update_cpu_quota_concurrency_in_memory_();
    ObLatchWGuard guard(bootstrap_lock_, ObLatchIds::RS_BOOTSTRAP_LOCK); // 防并发
    ObBootstrap bootstrap(rpc_proxy_, *lst_operator_, ddl_service_, tenant_ddl_service_,
                          unit_manager_, *config_, arg, common_proxy_);
    if (OB_FAIL(bootstrap.execute_bootstrap(server_zone_op_service_))) { ... }
    if (OB_SUCC(ret)) {
      if (OB_FAIL(load_all_sys_package())) { ... }
      else if (OB_FAIL(do_restart())) { ... }
      else if (OB_FAIL(check_ddl_allowed())) { ... }
      else if (OB_FAIL(update_all_server_and_rslist())) { ... }
      else if (OB_FAIL(zone_manager_.reload())) { ... }
      else if (OB_FAIL(set_cluster_version())) { ... }
      else if (OB_FAIL(finish_bootstrap())) { ... }
      else if (OB_FAIL(update_baseline_schema_version())) { ... }
      else if (OB_FAIL(wait_all_rs_in_service_after_bootstrap_(server_list))) { ... }
      ...
    }
    clear_special_cluster_schema_status();  // 无论成败都清理 bootstrap 标记
  }
  return ret;
}

流程先加 bootstrap_lock_ 防止多节点同时引导,随后调用 ObBootstrap 完成核心元数据创建,再通过 do_restart() 启动后台任务,最后等待所有 RS 进入 IN_SERVICE。每个关键步骤都带有 DBA 级日志与错误建议,运维人员可以根据错误码快速排查。

心跳纽带:renew_lease

renew_lease() 处理 OBServer 上报的心跳请求,是 RS 与集群节点保持连接的纽带。它不仅更新节点状态,还在 full_service 后把租约过期时间、schema 版本、主密钥版本等信息回传给节点:

int ObRootService::renew_lease(const ObLeaseRequest &lease_request,
                               ObLeaseResponse &lease_response)
{
  if (!inited_) { ret = OB_NOT_INIT; }
  else if (!lease_request.is_valid()) { ret = OB_INVALID_ARGUMENT; }
  else if (OB_FAIL(server_manager_.receive_hb(lease_request, server_id, to_alive))) { ... }
  else {
    lease_response.rs_server_status_ = RSS_INVALID;
    if (is_full_service()) {
      zone_manager_.get_lease_info_version(lease_info_version);
      server_manager_.get_server_status(lease_request.server_, server_stat);
      if (!ObHeartbeatService::is_service_enabled()) {
        server_manager_.is_server_stopped(lease_request.server_, is_stopped);
        lease_response.rs_server_status_ = is_stopped ? RSS_IS_STOPPED : RSS_IS_WORKING;
      }
    }
    lease_response.version_ = ObLeaseResponse::LEASE_VERSION;
    construct_lease_expire_time(lease_request, lease_response, server_stat);
    lease_response.server_id_ = server_id;
    lease_response.baseline_schema_version_ = baseline_schema_version_;
    schema_service_->get_tenant_schema_version(OB_SYS_TENANT_ID, lease_response.schema_version_);
    schema_service_->get_refresh_schema_info(lease_response.refresh_schema_info_);
  }
  return ret;
}

心跳不仅是”探活”,更是状态同步通道:节点通过它感知 RS 是否正常工作,RS 通过它维护整个集群的 Server 列表与租约时钟。

小结

ObRootService 把原本分散在集群各处的全局能力收敛到一个类中,通过 INIT → STARTING → IN_SERVICE → STOPPING → INIT 的状态机控制所有子系统的启停顺序。init 负责装配、start_service 负责激活、stop_service 负责优雅退出、execute_bootstrap 负责集群首次创建、renew_lease 负责维持节点心跳。这种”单点总控 + 状态机驱动”的设计,让 OceanBase 在面对集群扩缩容、升级、故障恢复时,有了统一的控制平面与清晰的错误传播路径。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注