242021.06

技术干货 | 数据库无法登录,该怎么定位?

2021.06.24

DBA们在数据库运维工作中可能会遇到这样一个问题:在一台旧的 centos 7 服务器上面新安装了 mysql 8.0.19,使用下面的初始化命令:


mysqld --initialize-insecure --user=mysql --basedir=/usr/local/mysql --lower-case-table-names=1 --datadir=/data/mysql


初始化且启动成功后,使用命令mysql -S /data/mysql/mysql.sock用于登录实例,做其他操作,结果遇到故障。


1.jpg


这种情况该怎么解决呢?首先要定位故障点


定位过程

在只使用 socket 无法登陆数据库的情况下,做了如下测试:


mysql -S /data/mysql/mysql.sock -- 无法登陆返回报错
mysql --defaults-file=/data/mysql/my.cnf -- 正常登陆数据库
mysql -S /data/mysql/mysql.sock -p -- 然后连续两个回车,可以正常登陆数据库(第一个回车提示输入密码,第二个回车为确认输入空密码)


按照正常理解,上面三种方式没有本质区别,但却只有第一种无法登陆数据库,这就比较奇怪了。反观第 2、3 种方式可以登录数据库进行正常的操作,说明数据库是正常运行的。


在没有头绪的情况下,对第一种和第二种做了 strace 跟踪获取日志,对比日志差异,命令如下:


strace -T -tt -s 200 -o strace_socket.log mysql -S /data/mysql/mysql.sockstrace -T -tt -s 200 -o 
strace_cnf.log mysql --defaults-file=/data/mysql/my.cnf


在对比两个 strace 日志的时候,发现如下区别:strace_socket.log 日志中,登录过程依次尝试打开文件


/etc/my.cnf
/etc/my.cnf.d/mysql-clients.cnf
/etc/mysql/my.cnf/usr/local/mysql/etc/my.cnf
/root/.my.cnf


并且在打开/root/.my.cnf 中获取到 user 和 password 的信息


2.png


而在 strace_cnf.log 日志中,登录过程依次尝试打开的文件仅仅为


/data/mysql/my.cnf
/root/.mylogin.cnf


且并未获取到相关的 user 和 password 信息


3.png


通过日志文件 strace_socket.log 中提示的信息,在服务器上面确实找到了文件/root/.my.cnf,其内容如下图,而内容中的 user 和 password 正是 strace 日志中获取到的内容


4.png


为什么在使用 socket 登录的时候,会去寻找/root/.my.cnf 文件呢?


经过官网文档的查找发现,mysql 默认会从下面的路径中从上往下寻找配置文件,如果其中有[client]域则会用于 mysql 客户端的登录使用,因此我们能够在 strace_socket.log 中发现 password=drACgwoqtM 的信息


5.png



作为验证,我将文件/root/.my.cnf 删除,再次使用 mysql -S /data/mysql/mysql.sock就可以正常登陆数据库了。


6.png


至此原因定位清楚了,问题得到了解决:由于服务器上面有历史配置文件,导致新的实例连接读取了错误的配置文件,无法正常连接到数据库中。


后记

在定位过程中,查询初始化数据库--initialize-insecure 的时候发现,可以使用--skip-password,也能有效地避免这个问题。当密码为空时,官网建议使用该参数,而不是通过配置文件查找。


7.png


整个问题解析,strace 非常快捷地发现了问题所在,这里简单介绍一下strace

strace 是 Linux 环境下的一款程序调试工具,用来监测一个应用程序所使用的系统调用。它是一个简单的跟踪系统调用执行的工具,在其最简单的形式中,它可以从开始到结束跟踪二进制的执行,并在进程的生命周期中输出一行具有系统调用名称、每个系统调用的参数和返回值的文本行。


常用参数:

  • T:strace 输出显示时间

  • t:可以在每行的输出之前添加时间戳

  • tt:可以精确到微秒级别

  • ttt:也可以精确到微秒级,但是它并不是打印当前时间,而是显示自从epoch以来的所经过的秒数

  • s:指定输出的字符串的最大长度,默认为 32,如果输出到文件的话会全部输出

  • o:指定将strace输出到文件

  • ff:如果提供-o filename,则所有进程的跟踪结果输出到相应的 filename.pid中,pid 是各进程的进程号

  • e:指定跟踪某个行为,例如-e trace=open 指定只跟踪 open 行为

  • y:将文件句柄用文件路径代替显示


简单使用举例:


strace -T -tt -o /tmp/strace.log CMD
strace -T -tt CMD 2>&1 |tee /tmp/strace.log
strace -T -tt -s 200 -o /tmp/strace.log CMD
strace -T -tt -s 200 -ff -o /tmp/strace.log CMD
strace -T -tt -s 200 -e trace=XXXX -o /tmp/strace.log CMD