+ 说明
+ 客户端断连接的场景下,ODP 无法收集更为详细的信息,只能指出客户端方面主动断开连接的操作。比较常见的断连接问题有驱动超时主动断开连接、Druid/Hikaricp/Nginx 等中间件主动断连接、网络抖动等问题,具体情况可与客户端配合诊断。
+
+
+### ODP 或 OceanBase 数据库内部错误
+
+ODP 内部错误对应的 trace_type 为 PROXY_INTERNAL_TRACE,OceanBase 数据库内部错误对应的 trace_type 为 SERVER_INTERNAL_TRACE。ODP 内部错误的诊断日志示例如下:
+
+```shell
+[2023-08-10 23:26:12.558201] [32339][Y0-00007F74C9A244E0] [CONNECTION](trace_type="PROXY_INTERNAL_TRACE", connection_diagnosis={cs_id:838860805, ss_id:0, proxy_session_id:7230691830869983237, server_session_id:0, client_addr:"10.10.10.1:44379", server_addr:"", cluster_name:"undefined", tenant_name:"sys", user_name:"root", error_code:-10019, error_msg:"OBProxy reached the maximum number of retrying request", request_cmd:"COM_QUERY", sql_cmd:"COM_QUERY"}{user_sql:"USE `ý<8f>ý<91>ý<92>`"})
+```
+
+额外诊断信息为 `user_sql`,表示用户请求 SQL。
+
+ODP 或 OceanBase 数据库内部错误有如下几种场景。
+
+| 诊断类型 | 场景 | 错误码 | 错误信息 | 解决方法 |
+|------------|---------|-------------|-------------|-----------|
+| PROXY_INTERNAL_TRACE | 租户分区信息查询失败 | 4664 | dummy entry is empty, disconnect | 未预期错误场景,您可联系技术支持人员协助排查或在开源官网 [问答区](https://ask.oceanbase.com/) 提问。 |
+| PROXY_INTERNAL_TRACE | ODP 部分内部请求执行失败 | 10018 | proxy execute internal request failed, received error resp, error_type: xxx | 未预期错误场景,您可联系技术支持人员协助排查或在开源官网 [问答区](https://ask.oceanbase.com/) 提问。 |
+| PROXY_INTERNAL_TRACE | ODP 重试请求达上限 | 10019 | OBProxy reached the maximum number of retrying request | 未预期错误场景,您可联系技术支持人员协助排查或在开源官网 [问答区](https://ask.oceanbase.com/) 提问。 |
+| PROXY_INTERNAL_TRACE | ODP 目标 Session 被关闭 | 10001 | target session is closed, disconnect | 未预期错误场景,您可联系技术支持人员协助排查或在开源官网 [问答区](https://ask.oceanbase.com/) 提问。 |
+| PROXY_INTERNAL_TRACE | 其他未预期的错误场景 | 10001 | 诊断信息为空 | 未预期错误场景,您可联系技术支持人员协助排查或在开源官网 [问答区](https://ask.oceanbase.com/) 提问。 |
+| SERVER_INTERNAL_TRACE | CheckSum 校验出错 | 10001 | ora fatal error | 未预期错误场景,您可联系技术支持人员协助排查或在开源官网 [问答区](https://ask.oceanbase.com/) 提问。 |
+| SERVER_INTERNAL_TRACE | 主备库切换场景 | 10001 | primary cluster switchover to standby, disconnect | 主备库切换过程中可能存在的断连接问题,符合预期的场景。 |
+
+### 其他场景
+
+除上述场景外,诊断日志中还会存在如下两种符合预期的场景,对应的 trace_type 为 PROXY_INTERNAL_TRACE。
+
+| 场景 | 错误码 | 错误信息 | 备注 |
+|---------|-------------|-------------|-----------|
+| kil 当前会话 | 5065 | connection was killed by user self, cs_id: xxx | 符合预期的场景,诊断日志作记录。 |
+| kill 其他会话 | 5065 | connection was killed by user session xxx | 符合预期的场景,诊断日志作记录。 |
+
+诊断日志示例如下,额外诊断信息为 `user_sql`,表示用户请求 SQL。
+
+```shell
+[2023-08-10 23:27:15.107427] [32339][Y0-00007F74CAAE84E0] [CONNECTION](trace_type="PROXY_INTERNAL_TRACE", connection_diagnosis={cs_id:838860806, ss_id:21, proxy_session_id:7230691830869983238, server_session_id:3221695443, client_addr:"10.10.10.1:44536", server_addr:"10.10.10.1:21100", cluster_name:"undefined", tenant_name:"sys", user_name:"", error_code:-5065, error_msg:"connection was killed by user self, cs_id: 838860806", request_cmd:"COM_QUERY", sql_cmd:"COM_QUERY"}{user_sql:"kill 838860806"})
+```
+
+## 示例
+
+客户端请求到 OceanBase 数据库的链路比较常见的有下图两种。
+
+
+
+客户端的请求到 OceanBase 数据库之间的链路需要经过多个节点,任一节点出现问题都有可能会导致客户端的连接断开。所以当发生断连接且客户端没有收到明确的错误包提示断连接原因时,排查断连接问题需先确定断连接方,之后再根据断连接方对应排查断连接原因。具体操作如下。
+
+### 步骤一:确定断连接方
+
+如果当前使用的 ODP 具备连接诊断能力,可通过诊断日志 `obproxy_diagnosis.log` 快速判断出现断连接问题的一方。您可根据用户名、租户名、集群名、从驱动中拿到的 thread_id(对应日志 cs_id)、断连接时间等信息从日志中快速筛选出对应的断连接日志,根据 trace_type 字段判断断连接方,trace_type 字段和断连接方的对应情况如下。
+
+* CLIENT_VC_TRACE:客户端断连接
+
+* SERVER_VC_TRACE:OceanBase 数据库主动断开连接
+
+* SERVER_INTERNAL_TRACE:OceanBase 数据库内部错误
+
+* PROXY_INTERNAL_TRACE:ODP 内部错误
+
+* LOGIN_TRACE:登录失败
+
+* TIMEOUT_TRACE:执行超时
+
+### 步骤二:排查断连接原因
+
+根据不同的断连接方,有如下几种不同的排查方法。
+
+#### 客户端断连接
+
+JDBC 默认的 socketTimeout 配置为 0,即不会产生 socketTimeout 超时,但是部分客户端比如 Druid/MyBatis 自身有控制 socketTimeout 的参数,如果发生请求执行时间过长导致的断连接,可以优先确认 socketTimeout 的配置,详细信息可参见 OceanBase 数据库文档 [数据库连接池配置](https://www.oceanbase.com/docs/common-oceanbase-database-cn-1000000000218815)。
+
+1. 查看对应的 ODP 连接诊断日志,确定断连接的基本信息。
+
+ ```shell
+ [2023-09-07 15:59:52.308553] [122701][Y0-00007F7071D194E0] [CONNECTION](trace_type="CLIENT_VC_TRACE", connection_diagnosis={cs_id:524328, ss_id:0, proxy_session_id:7230691833961840700, server_session_id:0, client_addr:"10.10.10.1:38877", server_addr:"10.10.10.2:50110", cluster_name:"ob1.changluo.cc.10.10.10.2", tenant_name:"mysql", user_name:"root", error_code:-10011, error_msg:"An unexpected connection event received from client while obproxy handling request", request_cmd:"COM_QUERY", sql_cmd:"COM_QUERY"}{vc_event:"VC_EVENT_EOS", total_time(us):5016353, user_sql:"select sleep(20) from dual"})
+ ```
+
+ 主要诊断信息如下。
+
+ * trace_type: 示例中诊断类型为 `CLIENT_VC_TRACE`,可判断出是客户端主动断开的连接。
+
+ * error_msg : 示例中错误信息为 `An unexpected connection event received from client while obproxy handling request`,可判断出客户端在 ODP 处理请求时断开连接。
+
+ * total_time: 示例中请求执行时间为 `5016353`,表示请求总的执行时间为 5s 左右,可以通过 total_time 去匹配客户端的超时参数。
+
+2. 根据 ODP 连接诊断日志信息确定是客户端主动断开了连接,从客户端入手排查,查看 JDBC 堆栈。
+
+ ```shell
+ The last packet successfully received from the server was 5,016 milliseconds ago. The last packet sent successfully to the server was 5,011 milliseconds ago.
+ at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
+ at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
+ at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
+ at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
+ at com.mysql.jdbc.Util.handleNewInstance(Util.java:411)
+ at com.mysql.jdbc.SQLError.createCommunicationsException(SQLError.java:1129)
+ at com.mysql.jdbc.MysqlIO.reuseAndReadPacket(MysqlIO.java:3720)
+ at com.mysql.jdbc.MysqlIO.reuseAndReadPacket(MysqlIO.java:3609)
+ at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:4160)
+ at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2617)
+ at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2778)
+ at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2819)
+ at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2768)
+ at com.mysql.jdbc.StatementImpl.execute(StatementImpl.java:949)
+ at com.mysql.jdbc.StatementImpl.execute(StatementImpl.java:795)
+ at odp.Main.main(Main.java:12)
+ Caused by: java.net.SocketTimeoutException: Read timed out
+ at java.net.SocketInputStream.socketRead0(Native Method)
+ at java.net.SocketInputStream.socketRead(SocketInputStream.java:116)
+ at java.net.SocketInputStream.read(SocketInputStream.java:170)
+ at java.net.SocketInputStream.read(SocketInputStream.java:141)
+ at com.mysql.jdbc.util.ReadAheadInputStream.fill(ReadAheadInputStream.java:114)
+ at com.mysql.jdbc.util.ReadAheadInputStream.readFromUnderlyingStreamIfNecessary(ReadAheadInputStream.java:161)
+ at com.mysql.jdbc.util.ReadAheadInputStream.read(ReadAheadInputStream.java:189)
+ at com.mysql.jdbc.MysqlIO.readFully(MysqlIO.java:3163)
+ at com.mysql.jdbc.MysqlIO.reuseAndReadPacket(MysqlIO.java:3620)
+ 9 more
+ ```
+
+ 从堆栈以及收发包时间可大致判断出示例中为 socketTimeout 触发的问题。
+
+#### ODP 断连接
+
+ODP 会读取 OceanBase 数据库设置的 `net_write_timeout` 配置,控制收包和发包时传包的超时时间,该配置默认时间为 60s。当网络环境比较极端或者 OceanBase 数据库回包处理较慢时,可能会出现 ODP 等待回包数据超时断连接的问题。此处以 ODP 等待回包数据超时场景为例介绍如何排查断连接原因。
+
+根据 ODP 断连接诊断日志判断断连接方。
+
+```shell
+[2023-09-08 01:22:17.229436] [81506][Y0-00007F455197E4E0] [CONNECTION](trace_type="TIMEOUT_TRACE", connection_diagnosis={cs_id:1031798827, ss_id:342, proxy_session_id:7230691830869983244, server_session_id:3221753829, client_addr:"10.10.10.1:34901", server_addr:"10.10.10.1:21102", cluster_name:"undefined", tenant_name:"mysql", user_name:"root", error_code:-10022, error_msg:"OBProxy inactivity timeout", request_cmd:"COM_QUERY", sql_cmd:"COM_QUERY"}{timeout(us):6000000, timeout_event:"CLIENT_NET_WRITE_TIMEOUT", total_time(us):31165295})
+```
+
+主要诊断信息如下。
+
+* trace_type: 示例中诊断类型为 `TIMEOUT_TRACE`, 可判断出是因为 ODP 执行超时导致断连接。
+
+* timeout_event: 示例中超时事件为 `CLIENT_NET_WRITE_TIMEOUT`,可判断出 ODP 因为等待回包数据超时而发生断连接。
+
+根据诊断信息可以确定触发了 net_write_timeout,客户端连接等待数据超过 6s(非默认值),导致连接断开,通过修改系统变量延长超时限制可暂时规避。
+
+#### 登录失败
+
+此处以两种场景介绍如何排查断连接原因。
+
+* 以 rootservice_list 指定的 OBServer 节点不可用为例介绍如何排查断连接原因,连接诊断日志如下。
+
+ ```shell
+ [2023-09-08 10:37:21.028960] [90663][Y0-00007F8EB76544E0] [CONNECTION](trace_type="LOGIN_TRACE", connection_diagnosis={cs_id:1031798785, ss_id:0, proxy_session_id:0, server_session_id:0, client_addr:"10.10.10.1:44018", server_addr:"*Not IP address [0]*:0", cluster_name:"undefined", tenant_name:"sys", user_name:"root", error_code:-10018, error_msg:"fail to check observer version, empty result", request_cmd:"COM_SLEEP", sql_cmd:"COM_LOGIN"}{internal_sql:"SELECT ob_version() AS cluster_version"})
+ ```
+
+ 主要诊断信息如下。
+
+ * trace_type:示例中诊断类型为 `LOGIN_TRACE`,可确定是登录失败的问题。
+
+ * internal_sql:示例中 ODP 当前执行的内部请求为 `SELECT ob_version() AS cluster_version`,可确定登录过程中 ODP 执行该内部请求失败。
+
+ * error_msg:示例中错误信息为 `fail to check observer version, empty result`,可确定内部请求失败的原因为结果集为空。
+
+ 诊断信息总结即为:ODP 执行内部请求 `SELECT ob_version() AS cluster_version` 失败,结果集为空。`SELECT ob_version() AS cluster_version` 这条 SQL 是 ODP 查询集群版本的请求,在您首次登录时 ODP 会执行这条请求校验集群信息,当 ODP 启动时配置的 rootservice_list 错误或者 OBServer 节点宕机时,ODP 查询失败,便会导致登录失败。
+
+* 以客户端连接达到 ODP 上限为例介绍如何排查断连接原因。
+
+ 客户端连接达到 ODP 上线导致断连接有如下两种排查方法。
+
+ * 方法一:排查连接诊断日志。
+
+ ```shell
+ [2023-09-08 11:19:26.617385] [110562][Y0-00007FE1F06AC4E0] [CONNECTION](trace_type="LOGIN_TRACE", connection_diagnosis={cs_id:1031798805, ss_id:0, proxy_session_id:0, server_session_id:0, client_addr:"127.0.0.1:40004", server_addr:"*Not IP address [0]*:0", cluster_name:"undefined", tenant_name:"sys", user_name:"root", error_code:-5059, error_msg:"Too many sessions", request_cmd:"COM_SLEEP", sql_cmd:"COM_LOGIN"}{internal_sql:""})
+ ```
+
+ 主要诊断信息如下。
+
+ * trace_type:示例中诊断类型为 `LOGIN_TRACE`,可确定是登录失败的问题。
+
+ * error_msg:示例中错误信息为 `Too many session`,可确定是因为连接数达到上限导致登录失败。
+
+ * 方法二:直接根据错误包判断,执行连接命令,输出 `Too many sessions`。
+
+ ```shell
+ $ obclient -h127.0.0.1 -P2899 -uroot@sys -Dtest -A -c
+ ERROR 1203 (42000): Too many sessions
+ ```
diff --git a/docs/user_manual/operation_and_maintenance/tool_emergency_handbook/odp_troubleshooting_guide/04_routing_diagnosis.md b/docs/user_manual/operation_and_maintenance/tool_emergency_handbook/odp_troubleshooting_guide/04_routing_diagnosis.md
new file mode 100644
index 000000000..51f46da7d
--- /dev/null
+++ b/docs/user_manual/operation_and_maintenance/tool_emergency_handbook/odp_troubleshooting_guide/04_routing_diagnosis.md
@@ -0,0 +1,490 @@
+---
+title: 排查 ODP 路由问题
+weight: 4
+---
+
+> 本小节将介绍路由诊断功能被开发的原因、如何使用路由诊断功能,以及如何根据诊断信息查找和解决问题。
+
+ODP 是 OceanBase 数据库的接入层和路由层,而路由是 ODP 的核心功能,目前使用过程中发现,路由过程出现问题的情况下排查问题较为困难,因此 ODP V4.2.1 迭代中开发了路由诊断功能,通过在 ODP 路由转发的关键过程中设置诊断点来记录关键状态信息,这些诊断点可以被输出到日志或以结果集方式返回。
+
+通过分析输出的诊断点,可以清晰地了解一条 SQL 语句从进入 ODP 到被转发出去的过程中发生了什么。
+
+## 路由诊断流程
+
+使用路由诊断功能排查问题的流程如下。
+
+1. 获取诊断信息,详细介绍可参见 “获取诊断信息” 部分。
+
+2. 根据诊断信息排查问题,详细介绍可参见 “诊断点排查” 部分。
+
+
+## 获取诊断信息
+
+本文介绍两种获取诊断信息的方法,可通过如下任一方法获取诊断信息。
+
+### 命令行语句
+
+可通过 `explain route