---
title: "保证 OceanBase 数据库高可用 - 数据库代理  V4.3.2 | OceanBase 文档中心"
description: 保证 OceanBase 数据库高可用 ODP 除了其服务的高可用， 另一个重要特性就是帮助 OceanBase 数据库实现高可用特性，ODP 属于 OceanBase 数据库高可用体系中重要的一环。当 OceanBase 数据库出现问题后，一方面需要数据库系统及时恢复服务；另一方面需要 ODP 感知 OBServe…
---
切换语言

- 中文站 - 简体中文
- International - English
- 日本站 - 日本語

文档反馈![](https://mdn.alipayobjects.com/huamei_22khvb/afts/img/A*nSAhQbrBXKwAAAAAAAAAAAAADiGDAQ/original) 数据库代理 V 4.3.2

# 保证 OceanBase 数据库高可用

更新时间：2026-04-14 17:41:09

[编辑](https://github.com/oceanbase/oceanbase-proxy-doc/edit/V4.3.2/zh-CN/700.high-availability/300.ob-high-availability.md)  

ODP 除了其服务的高可用， 另一个重要特性就是帮助 OceanBase 数据库实现高可用特性，ODP 属于 OceanBase 数据库高可用体系中重要的一环。当 OceanBase 数据库出现问题后，一方面需要数据库系统及时恢复服务；另一方面需要 ODP 感知 OBServer 节点机器故障和服务变更。

ODP 要实现上述功能，主要通过故障探测、黑名单机制和 SQL 重试三种手段。故障探测用于发现故障节点，黑名单机制影响 ODP 的路由，SQL 重试保证 SQL 尽可能执行成功。

## 故障探测和黑名单机制

### 故障探测

在讲故障探测前，首先需要说明下故障的种类和探测难点。

对于故障的种类，我们主要分为以下两部分。

- 机器和进程故障：如机器宕机、网络故障、进程 core 等机器硬件问题或进程问题。
 - 业务逻辑问题：指 OceanBase 数据库自身逻辑问题导致服务不可用，如 Paxos 选举失败导致无 LEADER 提供服务等。

目前，对于业务逻辑引发故障，与数据库的实现紧密相关，很难去确定问题边界并解决所有问题，比如业务逻辑出现死循环导致服务不可用，ODP 目前是无法解决这种问题的。

因此，ODP 的策略是在处理 OBServer 节点机器和进程故障的基础上，根据一些已知现象去处理一些业务逻辑问题，如 OBServer 节点返回的特定错误码（如机器内存不足）、OBServer 节点长时间无响应等。

在分布式系统中，故障探测的结果有三种：成功、失败和超时。其中，超时是最难处理的情况。比如一个 SQL 执行了 100s 仍然未返回结果，此时很难确定执行这个 SQL 的 OBServer 节点是否正常，有可能仅仅是 OBServer 节点执行慢，但也有可能确实是 OBServer 节点出现了问题；

另一方面，探测任务一般都是周期性的，在两次探测之间如果 OBServer 节点发生了状态变化，ODP 无法做到实时感知，因此可能会使用过期的信息去做一些路由选择，但这样就可能会导致一些慢 SQL 或者 SQL 执行失败。

故障探测的基础是节点状态定义，如定义健康和故障两种状态。但 OBServer 节点的状态要复杂很多，主要是因为将状态定义更加精细才能实现更多的高可用功能，让客户体验更好。ODP 对 OBServer 节点定义了如下八种状态。

- `ACTIVE` 状态：表示 OBServer 节点正常，可以提供服务。
 - `INACTIVE` 状态：表示 OBServer 节点异常，无法提供服务。
 - `UPGRADE` 状态：表示 OBServer 节点正在数据库版本升级阶段。
 - `REPLAY` 状态：表示 OBServer 节点在进行数据库日志的回放阶段。
 - `DELETING` 状态：表示 OBServer 节点正在被删除，此时可能正在进行数据迁移等操作。
 - `DELETED` 状态：表示节点已经被删除，不再属于该集群。
 - `DETECT_ALIVE` 状态：表示 ODP 对 OBServer 节点探测成功，认为 OBServer 节点状态正常。
 - `DETECT_DEAD` 状态：表示 ODP 对 OBServer 节点探测失败，认为 OBServer 节点状态异常。

虽然 OBServer 节点的状态很多，但是从原理上思考就会好记很多，如进程 core（INACTIVE 状态）、节点下线被删除（DELETING 或者 DELETED 状态）、新增节点（REPLAY 状态）、版本升级（UPGRADE 状态）、进程 hang 住（DETECT_DEAD 状态）。

其中前六个状态通过访问 OBServer 节点的视图可以获得，ODP 会周期性（20s/次）从 `DBA_OB_SERVERS` 和 `DBA_OB_ZONES` 视图中获取集群的机器状态信息，ODP 会通过 status、start_service_time、stop_time 定义 OBServer 节点状态。而 `DETECT_ALIVE` 和 `DETECT_DEAD` 状态则通过 ODP 的探测机制获得。

查询结果如下所示：

```sql
MySQL [oceanbase]> select * from DBA_OB_SERVERS\G
*************************** 1. row ***************************
               SVR_IP: 10.10.10.2
             SVR_PORT: 2882
                   ID: 1
                 ZONE: zone1
             SQL_PORT: 2881
      WITH_ROOTSERVER: YES
               STATUS: ACTIVE
   START_SERVICE_TIME: 2022-10-31 11:48:38.677315
            STOP_TIME: NULL
BLOCK_MIGRATE_IN_TIME: NULL
          CREATE_TIME: 2022-10-31 11:48:24.684250
          MODIFY_TIME: 2022-10-31 11:48:39.682642
        BUILD_VERSION: 4.0.0.0_100000252022102910-df01cef074936b9c9f177697500fad1dc304056f(Oct 29 2022 10:27:50)

MySQL [oceanbase]> select * from DBA_OB_ZONES\G
*************************** 1. row ***************************
       ZONE: zone1
CREATE_TIME: 2022-10-31 11:48:29.040552
MODIFY_TIME: 2022-10-31 11:48:29.041609
     STATUS: ACTIVE
        IDC:
     REGION: default_region
       TYPE: ReadWrite

```

### 黑名单机制

需要注意的是，OBServer 节点发生状态变更后，ODP 会根据状态变更结果触发高可用相关的逻辑，许多内容和黑名单机制有关。

展开来讲，就是 ODP 探测出 OBServer 节点状态后，先修改黑名单，然后根据黑名单进行节点拉黑或节点洗白操作。根据不同的探测机制，ODP 实现了状态黑名单、探测黑名单和活不可用黑名单三种不同的黑名单。

#### 状态黑名单

状态黑名单依赖于 OBServer 节点的状态变更。因为历史原因，和状态黑名单相关的状态不包含 `DETECT_ALIVE` 和 `DETECT_DEAD` 两种状态，剩下的状态变更都可以通过访问 OBServer 节点的视图获得。

当通过周期任务获得 OBServer 节点最新状态后，ODP 会进行根据 OBServer 节点状态的不同分别进行如下操作。

- `ACTIVE`：将 OBServer 节点从状态黑名单中移除，洗白 OBServer 节点。
 - `INACTIVE`/`REPLAY`：将 OBServer 节点加入状态黑名单。
 - `DELETED`/`DELETING` 状态：更新内存中 OBServer 节点的机器列表，不会向该节点转发 SQL。
 - `UPGRADE` 状态：不加入状态黑名单，但也不会向该节点转发 SQL，效果和黑名单类似。

#### 探测黑名单

状态黑名单是从 OceanBase 的总控服务节点 RS 处获得信息，这种信息有时不能反映 ODP 和 OBServer 节点之间的情况。如下图所示， ODP 从 RS 处获得 OBServer1 节点状态为 ACTIVE，但 ODP 和 OBServer1 节点之间网络不通。

![示例](https://obbusiness-private.oss-cn-shanghai.aliyuncs.com/doc/img/odp/V4.2.1/zh-CN/700.high-availability/1.png)

因此，ODP 在现有的状态黑名单基础上又实现了探测黑名单，通过给 OBServer 节点发送探测 SQL 来确定 OBServer 节点状态。ODP 会给 OceanBase 数据库的 sys 租户发送探测 SQL `select 'detect server alive' from dual`，并设置 5s 的超时时间，当超时时间内无结果返回时，会增加一次探测失败次数，当连续失败次数超过 3 次后认为探测失败，设置 OBServer 节点状态为 `DETECT_DEAD`。如果有结果返回，会将探测失败次数清零，设置 OBServer 节点状态为 `DETECT_ALIVE`。发生探测状态变更后，触发 ODP 行为如下。

- `DETECT_ALIVE` 状态：将 OBServer 节点从探测黑名单中洗白。
 - `DETECT_DEAD` 状态：将 OBServer 节点加入到探测黑名单，并将所有和该 OBServer 节点的连接关闭。

#### 说明

如果将 OBServer 节点加入到探测黑名单后，不断开和该 OBServer 节点的连接，那么连接会被一直占用，无法发送新的 SQL，在性能数据上会看到这段时间的这台 OBServer 节点的 TPS 为 0。断开后，对于后续请求，ODP 会根据黑名单进行路由，不会转发给这台 OBServer 节点，TPS 就可以恢复。

#### 活不可用黑名单

凭借状态黑名单和探测黑名单，ODP 已经可以很好地处理机器和进程故障，但 ODP 希望可以更近一步感知每个 SQL 执行失败的原因，去处理更复杂的情况，因此实现了活不可用黑名单。

活不可用黑名单机制的核心是根据业务 SQL 的执行结果去定义 OBServer 节点的状态，触发拉黑和洗白操作。相较于状态黑名单和探测黑名单，活不可用黑名单的拉黑和洗白谨慎了很多，主要是为了防止一次 SQL 执行结果产生误判。具体操作如下。

- 失败：根据时间点记录下一次失败事件。

     - ODP 向 OBServer 节点发送 SQL 后，超过 ob_query_timeout 时间后仍然无响应。
     - OBServer 节点返回错误码 OB_SERVER_IS_INIT、OB_SERVER_IS_STOPPING、OB_PACKET_CHECKSUM_ERROR、OB_ALLOCATE_MEMORY_FAILED。
     - ODP 和 OBServer 节点建连失败/报文解析失败，数据传输失败。
 - 拉黑：OBServer 节点在 120s 内有五次活不可用的失败记录则拉黑这台 OBServer 节点。
 - 尝试：加入活不可用黑名单超过 20s 后，尝试再次向该 OBServer 节点发送 SQL。
 - 洗白：如果尝试的 SQL 执行成功则进行洗白。

可以看到，上文介绍的三种黑名单解决了不同维度的问题，少了任何一个都可能导致某种异常无法处理。上述三种黑名单之间并没有优先级，只要 OBServer 节点在任何一个黑名单中，这台机器就无法接收请求，换而言之，只有当 OBServer 节点不在任何黑名单中才会接收到请求。

普通代理一般只实现了探测机制对后端服务器做健康检查，但这种探测只能解决一些简单的问题。ODP 针对 OceanBase 数据库特性，做了更多的工作，如感知 OceanBase 数据库版本升级、日志回放、SQL 执行错误等。这是普通代理完全无法做到的。

#### 查看黑名单

您可参考如下步骤查看黑名单。

1. 在客户端中使用 root 用户，通过 ODP 代理登录集群的 sys 租户。

   ```shell
   obclient -h10.10.10.1 -uroot@sys#obdemo -P2883 -p -c

   ```

   此处是以 ODP 机器 IP 为 `10.10.10.1`，集群名称为 `obdemo`，连接端口为 `2883` 为例，通过 OBClient 连接集群，您需根据实际情况进行修改。
 2. 执行如下命令查看黑名单信息。

   ```sql
   SHOW PROXYCONGESTION [all] [clustername];

   ```

   相关参数说明如下：

      - 不指定可选项时，可查询所有集群的黑名单信息。
      - 仅指定 `all` 时，可显示所有集群的 OBServer 节点信息（包括黑名单中和非黑名单中的 OBServer 节点信息）。
      - 仅指定 `clustername` 时，可显示指定集群的黑名单信息，指定 `clustername` 时需使用英文单引号或双引号引起来。
      - 同时指定 `all` 和 `clustername` 时，可显示指定集群的 OBServer 节点信息。

此处以查看单节点集群 `obcluster` 的黑名单信息为例。

```shell
show proxycongestion 'obcluster'\G

```

输出如下：

```shell
*************************** 1. row ***************************
         cluster_name: obcluster
            zone_name: zone1
          region_name: sys_region
           zone_state: ACTIVE
            server_ip: xxx.xxx.xxx.xxx:2881
           cr_version: 5
         server_state: ACTIVE
      alive_congested: 0
 last_alive_congested: 0
       dead_congested: 0
  last_dead_congested: 0
  stat_alive_failures: 0
   stat_conn_failures: 0
  conn_last_fail_time: 0
  conn_failure_events: 0
 alive_last_fail_time: 0
 alive_failure_events: 0
            ref_count: 2
     detect_congested: 0
last_detect_congested: 0

```

#### 说明

- `dead_congested` 和 `alive_congested` 两个字段分别对应黑名单和活不可用黑名单，这两个字段中任意一个状态为 `1` 时，表示该 OBServer 节点已被加入黑名单。
 - 如果机器被加入活不可用黑名单，ODP 在 `congestion_retry_interval` 时间内不会转发任何请求给该机器，并在 `congestion_retry_interval` 时间后发起重试，并且该 OBServer 节点在 `min_keep_congestion_interval` 时间内不能被洗白。

## SQL 重试

有了黑名单之后就可以实现 SQL 重试功能，SQL 重试的目的是让 SQL 完成执行，而不是简单地把错误抛给客户端。

可以进行重试的一个重要原则是不能产生预期外的行为。举个例子，用户执行了 SQL `insert into t1 values (c1 + 1, 1)`，OBServer 节点很长一段时间没有响应，此时不能重新发给另一台 OBServer 节点，否则有可能导致 c1 变成了 c1 + 2，错误的重试危害更大。

ODP 的重试发生在两个阶段，一个是给 OBServer 节点转发前，一个是给 OBServer 节点转发后，下文将分别介绍这两个阶段。

### 转发前重试

本节以 ODP 架构图讲解转发前重试，下图中橙黄色部分即为转发前重试发生的位置。

![转发前重试](https://obbusiness-private.oss-cn-shanghai.aliyuncs.com/doc/img/odp/V4.2.1/zh-CN/700.high-availability/2.png)

以一个普通的 SQL `select * from t` 为例讲解转发前的重试逻辑。

假设 t 为分区表，表的 partition 的 LEADER 分布在 OBServer1 节点上，OBServer1 节点的 observer 进程 core 之后，RS 发现该机器 core 掉，设置节点状态为 `INACTIVE`。

ODP 会在数据路由阶段选择 OBServer1 节点，之后进行容灾管理检查，发现 OBServer1 节点在状态黑名单中，此时就需要进行路由重试。通过 [租户内路由](https://www.oceanbase.com/docs/common-odp-doc-cn-1000000001601264)，从租户的机器列表中选择机器路由，然后再进行容灾检查，直到容灾检查通过才进行转发。

和所有故障一样，越早发现问题并解决效率越高，转发前重试只发生在 ODP 内部，快速的处理了问题，业务几乎无感知。

### 转发后重试

转发前重试很高效，但依赖黑名单的准确性，在分布式系统中，ODP 无法实时感知机器状态，因此在进行转发前，可能并不知道机器发生了问题。此时根据转发的结果可以进行一定程度的重试。

转发的常见结果有两种

- OBServer 节点机器故障导致 TCP 连接失败

  如果无特殊限制（如事务路由），此时可以选择新的机器进行重试。
 - OBServer 节点执行失败返回错误码

  因为错误码太过于细节本文就不作详细介绍，可以参考 ODP 的开源代码 `ObMysqlTransact::handle_oceanbase_server_resp_error` 去梳理。举例说明， 如果 OBServer 节点返回错误码 `REQUEST_SERVER_INIT_ERROR`，说明 OBServer 节点初始化失败，则可以进行重新转发，后续逻辑和转发前重试逻辑相似。

通过转发前重试和转发后重试，ODP 处理了大量的 OBServer 节点问题，整个过程对用户完全透明，用户可能都不知道发生过故障。其中，转发前重试效率高，但依赖黑名单机制；转发后重试是转发前重试一种补充，尽可能地屏蔽后端异常情况。

总之，故障探测、黑名单和 SQL 重试是 ODP 高可用特性非常重要的三个功能，三者也有一定的关系。比如转发后重试和活不可用黑名单都依赖 OBServer 节点的反馈信息，转发前重试依赖黑名单机制。

通过上面三个高可用功能， ODP 处理了大部分的 OBServer 节点异常，如网络故障、observer 进程异常、机器宕机等；同时，ODP 也进一步识别 OceanBase 数据库本身的一些逻辑异常，如版本升级、日志回放等，让 OceanBase 数据库做的更加的好用。

## 和 OceanBase 高可用关系

OceanBase 数据库的高可用和 ODP 不同，OceanBase 数据库基于 Paxos 算法，保证在多数派正常情况下就可以正常提供服务，容忍了少数派节点异常。但 OceanBase 数据库的高可用可能会导致服务节点从 A 切换到 B（切主操作），因此需要 ODP 更快更准的找到正常服务节点。所以两者之间相互配合，对用户提供稳定的服务。

更多 OceanBase 数据库高可用介绍，请参考 OceanBase 数据库文档 [高可用](https://www.oceanbase.com/docs/common-oceanbase-database-1000000000033233) 章节。

 上一篇 下一篇 ![有帮助](https://gw.alipayobjects.com/mdn/ob_asset/afts/img/A*y6ocSqN8cqsAAAAAAAAAAAAAARQnAQ)![无帮助](https://gw.alipayobjects.com/mdn/ob_asset/afts/img/A*BG9IQJyLHF8AAAAAAAAAAAAAARQnAQ)![反馈](https://gw.alipayobjects.com/mdn/ob_asset/afts/img/A*eTWdQKCRKHwAAAAAAAAAAAAAARQnAQ)[AI](https://www.oceanbase.com/obi) 咨询热线
