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
 
 

 

發佈了166 篇原創文章 · 獲贊 37 · 訪問量 32萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章