OceanBase 业务突然变慢,但数据库没有宕机

生产 OceanBase 集群运行正常,业务突然反馈:系统能登录,数据库也能连接,但是查询和提交越来越慢,部分接口开始超时了,请教各位大佬!急救

我执行SQL:SELECT NOW();可以正常返回,数据库没挂,业务SQL从原来的50ms,现在需要5-10秒了,而且发现其中一个节点CPU明显跑高,都快打满了,一直90多

1.用obdiag收集集群近5分钟的日志

2.用obdiag收集集群的ash报告

以上信息提供下

2 个赞

从现象来看,SELECT NOW() 能正常返回,只能说明数据库基本连接和简单 SQL 执行正常,并不能说明 OceanBase 集群整体没有性能问题。

目前比较关键的两个现象是:

  1. 业务 SQL 从原来的 50ms 上升到了 5~10 秒;
  2. 集群中有一个 OBServer 节点 CPU 已经达到 90% 左右。

这种情况我建议优先从 节点负载、租户资源、慢 SQL、等待事件、锁、大事务、执行计划以及数据热点 这几个方向排查。

一、先确认影响范围

首先确认到底是:

  • 所有业务 SQL 都慢;
  • 某一个租户慢;
  • 某几个 SQL 慢;
  • 还是只有访问某个节点的数据慢。

如果只是简单执行:

SELECT NOW();

正常,而业务 SQL 明显变慢,通常说明数据库没有完全失去服务能力,更像是某类业务请求发生了资源争抢或者执行效率下降。

OceanBase 本身是分布式数据库,同一个集群中的不同租户、不同 Tablet、不同 Leader 可能分布在不同 OBServer 上,因此出现“一个节点 CPU 90%,其他节点正常”的情况时,要重点怀疑负载是否集中到了这个节点。

二、先看 OBServer 节点是不是负载不均

建议先从 SYS 租户查看节点状态和资源使用情况。

先确认所有 OBServer 是否正常:

SELECT
    SVR_IP,
    SVR_PORT,
    ZONE,
    STATUS,
    START_SERVICE_TIME,
    STOP_TIME
FROM oceanbase.DBA_OB_SERVERS;

重点确认:

  • STATUS 是否正常;
  • 是否有节点刚刚重启;
  • 是否有节点退出服务;
  • 是否只有某一个节点异常。

操作系统层也可以同时观察:

top

或者:

top -H -p $(pidof observer)

再看:

vmstat 1 10
iostat -x 1 10

这里重点看三个方向:

  • CPU 是 us 高还是 sy 高;
  • 磁盘 %util、await 是否异常;
  • 是否存在明显的 IO 等待。

如果只有一个 OBServer CPU 90%,其他节点 CPU 只有 20%~30%,就不能简单认为是“整个集群资源不足”,需要继续看是不是这个节点承担了大量 SQL、Leader 或热点数据。

三、检查是不是某个租户把 CPU 打满了

OceanBase 是多租户架构,CPU、内存等资源是按照租户资源单元进行隔离的,因此还要区分:

是服务器 CPU 真不够,还是某个租户自己的 CPU 配额已经接近上限。

先确认当前租户信息,例如:

SELECT
    TENANT_ID,
    TENANT_NAME,
    TENANT_TYPE,
    STATUS
FROM oceanbase.DBA_OB_TENANTS;

再检查对应租户资源配置。

重点看该租户对应的 Unit / Resource Pool 的 CPU、内存配置。

如果一个租户配置:

MAX_CPU = 8

即使整台服务器还有很多 CPU,该租户自身能够使用的 CPU 资源仍然受其资源配置影响。

所以这里要区分:

服务器 CPU 90%

和:

租户 CPU 配额已经打满

这是两个概念。

OceanBase 的租户资源本身具有隔离机制,Resource Unit 中包含 CPU、内存等资源。

四、重点查最近的慢 SQL

既然现在最直接的现象是:

原来 50ms
现在 5~10 秒

建议马上查 GV$OB_SQL_AUDIT。

OceanBase 4.x 可以通过:

GV$OB_SQL_AUDIT

查看各个 OBServer 上 SQL 请求的执行情况,包括执行服务器、耗时以及等待信息等。

例如可以先查最近执行时间最长的 SQL:

SELECT
    SVR_IP,
    TENANT_ID,
    USER_NAME,
    SQL_ID,
    ELAPSED_TIME,
    EXECUTE_TIME,
    QUEUE_TIME,
    GET_PLAN_TIME,
    RETURN_ROWS,
    AFFECTED_ROWS,
    QUERY_SQL
FROM oceanbase.GV$OB_SQL_AUDIT
WHERE REQUEST_TIME > TIME_TO_USEC(NOW()) - 60 * 1000000
  AND IS_EXECUTOR_RPC = 0
ORDER BY ELAPSED_TIME DESC
LIMIT 20;

这条 SQL 很重要。

重点看:

SVR_IP
ELAPSED_TIME
EXECUTE_TIME
QUEUE_TIME
GET_PLAN_TIME
SQL_ID
QUERY_SQL

OceanBase 官方也推荐通过 GV$OB_SQL_AUDIT 找指定时间范围内执行时间最长的 SQL。

例如,如果发现:

SVR_IP       10.10.10.12
SQL_ID       A123456
ELAPSED_TIME 8500000
EXECUTE_TIME 8300000
QUEUE_TIME   150000

而恰好:

10.10.10.12

就是 CPU 90% 的节点,那么这个关联就非常重要。

说明慢 SQL 很可能集中在这个 OBServer 上执行。

五、判断慢在哪里

不能只看:

ELAPSED_TIME = 8 秒

还要继续拆。

如果是:

ELAPSED_TIME = 8s
EXECUTE_TIME = 7.8s

说明主要时间花在真正执行 SQL 上。

这时重点怀疑:

  • 全表扫描;
  • 扫描数据量突然增加;
  • 索引没有使用;
  • 执行计划变化;
  • 数据热点;
  • IO 变慢。

如果:

QUEUE_TIME 很高

例如:

ELAPSED_TIME = 8s
QUEUE_TIME   = 6s
EXECUTE_TIME = 1.5s

那反而说明 SQL 本身可能没那么慢。

真正的问题可能是:

请求已经进入 OceanBase,但是因为 CPU/工作线程繁忙,在队列里面排了很久。

这种情况和“某节点 CPU 达到 90%”就高度相关。

OceanBase 官方也特别提到,大查询如果抢占过多 CPU,可能造成 OLTP 请求变慢以及请求队列堆积。

六、检查当前有没有大量活动 SQL

再看看现在有哪些连接正在执行。

例如可以:

SHOW PROCESSLIST;

或者查看:

SELECT *
FROM oceanbase.GV$OB_PROCESSLIST;

重点观察:

  • 有没有大量相同 SQL;
  • 有没有大量长时间执行的请求;
  • 是否集中来自同一个应用 IP;
  • 是否都集中到了同一个租户。

假设突然发现:

应用服务器 10.20.30.15

同时开了几百个并发:

SELECT *
FROM t_order
WHERE customer_id = ?
ORDER BY create_time DESC
LIMIT 20;

那么基本就有方向了。

七、检查是否出现锁等待或者大事务

如果业务反馈不仅查询慢,而且:

INSERT
UPDATE
DELETE
COMMIT

也慢,就一定要查事务和锁。

OceanBase 4.2 以后可以通过:

GV$OB_LOCKS

查看锁的持有和请求情况。

如果发现大量事务都在等待同一条记录,那么可能是热点行。

例如业务同时执行:

UPDATE account
SET balance = balance - 100
WHERE account_id = 10001;

大量事务同时修改:

account_id = 10001

就会形成典型的热点行锁竞争。

表现出来就是:

数据库没挂
SELECT NOW() 正常
但是业务 UPDATE / COMMIT 很慢

OceanBase 本身也支持分布式死锁检测,因此如果业务存在循环锁等待,也需要排查死锁记录。

八、检查 SQL 执行计划有没有发生变化

假设问题 SQL是:

SELECT *
FROM t_order
WHERE customer_id = 10086
ORDER BY create_time DESC
LIMIT 20;

先执行:

EXPLAIN
SELECT *
FROM t_order
WHERE customer_id = 10086
ORDER BY create_time DESC
LIMIT 20;

重点看:

TABLE SCAN
INDEX SCAN
TABLE GET
EST. ROWS
COST

例如原本可能走:

INDEX RANGE SCAN

后来变成:

TABLE FULL SCAN

那么 CPU 突然升高就很好解释了。

例如:

以前:

扫描 20~100 行
耗时 50ms

现在:

扫描 500 万行
耗时 8 秒

如果这种 SQL又有:

200 个并发

那非常容易把单个 OBServer CPU 打到 90% 以上。

OceanBase 官方的慢 SQL 分析流程也是先通过 SQL Audit 找到慢 SQL,再结合执行计划进一步分析。

九、检查是不是数据热点

这一步是 OceanBase 和传统单机 MySQL/Oracle 排查相比特别需要关注的地方。

因为 OceanBase 数据是分布式的。

即使三台 OBServer:

OBServer1 CPU 25%
OBServer2 CPU 30%
OBServer3 CPU 92%

整个集群平均 CPU 看起来并不高。

但如果某个热点 Tablet / Leader 正好在:

OBServer3

大量请求都访问这部分数据,就可能造成:

OBServer3 CPU 爆高

例如订单表按照:

customer_id

进行数据分布。

结果某个超级客户:

customer_id = 10086

占了非常大的访问量。

业务高峰期所有请求都查询:

WHERE customer_id = 10086

那这部分数据就可能形成明显热点。

OceanBase 官方最佳实践中也把热点表导致的 CPU、内存、IO 消耗以及锁竞争列为典型性能问题。

十、检查是否正在做转储、合并或 Compaction

如果业务没有发布,SQL执行计划也没有明显变化,但某个时间点 CPU/IO 突然升高,还要检查 OceanBase 后台任务。

例如:

Minor Compaction
Major Compaction
MemTable 转储
数据迁移
副本迁移
负载均衡

这些后台任务也可能增加:

CPU
磁盘 IO
内存

特别是:

如果 iostat 同时发现磁盘 await、util 明显升高,就需要进一步判断是不是后台 Compaction 和业务 SQL 抢 IO。

所以需要把时间点对上。

例如:

09:58 开始合并
10:00 业务 SQL 从 50ms 上升到 8s
10:01 IO util 到 95%

这种关联性就很强。

十一、如果现在业务已经严重超时,怎么先止血

在没有完全确认根因之前,不建议直接重启 OBServer。

OceanBase 是分布式数据库,一个节点 CPU 高并不代表节点故障。

贸然重启可能导致:

Leader 切换
副本迁移
请求重新路由
其他节点负载升高

反而可能扩大影响。

建议先找到:

TOP SQL

如果确认某条 SQL 占用了绝大部分资源,例如:

SQL_ID = ABC123

执行次数:10000+
平均耗时:7.5 秒
CPU 占用极高

优先考虑:

  1. 应用侧临时降低该 SQL 并发;
  2. 对异常接口进行限流;
  3. 如果是错误任务,暂停该任务;
  4. 确认索引问题后再创建合适索引;
  5. 如果确实属于租户 CPU 不足,再考虑临时扩容租户资源。

不要第一时间:

kill observer
restart observer

十二、结合现在这个故障,我个人会按照下面顺序排查

第一步:

确认哪个 OBServer CPU 90%

第二步:

查 GV$OB_SQL_AUDIT

看最近 1~5 分钟 TOP SQL。

第三步:

看慢 SQL 是否集中在 CPU 高的 OBServer

第四步:

看:

ELAPSED_TIME
EXECUTE_TIME
QUEUE_TIME

判断到底是:

SQL 自己执行慢

还是:

CPU 打满以后排队慢

第五步:

检查:

锁
大事务
热点 SQL

第六步:

对最慢 SQL:

EXPLAIN ...

检查执行计划。

第七步:

如果 SQL 本身没有明显异常,再看:

租户 CPU
Tablet/Leader 热点
Compaction
磁盘 IO

十三、从目前提供的信息初步判断

现阶段只有两个明确线索:

业务 SQL:
50ms → 5~10 秒

某一个 OBServer:
CPU → 90%

所以我目前不会直接下结论说是索引问题。

但是会优先怀疑:

某条或者某批高并发 SQL
        ↓
集中访问某部分数据
        ↓
某个 OBServer 承担大量请求
        ↓
该节点 CPU 接近瓶颈
        ↓
请求开始排队
        ↓
SQL RT 从几十毫秒上升到数秒
        ↓
应用接口开始超时

下一步最有价值的信息就是 GV$OB_SQL_AUDIT。

可以先执行下面这条,把最近一分钟最慢的 20 条 SQL 发出来:

SELECT
    SVR_IP,
    TENANT_ID,
    USER_NAME,
    SQL_ID,
    ELAPSED_TIME,
    EXECUTE_TIME,
    QUEUE_TIME,
    GET_PLAN_TIME,
    RETURN_ROWS,
    AFFECTED_ROWS,
    QUERY_SQL
FROM oceanbase.GV$OB_SQL_AUDIT
WHERE REQUEST_TIME > TIME_TO_USEC(NOW()) - 60 * 1000000
  AND IS_EXECUTOR_RPC = 0
ORDER BY ELAPSED_TIME DESC
LIMIT 20;

如果这里发现 TOP SQL 全部集中在 CPU 90% 的那个 OBServer,那么故障范围基本就可以进一步缩小了。

建议楼主先把下面几项结果贴一下:

1. OceanBase具体版本
2. MySQL模式还是Oracle模式
3. 几台OBServer、几个Zone
4. CPU 90%的节点IP
5. GV$OB_SQL_AUDIT最近一分钟TOP 20
6. top / iostat结果
7. 问题SQL的EXPLAIN执行计划

拿到这些信息以后,基本可以继续判断到底是:

SQL执行计划问题
锁等待
大事务
租户CPU不足
热点Tablet/Leader
磁盘IO
还是Compaction后台任务

不建议现在直接重启节点。

2 个赞

好的,谢谢老师,我看看

哇哦,老师写的这么详细这么多,我看看试试,感谢各位老师的帮助

感谢大佬,我先按你说的查了一轮。
OceanBase 版本是 V4.2.1.10,MySQL 租户模式,3 个 Zone、3 台 OBServer,1-1-1 部署。
目前看节点状态都正常,没有掉节点,其中:
11 CPU 大概 25%
12 CPU 大概 92%
13 CPU 大概 30%

top看主要还是 observer 进程 CPU 比较高,内存目前没有明显异常。
我又查了一下最近一分钟的 GV$OB_SQL_AUDIT,发现最慢的 SQL 基本都集中在 12 上。
其中一条比较明显:

SVR_IP : 10.10.10.12
SQL_ID : 7F3C8Axxxx
ELAPSED_TIME : 8216347
EXECUTE_TIME : 1285460
QUEUE_TIME : 6812734
RETURN_ROWS : 20
对应 SQL 大概是:
SELECT *
FROM t_order
WHERE customer_id = ?
ORDER BY create_time DESC
LIMIT 20;
这个 SQL 最近一分钟执行次数很多,而且大部分请求都在 12。
我又看了另外几条慢 SQL,情况也差不多,ELAPSED_TIME` 很高,但是QUEUE_TIME占了大头。
目前没有看到明显的数据库节点宕机。
这种情况是不是说明 SQL 本身执行其实没有特别慢,主要是 10.10.10.12 CPU 高以后,请求在队列里面排队导致的?
下一步应该先查这个 SQL 为什么都集中到 10.10.10.12,还是先看它的执行计划和索引?

从你这组数据看,判断方向基本是对的。

现在最关键的信息其实不是 ELAPSED_TIME 8.2 秒,而是:

text
ELAPSED_TIME : 8216347
EXECUTE_TIME : 1285460
QUEUE_TIME : 6812734

也就是说这条 SQL 总耗时大概 8.2 秒,但真正执行 SQL 只有 1.28 秒左右,光排队就排了 6.8 秒。

所以目前业务慢的直接原因已经比较明显了:

text
12 负载过高

SQL 请求进入 OceanBase 后无法马上获得执行资源

QUEUE_TIME 大幅增加

SQL RT 从原来的几十毫秒上升到几秒

业务接口开始超时

因此现在不建议先纠结这条 SQL 本身为什么从 50ms 变成 1.28 秒,因为当前最大的问题还是为什么大量请求都堆到了 12。

下一步我建议先查两件事情:

1、先确认到底是哪条 SQL 在持续消耗 12 的资源

不要只按单次 ELAPSED_TIME 排序了,建议把最近一分钟按照 SQL_ID + SVR_IP 聚合一下:

SELECT
SVR_IP,
SQL_ID,
COUNT(*) AS EXEC_COUNT,
ROUND(SUM(ELAPSED_TIME) / 1000000, 2) AS TOTAL_ELAPSED_S,
ROUND(SUM(EXECUTE_TIME) / 1000000, 2) AS TOTAL_EXECUTE_S,
ROUND(SUM(QUEUE_TIME) / 1000000, 2) AS TOTAL_QUEUE_S,
ROUND(AVG(ELAPSED_TIME) / 1000, 2) AS AVG_ELAPSED_MS,
ROUND(AVG(EXECUTE_TIME) / 1000, 2) AS AVG_EXECUTE_MS,
SUBSTR(MIN(QUERY_SQL), 1, 200) AS SAMPLE_SQL
FROM oceanbase.GV$OB_SQL_AUDIT
WHERE REQUEST_TIME > TIME_TO_USEC(NOW()) - 60 * 1000000
AND IS_EXECUTOR_RPC = 0
GROUP BY SVR_IP, SQL_ID
ORDER BY TOTAL_EXECUTE_S DESC
LIMIT 20;

我现在更想知道的不是:

text
哪一条 SQL 单次最慢

而是:

text
最近一分钟到底是谁累计消耗的执行时间最多

比如如果你查出来:

text
SVR_IP SQL_ID EXEC_COUNT TOTAL_EXECUTE_S
12 7F3C8A… 12000 600+

那这条 SQL 就非常可疑。

因为生产环境经常不是某条 SQL 单次慢到几十秒才会把 CPU 打满。

有时候反而是:

text
单次执行 500ms~1s
但是一分钟执行上万次

最后一样可以把一个 OBServer 打到 90% 以上。


2、查这条业务 SQL 的执行计划和索引

你这个 SQL:

sql
SELECT *
FROM t_order
WHERE customer_id = ?
ORDER BY create_time DESC
LIMIT 20;

也需要重点看执行计划。

先执行:

sql
EXPLAIN
SELECT *
FROM t_order
WHERE customer_id = 10086
ORDER BY create_time DESC
LIMIT 20;

然后再查:

sql
SHOW INDEX FROM t_order;

如果方便的话再把:

sql
SHOW CREATE TABLE t_order\G

也贴出来。

我主要想确认几个东西:

text

  1. customer_id 有没有索引
  2. create_time 有没有参与联合索引
  3. 执行计划是 INDEX SCAN 还是 TABLE SCAN
  4. ORDER BY create_time DESC 有没有额外排序
  5. 一次实际扫描了多少行

因为虽然目前 8 秒里面有 6.8 秒是在排队,但 EXECUTE_TIME 现在也有 1.28 秒。

你说这条 SQL 原来只有 50ms 左右,现在真正执行已经到了 1 秒以上,所以这里可能还存在第二层问题:

text
SQL 本身执行效率下降
+
节点 CPU 高导致排队

两个问题叠加在一起。


3、还要确认为什么大量请求都集中到 12

这个也非常关键。

现在三个节点:

text
11 CPU 25%
12 CPU 92%
13 CPU 30%

如果只是整个租户整体业务量突然增加,理论上一般不会表现得这么不均衡。

现在这种现象反而更像:

text
某一批热点数据

对应 Tablet / LS 的 Leader 在 12

大量请求都访问这批数据

请求主要集中到 12

尤其你这条 SQL是:

sql
WHERE customer_id = ?

可以顺便确认一下最近大量执行的参数是不是高度集中在少数几个 customer_id。

如果业务突然都在查同一个客户、同一批订单或者同一个分区的数据,就很容易形成热点。


4、租户 CPU 配额也一起看一下

还有一个容易忽略的地方:

服务器 CPU 高和租户 CPU 配额不足不是完全一回事。

建议把这个业务租户的 Resource Unit 也查一下,重点看:

text
MIN_CPU
MAX_CPU
MEMORY_SIZE

如果租户本身 MAX_CPU 就比较小,而且已经吃满了,那么即使物理机还有余量,请求一样可能发生排队。

所以目前建议你先把这几组结果贴一下:

text

  1. 最近一分钟按 SQL_ID 聚合后的 TOP SQL
  2. 问题 SQL 的 EXPLAIN
  3. SHOW INDEX FROM t_order
  4. 业务租户的 MIN_CPU / MAX_CPU

如果能再补一组:

text
最近一分钟问题 SQL 的执行次数,以及是否主要集中在某几个 customer_id

就更好了。

从目前信息看,我暂时不建议重启 12。

因为现在节点本身还是 ACTIVE,数据库也能正常提供服务,现象更像资源热点而不是 OBServer 故障。

如果直接重启 12,热点 Leader 和业务请求可能只是被转移到 11 或 13,搞不好过一会儿就变成:

text
11 CPU 95%

问题本身并没有解决。

先把上面几组数据贴出来,我们基本就能判断下一步是:

text
高并发 SQL 问题
执行计划 / 索引问题
租户 CPU 配额问题
还是 Tablet / LS 热点问题

感谢大佬,我继续按你说的查了下,结果如下。
先查了最近一分钟按 SQL_ID 聚合的 TOP SQL,确实有一条特别明显:
SVR_IP SQL_ID EXEC_COUNT TOTAL_EXECUTE_S TOTAL_QUEUE_S
12 7F3C8A4B9E… 11863 612.47 3821.65
12 A81D92C7… 426 38.21 56.32
13 C91A7812… 318 21.76 12.44
11 5F72C221… 295 18.63 9.81

第一条就是之前这个:
SELECT *
FROM t_order
WHERE customer_id = ?
ORDER BY create_time DESC
LIMIT 20;

最近一分钟执行了 11863 次,明显比其他 SQL 高很多,而且基本都集中在 12。
然后我查了执行计划:

EXPLAIN
SELECT *
FROM t_order
WHERE customer_id = 10086
ORDER BY create_time DESC
LIMIT 20;

结果里面看到主要是:
TABLE FULL SCAN
SORT
LIMIT

估算扫描行数大概有 300 多万行。
然后查了:
SHOW INDEX FROM t_order;

目前这个表只有主键:
PRIMARY KEY (id)

没有 customer_id 相关索引,也没有 customer_id, create_time 的联合索引。
t_order 目前数据量大概 3000 多万。
租户资源我也看了一下:

MIN_CPU : 8
MAX_CPU : 16
MEMORY : 32G

目前看不像是租户本身只配了很少 CPU。
另外跟业务确认了一下,今天上午刚上线了一个订单查询功能,接口会高频调用这个 SQL。
而且业务说今天有一个大客户在批量查询历史订单,customer_id 基本集中在少数几个值,其中 10086 的访问量特别大。
这样看是不是已经比较明确了?
是不是因为这个 SQL 没有索引,大量全表扫描,再加上同一个 customer_id 请求特别多,最后导致 12 CPU 被打高?
如果是这样,现在生产还在超时,应该先让应用限流,还是可以直接给 t_order 创建 (customer_id, create_time) 联合索引?
这个表有 3000 多万数据,在线建索引会不会对现在本来就比较高的 CPU 和业务造成更大影响?

从你现在贴出来的结果看,根因已经比较明确了。

现在不是单一问题,而是几个因素叠加:

新功能上线

高频调用订单查询 SQL

t_order 3000 多万数据

没有 customer_id / create_time 合适索引

执行计划 TABLE FULL SCAN + SORT

一分钟执行 11863 次

大量消耗 CPU

10.10.10.12 CPU 升到 90%+

SQL 大量进入队列

QUEUE_TIME 持续升高

最终业务接口超时

所以目前可以基本定性为:
高并发 SQL + 缺少合适索引,导致大量全表扫描和排序,进一步造成单节点资源热点和请求排队。**
你这里还有一个很关键的数据:

最近 1 分钟执行次数:11863 次
TOTAL_EXECUTE_S:612.47 秒

这说明这条 SQL 本身的总资源消耗已经非常高。
虽然单次 SQL 不一定慢到几十秒,但是这种:

单次几百毫秒 ~ 1 秒
×
一分钟 1 万多次

一样可以把节点 CPU 打满。


现在先不要急着建索引,先止血
目前 10.10.10.12 CPU 已经 92% 左右,而且业务还在持续超时。
这时候如果直接对 3000 多万行的表建索引,建索引过程本身还会消耗:

CPU
磁盘 IO
内存
临时空间

可能进一步加重当前节点负载。
所以我建议第一步先让应用侧处理:

  1. 对这个新上线的接口临时限流
  2. 降低并发
  3. 如果可以,暂时关闭批量历史订单查询
  4. 特别是 customer_id=10086 这类热点请求先降下来

先观察 5~10 分钟。
重点看:

10.10.10.12 CPU
QUEUE_TIME
SQL 每分钟执行次数
接口响应时间

如果限流以后出现:

CPU 92% → 50%
QUEUE_TIME 6s → 几十毫秒
接口恢复

那就进一步证明这条 SQL 是这次事故的主要触发因素。


第二步,再处理索引

你这条 SQL:

sql
SELECT *
FROM t_order
WHERE customer_id = ?
ORDER BY create_time DESC
LIMIT 20;

从访问模式来看,比较适合考虑联合索引:

(customer_id, create_time)

因为它同时满足:
customer_id 条件过滤
+
create_time 排序

理想情况下,优化后执行计划应该从:

TABLE FULL SCAN
SORT
LIMIT

变成类似:

INDEX RANGE SCAN
LIMIT

这样数据库可以先根据:

customer_id

定位到对应索引范围,再按照 create_time 顺序直接取前 20 条。

就不用每次扫描几百万行再排序了。


但是生产不要直接上 CREATE INDEX

你这个表有 3000 多万行,而且现在节点本身还处于高负载状态。

建议先确认业务低峰窗口,然后再评估创建索引。

如果有测试环境,最好先在测试库或者同结构数据上验证:

CREATE INDEX idx_t_order_cust_time
ON t_order(customer_id, create_time);

建完以后重新:

EXPLAIN
SELECT *
FROM t_order
WHERE customer_id = 10086
ORDER BY create_time DESC
LIMIT 20;

确认执行计划确实使用这个索引。

然后实际执行几次,比较:

执行时间
扫描行数
CPU 消耗

再决定生产实施。


另外还有一点需要继续确认

你说:

很多请求集中在 customer_id = 10086

这个现象说明还可能存在数据热点。

但是这里要区分两个概念。

第一种:SQL 没索引

这是确定存在的问题。

第二种:热点 Tablet / LS

现在还没有完全确认。

所以暂时不要直接说:

就是 Tablet Leader 热点导致的。”

更准确的说法是:

当前已经确认 SQL 本身存在明显执行效率问题,同时请求又高度集中在少数 customer_id,因此不排除进一步形成 Tablet / LS 访问热点。**

如果把索引优化以后:CPU明显下降 QUEUE_TIME恢复

那主要根因就是 SQL。

如果索引优化以后:

11、13节点CPU 20%
12节点CPU仍然80%

那时候再继续查 Tablet / LS Leader 分布就更有意义。


现在建议你按这个顺序操作

第一步:
应用限流 / 暂停批量查询

第二步:
观察CPU和QUEUE_TIME是否回落

第三步:
测试环境验证(customer_id, create_time)联合索引

第四步:
确认执行计划从全表扫描变成索引扫描

第五步:
业务低峰生产建索引

第六步:
重新观察GV$OB_SQL_AUDIT

第七步:
如果12节点仍然明显高于11、13,再继续查Tablet / LS热点

当前阶段我不建议:重启 OBServer

因为节点本身没有故障,重启解决不了 SQL 全表扫描的问题。

也不建议现在立刻:扩租户 CPU

因为如果根本问题是 SQL 每分钟全表扫描一万多次,就算临时把 CPU 从 16 扩到 32,也只是让问题晚一点出现,本质上还是会把更多 CPU 吃掉。
先把异常流量压下来,再解决执行计划问题,才是比较稳妥的处理方式。
你先让应用把这个接口并发降下来,然后再贴一下:

限流前后 10.10.10.12 CPU
限流前后 QUEUE_TIME
限流后该 SQL 每分钟执行次数

如果这三个指标明显下降,基本就可以把这次故障的主因定下来了。

如果是转移积分 希望你删掉帖子 要不然转了积分 会被取消 积分也会扣掉 社区禁止

转移积分 有些明显啊