V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
MySQL 5.5 Community Server
MySQL 5.6 Community Server
Percona Configuration Wizard
XtraBackup 搭建主从复制
Great Sites on MySQL
Percona
MySQL Performance Blog
Severalnines
推荐管理工具
Sequel Pro
phpMyAdmin
推荐书目
MySQL Cookbook
MySQL 相关项目
MariaDB
Drizzle
参考文档
http://mysql-python.sourceforge.net/MySQLdb.html
lihongjie0209
V2EX  ›  MySQL

MySQL 连接时尽量使用 127.0.0.1 而不是 localhost

  lihongjie0209 · 2019-11-27 14:37:49 +08:00 · 15188 次点击
这是一个创建于 1604 天前的主题,其中的信息可能已经有所发展或是发生改变。

原因

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

为什么我使用 localhost 一直没出问题

因为你的本机中只有一个 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
第 1 条附言  ·  2019-11-27 15:36:28 +08:00

使用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

第 2 条附言  ·  2019-11-27 15:39:47 +08:00

使用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


70 条回复    2023-12-28 23:20:58 +08:00
GoRoad
    1
GoRoad  
   2019-11-27 14:55:24 +08:00
收藏了
lihongjie0209
    2
lihongjie0209  
OP
   2019-11-27 14:57:32 +08:00
@GoRoad #1 谢谢反馈
canyue7897
    3
canyue7897  
   2019-11-27 14:58:39 +08:00 via iPhone
如果是 ipv6 呢? 127.0.0.1 就不行了吧!
chendy
    4
chendy  
   2019-11-27 15:00:09 +08:00   ❤️ 1
MySQL 尽量不要和应用部署在一台机器上…
wiewiewie
    5
wiewiewie  
   2019-11-27 15:02:38 +08:00
谢谢 收了
lihongjie0209
    6
lihongjie0209  
OP
   2019-11-27 15:06:05 +08:00
@canyue7897 #3 写 ipv6 的地址就可以了
lihongjie0209
    7
lihongjie0209  
OP
   2019-11-27 15:06:53 +08:00
@chendy #4 我测试单机多进程主从同步时遇到的, 开发环境和 qa 环境可能会遇到这种情况
jxxz
    8
jxxz  
   2019-11-27 15:18:54 +08:00
确实,之前测试单机多实例登录的时候也发现了
jxxz
    9
jxxz  
   2019-11-27 15:21:13 +08:00
也可以指定 socket 文件,-S xxx.mysql.sock
ik
    10
ik  
   2019-11-27 15:21:49 +08:00 via iPhone
感谢分享
golden0125
    11
golden0125  
   2019-11-27 15:24:31 +08:00
优质内容
lihongjie0209
    12
lihongjie0209  
OP
   2019-11-27 15:28:56 +08:00
@jxxz #8 我做主从,发现不管怎么登陆都只能连接到 master, 查找了半天
tiedan
    13
tiedan  
   2019-11-27 15:31:57 +08:00
学习了
jxxz
    14
jxxz  
   2019-11-27 15:33:01 +08:00
@lihongjie0209 我当时没用 etc 下的默认 my.cnf 配置文件启动 mysql,结果用 localhost 多实例登录的时候提示找不到 /etc/my.cnf 配置文件中的指定的 socket 文件,才发现指定 localhost 都会走默认配置文件下的 socket
zhoushiya
    15
zhoushiya  
   2019-11-27 15:35:18 +08:00
我没研究那么多,只是测试中发现在 windows 下搭建的环境都用 127.0.0.1,在 linux VPS 上都用 localhost 就行了。。。在 windows 下用 localhost 那叫一个慢啊
lihongjie0209
    16
lihongjie0209  
OP
   2019-11-27 15:37:08 +08:00
@zhoushiya #15 警惕 windows ipv6 的问题,windows 是真的坑
xiangchen2011
    17
xiangchen2011  
   2019-11-27 15:38:40 +08:00
学习到了。。。
ysn2233
    18
ysn2233  
   2019-11-27 15:40:02 +08:00
我记得用 docker 的话只能 127.0.0.1 因为 localhost 走的是本地的 socks
killerv
    19
killerv  
   2019-11-27 15:42:57 +08:00
支持
lululau
    20
lululau  
   2019-11-27 15:43:00 +08:00
不管 3721 都走 TCP/IP,那 Unix Domain Socket 存在的意义是啥。。。
lihongjie0209
    21
lihongjie0209  
OP
   2019-11-27 15:49:23 +08:00
@lululau #20 历史遗留问题, 之前的 IPC 只局限在单机
sagaxu
    22
sagaxu  
   2019-11-27 15:54:41 +08:00 via Android   ❤️ 1
@lululau unix 套接字性能更高
tomychen
    23
tomychen  
   2019-11-27 17:39:09 +08:00
所以一台服务(主机)跑两个实例是不被推荐的做法
因为很多 localhost 不出现的 bug 在实际环境中,可能就出来了
ddzzhen
    24
ddzzhen  
   2019-11-27 17:42:32 +08:00 via Android
当年踩了这个坑,搞了很久
salamanderMH
    25
salamanderMH  
   2019-11-27 17:51:48 +08:00
是的,当年也是这个坑,Linux 上 localhost 会用`unix socket`
laminux29
    26
laminux29  
   2019-11-27 17:56:47 +08:00   ❤️ 1
不要在一个 OS 里,跑 1 个以上的数据库实例,这是你的错误,别怪 mysql。你不按照业界共识去做,必然会遇到各种各样的花式 bug。
lihongjie0209
    27
lihongjie0209  
OP
   2019-11-27 18:06:01 +08:00   ❤️ 6
@laminux29 #26 什么叫业界共识? 我测试主从同步还需要建立两个虚拟机?要不两个物理机?

我要测试一个 k8s 集群我需要多少台虚拟机 /物理机?



回到正题:一个软件使用 TCP 通讯, 只要有 IP+端口, 你是地球两端的物理机还是在同一个物理机上的两个进程都应该是表现一致的, 这是网络层带给我们的抽象,我们要合理的利用这个抽象来达到我们的目的: 比如说在一个 OS 中搭建一个 MySQL/Redis 集群用于测试。

MySQL 的这个问题和所谓的‘业界共识’没有任何关系, 这只是一个历史遗留问题导致的反常识的现象, 我记录出来也是为了给遇到同样问题的人提个醒。
lihongjie0209
    28
lihongjie0209  
OP
   2019-11-27 18:09:48 +08:00
@laminux29 #26 在一个 OS 中跑两个数据实例我还是能想到一些应用场景的。
1. 对于 Redis 这种单线程的数据库, 只有多进程才能完整利用高性能的服务器。
2. Mysql 也是同样的, 有一台性能极高的物理服务器, 系统负载只有 10%, 那么这时候需要再搭建一个数据库,你是选择再买一个服务器还是在同样的服务器上再跑一个 Mysql ?
zzzmode
    29
zzzmode  
   2019-11-27 18:13:47 +08:00 via iPhone
好像用 localhost 流量不需要经过网卡性能更高
ganymedenil590
    30
ganymedenil590  
   2019-11-27 18:19:27 +08:00
@lihongjie0209 测试无所谓,但是生产环境肯定是拆分两个 vps。按照程序的特点来合理选择配置购买。
不然其中一个把系统打爆,另一个一起遭殃。
superrichman
    31
superrichman  
   2019-11-27 19:08:47 +08:00 via iPhone
生产环境上一台服务器跑两个数据库实例也真是不怕死。你把鸡蛋都放一个篮子里了,一摔全得碎。
lihongjie0209
    32
lihongjie0209  
OP
   2019-11-27 19:11:15 +08:00
@superrichman #31
这么做的目的绝对不是为了高可用, 只是为了压榨物理服务器的性能而已。

最起码我知道 redis 是这么做的。

其次, 数据库也分重要性, 不重要的几个放一台服务器我觉得没什么问题
junbaor
    33
junbaor  
   2019-11-27 19:19:24 +08:00 via iPhone
学习了
opengps
    34
opengps  
   2019-11-27 19:20:47 +08:00
不光是这种高级的问题,我还遇到过 hosts 里没有把 localhost 解析到 127.0.0.1 的情况,新装的系统竟然能遇到这种鬼
lihongjie0209
    35
lihongjie0209  
OP
   2019-11-27 19:22:38 +08:00
@opengps #34 所以我以后能用 127.0.0.1 的绝对不用 localhost
ccalywm
    36
ccalywm  
   2019-11-27 19:25:30 +08:00
学到了
xuanbg
    37
xuanbg  
   2019-11-27 19:31:36 +08:00
只有一个 node 的就不会受影响。话说,一个主机上多个 mysql node,同时应用也在上面跑的情况还真是罕见
xuanbg
    38
xuanbg  
   2019-11-27 19:33:13 +08:00
@lihongjie0209 数据不重要的话,也就没必要做主从了吧。
laminux29
    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 与系统管理员,在配置数据库服务器前,必然会对其负载有准确的预算。如果这种场景下,他们仍然选择让服务器在大部分时间以超低负荷运行,那么他们必然有特殊安排,比如首要目标是稳定,而不是资产利用率。
panzhc
    40
panzhc  
   2019-11-27 20:12:26 +08:00
感谢分享,用 docker 也能解决单机多实例的问题
lihongjie0209
    41
lihongjie0209  
OP
   2019-11-27 20:18:12 +08:00
@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 的公司不多, 但是想省钱又不太在意高可用的公司不少。 说实话又许多应用没那么重要,但对于一些公司又是必不可少
Aruforce
    42
Aruforce  
   2019-11-27 21:29:23 +08:00 via Android
是所有的 connector 都这样?还是只有特定的版本?
xiaooloong
    43
xiaooloong  
   2019-11-28 00:01:51 +08:00
localhost 使用 Linux socket 不是常识么
wangyzj
    44
wangyzj  
   2019-11-28 00:39:11 +08:00
连接可以指定 socket 地址的
另外
我都用 IP
大应用只能用 IP 作分离
小应用也不需要 socket 的高性能
conn4575
    45
conn4575  
   2019-11-28 01:05:43 +08:00 via Android
哇,一直都没注意居然还有这样的问题,真的坑
zuoer123
    46
zuoer123  
   2019-11-28 01:39:30 +08:00 via iPhone
make
jinliming2
    47
jinliming2  
   2019-11-28 02:10:20 +08:00 via iPhone
一般建议还是用 unix sock,一个方面是更快,另一方面是相对更安全
(不过 MySQL 为啥这么奇葩,localhost 和 unix sock 混为一谈?一个是 tcp://,一个是 unix://,两个差老远了啊!
LuciferGo
    48
LuciferGo  
   2019-11-28 09:09:29 +08:00
遇到过 localhost 的问题,没研究过这么细,赞
iwtbauh
    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”

还是需要继续提高姿势水平
paoqi2048
    50
paoqi2048  
   2019-11-28 10:11:09 +08:00
学习了
T3RRY
    51
T3RRY  
   2019-11-28 10:51:41 +08:00
赞了
belain
    52
belain  
   2019-11-28 11:45:45 +08:00
学习了!谢谢!
lihongjie0209
    53
lihongjie0209  
OP
   2019-11-28 11:50:50 +08:00
@laminux29 #39 刚刚在 高性能 Mysql 中看到的
abmin521
    54
abmin521  
   2019-11-28 12:07:30 +08:00 via iPhone
别的客户端应该都会做解析的吧
laminux29
    55
laminux29  
   2019-11-28 13:48:59 +08:00
@lihongjie0209 数据库的负载,与很多因素有关。你发的截图,它这书里,只是针对它自己的环境与业务,给出 mysql 的负载信息而已。这种数据看看就行了,不用太关注。你应该更关注你自己的业务。
rrfeng
    56
rrfeng  
   2019-11-28 13:51:56 +08:00
你试试 -h localhost:3307 呢?
你一个机器上俩实例,端口不一样,都用 localhost 吗?不加端口嘛?

事实上是这样你讲的没错,但是逻辑上不是的。
lihongjie0209
    57
lihongjie0209  
OP
   2019-11-28 13:56:57 +08:00
@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 解析了
lihongjie0209
    58
lihongjie0209  
OP
   2019-11-28 13:57:44 +08:00
@rrfeng #56 有加
lihongjie0209
    59
lihongjie0209  
OP
   2019-11-28 14:04:12 +08:00
@abmin521 #54 并没有测试, 在 StackOverflow 中有人提到了 PHP 也会有这个问题(没有测试过)

不过哪怕只是 mysql 相关的工具 mysql/mysqldump/mysqladmin 遇到这种问题, 很有可能导致备份 /重启 等过程发生在错误的 mysqld 进程中
passerbytiny
    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 跟他们不一个层次。
alphadog619
    61
alphadog619  
   2019-11-28 15:26:07 +08:00
我司一款 B/S 软件,配置文件写 127.0.0.1 死活连不上 SQL,写成 localhost 就没问题。
PhyllisLin
    62
PhyllisLin  
   2019-11-28 15:35:09 +08:00 via Android
前几天搭,,HBase 集群迁移数据实验遇到过类似的问题,已经给 local host 赋权了,可偏偏连不上,要用主机名才行。真的坑,不知道是不是题主的这个原因。
lihongjie0209
    63
lihongjie0209  
OP
   2019-11-28 15:42:07 +08:00
@alphadog619 #61 估计是只支持 unix socket 连接
walpurgis
    64
walpurgis  
   2019-11-28 15:50:15 +08:00 via Android
做过运维的表示,这基本上算是常识
lihongjie0209
    65
lihongjie0209  
OP
   2019-11-28 16:04:55 +08:00
@walpurgis #64 对于搞网络和开发的表示这很反常识
lzp1205186344
    66
lzp1205186344  
   2019-11-28 16:07:43 +08:00 via Android
dnsaq
    67
dnsaq  
   2019-11-29 09:04:38 +08:00 via iPhone
无论什么场景域名优先级永远比 ip 高,不用 localhost 的花建议用内部 dns 分配的域名,便于调度管理
waterlaw
    68
waterlaw  
   2019-12-08 20:27:55 +08:00
win10 下复制 mysql 目录(数据目录除外),改了 mysql 端口, 开启了两个服务,使用 localhost 和不同端口连接是不同的,不知道楼主怎么一个 MySQL 服务开启两个进程的,是改了配置文件又开了另一个服务吗?
adeng
    69
adeng  
   336 天前
卧槽, 怪不得我想导出 Linux 上 docker 部署的 MySQL 数据时, 只要用 localhost, 错误端口都能导出数据, 而用域名时, 只有正确端口, 原来是这样
mh494078416
    70
mh494078416  
   112 天前
学到了
关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   1350 人在线   最高记录 6543   ·     Select Language
创意工作者们的社区
World is powered by solitude
VERSION: 3.9.8.5 · 31ms · UTC 23:43 · PVG 07:43 · LAX 16:43 · JFK 19:43
Developed with CodeLauncher
♥ Do have faith in what you're doing.