Ubuntu16.04下MySQL集群HAproxy读写分离遇连接错误求助
让我来帮你拆解下问题:你遇到的unknown MySql server host错误,核心原因是HAproxy的运行模式和你想用的URL路径规则完全不匹配,具体细节和解决方案如下:
为什么会出错?
你的HAproxy配置里defaults段设置了mode tcp,这意味着HAproxy会把所有流量当成纯TCP字节流转发,不会解析任何HTTP请求内容。但你又用了acl write url_beg /write这种HTTP层的规则——TCP模式下HAproxy根本看不到所谓的"URL路径",这条ACL规则完全不会生效。
更糟的是,当你试图通过X.X.X.X/write访问时,客户端发送的HTTP请求(比如GET /write HTTP/1.1)会被原封不动转发到MySQL的3306端口,MySQL会把这些HTTP报文里的奇怪内容当成"主机名"解析,自然就抛出了"未知MySQL服务器主机"的错误。
针对你的场景,两种可行解决方案
方案一:用端口区分读写(适合原生MySQL客户端)
原生MySQL是纯TCP协议,客户端连接时只会指定主机和端口,不会发送HTTP路径。所以更合理的方式是给读写流量分配不同端口:
global log 127.0.0.1 local0 notice maxconn 2000 user haproxy group haproxy defaults mode tcp log global retries 2 timeout connect 3000 timeout server 50000 timeout client 50000 backend read balance roundrobin server mysql1 192.168.0.4:3306 server mysql2 192.168.0.5:3306 server mysql3 192.168.0.6:3306 backend write server mysql1 192.168.0.4:3306 frontend read_frontend bind *:80 default_backend read frontend write_frontend bind *:81 default_backend write
配置完成后,MySQL客户端连接X.X.X.X:80就是读流量,连接X.X.X.X:81就是写流量,完全符合原生MySQL的使用逻辑。
方案二:用HTTP模式(仅当你用HTTP网关转MySQL时)
如果你确实需要通过URL路径区分(比如用了第三方HTTP转MySQL的网关服务),那必须把HAproxy改成HTTP模式,同时后端要指向网关的端口(不是MySQL的3306):
global log 127.0.0.1 local0 notice maxconn 2000 user haproxy group haproxy defaults mode http log global retries 2 timeout connect 3000 timeout server 30000 timeout client 30000 option httplog option forwardfor backend read balance roundrobin # 替换成你的HTTP网关实际端口 server mysql1_gw 192.168.0.4:8080 server mysql2_gw 192.168.0.5:8080 server mysql3_gw 192.168.0.6:8080 backend write # 同样指向写节点的HTTP网关 server mysql1_gw 192.168.0.4:8080 frontend local bind *:80 acl write url_beg /write use_backend write if write default_backend read
注意:原生MySQL的3306端口不处理HTTP请求,直接转发会报错,必须确保后端是能处理HTTP请求的MySQL网关服务。
内容的提问来源于stack exchange,提问作者ORIK

