原文:https://ocelot.ca/blog/blog/2015/07/19/connecting-to-mysql-or-mariadb-with-sockets-on-linux/
MySQL手册上面有这样一段话:
--socket=file_name, -S file_name ... On Unix, the name of the Unix socket file to use, for connections made using a named pipe to a local server.
The default Unix socket file name is /tmp/mysql.sock.
但是往往真正在使用unix socket连接的时候会报 "Can't connect to local MySQL server through socket '[something-other-than-/tmp/mysql.sock]'".
我接下来会解释一下为什么文件名总是不同的,如何知道mysql究竟在监听什么,对于用户和应用开发者来说固定不变的是什么.
首先,Linux Foundation发布了一个"文件系统目录等级标准"的文档,在2.3版本中,对于/var/run路径的说法为:维护临时的unix socket文件必须存储在这里.但是在版本3中对于/var/run目录的说明做了一些修改:临时的unix socket文件必须放在该目录下,或者放到上述的一个合适的子目录下面(or an appropriate subdirectory as outlined above),3版本同时也说:总体来说,为了能够实现向后兼容,程序可以继续使用/var/run,所以./var/run依然是标准的存放unix socket文件的地方.
其次,Mysql的附录部分隐藏了一些有趣的东西:对于一些linux版本,unix socket的路径有可能是不同的,对于RPMs操作系统是/var/lib/mysql.这是一种模糊的说法,unix socket文件的路径在安装阶段(source-installation time)已经决定了.
在安装阶段,通过-DINSTALL_LAYOUT={STANDALONE|RPM|SVR4|DEB}决定:
SET(INSTALL_UNIX_ADDRDIR_STANDALONE "/tmp/mysql.sock")
SET(INSTALL_UNIX_ADDRDIR_RPM "/var/lib/mysql/mysql.sock")
SET(INSTALL_UNIX_ADDRDIR_DEB "/var/run/mysqld/mysqld.sock")
SET(INSTALL_UNIX_ADDRDIR_SVR "/tmp/mysql.sock")
所以说,不同的机器,mysql的unix socket默认路径是不同的,下面的配置是我在很久以前总结出来的,所以可能已经过时:
Non-Linux e.g. FreeBSD or Solaris: /tmp/mysql.sock
Debian-based e.g. Ubuntu, and archlinux: /var/run/mysqld/mysqld.sock
SUSE (after v11.2): /var/run/mysql/mysql.sock
Red Hat, and SUSE (before v11.2): /var/lib/mysql/mysql.sock
archlinux (very old versions): /tmp/mysqld.sock
有时,你可以通过 mysql_config --socket命令找出你机器上的mysql unix socket文件究竟在哪里.
如果说你不是mysql的安装者,或者说或者说你已经忘记了mysql安装的细节,下面有一些方法可以找到mysql究竟打开了哪些socket.但是这些方法或多或少都有一些缺陷.
方法一:
netstat -lpn | grep mysqld
这种方式的缺陷是,如果你不是root用户,那么无法查看所有的进程,而且 |grep mysqld假设mysql server的名字就是mysqld.
方法二:
find /tmp /var/lib/mysql /var/run/mysqld -name "mysql*.sock"
find: 'var/lib/mysql': Permission denied
/var/run/mysqld/mysqld.sock
这种方法的缺陷是你必须实现猜测mysql unix socket文件存放在哪个目录下面.
方法三:
mysql -h 127.0.0.1 -e "select @@socket"
+-----------------------------+
| /var/run/mysqld/mysqld.sock |
+-----------------------------+
这种做法的缺点是假设mysql的端口就是默认端口3306,并且本地mysql可以访问,每个人都有访问mysql的权限.(我敲这个命令就提示无权限访问本地mysql)
当你发现了mysql server使用的unix socket,你可以为这个unix socket重定向一下:
ln -s /var/run/mysqld/mysqld.sock /tmp/mysql.sock
另外一个解决方案就是,告诉客户端程序unix socket是什么,对于遵循mysql guidelines的客户端程序来说,可以设定MYSQL_UNIX_PORT环境变量,或者命令行启动mysql的时候添加 --socket=X,或者更改配置文件(比如~/.my.cnf),在配置文件中增加一行 socket=X.注意mysql unix socket 文件路径也有可能存储在其他地方,比如/etc/mysql/debian.cnf 或php.ini.
开发客户端程序的人不应该把unix socket带来的一些问题带给用户,一个简单的解决方法是,把unix socket文件硬编码进程序中.
也有一些GUI的客户端程序默认就使用TCP进行连接,MYSQL有一个很麻烦的地方就是,当用户输入"host=localhost"的时候,我们不知道他们是要用TCP还是unix socket进行连接,Ocelet就默认的使用tcp连接.
所以说,ocelotgui通过把最有可能的unix socket路径硬编码进来让事情变得简单.也就是说,如果用户并没有指明unix socket,host是默认值或者localhost的时候,ocelotgui会尝试通过/tmp/mysql.sock连接如果失败的话尝试/var/lib/mysql/mysql.sock,如果再失败城市/var/run/mysqld/mysqld.sock.ocelotgui目前只是计划这样做,还没有真正的做.
我们之所以使用unix socket是因为性能问题,使用unix socket的数据传输率比tcp要快,而且再大数据量的情况下,花时间取配置unix socket是值得的.
TCP VS Unix Socket 是一个linux问题,所以说这不应该是mysql解决,而应该是linux开发者来解决(好像说的挺有道理)所以说google做了一个修补,如果连接的是本地mysql,将TCP连接直接转换成unix socket.有一篇2012年的文章是关于这一点的,在那之后mysql怎样,我并不清楚.(So there is a fix, or more precisely there is a Google patch, which turns a TCP/IP connection into a socket connection if the target is localhost. There was an article about it on lwn.net in 2012. What happened after that, I don't know.)