# Config-Center Client Guide / 客户端使用指南

> Last updated: 2026-04-17. Supersedes the 2025/8 version.
>
> Proto definition: `proto/config_center/config_center.proto`
>
> Constants & mappings: `proto/config_center/const.go`

## Principles / 原则

1. All configs must be explicitly created; `Get` will not return default values for non-existent resources / 所有配置必须显式创建，`Get` 不会返回不存在资源的默认值
2. Configs remain unchanged unless explicitly updated; repeated `Get` returns byte-identical `text` / 未显式更新时配置不变，多次 `Get` 返回逐字节相同的 `text`
3. Read configs only when needed, not by polling / 按需读取，不要轮询
4. Update promptly; only send changed fields / 及时更新，只发送变更字段

## Scenarios / 使用场景

### Create Dedicated TiDB Cluster / 创建 Dedicated TiDB 集群

Dedicated clusters are created by global dedicated service (mgmt) with a **single `AutoUpdateClusterMeta`** call that carries all components and config files atomically. mgmt uses **neither** `InitClusterMeta` (that is NG-only) nor a separate `BatchUpdateClusterComponents` step.

Dedicated 集群由 global dedicated 服务 (mgmt) 通过**一次 `AutoUpdateClusterMeta`** 调用原子创建，请求中携带全部组件与配置文件。mgmt **既不使用** `InitClusterMeta`（那是 NG 专用），**也不**单独调用 `BatchUpdateClusterComponents`。

```
1. Resolve versions (mgmt-side):
   cluster version comes from the caller; for components that may differ
   (e.g. tiproxy) mgmt reads GetClusterComponent and falls back to
   GetDefaultVersion(cloud, region, tenant) when no record exists yet.
   解析版本（mgmt 侧）：集群版本由调用方给出；对可能不同版本的组件
   （如 tiproxy）先 GetClusterComponent，无记录时回退 GetDefaultVersion。

2. AutoUpdateClusterMeta {
     cluster_type: DEDICATED_TIDB, cluster_id, version
     component_requests: [           // one per component
       { component_name, version, cloud_provider, node_instance,
         overwrite_image_tag: "",    // "" = use default tag mapping
         allow_missing: true }
     ]
     configuration_file_requests: [  // auto-update; +tiflash_learner if tiflash, +INIT_SQL, +backup
       { configuration_filename, configuration_type, belong_to_component,
         format, version, cloud_provider, node_instance, tenant_id }
     ]
   }
   → auto-find image for each component (version → component_images)
   → auto-select default template from (version, cloud, node_instance)
   → auto-fill custom_params from tenant initial params for new files
   → returns components (effective_image_tag) and configs (text)
```

`AutoUpdateClusterMeta` internally runs `BatchUpdateClusterComponents` + `BatchAutoUpdateClusterConfigurationFiles` in one transaction, so versions/images and config files are created together. Existing custom params are merged (preserved), not overwritten.

`AutoUpdateClusterMeta` 内部在同一事务中执行 `BatchUpdateClusterComponents` + `BatchAutoUpdateClusterConfigurationFiles`，组件版本/镜像与配置文件一起创建。已有 custom params 会被合并保留，不会被覆盖。

### Open a new region (register regional config-center) / 开区（注册 regional config-center）

Part of onboarding a new TiDBCloud Premium / BYOC region. After the region's **config-center regional is deployed**, you register it **on global**; global then **pushes (syncs) all global data** (templates, component images, default versions, tenant initial params) down into the new regional. Registration is per `cluster_type`: register `SHARED_POOL` first, wait until it is fully synced, then register `LOGICAL_CLUSTER`.

属于 TiDBCloud Premium / BYOC 新区上线流程的一环。该 region 的 **config-center regional 部署完成后**，在 **global** 上注册它；随后由 global **把全部全局数据（模板、组件镜像、默认版本、租户初始参数）推送（同步）**到新的 regional。注册按 `cluster_type` 进行：先注册 `SHARED_POOL`，等其完全同步后，再注册 `LOGICAL_CLUSTER`。

**Prerequisite / 前置条件:** register only after the regional pod **and** its API gateway / DNS are ready and reachable. Registration triggers global → regional sync, and global connects to the `server_address` to push data — if the endpoint is not yet routable the sync goes to `failed`.

**前置条件：** 必须等 regional pod **以及**其 API gateway / DNS 就绪可达后再注册。注册会触发 global → regional 同步，global 会连到 `server_address` 推送数据——若该端点尚不可路由，同步会变为 `failed`。

Calls go to global config-center through the `inner-central` proxy, which requires the `/inner` path prefix and a `Basic` auth key.

调用经由 `inner-central` 代理打到 global config-center，代理要求 `/inner` 路径前缀和 `Basic` 认证 key。

```bash
ENV=prod                              # deployment env / 部署环境
REGION=us-west-2
ADDR=config-center-regional.us-west-2:8081
CENTRAL=https://inner-central.${ENV}.tidbcloud.com
# GLOBAL_AUTH_KEY: the Basic auth key for inner-central / inner-central 的 Basic 认证 key

# 1. Register SHARED_POOL — upserts route + kicks off async sync, returns sync_status "pending"
#    注册 SHARED_POOL —— upsert 路由 + 异步触发同步，立即返回 sync_status "pending"（幂等，可重试）
curl -fsS -X POST -H "Content-Type: application/json" -H "Authorization: Basic $GLOBAL_AUTH_KEY" \
  "$CENTRAL/inner/config-center/cluster-types/SHARED_POOL/regional-servers" \
  -d "{\"logical_region\":\"$REGION\",\"server_address\":\"$ADDR\",\"is_byoc\":false}"

# 2. Poll status until "synced"  (pending → syncing → synced | failed)
#    轮询状态直到 "synced"
curl -fsS -H "Authorization: Basic $GLOBAL_AUTH_KEY" \
  "$CENTRAL/inner/config-center/cluster-types/SHARED_POOL/regional-servers/$REGION"

# 3. If status is "failed", retry the sync, then poll again (step 2)
#    若为 "failed"，重试同步后回到步骤 2 继续轮询
curl -fsS -X POST -H "Authorization: Basic $GLOBAL_AUTH_KEY" \
  "$CENTRAL/inner/config-center/cluster-types/SHARED_POOL/regional-servers/$REGION/sync"

# 4. Once SHARED_POOL is "synced", repeat steps 1–3 for LOGICAL_CLUSTER
#    SHARED_POOL 同步完成后，对 LOGICAL_CLUSTER 重复步骤 1–3
curl -fsS -X POST -H "Content-Type: application/json" -H "Authorization: Basic $GLOBAL_AUTH_KEY" \
  "$CENTRAL/inner/config-center/cluster-types/LOGICAL_CLUSTER/regional-servers" \
  -d "{\"logical_region\":\"$REGION\",\"server_address\":\"$ADDR\"}"
```

`cluster_type` is a path segment (`SHARED_POOL` / `LOGICAL_CLUSTER`); the body fields go to `RegisterRegionalServer`. The `/inner` prefix and `Authorization` header are needed because the call goes through the `inner-central` proxy. For direct, in-cluster calls (no proxy), see the operations-guide — those hit `localhost:8081` with the plain path and no auth.

`cluster_type` 是路径段（`SHARED_POOL` / `LOGICAL_CLUSTER`），body 字段对应 `RegisterRegionalServer`。`/inner` 前缀和 `Authorization` 头是因为请求经 `inner-central` 代理才需要。集群内直连（不经 proxy）的方式见 operations-guide——直接打 `localhost:8081`、用不带前缀的路径、无需认证。

### Create NG Resource Pool / 创建 NG 资源池

NG clusters (`SHARED_POOL` / `LOGICAL_CLUSTER`) use regional config-center. cluster-service-ng calls the regional config-center **directly** (they share the regional RDS); external callers may instead hit global, which proxies to regional. Cluster data is stored in the regional DB, not in global.

NG 集群使用 regional config-center。cluster-service-ng **直接**调用 regional config-center（两者共享 regional RDS）；外部调用方也可走 global，由其代理到 regional。集群数据存储在 regional DB 中，不在 global。

NG clusters are created atomically with `InitClusterMeta`. Note: NG default templates are **node_instance-independent** (the kernel handles hardware differences), so cluster-service-ng sets **no** `node_instance` / `cloud_provider` on components or config sources — the template is selected by `(version, tenant_id)` only.

NG 集群用 `InitClusterMeta` 原子创建。注意：NG 默认模板**与机型无关**（内核自行处理硬件差异），cluster-service-ng 在组件和配置来源上**都不设置** `node_instance` / `cloud_provider`——模板仅按 `(version, tenant_id)` 选择。

`CreateClusterConfigFileRequest` (used inside `InitClusterMeta`) picks the template via a `system_template_source` oneof and the initial custom params via a `custom_params_source` oneof — not flat fields. The SHARED_POOL pool creation uses `FromSKU` + `FromTenant`:

`CreateClusterConfigFileRequest`（`InitClusterMeta` 内部使用）通过 `system_template_source` oneof 选模板、通过 `custom_params_source` oneof 取初始 custom params——不是平铺字段。SHARED_POOL 资源池创建用 `FromSKU` + `FromTenant`：

```
InitClusterMeta {
  cluster_type: SHARED_POOL
  cluster_id: "pool-xxx"
  components: [
    { component_name: "tikv", version: v, overwrite_image_tag: "", tenant_id: 123 },
    { component_name: "pd",   version: v, overwrite_image_tag: "", tenant_id: 123 },
    // ... no node_instance / cloud_provider for NG
  ]
  configuration_files: [
    { configuration_filename: "tikv", configuration_type: "tikv", belong_to_component: "tikv",
      format: TOML,
      system_template_source: { from_sku: { version: v, tenant_id: 123 } },
      custom_params_source:   { from_tenant: { tenant_id: 123 } } },
    // ... + tidb, tiproxy, INIT_SQL (LINES), tidb_sem (JSON)
  ]
}
```

`InitClusterMeta` carries no region field and is **not** proxied by global; send it directly to the target regional config-center endpoint.

`InitClusterMeta` 不带 region 字段，且不经 global 代理；请直接发送到目标 regional config-center 端点。

**Logical cluster (tenant TiDB cluster within a pool):** also created via `InitClusterMeta` (`cluster_type: LOGICAL_CLUSTER`), but it derives from the pool's templates — config sources are `FromTemplate{template_id}` (the pool's tidb/tiproxy template) + `FromInputValues{custom_params}` (copied from the pool), and `overwrite_image_tag` is pinned to the pool component's effective image tag.

**逻辑集群（池内的租户 TiDB 集群）：** 同样用 `InitClusterMeta` 创建（`cluster_type: LOGICAL_CLUSTER`），但派生自资源池的模板——配置来源为 `FromTemplate{template_id}`（池的 tidb/tiproxy 模板）+ `FromInputValues{custom_params}`（从池复制），并将 `overwrite_image_tag` 固定为池组件的 effective image tag。

### Create NG Resource Pool with MetaProfile / 使用 MetaProfile 创建资源池

```
InitClusterMeta {
  cluster_type: SHARED_POOL
  cluster_id: "pool-xxx"
  meta_profile_id: 12345    // MetaProfile ID
  components: [...]
  configuration_files: [...]
}
```

When `meta_profile_id` is set, MetaProfile overrides: component image tags from `ComponentTags`, custom_params source from `ConfigCustomTemplates`.

设置 `meta_profile_id` 时，MetaProfile 覆盖：从 `ComponentTags` 获取组件镜像标签，从 `ConfigCustomTemplates` 获取 custom_params 来源。

### Scale-up / 升配

```
UpdateClusterComponent {
  cluster_type, cluster_id, component_name
  node_instance: "new-instance-type"
  update_related_configuration_files: true   // auto-update template for new SKU
}
```

Only the affected component's config files are updated. Custom params remain unchanged.

仅更新受影响组件的配置文件。Custom params 保持不变。

### Scale-out from zero / 从 0 扩容

```
UpdateClusterComponent {
  component_name: "tiflash"
  version, cloud_provider, node_instance
  allow_missing: true
  update_related_configuration_files: true
}
```

### Upgrade / 升级

**Automated path (mgmt version-release workflow):** a single `AutoUpdateClusterMeta` — config-center auto-selects the template for the target version, and per-release image tags are pinned via `overwrite_image_tag` on each component. This is what the dedicated mgmt service actually does.

**自动路径（mgmt 版本发布工作流）：** 一次 `AutoUpdateClusterMeta`——config-center 按目标版本自动选模板，每个组件通过 `overwrite_image_tag` 固定该次发布的镜像标签。这是 dedicated mgmt 服务的实际做法。

```
AutoUpdateClusterMeta {
  cluster_type: DEDICATED_TIDB, cluster_id
  version: "v8.5.5"
  component_requests: [
    { component_name: "tidb", version: "v8.5.5", cloud_provider, node_instance,
      overwrite_image_tag: "<release_tag>", allow_missing: true },
    // ...
  ]
  configuration_file_requests: [   // auto-update: template auto-selected by (version, cloud, instance)
    { configuration_filename: "tidb", version: "v8.5.5", cloud_provider, node_instance, tenant_id },
    // ...
  ]
}
```

**Manual path (ops portal):** `UpdateClusterMeta` with explicit `template_id` per file (template IDs come from ops portal preview).

**手动路径（ops portal）：** `UpdateClusterMeta`，每个文件显式指定 `template_id`（template ID 来自 ops portal 预览）。

```
UpdateClusterMeta {
  components: [ { component_name: "tidb", version: "v8.5.5" }, /* ... */ ]
  configuration_files: [ { configuration_filename: "tidb", template_id: <new_template_id> }, /* ... */ ]
}
```

In both paths custom params are preserved unless explicitly changed.

两种路径下 custom params 均保留不变，除非显式修改。

### Hotfix (change image tag only) / Hotfix（仅改镜像标签）

```
BatchUpdateClusterComponents {
  requests: [
    { component_name: "tikv", overwrite_image_tag: "v8.5.4-hotfix-123" }
  ]
}
```

Set `overwrite_image_tag` to override the tag mapped from version. Set it to `""` to clear and revert to default mapping.

设置 `overwrite_image_tag` 覆盖从 version 映射的标签。设为 `""` 清除并恢复默认映射。

### Modify cluster config / 修改集群配置

**Option A: Full replace custom_params / 全量替换 custom_params**
```
UpdateClusterConfigurationFile {
  configuration_filename: "tikv"
  custom_params: { "log.level": {value: "debug"}, ... }   // full set of desired custom params
}
```

**Option B: Upsert specific params / 增量更新指定参数**
```
UpsertClusterCustomParams {
  configuration_filename: "tikv"
  upserted_params: { "log.level": {value: "debug"} }      // only changed params
}
```

**Clear all custom params / 清除所有自定义参数：**
```
UpdateClusterConfigurationFile {
  configuration_filename: "tikv"
  clear_custom_params: true
}
```

> Warning: An empty/nil `custom_params` map keeps existing params **unchanged** (proto3 cannot distinguish `{}` from `nil`). To actually clear, set `clear_custom_params: true`.
>
> 警告：空或 nil 的 `custom_params` 会**保持原有参数不变**（proto3 无法区分 `{}` 和 `nil`）。要真正清除，须设置 `clear_custom_params: true`。

### Modify tenant default config / 修改租户默认配置

```
BatchUpdateTenantInitialCustomParams {
  tenant_id: 123
  params: [
    { configuration_type: "tikv", params: { "log.level": {value: "info"} } }
  ]
}
```

Only affects new clusters created after the change. Existing clusters are not modified.

仅影响变更后新创建的集群。现有集群不受影响。

## Error Handling / 错误处理

| gRPC Code | Meaning / 含义 |
|-----------|---------------|
| `NOT_FOUND` | Resource doesn't exist / 资源不存在 |
| `ALREADY_EXISTS` | Duplicate creation / 重复创建 |
| `INVALID_ARGUMENT` | Bad request (unknown config type, invalid format, etc.) / 请求错误 |
| `FAILED_PRECONDITION` | previous_text mismatch / previous_text 不匹配 |
| `INTERNAL` | Server error / 服务端错误 |

## Limits / 限制

| Field | Max Length |
|-------|-----------|
| cluster_id | 63 bytes |
| configuration_filename | 255 bytes |
| param key | 255 bytes |
| param value | TEXT (unlimited, but keep reasonable) |
| version | 63 bytes |
| node_instance | 63 bytes |
