当前位置: 首页 > news >正文

MySQL:终于为OS层面的线程命名了


能力有限,如果有误请谅解。


一、问题来源

最近在检查某个数据库性能的时候,通过top -Hu mysql看到了一个特别奇怪的现象,线程有了自己的名字,我开始以为是哪个大厂自己维护的版本,如下:

PID USER      PR  NI    VIRT    RES    SHR S %CPU %MEM     TIME+ COMMAND                                                                                                                  
  8146 mysql     20   0 4164720 734540  26624 S  0.0  9.9   0:00.96 mysqld                                                                                                                   
  8159 mysql     20   0 4164720 734540  26624 S  0.0  9.9   0:00.02 ib_io_ibuf                                                                                                               
  8160 mysql     20   0 4164720 734540  26624 S  0.0  9.9   0:00.02 ib_io_log                                                                                                                
  8161 mysql     20   0 4164720 734540  26624 S  0.0  9.9   0:00.04 ib_io_rd-1                                                                                                               
  8162 mysql     20   0 4164720 734540  26624 S  0.0  9.9   0:00.03 ib_io_rd-2   
...

后来装了一个8.0.28才发现确实是官方版本的新玩意。但是虽然能够猜到一些线程的功能,可还是很陌生的样子,因为这个名字和performance_schema.thread中的名字并不一样。 

这里我们就来看看它的做法和对应关系。不过这一小步,却是DBA的一大步,我们以往在看Oracle的进程的时候都习惯了有命名的进程名字,这带来的好处是直接从OS层面就能判断大概哪个功能的压力增高。

二、以往的对应方法

我们知道以前在获取到线程的LWP号后需要到performance_schema.thread通过lwp和thread_os_id 对应,得到如下结果:

PID USER      PR  NI    VIRT    RES    SHR S %CPU %MEM     TIME+ COMMAND                                                                                                                  
  5524 mysql     20   0 4052588 792400  11676 S  0.0 27.4   0:03.82 mysqld                                                                                                                   
  5533 mysql     20   0 4052588 792400  11676 S  0.0 27.4   0:00.00 mysqld                                                                                                                   
  5556 mysql     20   0 4052588 792400  11676 S  0.0 27.4   0:00.00 mysqld                                                                                                                   
  5557 mysql     20   0 4052588 792400  11676 S  0.0 27.4   0:00.00 mysqld 
...
----------------------------------------+--------------+
| name                                   | thread_os_id |
+----------------------------------------+--------------+
| thread/sql/main                        |         5524 |
| thread/sql/thread_timer_notifier       |         5533 |
| thread/innodb/io_ibuf_thread           |         5556 |
| thread/innodb/io_read_thread           |         5558 |
| thread/innodb/io_log_thread            |         5557 |
...

如果某个线程的CPU高或者IO高我们就能够知道是什么线程。当然你也可以和information_schema.processlist做join得到process id和state等有用的信息。

三、简单的实现方法讨论

比如以innodb为例,所有的线程的OS thread name都放到了all_innodb_threads这个一个数组中,其中每个元素是一个结构体,结构体中包含了我们OS thread name这个元素给予了大量的代码注释,我就放一点我们容易看懂的:

typedef struct PSI_thread_info_v5 PSI_thread_info;
    The thread name to advertise to the operating system.
    This feature is optional, and improves
    observability for platforms that support
    a flavor of pthread_setname_np().

这里我们也看到需要支持pthread_setname_np函数才行。在调用register_thread_class注册所有的class的时候会将这些OS thread name放到一个叫做thread_class_array全局内存中,这样再建立线程应该能轻松的从全局内存中拿到每个线程的OS thread name(当然我没去细看了)。接着,在建立线程的时候我们调用my_thread_self_setname设置OS thread name就可以了,实际上就是调用pthread_setname_np。

四、新的Linux OS thread name和performance_schema.threads中name的对应

为了快速的得到对应的办法,我稍微加了点输出内容,这样只要有线程启动,就会打印到error日志,因为如果一个一个去看每个线程启动的时候带入的OS thread name实在太慢了,耗不起,。得到的结果如下:

cat mysql3380.err |grep -w 'init threads'
[init threads] os name:boot -- mysql name:thread/sql/bootstrap  
[init threads] os name:ib_io_ibuf -- mysql name:thread/innodb/io_ibuf_thread  
[init threads] os name:ib_io_log -- mysql name:thread/innodb/io_log_thread  
[init threads] os name:ib_io_rd-1 -- mysql name:thread/innodb/io_read_thread  
[init threads] os name:ib_io_rd-2 -- mysql name:thread/innodb/io_read_thread  
[init threads] os name:ib_io_rd-3 -- mysql name:thread/innodb/io_read_thread  
[init threads] os name:ib_io_rd-4 -- mysql name:thread/innodb/io_read_thread  
[init threads] os name:ib_io_rd-5 -- mysql name:thread/innodb/io_read_thread  
[init threads] os name:ib_io_rd-6 -- mysql name:thread/innodb/io_read_thread  
[init threads] os name:ib_io_rd-7 -- mysql name:thread/innodb/io_read_thread  
[init threads] os name:ib_io_rd-8 -- mysql name:thread/innodb/io_read_thread  
[init threads] os name:ib_io_wr-1 -- mysql name:thread/innodb/io_write_thread  
[init threads] os name:ib_io_wr-2 -- mysql name:thread/innodb/io_write_thread  
[init threads] os name:ib_io_wr-3 -- mysql name:thread/innodb/io_write_thread  
[init threads] os name:ib_io_wr-4 -- mysql name:thread/innodb/io_write_thread  
[init threads] os name:ib_pg_flush_co -- mysql name:thread/innodb/page_flush_coordinator_thread  
[init threads] os name:ib_pg_flush-1 -- mysql name:thread/innodb/page_flush_thread  
[init threads] os name:ib_pg_flush-2 -- mysql name:thread/innodb/page_flush_thread  
[init threads] os name:ib_pg_flush-3 -- mysql name:thread/innodb/page_flush_thread  
[init threads] os name:ib_recv_write -- mysql name:thread/innodb/recv_writer_thread  
[init threads] os name:ib_log_checkpt -- mysql name:thread/innodb/log_checkpointer_thread  
[init threads] os name:ib_log_fl_notif -- mysql name:thread/innodb/log_flush_notifier_thread  
[init threads] os name:ib_log_flush -- mysql name:thread/innodb/log_flusher_thread  
[init threads] os name:ib_log_wr_notif -- mysql name:thread/innodb/log_write_notifier_thread  
[init threads] os name:ib_log_writer -- mysql name:thread/innodb/log_writer_thread  
[init threads] os name:ib_par_rseg-0 -- mysql name:thread/innodb/parallel_rseg_init_thread  
[init threads] os name:ib_par_rseg-0 -- mysql name:thread/innodb/parallel_rseg_init_thread  
[init threads] os name:ib_srv_lock_to -- mysql name:thread/innodb/srv_lock_timeout_thread  
[init threads] os name:ib_srv_err_mon -- mysql name:thread/innodb/srv_error_monitor_thread  
[init threads] os name:ib_srv_mon -- mysql name:thread/innodb/srv_monitor_thread  
[init threads] os name:ib_buf_resize -- mysql name:thread/innodb/buf_resize_thread  
[init threads] os name:ib_src_main -- mysql name:thread/innodb/srv_master_thread  
[init threads] os name:ib_dict_stats -- mysql name:thread/innodb/dict_stats_thread  
[init threads] os name:ib_fts_opt -- mysql name:thread/innodb/fts_optimize_thread  
[init threads] os name:xpl_worker-1 -- mysql name:thread/mysqlx/worker  
[init threads] os name:xpl_worker-2 -- mysql name:thread/mysqlx/worker  
[init threads] os name:xpl_accept-1 -- mysql name:thread/mysqlx/acceptor_network  
[init threads] os name:ib_buf_dump -- mysql name:thread/innodb/buf_dump_thread  
[init threads] os name:ib_clone_gtid -- mysql name:thread/innodb/clone_gtid_thread  
[init threads] os name:ib_srv_purge -- mysql name:thread/innodb/srv_purge_thread  
[init threads] os name:ib_srv_wkr-1 -- mysql name:thread/innodb/srv_worker_thread  
[init threads] os name:ib_srv_wkr-2 -- mysql name:thread/innodb/srv_worker_thread  
[init threads] os name:ib_srv_wkr-3 -- mysql name:thread/innodb/srv_worker_thread  
[init threads] os name:sig_handler -- mysql name:thread/sql/signal_handler  
[init threads] os name:xpl_accept-2 -- mysql name:thread/mysqlx/acceptor_network  
[init threads] os name:xpl_accept-3 -- mysql name:thread/mysqlx/acceptor_network  
[init threads] os name:gtid_zip -- mysql name:thread/sql/compress_gtid_table  
[init threads] os name:connection -- mysql name:thread/sql/one_connection

可以看到建立的线程非常的多,但是我们得到它们的对应关系这就够了。这里不一一讨论每个线程的功能了,不过大部分我们都非常熟悉了,比如purge线程/cleaner线程 ,这里我列出一些,其他的就自己看看吧。

  • purge线程 srv_purge_thread 主要用于清理delete flag和释放undo表空间

  • clean线程 page_cleaner_thread DBWR 主要用于进行脏数据的刷盘和LRU链表的管理

  • 异步IO线程 io_read_thread/io_write_thread 通常数据预读和刷脏会使用到异步AIO,用于合并可能的散列IO为连续IO提高性能

  • 字典收集线程 dict_stats_thread 数据修改的10%后会触发统计数据的收集

  • 锁超时监控线程srv_lock_timeout_thread 用于监控innodb行锁的超时,超时进行事务回退

  • GTID压缩线程compress_gtid_table 将历史的gtid压缩为范围,避免gtid_executed表过长

  • slave io线程 slave_io 从库接收来自DUMP线程的binlog Event。将这些Event写入到relay log。

  • slave dump线程 这是前台线程 主库监控binlog的变化,发送binlog Event

  • slave sql线程 slave_sql 从库负责执行binlog Event

  • 用户线程one_connection 一个session就是一个用户线程,对于用户线程而言。可以通过processlist_id和show processlist

  • srv_error_monitor_thread 所谓的信号量监控线程,注意这个信号量不是OS的信号量。是Innodb内部的rw lock和mutex

  • srv_monitor_thread 这个线程当参数innodb_status_output打开的情况下,每15秒输出一个show engine innodb status信息到日志文件。也会自动开启比如Innodb内存不足会自动开启。

  • log_writer线程:将redo写到redo文件

  • log_write_notifier线程:通知用户会话写入redo文件结束

  • log_flusher线程:将redo fsync到redo文件

  • log_flush_notifier线程:通知用户会话fsync结束

  • log_checkpointer线程:定期检查脏数据写盘的redo 位置。

五、用pthread_setname_np为线程命名

这里我就随便写了4个循环的线程调用这个函数为我的线程命名为D-GPWK,需要耗用较高的CPU,看到的结果如下:

9d426563af7bef299d00531ce154ab40.png
image.png

如果这个线程是MySQL的线程,当看到这个结果,我们就能明白大概的方向了(卧槽,慢SQL吧^_^)。

如果觉得本文有用,感谢各位朋友的转发

相关文章:

  • 今日杂感-20220322
  • 从RDS算不算国产数据库谈起
  • 工具| Innodb 恢复工具介绍
  • 重磅新品 MySQL HeatWave 机器学习(ML)
  • 从程序员的尽头是业务说起
  • 云上MongoDB常见索引问题及最优索引规则大全
  • 今天的一点杂感-20220414
  • MySQL:修改系统时钟会导致数据库hang住吗?
  • 规划自己的健康问题
  • 新数据库时代,DBA 发展之路该如何选择
  • 翻译|MySQL统计信息不准导致的性能问题
  • MySQL 8.0.29正式发行(GA)
  • pt-archiver 与自增主键的那些事儿
  • 我们的企业为什么写不好文档
  • 教孩子学习乘法和除法,我算是绞尽脑汁了
  • 「前端早读君006」移动开发必备:那些玩转H5的小技巧
  • 【Under-the-hood-ReactJS-Part0】React源码解读
  • extract-text-webpack-plugin用法
  • java第三方包学习之lombok
  • Java精华积累:初学者都应该搞懂的问题
  • js作用域和this的理解
  • leetcode378. Kth Smallest Element in a Sorted Matrix
  • VuePress 静态网站生成
  • Web设计流程优化:网页效果图设计新思路
  • 阿里研究院入选中国企业智库系统影响力榜
  • 阿里云购买磁盘后挂载
  • 第2章 网络文档
  • 机器人定位导航技术 激光SLAM与视觉SLAM谁更胜一筹?
  • 解决jsp引用其他项目时出现的 cannot be resolved to a type错误
  • 开源地图数据可视化库——mapnik
  • 理清楚Vue的结构
  • 目录与文件属性:编写ls
  • 悄悄地说一个bug
  • 数据仓库的几种建模方法
  • 我看到的前端
  • 用jQuery怎么做到前后端分离
  • ​​​​​​​​​​​​​​Γ函数
  • ​什么是bug?bug的源头在哪里?
  • #include
  • #pragma 指令
  • $.extend({},旧的,新的);合并对象,后面的覆盖前面的
  • (13)Hive调优——动态分区导致的小文件问题
  • (20050108)又读《平凡的世界》
  • (4)STL算法之比较
  • (一)eclipse Dynamic web project 工程目录以及文件路径问题
  • (转) Face-Resources
  • (转)可以带来幸福的一本书
  • .bat批处理(九):替换带有等号=的字符串的子串
  • .NET CF命令行调试器MDbg入门(二) 设备模拟器
  • .Net MVC4 上传大文件,并保存表单
  • .NET/ASP.NETMVC 深入剖析 Model元数据、HtmlHelper、自定义模板、模板的装饰者模式(二)...
  • .NET/C# 避免调试器不小心提前计算本应延迟计算的值
  • .net操作Excel出错解决
  • .net流程开发平台的一些难点(1)
  • @FeignClient 调用另一个服务的test环境,实际上却调用了另一个环境testone的接口,这其中牵扯到k8s容器外容器内的问题,注册到eureka上的是容器外的旧版本...