我一直在尝试测试如下设置:
网站:Http GET 请求 -> Nginx -> HAProxy -> .Net 应用程序
我将 Nginx 和 HAProxy 放在了同一台 Debian 机器上。但是,HAProxy 不断返回“错误请求(无效主机)”。我首先将请求直接从网站发送到 .Net 应用程序,然后确定 HAProxy 有问题,这种方法有效。将 Nginx 链接到 .Net 应用程序也有效。但是,当我尝试使用 HAProxy 进行测试时,我开始收到错误。无论 .Net 应用程序是否实际在 HAProxy 后面运行,我总是收到错误。
我尝试发送的消息的一个示例是http://192.168.7.119:81/a:diff1
。预期的回复是 JPG 图像。当发送到 HAProxy 以外的任何设备(Apache、Nginx、应用程序)时,这似乎工作正常,但 HAProxy 只是说“错误请求”。奇怪的是,我没有在日志文件中看到任何错误。
以下是日志文件中的一个示例:
Feb 2 15:10:08 companyDebian haproxy[5566]: 192.168.7.114:51105 [02/Feb/2015:15:10:08.415] renderfarm renderfarm/renderA 0/0/0/1/1 400 212 - - ---- 1/1/0/1/0 0/0 "GET /a:diff1 HTTP/1.1"
Feb 2 15:10:08 companyDebian haproxy[5566]: 192.168.7.114:51105 [02/Feb/2015:15:10:08.417] renderfarm renderfarm/renderA 73/0/0/4/77 400 212 - - ---- 1/1/0/1/0 0/0 "GET /favicon.ico HTTP/1.1"
我的配置文件如下所示:
global
log /dev/log local0
log /dev/log local1 notice
chroot /var/lib/haproxy
stats socket /run/haproxy/admin.sock mode 660 level admin
stats timeout 30s
user haproxy
group haproxy
daemon
# Default SSL material locations
ca-base /etc/ssl/certs
crt-base /etc/ssl/private
# Default ciphers to use on SSL-enabled listening sockets.
# For more information, see ciphers(1SSL).
ssl-default-bind-ciphers kEECDH+aRSA+AES:kRSA+AES:+AES256:RC4-SHA:!kEDH:!LOW:!EXP:!MD5:!aNULL:!eNULL
ssl-default-bind-options no-sslv3
defaults
log global
mode http
option httplog
option dontlognull
timeout connect 5000
timeout client 50000
timeout server 50000
errorfile 400 /etc/haproxy/errors/400.http
errorfile 403 /etc/haproxy/errors/403.http
errorfile 408 /etc/haproxy/errors/408.http
errorfile 500 /etc/haproxy/errors/500.http
errorfile 502 /etc/haproxy/errors/502.http
errorfile 503 /etc/haproxy/errors/503.http
errorfile 504 /etc/haproxy/errors/504.http
listen renderfarm
bind 192.168.7.119:81
mode http
balance roundrobin
server renderA 192.168.7.114:40000 maxconn 1
我之前没有使用过 HAProxy,只是因为有人向我推荐了它才使用它。因此,我不知道我还能采取什么其他步骤来解决这个问题。配置手册提到了您可以设置的各种选项,例如 tune.bufsize 和选项 accept-invalid-http-request,但这些选项不起作用。
笔记:一旦此设置成功,我们的想法是添加更多运行该应用程序的服务器。每个服务器实际上一次只能处理 1 个请求。
答案1
我遇到了同样的问题并花了一段时间才弄清楚为什么会发生这种情况。
我的环境由 1 个 HAproxy 和 2 个 nginx 作为后端以及 nodejs 作为类 CGI 组成。
根本原因在于 HAproxy 如何构建 HTTP 请求。默认情况下,HAproxy 不会在请求中包含主机标头,因此您需要手动添加,否则 nginx 将默认返回 400,HAproxy 会将其标记为不健康。
以下示例:
HAproxy 健康检查配置:
option httpchk HEAD / HTTP/1.1
等效 HTTP 请求:
tony@calderona:~ $ telnet A.B.C.D 80 Trying A.B.C.D... Connected to A.B.C.D. Escape character is '^]'. HEAD / HTTP/1.1 HTTP/1.1 400 Bad Request Server: nginx/1.10.3 Date: Sun, 10 Dec 2017 09:52:12 GMT Content-Type: text/html Content-Length: 173 Connection: close
HAproxy 健康检查配置:
option httpchk HEAD / HTTP/1.1\r\nHost:\ www.temporaryworkaround.org
等效 HTTP 请求:
tony@calderona:~ $ telnet A.B.C.D 80 Trying A.B.C.D... Connected to A.B.C.D. Escape character is '^]'. HEAD / HTTP/1.1 host: www.temporaryworkaround.org HTTP/1.1 200 OK Server: nginx/1.10.3 Date: Sun, 10 Dec 2017 09:52:24 GMT Content-Type: text/html; charset=utf-8 Content-Length: 10282 Connection: keep-alive
干杯
答案2
如果您想查看 HAproxy 遇到的确切错误,可以使用socat
连接到管理套接字。socat
通过安装apt-get install socat
,然后运行以下命令:
echo "show errors" | socat unix-connect:/run/haproxy/admin.sock stdio
如果您在收到“错误请求”错误后立即运行此程序,它将准确地显示 HAproxy 对客户端发出的 HTTP 请求不喜欢的内容。
笔记:上述操作仅在您启用 时才有效
Unix Socket commands
。您必须在部分HAProxy
下添加一行配置才能启用此功能。global
global stats socket /var/run/haproxy.sock mode 600 level admin
答案3
将 HAProxy 置于 Nginx 之后似乎是轻率的,因为 Nginx 或 HAProxy 都可以单独提供您似乎需要的功能。
考虑将 listen 部分拆分为带有或acls 的frontend
部分,并简化配置,直到收到响应。还可以考虑单独使用一台服务器或添加另一台服务器。一些示例-backend
host
path_beg
forwardfor
roundrobin
frontend http-in
bind 0.0.0.0:80
acl host_1 hdr(host) -i firstsite.com
acl host_nginx hdr(host) -i secondsite.com
前端和后端配对
use_backend firstsite_redirect if host_1
use_backend nginx if host_nginx
后端配置-
backend firstsite_redirect
mode http
option forwardfor
server firstserver 192.168.0.2:8080
backend nginx
mode http
balance roundrobin
option httpclose
option forwardfor
cookie SRVNAME insert
server nginx01 192.168.0.3:8080 cookie s1 check
server nginx02 192.168.0.4:8080 cookie s2 check
如果要根据 URL 重定向,请考虑path_beg
在frontend
配置中使用-
frontend http-in 0.0.0.0:80
acl docs path_beg /docs
acl phpmyadmin path_beg /phpmyadmin
答案4
尝试将 HAProxy 配置从 HTTP 改为 TCP 或许是值得的。您会失去 HTTP 提供的一些高级负载平衡选项(设置 cookie 以进行持久化等),但无论如何您现在似乎没有使用它们。
下面是我使用 HAProxy 实现 MySQL 负载平衡的示例配置:
listen mysql-failover
bind 10.10.10.210:3306
mode tcp
option tcplog
option mysql-check user haproxy
server db1 10.10.10.13:3306 check fall 2 inter 1000
server backup 10.10.10.11:3306 check
请注意,如果您更改为 TCP,您将无法访问内置的 HTTP 统计信息页面,您可以在单独的 listen 语句中定义该页面。例如:
listen stats
bind 10.10.10.200:80
mode http
stats enable
stats hide-version
stats uri /
option httpclose
stats auth username:password