一次MariaDB问题的排查

一次MariaDB问题的排查

起因

在某云买了个新的VPS,接下来自然是把之前的网站搬上去了。之前我是用lnmp脚本安装的环境。这一次我要自己安装!

一顿操作之后,Nginx+MariaDB+PHP安装好了!既然换了新机器,肯定软件都要安装新的啦。于是:

  • PHP 7.3.17 -> 7.4.10
  • Nginx 1.12.2 -> 1.18.0
  • MariaDB 10.1.19 -> 10.5.5

一顿操作完安装好后,自然是开始配置了

改密码

第一件事自然是给MariaDB改个密码了。轻车熟路的,先用skip-grant-tables模式启动,然后开始噼里啪啦的敲SQL:

MariaDB [(none)]> use mysql
Database changed
MariaDB [mysql]> UPDATE user SET Password=password('123') WHERE User='root' AND Host='localhost'
ERROR 1356 (HY000): View 'mysql.user' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them

哎?怎么修改不了?仔细一琢磨,原来mysql.user是个View。那就换成其他方式吧。说实话用SET也挺好

MariaDB [mysql]> SET Password FOR root@localhost = password('123');
MariaDB [mysql]> FLUSH PRIVILEGES;

连接

接下来当然是导入之前的数据了,打开phpMyAdmin,密码已经被KeePass自动填充上了。点击登录。哎?怎么报错mysqli_real_connect(): (HY000/2002): No such file or directory了?

网上搜索了一下,有人说把地址改一下就行了。于是在config.inc.php里面把localhost改成了127.0.0.1,然后继续重试。倒是不提示No such file了,变成一个更奇怪的提示:

Packets out of order. Expected 0 received 1. Packet size=68
mysqli::real_connect(): Error while reading greeting packet. PID=10000
mysqli::real_connect(): MySQL server has gone away

看上去没有任何头绪。一开始以为是驱动版本不兼容,换了Navicat尝试还是不行。后来尝试新建了一个用于127.0.0.1的用户,然后刷新权限重启MariaDB才连接成功。

Systemd?

连接成功,导入数据,上传程序,一气呵成。接下来一运行,又遇到了“No such file or directory”的错误提示。嗯?那看来得解决解决。

查了一堆资料,了解到localhost会在内部当做Unix socket连接方式处理。问题不外乎有几个:

  • sock位置不对
  • 没有权限

把phpinfo打印出来,发现路径是/tmp/mysql.sock,没有问题。再到tmp目录下ls看了看:

[root@shuangya web]# ls -l /tmp
total 276
srwxrwxrwx 1 mysql mysql      0 Sep 26 22:44 mysql.sock

看上去也没有问题呀?写一个测试脚本试试:

<?php
$host = "localhost";
$username = "root"; 
$password = "*******"; 
$dbname = "mysql"; 
$charset = "utf8"; 
$dsn = "mysql:dbname=$dbname;port=3306;host=$host";

try{
	$pdo = new Pdo($dsn, $username, $password);
	$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch(PDOException $e){
	die("连接失败: ".$e->getMessage());
}

var_dump($pdo->query('SELECT * FROM user'));
echo "ok";

运行一看,完全正常……

难道是用户问题?于是把www用户打开,切换过去运行,发现也完全正常。

怎么回事?试试手动读取一下tmp目录,要是能读出来的话,那就可以排除掉权限问题了。

<?php
$dh = opendir('/tmp');
while ($d = readdir($dh)) {
	var_dump($d);
}
closedir($dh);

出乎人意料的结果:

.
..
sess_1716b75d954b27ba1e53b088d1c23809

哎?居然没有mysql.sock?但是我在tmp目录下面也没有看到这个“sess_”的文件呀?全盘搜索了一下,结果发现它位于systemd-private-xxxxxxxxxxxxx下面。

看这个名字就猜到了,它一定和systemd有点什么关系。打开php-fpm.service一看:

[Unit]
Description=The PHP FastCGI Process Manager
After=syslog.target network.target

[Service]
Type=forking
PIDFile=/var/run/php-fpm.pid
ExecStart=/usr/local/php/sbin/php-fpm
ExecReload=/bin/kill -USR2 $MAINPID
PrivateTmp=true

那看来这个PrivateTmp=true应该就是罪魁祸首了。搜索了一下,这个选项会让启动的服务有一个私有的tmp目录。怪不得php找不到mysql的sock文件……

解决方法就更简单了,把它关掉,万事大吉~