欢迎阅读 陈同学博客原文
参考资料 MySQL Threads The threads Table How MySQL Uses Threads for Client Connections MySQL terminology: processes, threads & connections Matching MariaDB internal thread ID with OS thread 《MySQL技术内幕:InnoDB存储引擎》
本文作为 Mysql插入2.6亿条垃圾数据后会发生什么? 、手工重现Mysql插入的”2.6亿”垃圾数据 的续篇,初始目的是想看看kill掉执行中的事务对应的os thread之后会发生什么,同时学习下mysql thread与os thread的相关知识。
测试环境信息如下:
在Mysql中,连接管理线程(Connection manager threads)用于处理来自客户端的TCP/IP连接请求,它会将每个client connection关联到一个专门的mysql thread,这个thread负责处理通过connection发出的所有请求(也包含请求的安全认证)。
mysql thread并非操作系统上的真实线程,只是mysql中的一个对象,但是会与os thread(操作系统真实的线程)关联起来。下面了解下如果查看mysql thread。
最简单的方式是使用 show processlist
查看当前连接,这个命令与查看information_schema.processlist
表效果一致。
每一个连接进来时,都可以在看到一条新的记录。可以通过不断打开与关闭连接来测试,每次打开一个连接后在 processlist 中将会多出一条记录,连接关闭后这条记录也会被移除。
如果当前连接正在进行事务处理,也可以通过information_schema.innodb_trx
事务表查看,其中trx_mysql_thread_id
字段为mysql thread id,与processlist中id一致
如果启用了mysql的性能监控功能( 通过SHOW VARIABLES LIKE 'performance_schema'
查看 ),可以通过performance_schema.threads
查看,其中有PROCESSLIST_ID
,与上面的两个ID保持一致。
虽然每次打开连接,可以看到一个新的 mysql thread 产生,但是OS并不一定会为每个连接创建一个新的os thread。
首先,看看mysqld进程对应的所有os线程。
执行命令 ps -ef | grep mysql
得到mysqld的PID(进程ID)为 16286
999 16286 16267 4 22:39 ? 00:00:00 mysqld
ubuntu 16362 9909 0 22:39 pts/1 00:00:00 grep --color=auto mysql
通过top -H -p 16286
查看进程下的所有线程:
mysqld下有27个线程,PID为每个线程的ID。mysql thread和os thread并不能直接匹配起来。
可以通过一个例子来看看mysql thread与os thread的关系。
运行两个事务,每个事务往 test表中插入1000W条记录,事务处理时间较长。
在 processlist 表中可以看到两个执行 insert 操作的mysql thread.
在os threads中将会使用两个thread来进行实际的处理,top命令可以看到mysqld进程下的线程占用的CPU和内存情况。
也可以进行如下测试,会发现一些有趣的事情:
本小节的探讨基于 thread_handling=one-thread-per-connection,即线程模型是为每个连接分配一个mysql thread
三者的关联如下:
下面做一个小测试:
假定max_connections=151
, 使用以下语句应用中循环1000次不断获取连接并且不释放连接
DriverManager.getConnection(url, user, password);
可以观察到以下现象:
MySQLNonTransientConnectionException: Too many connections
,同时mysql将无法再创建连接一般应用都会通过连接池与DB交互,同时会定期通过连接发送请求(mysql 可以发送select 1
) 给DB以重置connection的空闲时间
如果有事务正在执行,通过 show engine innodb status
查看事务信息,下面是该命令输出的部分信息:
------------
TRANSACTIONS
------------
...
1 lock struct(s), heap size 1136, 0 row lock(s), undo log entries 568226
MySQL thread id 65, OS thread handle 139656030103296, query id 229749097 218.104.153.55 test update
INSERT INTO test (uid, uid2, uid3)
VALUES (UUID(), UUID(), UUID())
可以看到mysql thread为65,OS thread为139656030103296
MySQL thread id 65, OS thread handle 139656030103296
题外话之mysql 官方说明:访问threads表对mysql没有什么性能影响,但访问processlist表或者show processlist对性能有一定影响,因为它们都需要mutex(互斥)
performance.threads 表中有 thread_os_id 字段,存储了mysql thread和os thread的关系
关于 thread_os_id:
thread_os_id 是操作系统定义的thread或task标识符:
在windows下,thread_os_id可以在任务管理器中看到;在linux下,thread_os_id和gettid()方法对应,可以使用perl
、ps -L
命令或者使用proc
文件系统(/proc/pid/task/tid)
不过查阅许多资料后也没有结果,我也没有找到合适的方式将thread_os_id与
os线程直接对应起来,只能侧面判断。
有资料 提供了一个偏方:通过gdb attach
命令来调试正在运行的程序,但是这会导致mysqld进程被暂停,并没有实际意义,不过本身找到mysql thread对应的os thread也没什么意义。先贴一下通过gdb attach得到的数据:
先执行gdb attach 11646
,再执行info threads
命令,输入如下:
包含了线程ID和对应的16进制ID,资料显示:16进制ID在show engine innodb status
输出信息中是可以看到的,不过我在mysql 5.7.18版本的输出信息中并未找到16进制的线程ID数据。
通过上述讲述和一些例子,可以了解到以下几点:
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。