---
title: "租户内路由 - 数据库代理  V4.2.1 | OceanBase 文档中心"
description: 租户内路由 租户内路由是指在获取租户的机器列表后，选择合适的节点执行 SQL。 对于租户内路由，ODP 可以像普通代理（如 HAProxy）一样，一个客户端连接对应一个服务端连接，服务端机器从租户机器列表选取，这样功能就会简单很多，但无法满足性能和高可用要求，可见路由影响了连接管理。 租户内路由是路由功能最复杂的部分…
image: https://mdn.alipayobjects.com/huamei_22khvb/afts/img/A*OSPzQ6GUQF4AAAAAQHAAAAgAeiGDAQ/original
---
切换语言

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

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

# 租户内路由

更新时间：2026-07-22 16:51:01

[编辑](https://github.com/oceanbase/oceanbase-proxy-doc/edit/V4.2.1/zh-CN/600.data-routing/400.intra-tenant-routing.md)  

租户内路由是指在获取租户的机器列表后，选择合适的节点执行 SQL。

对于租户内路由，ODP 可以像普通代理（如 HAProxy）一样，一个客户端连接对应一个服务端连接，服务端机器从租户机器列表选取，这样功能就会简单很多，但无法满足性能和高可用要求，可见路由影响了连接管理。

租户内路由是路由功能最复杂的部分，主要原因在于如何提供更好的性能和更高的可用性。本章将按照主副本路由、备副本路由、租户机器路由、缓存信息、路由策略、事务路由和常见问题这七部分进行介绍。

## 主副本路由

在分布式系统中，为了容灾高可用，会采用多副本机制。副本之间需要保证数据一致性，往往采用 Paxos 或者 Raft 算法，在工程实践中，有一个特殊副本，该副本数据最新，并控制数据在副本间的同步，这个副本叫做主副本，其它副本统称为备副本。

由于 OceanBase 数据库只有一个主副本，因此，主副本路由策略就是发往该副本。此处以 `select c1 from t1` 语句为例，介绍主副本路由需要满足的两个条件：

- SQL 语句操作（查询、插入、更新和删除等）实体表，如上例中的 t1 表。
 - 请求必须读到最新数据，即强读。

在 ODP 日志中，主副本路由的关键字是 `ROUTE_TYPE_LEADER`。要实现主副本路由，就需要知道访问的分区标识和分区所在的位置。在 ODP 的实现中，分为两种情况。

- 单分区表

  表只有一个分区，根据表名就可以获得副本位置信息；
 - 多分区表

  表有多个分区，ODP 需要根据 SQL 中的表名和分区键计算出分区标识，之后再获取副本位置信息。副本信息包含主副本信息和备副本信息，主副本路由只需要使用主副本信息。

对于多分区路由，涉及分区方式（如 hash、range 和 list）、分区键类型（number、varchar 等）、分区算法（如 hash 算法）、类型转换（如 SQL 中的值类型和分区键类型不同）等知识点，实现比较复杂。以二级分区为例，路由分为如下 10 个步骤：

1. 解析 SQL 获取表名
 2. 根据表名访问 OceanBase 内部表，确认是分区表
 3. 解析 SQL 中的列表达式（如 c1=1）
 4. 访问 OceanBase 内部表获取分区表信息
 5. 访问 OceanBase 内部表获取一级分区信息
 6. 根据列表达式计算一级分区的 partition_id
 7. 访问 OceanBase 内部表获取二级分区信息
 8. 根据列表达式计算二级分区的 partition_id
 9. 计算最终的 partition_id
 10. 访问 OceanBase 内部表获取对应 partition_id 的位置信息

## 备副本路由

和主副本路由相似，备副本路由也需要满足两个条件：

1. SQL 语句查询实体表，如 `select c1 from t1` 中的 t1 表。
 2. 请求要求弱读即可，即不要求读到最新数据。

这两个条件和主副本路由需要满足的条件是有区别的：

- 对于条件 1，备副本路由只支持查询语句，不支持其他语句，这也是 Paxos 算法的实现要求。
 - 对于条件 2，需要主动设置弱读标记 `ob_read_consistency=weak`，可以通过 hint、session 等设置。

对于备副本路由，SQL 发往主副本和备副本都可以正常工作，因此备副本路由的选择变多了（多个副本选择的问题请参考 [路由策略](https://www.oceanbase.com/docs/common-odp-doc-cn-1000000000050279)）。

和备副本相关的一个重要话题就是读写分离，请求进行读写分离后，可以降低主副本压力。ODP 也实现了读写分离功能，并在不断打磨细节，在 OceanBase 公有云等场景帮助客户解决了性能问题。读写分离详细信息请参考 [读写分离](https://www.oceanbase.com/docs/common-odp-doc-cn-1000000000050281)。

## 租户机器路由

有时 ODP 无法获取主副本或备副本，此时可以从租户机器中选取一台，这就是租户机器路由。常见的租户机器路由场景如下：

- SQL 本身不包含表名，如 `select 1` 语句。
 - 主副本或者备副本所在的机器有故障。
 - ODP 本身功能限制，如复杂 SQL 无法获得表名，无法走副本路由。

通过租户机器路由，ODP 将 SQL 发往租户所在的机器，因此可以保障功能正常。租户机器路由和备副本路由一样，有多个副本可以选择，也存在着路由策略的问题。

## 缓存信息

主副本路由、备副本路由和租户机器路由都需要通过 sys 租户查询副本路由信息，为了提升性能和降低对 sys 租户的压力，ODP 对路由信息做了缓存。

对于缓存信息，最重要的是时效性。sys 租户的缓存信息可以通过定期访问内部表创建和刷新，但是副本路由的缓存信息却不可以采用此策略，主要问题是拉取副本路由信息的 SQL 太多，会对 sys 租户造成很大的压力。

SQL 数量 = 副本的个数 * ODP 数量。

OceanBase 数据库可以支持十万、百万分区，分区数极大。因此，缓存时效性对 ODP 是一大难题，使用了过期的缓存信息就会出现常说的“路由不准”的问题。那么，怎么保证缓存的时效性呢？

我们先看一下缓存信息在 ODP 中的内容。使用 `root@proxysys` 账号登录 ODP，通过 `show proxyroute` 命令可以查看表的缓存信息，如下：

```sql
MySQL [(none)]> show proxyroute like 'ob1.hudson tt1 test sbtest1'\G
*************************** 1. row ***************************
        cluster_name: ob1.hudson
         tenant_name: tt1
       database_name: test
          table_name: sbtest1
               state: AVAIL
       partition_num: 1
         replica_num: 3
            table_id: 1101710651081698
     cluster_version: 2
      schema_version: 1649196335597728
         from_rslist: N
         create_time: 2022-04-07 12:41:16
     last_valid_time: 2022-04-07 12:41:16
    last_access_time: 2022-04-07 12:41:16
    last_update_time: 1970-01-01 08:00:00
         expire_time: 2022-04-12 12:48:42
relative_expire_time: 2022-04-07 12:40:41
         server addr: server[0]=xx.xx.xx.xx:xx,leader,FULL; server[1]=xx.xx.xx.xx:xx,follower,FULL; server[2]=xx.xx.xx.xx:xx,follower,FULL;

```

这个例子展示了缓存包含的重要信息：集群名、租户名、库名、表名、分区数、副本数、时间、地址信息和缓存状态等。其中，缓存状态是需要重点关注的对象，缓存策略都是通过修改状态信息实现的，这些状态影响缓存的刷新机制。缓存信息分为如下 5 个状态。

- `BUILDING` 状态：缓存正在创建，需等待创建完成然后使用。
 - `AVAIL` 状态：缓存正常，直接使用即可。
 - `DIRTY` 状态：缓存失效，信息不准确。
 - `UPDATING` 状态：失效的缓存正在更新过程中。
 - `DELETED` 状态：缓存已经被删除，不可以使用，后续会被清理掉。

通过修改缓存状态可以刷新缓存状态，从而保证时效性，下面从创建、淘汰和刷新这三方面介绍缓存刷新机制。

- 缓存创建：首次访问分区时，ODP 通过查询 sys 租户的 `__all_virtual_proxy_schema` 获得，指定表名为真实表名，注意和租户路由信息部分区分，创建好后缓存状态为 `AVAIL`。
 - 缓存淘汰：当 OBServer 节点返回路由不准时（OBServer 节点会通过 OK 报文中携带的 `is_partition_hit` 字段反馈），ODP 修改缓存状态为 `DIRTY`。
 - 缓存刷新：当缓存信息变为 `DIRTY` 状态后，淘汰过期缓存，并重新创建或者更新缓存信息。

#### 说明

目前缓存淘汰主要通过 OBServer 节点的报文反馈实现，这样就无法实时感知，只有出现一次“错误”路由后，才能刷新，这也是容易出问题一个地方。

## 事务路由

上文介绍了单个 SQL 的路由策略，有些功能（如事务功能）包含一条或多条 SQL，此时就需要使用到事务路由。

ODP 针对事务有两种路由方式，一种是将同一个事务的语句统一路由到一个数据节点上执行；另一种是将事务中的语句拆分，路由到不同的数据节点执行，通过 ODP 同步不同数据节点事务的状态，完成事务的拆分执行。

#### 说明

事务路由依赖 OceanBase 2.0 协议进行事务状态的同步。

### 事务路由节点选择

事务路由的执行节点分为协调者和参与者两种节点。协调者节点即事务的开启节点，负责执行会影响事务状态的非 DML 语句，比如 BEGIN、START TRANSACTION、COMMIT、ROLLBACK 等；参与者节点负责执行事务中不会影响事务状态的 DML 语句。

ODP 包含简单的 SQL Parser，能够解析出 SQL 语句是否为 DML 语句，ODP 解析出一条语句属于 DML 语句之后，会通过表路由或者 LDC 路由将语句路由到合适的节点，被路由到的节点即成为事务的参与者节点。而事务的协调者节点即事务中第一条语句的执行节点。

#### 说明

LDC 路由信息请参考 [路由策略](https://www.oceanbase.com/docs/common-odp-doc-cn-1000000000050279)。

### 事务路由配置

默认情况下事务路由的功能是开启的，可以使用以下语句查询、运维事务路由的功能。

1. 在客户端中使用 root 用户登录集群的 sys 租户。
 2. 检查修改 OceanBase 2.0 协议的配置，确保 OceanBase 2.0 协议启用。

   ```sql
   obclient> SHOW PROXYCONFIG LIKE enable_ob_protocol_v2;
   obclient> ALTER PROXYCONFIG SET enable_ob_protocol_v2=True;

   ```
 3. 执行以下语句对 ODP 的事务路由进行配置。

   ```sql
   obclient> SHOW PROXYCONFIG LIKE enable_transaction_internal_routing;
   obclient> ALTER PROXYCONFIG SET enable_transaction_internal_routing=True;

   ```

## 常见问题

在进行租户内路由时，有以下几项常见问题：

- 无法获取表名（主副本路由）

     - SQL 太复杂，目前 ODP 无法识别所有的 SQL 语句。
     - SQL 太长，ODP 存储 SQL 的 buffer 只有 4k，SQL 太长不会全解析。
 - 分区计算失败（主副本路由）

     - ODP 无法支持多分区键的计算，如 range(c1,c2)。
     - SQL 语句中没有分区键的表达式或 ODP 未提取出来。
     - 分区键表达式 ODP 无法处理，如 c1=now()，ODP 还未支持 now 函数。
 - 使用过期缓存（缓存信息）

     - ODP 无主动刷新机制。
     - OBServer 节点未进行路由反馈，如分布式计划 OBServer 节点不反馈。
 - 配置错误：

     - 未设置路由策略为 `FOLLOWER_FIRST`，弱读发往了主副本（备副本路由）。
     - 未设置 LDC 路由信息或者信息设置错误导致跨机房或者跨城（路由策略）。

 上一篇 下一篇 ![有帮助](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) 咨询热线
