本文节选自八怪专栏《深入理解MySQL主从原理32讲》第29节
想阅读更多内容请点击订阅专栏
最后我想简单说一下我的MySQL调试环境的搭建,但是在此之前不得不简单说一下什么是线程,因为如果不解释一下什么是线程,简单的调试可能都会有阻碍,同时了解线程对我们普通D BA诊断性能问题也有极大的帮助。 但是详细解释线程已经超出了我的能力范围也超出了本系列讨论的范围 ,具体我推荐给大家两本书:
- 《POSIX多线程程序设计》
- 《Linux UNIX系统编程手册》第29到32章
一、线程简介
我们知道MySQLD是一个单进程多线程的用户程序,因此我们有必要了解一下什么线程。实际上MySQL中的线程都是POSIX线程,比如我们的会话线程、DUMP线程、IO线程以及其他一些Innodb线程都是POSIX线程。进程实际上就是运行中的程序,一个进程中可以包含多个线程也可以只包含一个线程。在Linux中线程也叫轻量级进程(light-weight process)简称为LWP,进程的第一个线程通常称为主控线程。进程是内存分配的最小单位,线程是CPU调度的最小单位,也就是说如果CPU有足够多核,那么多个线程可以达到并行处理的效果,内核直接调度线程。下面是我学习Linux线程的时候看到的一张我认为比较好理解的图,我重新画了一下放在下面供大家参考:![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/5b79790fd3d48afbda7190703d430abd.png)
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/50287f99fbfcc0762613385c957b0896.png)
如果想了解线程到底共享了哪些资源,线程和进程到底各有什么优势和劣势,可执行参考上面我给出的书籍。
二、PID、LWP ID、Thread TID
如果要进行调试就需要了解这三种ID,其中PID和LWP ID是比较重要,因为不管是调试和运维都会遇到它们,而Thread TID不做多线程开发一般很少用到,下面是我对它们的总结:- PID:内核分配,用于识别各个进程的ID。这个应该是大家最熟悉的。
- LWP ID:内核分配,用于识别各个线程的ID,它就像是线程是‘PID’一样。同一个进程下的所有线程有相同的PID,但是LWP ID却不一样,主控线程的LWP ID就是进程PID。
- Thread TID:进程内部用于识别各个线程的内部ID,这个ID用得不多。
1.程序输出下面是程序的输出:
# ./gaopengtestmain thread: pid 13188 tid 2010470144 lwp 13188new thread: pid 13188 tid 2010461952 lwp 13189
我们可以看到两个线程的PID都是13188,但是主控线程的LWP ID是13188,新建立的一个线程LWP ID是13189。然后就是Thread TID了,不过多解释。
2.top -H 观察如下:我们可以看到这两个线程都是高耗CPU的线程,CPU已经处于饱和状态。这里我们看到top -H命令的输出中‘PID’就是LWP ID。这里我们还能看它们的内存信息完全一致,内存信息实际上是整个进程的内存信息,因为进程是内存分配的最小单位嘛。
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/158f3cf7d1d61d5aa96a0dafbd281d4c.png)
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/b36ea210fe98b75a3e382d6c20f11c66.png)
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/642482c2adb6e119cfce954eb7e5d0fb.png)
三、如何将MySQL的线程和LWP ID进行对应
在5.7中我们已经可以通过MySQL语句和LWP ID进行对应了,这让性能诊断变得更加便捷。比如我上面的列子如果两个高耗CPU的线程是MySQL的线程那么我们就拿到了线程的LWP ID,然后可以通过语句找到这两个线程到底是MySQL的什么线程。语句如下:mysql> select a.thd_id,b.THREAD_OS_ID,a.user,b.TYPE from sys.processlista,performance_schema.threads b where b.thread_id=a.thd_id;+--------+--------------+---------------------------+---------+------------| thd_id | THREAD_OS_ID | user | conn_id | TYPE+--------+--------------+---------------------------+---------+------------| 1 | 16370 | sql/main | NULL | BACKGROUND| 2 | 17202 | sql/thread_timer_notifier | NULL | BACKGROUND| 3 | 17207 | innodb/io_ibuf_thread | NULL | BACKGROUND| 4 | 17208 | innodb/io_log_thread | NULL | BACKGROUND| 5 | 17209 | innodb/io_read_thread | NULL | BACKGROUND| 6 | 17210 | innodb/io_read_thread | NULL | BACKGROUND| 7 | 17211 | innodb/io_read_thread | NULL | BACKGROUND| 8 | 17212 | innodb/io_read_thread | NULL | BACKGROUND| 9 | 17213 | innodb/io_read_thread | NULL | BACKGROUND| 10 | 17214 | innodb/io_read_thread | NULL | BACKGROUND| 11 | 17215 | innodb/io_read_thread | NULL | BACKGROUND| 12 | 17216 | innodb/io_read_thread | NULL | BACKGROUND| 13 | 17217 | innodb/io_write_thread | NULL | BACKGROUND| 14 | 17218 | innodb/io_write_thread | NULL | BACKGROUND| 15 | 17219 | innodb/io_write_thread | NULL | BACKGROUND| 16 | 17220 | innodb/io_write_thread | NULL | BACKGROUND| 17 | 17221 | innodb/io_write_thread | NULL | BACKGROUND......
![640?wx_fmt=png](https://i-blog.csdnimg.cn/blog_migrate/88bae91628f6e334439355dd49db0aba.png)
四、调试环境搭建
调试环境的搭建我认为不管使用什么方法只要能够起到调试的作用就可以了。这里介绍一下我的方法。我是在Linux下面直接使用gdb调试的,我觉得这个方法搭建非常简单并且很奏效,基本上只要会源码安装就能完成调试环境的搭建。下面来看看步骤:1. 第一步下载MySQL源码包,解压。
我特意重新下载了官方版的5.7.26源码。2. 使用源码安装的方法安装MySQL,注意需要开启debug选项
下面是我使用的选项:cmake -DCMAKE_INSTALL_PREFIX=/root/sf/mysql3312/ \-DMYSQL_DATADIR=/root/sf/mysql3312/data/ \-DSYSCONFDIR=/root/sf/mysql3312/ \-DWITH_INNOBASE_STORAGE_ENGINE=1 \-DWITH_ARCHIVE_STORAGE_ENGINE=1 \-DWITH_BLACKHOLE_STORAGE_ENGINE=1 \-DWITH_FEDERATED_STORAGE_ENGINE=1 \-DWITH_PARTITION_STORAGE_ENGINE=1 \-DMYSQL_UNIX_ADDR=/root/sf/mysql3312/mysql3312.sock \-DMYSQL_TCP_PORT=3306 -DENABLED_LOCAL_INFILE=1 \-DEXTRA_CHARSETS=all -DDEFAULT_CHARSET=utf8 \-DDEFAULT_COLLATION=utf8_general_ci -DMYSQL_USER=mysql \-DWITH_BINLOG_PREALLOC=ON \-DWITH_BOOST=/root/sf/mysql-5.7.26/boost/boost_1_59_0 \-DWITH_DEBUG=1
3. make&&make install
编译和安装。4. 准备参数文件和初始化MySQL数据库,并且确保能成功启动
这一步自己处理,注意权限。我的环境启动成功了如下:[root@gp1 support-files]# ./mysql.server startStarting MySQL....... SUCCESS![root@gp1 support-files]# ./mysql.server stopShutting down MySQL.. SUCCESS!
5. 准备gdb命令文件
如下是我准备的命令文件:[root@gp1 ~]# more debug.filebreak mainrun --defaults-file=/root/sf/mysql3312/my.cnf --user=mysql --gdb
第一行是在main函数处打一个断点。第二行就是gdb调用MySQLD的时候,MySQLD加什么参数了,注意run不要写掉了。
6.使用gdb启动MySQL
使用如下命令启动调试环境:gdb -x /root/debug.file /root/sf/mysql3312/bin/mysqld
# gdb -x /root/debug.file /root/sf/mysql3312/bin/mysqldGNU gdb (GDB) Red Hat Enterprise Linux (7.2-92.el6)Copyright (C) 2010 Free Software Foundation, Inc.License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>This is free software: you are free to change and redistribute it.There is NO WARRANTY, to the extent permitted by law. Type "show copying"and "show warranty" for details.This GDB was configured as "x86_64-redhat-linux-gnu".For bug reporting instructions, please see:<http://www.gnu.org/software/gdb/bugs/>...Reading symbols from /root/sf/mysql3312/bin/mysqld...done.Breakpoint 1 at 0xec7c53: file /root/sf/mysql-5.7.26/sql/main.cc, line 25.[Thread debugging using libthread_db enabled]Breakpoint 1, main (argc=5, argv=0x7fffffffe3b8) at /root/sf/mysql-5.7.26/sql/main.cc:2525 return mysqld_main(argc, argv);Missing separate debuginfos, use: debuginfo-install glibc-2.12-1.212.el6.x86_64libaio-0.3.107-10.el6.x86_64 libgcc-4.4.7-18.el6.x86_64 libstdc++-4.4.7-18.el6.x86_64nss-softokn-freebl-3.14.3-23.3.el6_8.x86_64(gdb) cContinuing.[New Thread 0x7fffee883700 (LWP 29375)][New Thread 0x7fff9a9f3700 (LWP 29376)][New Thread 0x7fff99ff2700 (LWP 29377)][New Thread 0x7fff995f1700 (LWP 29378)][New Thread 0x7fff98bf0700 (LWP 29379)][New Thread 0x7fff981ef700 (LWP 29380)][New Thread 0x7fff977ee700 (LWP 29381)][New Thread 0x7fff96ded700 (LWP 29382)][New Thread 0x7fff963ec700 (LWP 29383)].....
# /root/sf/mysql3312/bin/mysql -S'/root/sf/mysql3312/mysql3312.sock'Welcome to the MySQL monitor. Commands end with ; or \g.Your MySQL connection id is 2Server version: 5.7.26-debug-log Source distributionCopyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.Oracle is a registered trademark of Oracle Corporation and/or itsaffiliates. Other names may be trademarks of their respectiveowners.Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.mysql> select version() ;+------------------+| version() |+------------------+| 5.7.26-debug-log |+------------------+1 row in set (0.00 sec)
- info threads:查看全部线程
- thread n:指定某个线程
- bt:查看某个线程栈帧
- b:设置断点
- c:继续执行
- s:执行一行代码,如果代码函数调用,则进入函数
- n:执行一行代码,函数调用不进入
- p:打印某个变量值
- list:打印代码的文本信息
六、使用调试环境证明问题的一个列子
这里我们就用一个例子来看看调试环境的使用方法。我们前面第15节说过binlog cache是在order commit的flush阶段才写入到binary log的,调用的是函数binlog_cache_data::flush。好了我们可以将断点打到这个函数如下:(gdb) b binlog_cache_data::flushBreakpoint 2 at 0x1846333: file /root/sf/mysql-5.7.26/sql/binlog.cc, line 1674.
mysql> begin;Query OK, 0 rows affected (0.00 sec)mysql> insert into gpdebug values(1);Query OK, 1 row affected (0.03 sec)mysql> commit;
Breakpoint 2, binlog_cache_data::flush (this=0x7fff3c00df20...) at /root/sf/mysql-5.7.26/sql/binlog.cc:16741674 DBUG_ENTER("binlog_cache_data::flush");
我们使用bt命令查看栈帧发现如下:
#0 binlog_cache_data::flushat /root/sf/mysql-5.7.26/sql/binlog.cc:1674#1 0x0000000001861b41 in binlog_cache_mngr::flushat /root/sf/mysql-5.7.26/sql/binlog.cc:967#2 0x00000000018574ce in MYSQL_BIN_LOG::flush_thread_cachesat /root/sf/mysql-5.7.26/sql/binlog.cc:8894#3 0x0000000001857712 in MYSQL_BIN_LOG::process_flush_stage_queueat /root/sf/mysql-5.7.26/sql/binlog.cc:8957#4 0x0000000001858d19 in MYSQL_BIN_LOG::ordered_commitat /root/sf/mysql-5.7.26/sql/binlog.cc:9595#5 0x00000000018573b4 in MYSQL_BIN_LOG::commitat /root/sf/mysql-5.7.26/sql/binlog.cc:8851#6 0x0000000000f58de9 in ha_commit_transat /root/sf/mysql-5.7.26/sql/handler.cc:1799#7 0x000000000169e02b in trans_commitat /root/sf/mysql-5.7.26/sql/transaction.cc:239......
识别下方二维码添加作者为好友
END
点击下图小程序订阅
《深入理解MySQL主从原理32讲》专栏
可了解更多八怪技术文章
![分割线箭头动态 640?wx_fmt=gif](https://i-blog.csdnimg.cn/blog_migrate/b47893cd57c0a644e0017e4cd1e9c58a.gif)
扫码加入MySQL技术Q群
(群号:529671799)