3.6 processlist

processlist 用来查看 TiDB 服务器当前的会话信息。

3.6.1 查看 processlist 的方式

可以用以下 3 种方式查看 processlist 信息:

1. 执行 SQL: SHOW [FULL] PROCESSLIST

此语句可以查看当前 TiDB 服务器节点的会话信息。 下面给出一个实际的例子:

  1. SHOW FULL PROCESSLIST;
  1. +------+--------+-----------+--------+-----------+--------+---------+-----------------------+
  2. | Id | User | Host | db | Command | Time | State | Info |
  3. |------+--------+-----------+--------+-----------+--------+---------+-----------------------|
  4. | 1 | root | 127.0.0.1 | <null> | Sleep | 127 | 2 | <null> |
  5. | 3 | root | 127.0.0.1 | <null> | Sleep | 75 | 2 | <null> |
  6. | 5 | root | 127.0.0.1 | <null> | Query | 0 | 2 | show full processlist |
  7. +------+--------+-----------+--------+-----------+--------+---------+-----------------------+

输出字段含义说明如下:

  • Id:连接 TiDB 服务器会话的唯一标识,可以通过 KILL TiDB {ID} 来终止同一服务器上会话 Id 的连接。
  • User:当前会话的用户。
  • Host:会话客户端的主机名。
  • db:会话连接的数据库,如果没有则为 null。
  • Command:会话正在执行的命令类型,一般是休眠(Sleep),查询(Query)。
  • Time:会话处于当前状态的时间(以秒为单位)。
  • State:显示当前sql语句的状态,比如:Sending data,Sorting for group,Creating tmp table,Locked 等等。
  • Info:会话正在执行的语句,为 NULL 时表示没有在执行任何语句。

这里需要注意的是,如果不指定可选关键字 FULL,输出文本会被截断。

2. 查询系统表 INFORMATION_SCHEMA.PROCESSLIST

这种方式和第一种方式输出结果类似,不同点在于查询结果会比 show processlistMEMTxnStart列。这两列具体含义如下:

  1. * `MEM`:指正在处理的请求已使用的内存,单位是 byte。(从 v3.0.5 开始引入)
  2. * `TxnStart`:指当前处理请求的事务开始的时间戳。(从 v4.0.0 开始引入)

下面是一个实际的例子:

  1. select *
  2. from information_schema.processlist
  3. where command != 'Sleep'
  4. order by time desc\G
  1. *************************** 1. row ***************************
  2. ID: 1
  3. USER: root
  4. HOST: 172.16.5.169
  5. DB: NULL
  6. COMMAND: Query
  7. TIME: 0
  8. STATE: 2
  9. INFO: select * from information_schema.processlist where command != 'Sleep' order by time desc
  10. MEM: 4588
  11. TxnStart:
  12. 1 row in set (0.00 sec)

3. 查询系统表INFORMATION_SCHEMA.CLUSTER_PROCESSLIST

查询 TiDB 的 INFORMATION_SCHEMA.PROCESSLIST 系统表时,用户一定会遇到的问题是:此表只包含了当前 TiDB 节点的数据,而不是所有节点的数据。为了解决这个问题,TiDB 4.0 中新增了 INFORMATION_SCHEMA.CLUSTER_PROCESSLIST 系统表,用来查询 所有 TiDB 节点的 PROCESSLIST 数据。其使用方式和 PROCESSLIST 一致。CLUSTER_PROCESSLIST 表比 PROCESSLIST 多一个 INSTANCE 列,用来表示该条数据属于哪一个 TiDB 节点。具体示例如下:

  1. SELECT * FROM INFORMATION_SCHEMA.CLUSTER_PROCESSLIST\G
  1. *************************** 1. row ***************************
  2. INSTANCE: 172.16.4.235:10070
  3. ID: 1
  4. USER: root
  5. HOST: 172.16.5.169
  6. DB: NULL
  7. COMMAND: Query
  8. TIME: 0
  9. STATE: 2
  10. INFO: SELECT * FROM INFORMATION_SCHEMA.CLUSTER_PROCESSLIST
  11. MEM: 0
  12. TxnStart: 04-12 16:51:39.735(415939035066531841)
  13. *************************** 2. row ***************************
  14. INSTANCE: 172.16.5.189:10070
  15. ID: 1
  16. USER: root
  17. HOST: 172.16.5.169
  18. DB: NULL
  19. COMMAND: Sleep
  20. TIME: 6
  21. STATE: 2
  22. INFO: NULL
  23. MEM: 0
  24. TxnStart:
  25. 2 rows in set (0.00 sec)

注意: 只有 root 或者具有 ProcessPriv 权限的 User 能看到所有的会话信息,其他 User 只能看到和自己同一 User 的会话信息。

3.6.2 KILL [TIDB]

KILL TIDB 语句用于终止当前 TiDB 服务器中某个会话的连接。

KILL 语句的兼容性

TiDB 中 KILL xxx 的行为和 MySQL 不相同。在 TiDB 中,需要加上 TIDB 关键词,即 KILL TIDB xxx。但是在 TiDB 的配置文件中设置 compatible-kill-query = true 后,则不需要加上 TIDB 关键词。

KILL 语句兼容性的设计考量

当用户按下 Ctrl+C 时,MySQL 命令行客户端的默认行为是:创建与后台的新连接,并在该新连接中执行 KILL 语句。然而 TiDB 是一个分布式数据库,一个集群可能部署了多个 TiDB 实例。如果负载均衡器或代理已将该新连接发送到与原始会话不同的 TiDB 服务器实例,则该错误会话可能被终止,从而导致使用 TiDB 集群的业务中断。只有当您确定在 KILL 语句中引用的连接正好位于 KILL 语句发送到的服务器上时,才可以启用 compatible-kill-query。因此如果正尝试终止的会话位于同一个 TiDB 服务器上,可在配置文件里设置 compatible-kill-query = true

KILL 示例

  1. SHOW PROCESSLIST;
  1. +------+--------+-----------+--------+-----------+--------+---------+-----------------------+
  2. | Id | User | Host | db | Command | Time | State | Info |
  3. |------+--------+-----------+--------+-----------+--------+---------+-----------------------|
  4. | 5 | root | 127.0.0.1 | <null> | Query | 0 | 2 | show full processlist |
  5. +------+--------+-----------+--------+-----------+--------+---------+-----------------------+
  1. KILL TIDB 5;
  1. Query OK, 0 rows affected (0.00 sec)

再次查看,可以发现 ID 为 5 的 查询已经被 kill 掉了。

3.6.3 示例:利用 INFORMATION_SCHEMA.PROCESSLIST 定位问题查询

通过执行show full processlist 可以看到所有连接的情况,但是大多连接的 state 其实是 Sleep 的。这种连接其实处于空闲状态,没有太多查看价值。 我们要观察的是有问题的连接,可以使用 select 查询对 PROCESSLIST 系统表进行过滤:

  1. -- 查询非 Sleep 状态的链接,按消耗时间倒序展示,加条件过滤
  2. select *
  3. from information_schema.processlist
  4. where command != 'Sleep'
  5. order by time desc \G

这样就过滤出来哪些是正在运行的连接。之后再按照消耗时间倒序展示,排在最前面的,极大可能就是有问题的连接了。最后,通过查看 info 一列,我们就能看到具体执行的什么 SQL 语句了。

  1. *************************** 1. row ***************************
  2. ID: 1
  3. USER: root
  4. HOST: 172.16.5.169
  5. DB: NULL
  6. COMMAND: Query
  7. TIME: 0
  8. STATE: 2
  9. INFO: select *
  10. from information_schema.processlist
  11. where command != 'Sleep'
  12. order by time desc
  13. MEM: 4588
  14. TxnStart:
  15. 1 row in set (0.00 sec)

找出运行较长的 SQL 后,我们可以通过运行 EXPLAIN ANALYZE 语句获得一个 SQL 语句执行过程中的一些具体信息。关于 EXPLAIN ANALYZE 的具体使用,可查看 使用 EXPLAIN 来优化 SQL 语句

当 TiDB 节点内存不足时,可以用同样方式过滤出消耗内存最多的 10 条运行中的命令在具体执行的什么 SQL 语句。

  1. -- 查询非 Sleep 状态的链接,按消耗内存展示其 top10
  2. select *
  3. from information_schema.processlist
  4. where command != 'Sleep'
  5. order by mem desc
  6. limit 10 \G
  1. *************************** 1. row ***************************
  2. ID: 1
  3. USER: root
  4. HOST: 172.16.5.169
  5. DB: NULL
  6. COMMAND: Query
  7. TIME: 0
  8. STATE: 2
  9. INFO: select *
  10. from information_schema.processlist
  11. where command != 'Sleep'
  12. order by mem desc
  13. limit 10
  14. MEM: 4588
  15. TxnStart:
  16. 1 row in set (0.00 sec)

找出内存消耗较多的 SQL 后,同样可以通过运行 EXPLAIN ANALYZE 语来获具体 SQL 执行信息。

我们可以根据 command 和 time 条件找出有问题的执行语句,并根据其 ID 将其 kill 掉。如果觉得一个个 ID 来 kill 太慢,还可以通过 concat() 内置函数来实现快速 kill

  1. -- 查询执行时间超过2分钟,且非 sleep 的会话,然后拼接成 kill 语句
  2. select concat('kill ', 'TiDB', id, ';')
  3. from information_schema.processlist
  4. where command != 'Sleep'
  5. and time > 2*60
  6. order by time desc
  1. -- 然后再来查看执行时间超过2分钟,且非 sleep 的会话,发现已经全部被 kill
  2. select *
  3. from information_schema.processlist
  4. where command != 'Sleep'
  5. and time > 2*60
  6. order by time desc

输出样例:

  1. +------+--------+--------+------+-----------+--------+---------+--------+-------+------------+
  2. | ID | USER | HOST | DB | COMMAND | TIME | STATE | INFO | MEM | TxnStart |
  3. |------+--------+--------+------+-----------+--------+---------+--------+-------+------------|
  4. +------+--------+--------+------+-----------+--------+---------+--------+-------+------------+

3.6.4 示例:利用 INFORMATION_SCHEMA.CLUSTER_PROCESSLIST 定位问题查询

下面一个例子演示了如何利用INFORMATION_SCHEMA.CLUSTER_PROCESSLIST查询集群各个 TiDB 节点的运行时间超过2分钟的会话数量:

  1. select instance, count(*)
  2. from INFORMATION_SCHEMA.CLUSTER_PROCESSLIST
  3. where command != 'Sleep'
  4. and time > 2*60
  5. group by instance;

输出样例:

  1. +---------------+----------+
  2. | instance | count(*) |
  3. +---------------+----------+
  4. | 0.0.0.0:10081 | 1 |
  5. | 0.0.0.0:10080 | 3 |
  6. +---------------+----------+

如果某个节点的长时间运行会话较多,可以进一步查看该节点的具体会话情况,并结合 EXPLAIN ANALYZE 分析具体 SQL 。

3.6.5 与 MySQL 兼容性

  • KILL TIDB 语句是 TiDB 的扩展语法。如果正尝试终止的会话位于同一个 TiDB 服务器上,可在配置文件里设置 compatible-kill-query = true

  • TiDB 中的 State 列是非描述性的。在 TiDB 中,将状态表示为单个值更复杂,因为查询是并行执行的,而且每个 GO 线程在任一时刻都有不同的状态。

  • TiDB 的 show processlist 与 MySQL 的 show processlist 显示内容基本一样,不会显示系统进程号,而 ID 表示当前的 session ID。其中 TiDB 的 show processlist 和 MySQL 的 show processlist 区别如下:

    • 由于 TiDB 是分布式数据库,tidb-server 实例是无状态的 SQL 解析和执行引擎(详情可参考 TiDB 整体架构),用户使用 MySQL 客户端登录的是哪个 tidb-server,show processlist 就会显示当前连接的这个 tidb-server 中执行的 session 列表,不是整个集群中运行的全部 session 列表;而 MySQL 是单机数据库,show processlist 列出的是当前整个 MySQL 数据库的全部执行 SQL 列表。