Whenever you specify "localhost" or "localhost:port" as server, the MySQL client library will override this and try to connect to a local socket (named pipe on Windows). If you want to use TCP/IP, use "127.0.0.1" instead of "localhost". If the MySQL client library tries to connect to the wrong local socket, you should set the correct path as in your PHP configuration and leave the server field blank.
localhost 使用的 Linux socket,127.0.0.1 使用的是 tcp/ip
因为你的本机中只有一个 mysql 进程, 如果你有一个 node1 运行在 3306, 有一个 node2 运行在 3307
mysql -u root -h localhost -P 3306
mysql -u root -h localhost -P 3307
都会连接到同一个 mysql 进程, 因为 localhost 使用 Linux socket, 所以 -P 字段直接被忽略了, 等价于
mysql -u root -h localhost
mysql -u root -h localhost
而 -h 默认是 localhost, 又等价于
mysql -u root
mysql -u root
为了避免这种情况(比如你在本地开发只有一个 mysql 进程,线上或者 qa 环境有多个 mysql 进程)最好的方式就是使用 IP
mysql -u root -h 127.0.0.1 -P 3307
使用strace查看:
strace mysql -h localhost -P 3306 -u root &> /tmp/strace_mysql.txt
结果:
execve("/opt/app/mysql/bin/mysql", ["mysql", "-h", "localhost", "-P", "3306", "-u", "root"], [/* 25 vars */]) = 0
......
socket(AF_LOCAL, SOCK_STREAM, 0) = 3
connect(3, {sa_family=AF_LOCAL, sun_path="/tmp/mysql.sock"}, 110) = 0 // 这里
setsockopt(3, SOL_TCP, TCP_NODELAY, [1], 4) = -1 EOPNOTSUPP (Operation not supported)
setsockopt(3, SOL_SOCKET, SO_KEEPALIVE, [1], 4) = 0
使用ip地址的strace
strace mysql -h 127.0.0.1 -P 3306 -u root &> /tmp/strace_mysql_use_ip.txt
execve("/opt/app/mysql/bin/mysql", ["mysql", "-h", "127.0.0.1", "-P", "3306", "-u", "root"], [/* 25 vars */]) = 0
....
socket(AF_INET, SOCK_STREAM, IPPROTO_TCP) = 3
connect(3, {sa_family=AF_INET, sin_port=htons(3306), sin_addr=inet_addr("127.0.0.1")}, 16) = 0
setsockopt(3, SOL_TCP, TCP_NODELAY, [1], 4) = 0
setsockopt(3, SOL_SOCKET, SO_KEEPALIVE, [1], 4) = 0
1
GoRoad 2019-11-27 14:55:24 +08:00
收藏了
|
2
lihongjie0209 OP @GoRoad #1 谢谢反馈
|
3
canyue7897 2019-11-27 14:58:39 +08:00 via iPhone
如果是 ipv6 呢? 127.0.0.1 就不行了吧!
|
4
chendy 2019-11-27 15:00:09 +08:00 1
MySQL 尽量不要和应用部署在一台机器上…
|
5
wiewiewie 2019-11-27 15:02:38 +08:00
谢谢 收了
|
6
lihongjie0209 OP @canyue7897 #3 写 ipv6 的地址就可以了
|
7
lihongjie0209 OP @chendy #4 我测试单机多进程主从同步时遇到的, 开发环境和 qa 环境可能会遇到这种情况
|
8
jxxz 2019-11-27 15:18:54 +08:00
确实,之前测试单机多实例登录的时候也发现了
|
9
jxxz 2019-11-27 15:21:13 +08:00
也可以指定 socket 文件,-S xxx.mysql.sock
|
10
ik 2019-11-27 15:21:49 +08:00 via iPhone
感谢分享
|
11
golden0125 2019-11-27 15:24:31 +08:00
优质内容
|
12
lihongjie0209 OP @jxxz #8 我做主从,发现不管怎么登陆都只能连接到 master, 查找了半天
|
13
tiedan 2019-11-27 15:31:57 +08:00
学习了
|
14
jxxz 2019-11-27 15:33:01 +08:00
@lihongjie0209 我当时没用 etc 下的默认 my.cnf 配置文件启动 mysql,结果用 localhost 多实例登录的时候提示找不到 /etc/my.cnf 配置文件中的指定的 socket 文件,才发现指定 localhost 都会走默认配置文件下的 socket
|
15
zhoushiya 2019-11-27 15:35:18 +08:00
我没研究那么多,只是测试中发现在 windows 下搭建的环境都用 127.0.0.1,在 linux VPS 上都用 localhost 就行了。。。在 windows 下用 localhost 那叫一个慢啊
|
16
lihongjie0209 OP @zhoushiya #15 警惕 windows ipv6 的问题,windows 是真的坑
|
17
xiangchen2011 2019-11-27 15:38:40 +08:00
学习到了。。。
|
18
ysn2233 2019-11-27 15:40:02 +08:00
我记得用 docker 的话只能 127.0.0.1 因为 localhost 走的是本地的 socks
|
19
killerv 2019-11-27 15:42:57 +08:00
支持
|
20
lululau 2019-11-27 15:43:00 +08:00
不管 3721 都走 TCP/IP,那 Unix Domain Socket 存在的意义是啥。。。
|
21
lihongjie0209 OP @lululau #20 历史遗留问题, 之前的 IPC 只局限在单机
|
23
tomychen 2019-11-27 17:39:09 +08:00
所以一台服务(主机)跑两个实例是不被推荐的做法
因为很多 localhost 不出现的 bug 在实际环境中,可能就出来了 |
24
ddzzhen 2019-11-27 17:42:32 +08:00 via Android
当年踩了这个坑,搞了很久
|
25
salamanderMH 2019-11-27 17:51:48 +08:00
是的,当年也是这个坑,Linux 上 localhost 会用`unix socket`
|
26
laminux29 2019-11-27 17:56:47 +08:00 1
不要在一个 OS 里,跑 1 个以上的数据库实例,这是你的错误,别怪 mysql。你不按照业界共识去做,必然会遇到各种各样的花式 bug。
|
27
lihongjie0209 OP @laminux29 #26 什么叫业界共识? 我测试主从同步还需要建立两个虚拟机?要不两个物理机?
我要测试一个 k8s 集群我需要多少台虚拟机 /物理机? 回到正题:一个软件使用 TCP 通讯, 只要有 IP+端口, 你是地球两端的物理机还是在同一个物理机上的两个进程都应该是表现一致的, 这是网络层带给我们的抽象,我们要合理的利用这个抽象来达到我们的目的: 比如说在一个 OS 中搭建一个 MySQL/Redis 集群用于测试。 MySQL 的这个问题和所谓的‘业界共识’没有任何关系, 这只是一个历史遗留问题导致的反常识的现象, 我记录出来也是为了给遇到同样问题的人提个醒。 |
28
lihongjie0209 OP @laminux29 #26 在一个 OS 中跑两个数据实例我还是能想到一些应用场景的。
1. 对于 Redis 这种单线程的数据库, 只有多进程才能完整利用高性能的服务器。 2. Mysql 也是同样的, 有一台性能极高的物理服务器, 系统负载只有 10%, 那么这时候需要再搭建一个数据库,你是选择再买一个服务器还是在同样的服务器上再跑一个 Mysql ? |
29
zzzmode 2019-11-27 18:13:47 +08:00 via iPhone
好像用 localhost 流量不需要经过网卡性能更高
|
30
ganymedenil590 2019-11-27 18:19:27 +08:00
@lihongjie0209 测试无所谓,但是生产环境肯定是拆分两个 vps。按照程序的特点来合理选择配置购买。
不然其中一个把系统打爆,另一个一起遭殃。 |
31
superrichman 2019-11-27 19:08:47 +08:00 via iPhone
生产环境上一台服务器跑两个数据库实例也真是不怕死。你把鸡蛋都放一个篮子里了,一摔全得碎。
|
32
lihongjie0209 OP @superrichman #31
这么做的目的绝对不是为了高可用, 只是为了压榨物理服务器的性能而已。 最起码我知道 redis 是这么做的。 其次, 数据库也分重要性, 不重要的几个放一台服务器我觉得没什么问题 |
33
junbaor 2019-11-27 19:19:24 +08:00 via iPhone
学习了
|
34
opengps 2019-11-27 19:20:47 +08:00
不光是这种高级的问题,我还遇到过 hosts 里没有把 localhost 解析到 127.0.0.1 的情况,新装的系统竟然能遇到这种鬼
|
35
lihongjie0209 OP @opengps #34 所以我以后能用 127.0.0.1 的绝对不用 localhost
|
36
ccalywm 2019-11-27 19:25:30 +08:00
学到了
|
37
xuanbg 2019-11-27 19:31:36 +08:00
只有一个 node 的就不会受影响。话说,一个主机上多个 mysql node,同时应用也在上面跑的情况还真是罕见
|
38
xuanbg 2019-11-27 19:33:13 +08:00
@lihongjie0209 数据不重要的话,也就没必要做主从了吧。
|
39
laminux29 2019-11-27 19:58:34 +08:00 5
@lihongjie0209
1.业界共识,是虽未以文档告知,但无论是软件开发者,还是用户,都会这么去做的约定俗成。 2.测试主从同步当然至少需要建立两个虚拟机,如果有多台物理机必然更好。 3.测试集群,必然需要用更多的虚拟机甚至物理机。其次,如果当硬件条件都不具备时,不应该硬着头皮上集群。 4.这个问题与 IP +端口的定义没任何关系,这只是 mysql 对于业界共识的一种硬编码 bug 而已。如果是按照业界共识去做,就不会踩到这个 bug,仅此而已。 5.Redis 不是纯粹的单线程程序,并且它也并不总是 CPU 密集型问题的解决方案。 6.正规公司,招聘的合格的 DBA 与系统管理员,在配置数据库服务器前,必然会对其负载有准确的预算。如果这种场景下,他们仍然选择让服务器在大部分时间以超低负荷运行,那么他们必然有特殊安排,比如首要目标是稳定,而不是资产利用率。 |
40
panzhc 2019-11-27 20:12:26 +08:00
感谢分享,用 docker 也能解决单机多实例的问题
|
41
lihongjie0209 OP @laminux29 #39
1. 业界共识 ‘不要在一个 OS 里,跑 1 个以上的数据库实例’ 可能是你的共识, 我并没有在任何官方和非官方的场合下听到这种言论 2. 在 QA 环境下, 应用程序和 Redis 都跑在一台服务器上, 连接使用 127.0.0.1, 上线之后有专门的缓存服务器 120.xxx.xxx.xxx, 我只需要修改一下连接的地址就可以了, 难道我还在在 QA 环境部署一台专门的缓存服务器? 有些东西:比如说物理服务器的性能,资源数量啊当然是和生产环境一模一样最好, 可现实就是我们只需要一些最基本的配置就可以完成开发和测试的工作。 通过 TCP/IP 完全可以让开发无视这些物理服务器之间的区别,更快更好的完成开发工作, 何乐而不为。 3. 测试集群有很多的场景, 为了学习, 为了测试环境都有可能, 理想情况下需要 5 台高性能的实体服务器的集群在以学习为目的的情况下用 3 台性能一般的虚拟机就可以实现, 为什么非要加那么多的限制条件呢? 指望一个初学者为了学一个东西先准备 5 台实体服务器? k8s 还有专门为单机准备的教程呢。 4. 你这里的业界共识是指一个服务器一个数据库还是 localhost 就是指 linux socket ? 5. 和 CPU 密集型没有任何关系 6. 养 DBA 的公司不多, 但是想省钱又不太在意高可用的公司不少。 说实话又许多应用没那么重要,但对于一些公司又是必不可少 |
42
Aruforce 2019-11-27 21:29:23 +08:00 via Android
是所有的 connector 都这样?还是只有特定的版本?
|
43
xiaooloong 2019-11-28 00:01:51 +08:00
localhost 使用 Linux socket 不是常识么
|
44
wangyzj 2019-11-28 00:39:11 +08:00
连接可以指定 socket 地址的
另外 我都用 IP 大应用只能用 IP 作分离 小应用也不需要 socket 的高性能 |
45
conn4575 2019-11-28 01:05:43 +08:00 via Android
哇,一直都没注意居然还有这样的问题,真的坑
|
46
zuoer123 2019-11-28 01:39:30 +08:00 via iPhone
make
|
47
jinliming2 2019-11-28 02:10:20 +08:00 via iPhone
一般建议还是用 unix sock,一个方面是更快,另一方面是相对更安全
(不过 MySQL 为啥这么奇葩,localhost 和 unix sock 混为一谈?一个是 tcp://,一个是 unix://,两个差老远了啊! |
48
LuciferGo 2019-11-28 09:09:29 +08:00
遇到过 localhost 的问题,没研究过这么细,赞
|
49
iwtbauh 2019-11-28 09:36:51 +08:00 via Android
现在的人的基础知识已经如此差了吗?
“linux socket”我是第一次听说。我猜 lz 是想说“unix domain socket”( Unix 域套接字),见手册页 unix(7) "linux socket"更容易被理解为是“linux 上特有的非 POSIX 的 socket”,如“netlink socket” 还是需要继续提高姿势水平 |
50
paoqi2048 2019-11-28 10:11:09 +08:00
学习了
|
51
T3RRY 2019-11-28 10:51:41 +08:00
赞了
|
52
belain 2019-11-28 11:45:45 +08:00
学习了!谢谢!
|
53
lihongjie0209 OP |
54
abmin521 2019-11-28 12:07:30 +08:00 via iPhone
别的客户端应该都会做解析的吧
|
55
laminux29 2019-11-28 13:48:59 +08:00
@lihongjie0209 数据库的负载,与很多因素有关。你发的截图,它这书里,只是针对它自己的环境与业务,给出 mysql 的负载信息而已。这种数据看看就行了,不用太关注。你应该更关注你自己的业务。
|
56
rrfeng 2019-11-28 13:51:56 +08:00
你试试 -h localhost:3307 呢?
你一个机器上俩实例,端口不一样,都用 localhost 吗?不加端口嘛? 事实上是这样你讲的没错,但是逻辑上不是的。 |
57
lihongjie0209 OP @rrfeng #56
[root@localhost ~]# mysql -h localhost:3307 -u root ERROR 2005 (HY000): Unknown MySQL server host 'localhost:3307' (2) ``` socket(AF_INET, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, IPPROTO_IP) = 3 connect(3, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("192.168.2.254")}, 16) = 0 poll([{fd=3, events=POLLOUT}], 1, 0) = 1 ([{fd=3, revents=POLLOUT}]) sendmmsg(3, {{{msg_name(0)=NULL, msg_iov(1)=[{")d\1\0\0\1\0\0\0\0\0\0\16localhost:3307\0\0\1\0\1", 32}], msg_controllen=0, msg_flags=MSG_OOB|MSG_DONTWAIT|MSG_EOR|MSG_FIN|0x80000}, 32}, {{msg_name(0)=NULL, msg_iov(1)=[{"{\245\1\0\0\1\0\0\0\0\0\0\16localhost:3307\0\0\34\0\1", 32}], msg_controllen=0, msg_flags=0}, 32}}, 2, MSG_NOSIGNAL) = 2 poll([{fd=3, events=POLLIN}], 1, 5000) = 1 ([{fd=3, revents=POLLIN}]) ioctl(3, FIONREAD, [32]) = 0 recvfrom(3, ")d\201\202\0\1\0\0\0\0\0\0\16localhost:3307\0\0\1\0\1", 2048, 0, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("192.168.2.254")}, [16]) = 32 poll([{fd=3, events=POLLIN}], 1, 4998) = 1 ([{fd=3, revents=POLLIN}]) ioctl(3, FIONREAD, [32]) = 0 recvfrom(3, "{\245\201\202\0\1\0\0\0\0\0\0\16localhost:3307\0\0\34\0\1", 65536, 0, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("192.168.2.254")}, [16]) = 32 ``` 很明显把 localhost:3307 当做域名了, 直接去找 dns 解析了 |
58
lihongjie0209 OP @rrfeng #56 有加
|
59
lihongjie0209 OP @abmin521 #54 并没有测试, 在 StackOverflow 中有人提到了 PHP 也会有这个问题(没有测试过)
不过哪怕只是 mysql 相关的工具 mysql/mysqldump/mysqladmin 遇到这种问题, 很有可能导致备份 /重启 等过程发生在错误的 mysqld 进程中 |
60
passerbytiny 2019-11-28 14:10:21 +08:00
@lihongjie0209
Linux 上 localhost,以及.localhost 域名都是大坑,但是真得不建议用 127.0.0.1 替代 localhost。替代 localhost 的应该是 hostname,或者 hosts 中配置的假域名。localhost、hostname、domain 这三者是一个层次的,IP 跟他们不一个层次。 |
61
alphadog619 2019-11-28 15:26:07 +08:00
我司一款 B/S 软件,配置文件写 127.0.0.1 死活连不上 SQL,写成 localhost 就没问题。
|
62
PhyllisLin 2019-11-28 15:35:09 +08:00 via Android
前几天搭,,HBase 集群迁移数据实验遇到过类似的问题,已经给 local host 赋权了,可偏偏连不上,要用主机名才行。真的坑,不知道是不是题主的这个原因。
|
63
lihongjie0209 OP @alphadog619 #61 估计是只支持 unix socket 连接
|
64
walpurgis 2019-11-28 15:50:15 +08:00 via Android
做过运维的表示,这基本上算是常识
|
65
lihongjie0209 OP @walpurgis #64 对于搞网络和开发的表示这很反常识
|
66
lzp1205186344 2019-11-28 16:07:43 +08:00 via Android
@canyue7897 ::1
|
67
dnsaq 2019-11-29 09:04:38 +08:00 via iPhone
无论什么场景域名优先级永远比 ip 高,不用 localhost 的花建议用内部 dns 分配的域名,便于调度管理
|
68
waterlaw 2019-12-08 20:27:55 +08:00
win10 下复制 mysql 目录(数据目录除外),改了 mysql 端口, 开启了两个服务,使用 localhost 和不同端口连接是不同的,不知道楼主怎么一个 MySQL 服务开启两个进程的,是改了配置文件又开了另一个服务吗?
|
69
adeng 2023-05-18 12:35:43 +08:00
卧槽, 怪不得我想导出 Linux 上 docker 部署的 MySQL 数据时, 只要用 localhost, 错误端口都能导出数据, 而用域名时, 只有正确端口, 原来是这样
|
70
mh494078416 2023-12-28 23:20:58 +08:00
学到了
|