暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

MySQL黑盒子研究工具|strace

前言

作为一个把开源 MySQL 当黑盒子研究的砖家(初级 DBA),在学习和研究的时候必须要掌握一些黑盒子研究工具,用于观察程序的行为,那么 strace 应该是最简单上手的黑盒子研究工具之一。

strace是什么?

按照 strace 官网的描述, strace 是一个可用于诊断、调试和教学的 Linux 用户空间跟踪器。我们用它来监控用户空间进程和内核的交互,比如系统调用、信号传递、进程状态变更等。

strace 底层使用内核的 ptrace 特性来实现其功能。

strace能做什么?

strace 常用来跟踪进程执行时的系统调用和所接收的信号。

在 Linux 世界,进程不能直接访问硬件设备,当进程需要访问硬件设备(比如读取磁盘文件,接收网络数据等等)时,必须由用户态模式切换至内核态模式,通过系统调用访问硬件设备。strace 可以跟踪到一个进程产生的系统调用,包括参数,返回值,执行消耗的时间。

在运维的日常工作中,故障处理和问题诊断是个主要的内容,也是必备的技能。strace 作为一种动态跟踪工具,能够帮助运维高效地定位进程和服务故障。它像是一个侦探,通过系统调用的蛛丝马迹,告诉你异常的真相。

输出参数的含义

每一行都是一条系统调用,等号左边是系统调用的函数名及其参数,右边是该调用的返回值。strace 显示这些调用的参数并返回符号形式的值。strace 从内核接收信息,而且不需要以任何特殊的方式来构建内核。

$strace cat /dev/null
execve("/bin/cat", ["cat""/dev/null"], [/* 22 vars */]) = 0
brk(0)                                  = 0xab1000
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f29379a7000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
...

复制

参数

-c 统计每一系统调用的所执行的时间,次数和出错的次数等.
-d 输出strace关于标准错误的调试信息.
-f 跟踪由fork调用所产生的子进程.
-ff 如果提供-o filename,则所有进程的跟踪结果输出到相应的filename.pid中,pid是各进程的进程号.
-F 尝试跟踪vfork调用.在-f时,vfork不被跟踪.
-h 输出简要的帮助信息.
-i 输出系统调用的入口指针.
-q 禁止输出关于脱离的消息.
-r 打印出相对时间关于,,每一个系统调用.
-t 在输出中的每一行前加上时间信息.
-tt 在输出中的每一行前加上时间信息,微秒级.
-ttt 微秒级输出,以秒了表示时间.
-T 显示每一调用所耗的时间.
-v 输出所有的系统调用.一些调用关于环境变量,状态,输入输出等调用由于使用频繁,默认不输出.
-V 输出strace的版本信息.
-x 以十六进制形式输出非标准字符串
-xx 所有字符串以十六进制形式输出.
-a column
设置返回值的输出位置.默认 为40.
-e expr
指定一个表达式,用来控制如何跟踪.格式如下:
[qualifier=][!]value1[,value2]...
qualifier只能是 trace,abbrev,verbose,raw,signal,read,write其中之一.value是用来限定的符号或数字.默认的 qualifier是 trace.感叹号是否定符号.例如:
-eopen等价于 -e trace=open,表示只跟踪open调用.而-etrace!=open表示跟踪除了open以外的其他调用.有两个特殊的符号 all 和 none.
注意有些shell使用!来执行历史记录里的命令,所以要使用\\.
-e trace=set
只跟踪指定的系统 调用.例如:-e trace=open,close,rean,write表示只跟踪这四个系统调用.默认的为set=all.
-e trace=file
只跟踪有关文件操作的系统调用.
-e trace=process
只跟踪有关进程控制的系统调用.
-e trace=network
跟踪与网络有关的所有系统调用.
-e strace=signal
跟踪所有与系统信号有关的 系统调用
-e trace=ipc
跟踪所有与进程通讯有关的系统调用
-e abbrev=set
设定 strace输出的系统调用的结果集.-v 等与 abbrev=none.默认为abbrev=all.
-e raw=set
将指 定的系统调用的参数以十六进制显示.
-e signal=set
指定跟踪的系统信号.默认为all.如 signal=!SIGIO(或者signal=!io),表示不跟踪SIGIO信号.
-e read=set
输出从指定文件中读出 的数据.例如:
-e read=3,5
-e write=set
输出写入到指定文件中的数据.
-o filename
将strace的输出写入文件filename
-p pid
跟踪指定的进程pid.
-s strsize
指定输出的字符串的最大长度.默认为32.文件名一直全部输出.
-u username
以username 的UID和GID执行被跟踪的命令

复制

安装

yum -y install strace

复制

主要用法有两种:

1.从命令行调试一个新开始的程序
strace /etc/init.d/mysqld start

2.绑定到一个已有的PID上来调试一个正在运行的程序
strace -c -p 7945

复制

常用命令举例:

strace -o ~/mysqld.strace -T -tt -e trace=all -p <PID>
strace -p <PID>
strace -cp <PID>

复制

实用例子:

一、mysqld启动时读了的哪个配置文件?

我们学习 MySQL 时,从官方文档(https://dev.mysql.com/doc/refman/5.7/en/option-files.html)知道,MySQL5.7 如果不指定读取的配置文件,他是会按次序搜寻和读取加载 my.cnf 的,如下:

sequenceFile NamePurpose
1/etc/my.cnfGlobal options
2/etc/mysql/my.cnfGlobal options
3SYSCONFDIR
/my.cnf
Global options
4$MYSQL_HOME
/my.cnf
Server-specific options (server only)
5defaults-extra-fileThe file specified with --defaults-extra-file, if any
6~/.my.cnfUser-specific options
7~/.mylogin.cnfUser-specific login path options (clients only)

上面这个表格包含了 server(mysqld)、client(mysqladmin、mysqldump、mysql、mysqlbinlog 等等)的 my.cnf 搜寻顺序,还包含了编译版安装,特殊参数下的路径搜寻顺序,更准确的 mysqld 搜寻路径见下面这个:

mysqld --verbose --help |less
...
# 在第一页找到以下这两行
Default options are read from the following files in the given order:
/etc/my.cnf /etc/mysql/my.cnf /usr/local/mysql/etc/my.cnf ~/.my.cnf 
...

复制

能看出 mysqld 对 my.cnf 文件的搜寻和载入顺序如下:

序号文件路径
1/etc/my.cnf
2/etc/mysql/my.cnf
3/usr/local/mysql/etc/my.cnf
4~/.my.cnf

下面我们用 strace 来调试一下看是不是,见标蓝色部分,完全一致。

[root@fander bin]# pwd
/usr/local/mysql/bin
[root@fander bin]# ./mysqld --version
./mysqld  Ver 5.7.36 for linux-glibc2.12 on x86_64 (MySQL Community Server (GPL))
[root@fander bin]# strace ./mysqld 2>&1 |grep my.cnf
stat("/etc/my.cnf", 0x7ffd55e7c080)     = -1 ENOENT (No such file or directory)
stat("/etc/mysql/my.cnf", 0x7ffd55e7c080) = -1 ENOENT (No such file or directory)
stat("/usr/local/mysql/etc/my.cnf", 0x7ffd55e7c080) = -1 ENOENT (No such file or directory)
stat("/root/.my.cnf", 0x7ffd55e7c080)   = -1 ENOENT (No such file or directory)

复制

二、为什么我的mysqld没有读取/etc/my.cnf文件?

[root@fander bin]# strace ./mysqld --defaults-file=/data/mysql/mysql3307/my.cnf 2>&1  |grep my.cnf
stat("/data/mysql/mysql3307/my.cnf", {st_mode=S_IFREG|0644, st_size=8434, ...}) = 0
open("/data/mysql/mysql3307/my.cnf", O_RDONLY) = 3

复制

可见,指定了"--defaults-file"启动,只会读取此配置文件,而非按顺序把/etc/my.cnf
/etc/mysql/my.cnf
/usr/local/mysql/etc/my.cnf
~/.my.cnf
都加载一遍。

三、我的mysql客户端都读取和加载了哪些配置文件?

[root@fander bin]# strace ./mysql -uroot -proot -S /tmp/mysql3307.sock 2>&1  |grep my.cnf
stat("/etc/my.cnf", {st_mode=S_IFREG|0644, st_size=10, ...}) = 0
open("/etc/my.cnf", O_RDONLY)           = 3
stat("/etc/mysql/my.cnf", 0x7fff7159ba50) = -1 ENOENT (No such file or directory)
stat("/usr/local/mysql/etc/my.cnf", 0x7fff7159ba50) = -1 ENOENT (No such file or directory)
stat("/root/.my.cnf", 0x7fff7159ba50)   = -1 ENOENT (No such file or directory)

复制

明显的,stat 表示在寻找这个文件,值为 0 则找到了, -1 则找不到。可见很多文件都不存在,最后只找到了一个配置文件,就是 etc/my.cnf,open 就是打开和加载,3 表示加载成功,然后先后加载了里面 [mysql] 和 [client] 部分

[root@fander ~]# cat /etc/my.cnf
[mysql]
prompt = "fander 's mysql>"

[client]
prompt = "fander 's client>"

[root@fander ~]# mysql -uroot -proot -S /tmp/mysql3307.sock
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 10
Server version: 5.7.36-log MySQL Community Server (GPL)

Copyright (c) 2000, 2021, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

fander 's client>     #看这里,这里证明了我的 mysql 客户端读取加载了 /etc/my.cnf

复制

四、是谁偷走了mysqld的时间?

[root@192-168-199-110 ~]# ps -ef |grep mysqld
root       7440      1  0 10:50 pts/2    00:00:00 /bin/sh /opt/fanderdb/mysql//bin/mysqld_safe --datadir=/opt/fanderdb/mysql/data/ --pid-file=/opt/fanderdb/mysql/data//192-168-199-110.pid
mysql      7945   7440  1 10:50 pts/2    00:00:04 /opt/fanderdb/mysql/bin/mysqld --basedir=/opt/fanderdb/mysql/ --datadir=/opt/fanderdb/mysql/data/ --plugin-dir=/opt/fanderdb/mysql//lib/plugin --user=mysql --log-error=/opt/fanderdb/mysql/data//mysql-error.log --open-files-limit=65535 --pid-file=/opt/fanderdb/mysql/data//192-168-199-110.pid --socket=/tmp/mysql.sock --port=3306
root       8035   5157  0 10:53 pts/2    00:00:00 grep --color=auto mysqld
[root@192-168-199-110 ~]# strace -c -p 7945
Process 7945 attached - interrupt to quit
^CProcess 7945 detached
% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
 99.92    3.130370       22045       142           poll
  0.06    0.002008           7       286           futex
  0.02    0.000526           2       286           setsockopt
  0.00    0.000000           0       143           accept
  0.00    0.000000           0       429           fcntl
  0.00    0.000000           0         1           restart_syscall
------ ----------- ----------- --------- --------- ----------------
100.00    3.132904                  1287           total

复制

抛砖引玉,更多玩法请自行探索。

Enjoy MySQL!

参考:
https://linuxtools-rst.readthedocs.io/zh_CN/latest/tool/strace.html https://www.linuxidc.com/Linux/2018-01/150654.htm https://blog.csdn.net/csdn265/article/details/70050168


最后修改时间:2023-05-26 16:28:51
文章转载自芬达的数据库学习笔记,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论