线程简介和MySQL调试环境搭建
本文节选自八怪专栏《深入理解MySQL主从原理32讲》第29节
想内容请点击订阅专栏
注意:如果正文有图片不清晰可以将图片保存到本地查看(本文建议横屏观看效果更佳)
最后我想简单说一下我的MySQL调试环境的搭建,但是在此之前不得不简单说一下什么是线程,因为如果不解释一下什么是线程,简单的调试可能都会有阻碍,同时了解线程对我们普通DBA诊断性能问题也有极大的帮助。但是详细解释线程已经超出了我的能力范围也超出了本系列讨论的范围,具体我推荐给大家两本书:
- 《POSIX多线程程序设计》
- 《Linux UNIX系统编程手册》第29到32章
第一本书很老了,但是我觉得还可以,如果有兴趣可以参考一下。
一、线程简介
我们知道MySQLD是一个单进程多线程的用户程序,因此我们有必要了解一下什么线程。实际上MySQL中的线程都是POSIX线程,比如我们的会话线程、DUMP线程、IO线程以及其他一些Innodb线程都是POSIX线程。进程实际上就是运行中的程序,一个进程中可以包含多个线程也可以只包含一个线程。在Linux中线程也叫轻量级进程(light-weight process)简称为LWP,进程的第一个线程通常称为主控线程。进程是内存分配的最小单位,线程是CPU调度的最小单位,也就是说如果CPU有足够多核,那么多个线程可以达到并行处理的效果,内核直接调度线程。下面是我学习Linux线程的时候看到的一张我认为比较好理解的图,我重新画了一下放在下面供大家参考:
一个进程内部的所有线程都拥有相同的代码程序、堆、全局变量、共享库等,但是每个线程拥有自己独立栈空间和寄存器,他们共享进程的虚拟内存地址空间。下面我们假定是32位操作系统下的MySQLD进程,它的进程虚拟内存地址示意图如下,实际上这个图也是参考《Linux UNIX系统编程手册》画的:我们发现线程的堆内存和全局变量是共享的,因此线程之间数据共享很轻松,但是要控制好这些共享内存就需要引入我们的线程同步技术,比如我们常说的Mutex。
如果想了解线程到底共享了哪些资源,线程和进程到底各有什么优势和劣势,可执行参考上面我给出的书籍。
二、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用得不多。
下面我写了一个简单的C测试程序仅仅用于观察这些ID,它是通过主控线程再创建一个线程,也就是说这个进程包含了两个线程。它们分别打印自己的PID、LWP ID、Thread TID,然后做一个循环自加操作引起高CPU消耗现象便于观察。然后我们使用Linux的top -H和ps -eLlf命令分别进行观察。
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。这里我们还能看它们的内存信息完全一致,内存信息实际上是整个进程的内存信息,因为进程是内存分配的最小单位嘛。注意如果这个时候查看这个进程占用的%cpu就超过了100%,接近200%,如下:3.ps -eLlf 观察如下:我们可以看到这里包含了PID和LWP ID,不过多解释了,大家可以自己去试试。
三、如何将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......
这里的THREAD_OS_ID就是线程的LWP ID。然后我们使用刚才的ps -eLlf命令再看一下,如下:我们可以发现他们是可以对应上的,这个最好自己实际试试就知道了。
四、调试环境搭建
调试环境的搭建我认为不管使用什么方法只要能够起到调试的作用就可以了。这里介绍一下我的方法。我是在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
注意最后的-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)].....
注意到了这里的LWP ID了吗,前面我们已经讨论过了。这个时候MySQL客户端程序已经可以连接MySQLD了如下:
# /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)
好了到这里基本的调试环境就搭建起来了,我们可以发现很简单。之后我们就可以进行断点调试了。我常用的gdb命令包含:
- info threads:查看全部线程
- thread n:指定某个线程
- bt:查看某个线程栈帧
- b:设置断点
- c:继续执行
- s:执行一行代码,如果代码函数调用,则进入函数
- n:执行一行代码,函数调用不进入
- p:打印某个变量值
- list:打印代码的文本信息
当然gdb还有很多命令,可自行参考其他资料。
六、使用调试环境证明问题的一个列子
这里我们就用一个例子来看看调试环境的使用方法。我们前面第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客户端执行一个事物如下,并且提交:
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;
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......
好了看到这个栈帧,就能证明我们的说法了,如果想深入学习代码就可以从这个栈帧出发进行学习。但是值得注意的是,这是建立在知道函数接口功能的前提下的,如果我们不知道写入binary log会调用binlog_cache_data::flush函数那么调试也就不好进行了,我就经常遇到这样的困境。因此整个系列我给出了很多这样的接口,供有兴趣的朋友调试和测试。
识别下方二维码添加作者为好友
END
点击下图小程序订阅
《深入理解MySQL主从原理32讲》专栏
可了解更多八怪技术文章
扫码加入MySQL技术Q群
(群号:529671799)
线程简介和MySQL调试环境搭建相关推荐
- Nacos 简介与 本地调试环境搭建
目录 1.简介 2.Nacos架构 3.本地调试环境搭建 3.1 源码下载 3.3 单机启动 Nacos 3.4 集群方式启动:基于文件方式 4.Nacos源码模块介绍 5. 约定说明 1.简介 Na ...
- 2012 iis php mysql_Win2012 R2 IIS8.5+PHP(FastCGI)+MySQL运行环境搭建wordpress博客教程
Win2012 R2 IIS8.5+PHP(FastCGI)+MySQL运行环境搭建教程 一.环境说明: 操作系统:Windows Server2012 R2 PHP版本:php 5.5.8 MySQ ...
- auto.js id为参数滑动_【Autojs教程】02Autojs PC端开发调试环境搭建
[Autojs教程]02-Autojs PC端开发调试环境搭建 写在前面 本篇教程算是保姆级教程了,希望以此能吸引更多感兴趣的同学学习Autojs,也希望大家能因此碰撞出更多的奇思妙想 关注微信公众号 ...
- win2012 r2 iis php,Win2012 R2 IIS8.5+PHP(FastCGI)+MySQL运行环境搭建wordpress博客教程
运行环境搭建教程 一.环境说明: 操作系统:Windows Server2012 R2 PHP版本:php 5.5.8 MySQL版本:MySQL5.6.15 二.相关软件下载: 1.PHP下载地址: ...
- 陈力:传智播客古代 珍宝币 泡泡龙游戏开发第十九讲:apache+php+mysql开发环境搭建(wamp)
陈力:传智播客古代 珍宝币 泡泡龙游戏开发第十九讲:apache+php+mysql开发环境搭建(wamp) window环境下进行网站建设时,必须要进行wamp环境的搭建.本文介绍了如果配置apac ...
- iis8.5 php mysql_Win2012 R2 IIS8.5+PHP(FastCGI)+MySQL运行环境搭建教程
这篇文章主要介绍了Win2012 R2 IIS8.5+PHP(FastCGI)+MySQL运行环境搭建教程,需要的朋友可以参考下 准备篇 一.环境说明: 操作系统:Windows Server 201 ...
- rsyslog+mysql+loganalyzer 环境搭建日志服务器
环境:CentOS6.6 rsyslog+mysql+loganalyzer 环境搭建日志服务器 Client端: 192.168.2.10 MySQL服务器: 192.168.2.11 # ...
- mac 内核调试环境搭建
操作系统安装 先从 app store 下载 下载完后安装程序在应用里 打开 vm 新建 双击从光盘或映像安装 安装 安装失败 用其它工具安装 还可以先在 windows 上的 VM 下先安装好再拷贝 ...
- mysql 搭建日志服务器_rsyslog+mysql+loganalyzer 环境搭建日志服务器
环境:CentOS6.6 rsyslog+mysql+loganalyzer 环境搭建日志服务器 Client端:192.168.2.10 MySQL服务器:192.168.2.11 # Client ...
最新文章
- 将Ojective-C代码移植转换为Swift代码
- python爬虫采集网站数据
- Microsoft发布新工具,简化JavaScript Web应用的创建
- 堆之大,ZGC亦可速清也!
- 阿里高级技术专家邱小侠:微服务架构的理论基础 - 康威定律
- Vrep当中的一些好用的工具(未完)
- JavaScript面试大全(二)
- Tomcat从socket到java Servlet
- 程序设计流程图、项目管理流程图模板分享
- 虚拟机配置NAT网络后ping不通
- 艾永亮:亏损7年到年销100亿,百果园如何在小水果里做出大生意?
- 50条字面和实际意思大不同的英语
- 阿里云上部署kafka--遇到的坑
- 关于更佳学术搜索及Android SDK更新问题
- Pytorch实现性别识别,男女分类
- C语言-英文字母倒序转换
- 基于WiFi的室内定位
- sniper安装配置
- 雷军、马云、马化腾控股的公司
- 两部手机怎样才能把数据都传过来_两台苹果手机怎么传数据