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资源消耗的主要内容,如果未能解决你的问题,请参考以下文章

Java性能分析之线程栈详解(下)

MYSQL 内存排查

mysq'l系列之10.mysql优化&权限控制

redmine在linux上的mysql性能优化方法与问题排查方案

mysql问题排查与性能优化

mysql cpu100% 排查