Mysql性能排查—结合操作系统线程 查看mysql中的sql资源消耗
Posted 翔之天空
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Mysql性能排查—结合操作系统线程 查看mysql中的sql资源消耗相关的知识,希望对你有一定的参考价值。
当系统资源紧张时,可以通过系统的线程id 来查找对应mysql的sql语句。 以便快速定位问题。 --一、结合操作系统线程 查看mysql中的sql资源 消耗 ( 5.7 才可以, 5.7时 performance_schema.threads表 才加入的 thread_os_id 系统线程字段 )
--1、top -H 查看具体线程的CPU消耗
[root@hostmysql80 mysql]# top -H
--2、iotop -u mysql 查看具体线程的IO消耗
[root@hostmysql80 mysql_setup]# iotop -u mysql
--3、mysql中 查看操作系统线程id(thread_os_id) 和sql 对应
SELECT a.name,
a.thread_id,
a.thread_os_id, //操作系统的线程id (top -H 对应PID, iotop -u mysql 对应TID)
a.processlist_id, //mysql进程id,可以kill query 或者kill (connection)杀掉。
a.type, //线程类型,分前台线程和后台线程
b.user, //用户
b.host, //ip
b.db, //操作的库名称
b.command, //sql类型
b.time, //sql执行时间 单位:秒
b.state, //sql状态
b.info //sql语句
FROM performance_schema.threads a
LEFT JOIN information_schema.processlist b
ON a.processlist_id = b.id
where a.type = 'FOREGROUND';
--二、具体事例
--1、执行一个大sql
mysql> update test_limit_table set b=round(rand()*b,0);
--2、查看cpu高的线程是 2142,top -H 的时候 此时PID不是进程ID 而是线程id(LWP id)
[root@hostmysql80 mysql]# top -H
top - 10:41:23 up 17 min, 4 users, load average: 2.38, 2.39, 1.41
Threads: 324 total, 2 running, 322 sleeping, 0 stopped, 0 zombie
%Cpu(s): 69.9 us, 17.8 sy, 0.0 ni, 0.0 id, 10.3 wa, 0.0 hi, 2.1 si, 0.0 st
KiB Mem : 284388 total, 4424 free, 162408 used, 117556 buff/cache
KiB Swap: 2097148 total, 1566856 free, 530292 used. 79560 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
2142 mysql 20 0 2195448 74992 2348 R 83.1 26.4 0:03.78 mysqld
27 root 20 0 0 0 0 S 0.7 0.0 0:24.16 kswapd0
--3、查看 2142线程的 具体的sql
mysql> SELECT a.name,
a.thread_id,
a.thread_os_id,
a.processlist_id,
a.type,
b.user,
b.host,
b.db,
b.command,
b.time,
b.state,
b.info
FROM performance_schema.threads a
LEFT JOIN information_schema.processlist b
ON a.processlist_id = b.id
where a.type = 'FOREGROUND'
and a.thread_os_id =2142;
+---------------------------+-----------+--------------+----------------+------------+------+-----------+-------+---------+------+----------+-------------------------------------------------+
| name | thread_id | thread_os_id | processlist_id | type | user | host | db | command | time | state | info |
+---------------------------+-----------+--------------+----------------+------------+------+-----------+-------+---------+------+----------+-------------------------------------------------+
| thread/sql/one_connection | 34 | 2142 | 7 | FOREGROUND | root | localhost | flydb | Query | 28 | updating | update test_limit_table set b=round(rand()*b,0) |
+---------------------------+-----------+--------------+----------------+------------+------+-----------+-------+---------+------+----------+-------------------------------------------------+
1 row in set (2.23 sec)
--4、同理 监控IO资源的具体线程id 是TID, 也是2142线程
[root@hostmysql80 mysql_setup]# iotop -u mysql
Total DISK READ : 24.30 M/s | Total DISK WRITE : 23.36 M/s
Actual DISK READ: 45.48 M/s | Actual DISK WRITE: 26.56 M/s
TID PRIO USER DISK READ DISK WRITE SWAPIN IO> COMMAND
2142 be/4 mysql 7.33 M/s 1051.47 K/s 51.21 % 11.29 % mysqld --daemonize --pid-file=/var/run/mysqld/mysqld.pid
2108 be/4 mysql 2.20 M/s 7.73 M/s 0.00 % 8.03 % mysqld --daemonize --pid-file=/var/run/mysqld/mysqld.pid
2115 be/4 mysql 9.18 M/s 0.00 B/s 0.00 % 5.11 % mysqld --daemonize --pid-file=/var/run/mysqld/mysqld.pid
2117 be/4 mysql 1669.21 K/s 1113.90 K/s 0.00 % 4.82 % mysqld --daemonize --pid-file=/var/run/mysqld/mysqld.pid
2110 be/4 mysql 2.71 M/s 7.83 M/s 1.89 % 4.24 % mysqld --daemonize --pid-file=/var/run/mysqld/mysqld.pid
2106 be/4 mysql 0.00 B/s 0.00 B/s 0.00 % 2.41 % mysqld --daemonize --pid-file=/var/run/mysqld/mysqld.pid
2109 be/4 mysql 0.00 B/s 3.75 M/s 0.00 % 2.41 % mysqld --daemonize --pid-file=/var/run/mysqld/mysqld.pid
.......
--三、源码
--1、linux和POSIX的线程概念:
第一种:在linux下每一个进程都一个进程id,类型pid_t,可以由 getpid()获取。
第二种:POSIX线程也有线程id,类型pthread_t,可以由 pthread_self()获取,线程id由线程库维护。
但是各个进程独立,所以会有不同进程中线程号相同节的情况。那么这样就会存在一个问题,我的进程p1中的线程pt1要与进程p2中的线程pt2通信怎么办,进程id不可以,线程id又可能重复,所以这里会有一个真实的线程id唯一标识,tid。glibc没有实现gettid的函数,所以我们可以通过linux下的系统调用 syscall(SYS_gettid) 来获得。
--2、performance_schema.threads表的 thread_os_id字段的 来源 如下: linux环境下 是由syscall(SYS_gettid)实现gettid函数 来获得 是第一种 是linux下进程的中的线程id
/**
Return the operating system thread id.
With Linux, threads have:
- an internal id, @c pthread_self(), visible in process
- an external id, @c gettid(), visible in the operating system,
for example with perf in linux.
This helper returns the underling operating system thread id.
*/
static inline my_thread_os_id_t my_thread_os_id()
...
#ifdef HAVE_SYS_GETTID
/*
Linux.
See man gettid
See GLIBC Bug 6399 - gettid() should have a wrapper
https://sourceware.org/bugzilla/show_bug.cgi?id=6399
*/
return syscall(SYS_gettid); //linux环境下 是由syscall(SYS_gettid)实现gettid函数 来获得 是第一种 是linux下进程的中的线程id
#else
#ifdef _WIN32
/* Windows */
return GetCurrentThreadId(); //windows环境下 用的是GetCurrentThreadId() 返回系统线程id
#else
.......
--3、查看 show engine innodb status 中的 该sql语句的OS thread handle 为 140090860746496。 和 2142的linux下线程id 不同。 是第二种 POSIX线程的线程id,由pthread_self()函数取得。
mysql> show engine innodb status\\G
...
------------
TRANSACTIONS
------------
....
MySQL thread id 7, OS thread handle 140090860746496, query id 98 localhost root updating
update test_limit_table set b=round(rand()*b,0)
......
--源码,linux环境是调用pthread_self()返回 POSIX线程的线程id。 而windows系统依然是GetCurrentThreadId()函数返回的线程id。
static inline my_thread_t my_thread_self()
#ifdef _WIN32
return GetCurrentThreadId();
#else
return pthread_self();
#endif
总结: linux环境下 , performance_schema.threads表的 thread_os_id字段 是由syscall(SYS_gettid)实现gettid函数 来获得 linux的线程id。
show engine innodb status 中的OS thread handle 是由pthread_self()函数 来获得 POSIX线程的线程id。
windows环境下, performance_schema.threads表的 thread_os_id字段 和 show engine innodb status 中的OS thread handle 都是由GetCurrentThreadId() 函数获得一致的系统线程id
以上是关于Mysql性能排查—结合操作系统线程 查看mysql中的sql资源消耗的主要内容,如果未能解决你的问题,请参考以下文章