HAProxy 无缘无故返回错误请求(无效主机)

HAProxy 无缘无故返回错误请求(无效主机)

我一直在尝试测试如下设置:

网站: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部分,并简化配置,直到收到响应。还可以考虑单独使用一台服务器或添加另一台服务器。一些示例-backendhostpath_begforwardforroundrobin

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_begfrontend配置中使用-

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

相关内容