优化 HAProxy SSL 终止(使用 Ubuntu 上的 Nginx 后端)

优化 HAProxy SSL 终止(使用 Ubuntu 上的 Nginx 后端)

如何使用 SSL 终止功能优化 HAProxy 到 Ubuntu 上的 Nginx 后端?

设置工作正常,路由正确。但是,当我使用 HAProxy 执行 SSL 终止时,性能会受到很大影响(下面的测试)。密钥是 4096 位 rsa。HAProxy 强制使用 HTTPS 进行验证,然后终止 SSL,并将 HTTP 传达给后端 Nginx 服务器。Nginx 服务器相同,并提供多个静态页面,即 192.168.1.xx/page1.html、192.168.1.xx/page2.html 等。(我包含了 NodeJS 以保证系统的完整性,但只增加了不到 1ms 的延迟。NodeJS 可以忽略。)

以下是设置、配置和当前测试。每个虚拟机 (VM) 都运行 Ubuntu 14.04,并且可以拥有可变数量的 CPU 和 RAM。

  • HAProxy(1.5.14):192.168.1.10
  • Nginx-1:192.168.1.20
  • Nginx-2:192.168.1.21
  • Nginx-3:192.168.1.22
  • NodeJS-1:192.168.1.30

这是 HAProxy 配置:

    global
            maxconn 40000
            tune.ssl.default-dh-param 2048
            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

            # 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). This list is from:
            #  https://hynek.me/articles/harding-your-web-servers-ssl-ciphers/
            ssl-default-bind-ciphers ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+3DES:!aNULL:!MD5:!DSS
            ssl-default-bind-options no-sslv3


    defaults
            option forwardfor
            option http-server-close
            stats enable
            stats uri /stats
            stats realm Haproxy\ Statistics
            stats auth user:password
            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


    frontend www-http
            bind 192.168.1.10:80
            reqadd X-Forwarded-Proto:\ http
            default_backend www-backend

    frontend www-https
            bind 192.168.1.10:443 ssl crt /etc/ssl/private/company.pem
            reqadd X-Forwarded-Proto:\ https
            use_backend node-backend if { path_beg /socket.io }
            default_backend www-backend

    backend www-backend
            redirect scheme https if !{ ssl_fc }
            server www-1 192.168.1.20:80 check
            server www-2 192.168.1.21:80 check
            server www-3 192.168.1.22:80 check

    backend node-backend
            server node-1 192.168.1.30:8888 check

以下是对其中一台 Nginx 服务器进行的 ApacheBench (ab) 测试:

    $ ab -c 200 -n 10000 http://192.168.1.20/

    Server Software:        nginx/1.4.6
    Server Hostname:        192.168.1.20
    Server Port:            80

    Document Path:          /
    Document Length:        3130 bytes

    Concurrency Level:      200
    Time taken for tests:   2.257 seconds
    Complete requests:      10000
    Failed requests:        0
    Total transferred:      33720000 bytes
    HTML transferred:       31300000 bytes
    Requests per second:    4430.21 [#/sec] (mean)
    Time per request:       45.145 [ms] (mean)
    Time per request:       0.226 [ms] (mean, across all concurrent requests)
    Transfer rate:          14588.55 [Kbytes/sec] received

    Connection Times (ms)
                  min  mean[+/-sd] median   max
    Connect:        4   27 104.3     16    1187
    Processing:     4   18   8.2     16     358
    Waiting:        3   18   7.9     16     334
    Total:          9   45 105.8     32    1225

    Percentage of the requests served within a certain time (ms)
      50%     32
      66%     41
      75%     43
      80%     44
      90%     49
      95%     52
      98%     55
      99%     57
     100%   1225 (longest request)

以下是使用 http 对 HAProxy 进行的 ApacheBench (ab) 测试:

    $ ab -c 200 -n 10000 http://192.168.1.10/

    Server Software:        nginx/1.4.6
    Server Hostname:        192.168.1.10
    Server Port:            80

    Document Path:          /
    Document Length:        3130 bytes

    Concurrency Level:      200
    Time taken for tests:   1.918 seconds
    Complete requests:      10000
    Failed requests:        0
    Total transferred:      33720000 bytes
    HTML transferred:       31300000 bytes
    Requests per second:    5215.09 [#/sec] (mean)
    Time per request:       38.350 [ms] (mean)
    Time per request:       0.192 [ms] (mean, across all concurrent requests)
    Transfer rate:          17173.14 [Kbytes/sec] received

    Connection Times (ms)
                  min  mean[+/-sd] median   max
    Connect:        3   18   3.5     18      32
    Processing:     7   20   3.5     19      36
    Waiting:        7   20   3.4     19      36
    Total:         15   38   4.2     37      57

    Percentage of the requests served within a certain time (ms)
      50%     37
      66%     38
      75%     39
      80%     40
      90%     44
      95%     46
      98%     50
      99%     51
     100%     57 (longest request)

以下是使用 https 对 HAProxy 进行的 ApacheBench (ab) 测试:

    $ ab -c 200 -n 10000 https://192.168.1.10/

    Server Software:        nginx/1.4.6
    Server Hostname:        192.168.1.10
    Server Port:            443
    SSL/TLS Protocol:       TLSv1,DHE-RSA-AES256-SHA,2048,256

    Document Path:          /
    Document Length:        3130 bytes

    Concurrency Level:      200
    Time taken for tests:   566.303 seconds
    Complete requests:      10000
    Failed requests:        0
    Total transferred:      33720000 bytes
    HTML transferred:       31300000 bytes
    Requests per second:    17.66 [#/sec] (mean)
    Time per request:       11326.069 [ms] (mean)
    Time per request:       56.630 [ms] (mean, across all concurrent requests)
    Transfer rate:          58.15 [Kbytes/sec] received

    Connection Times (ms)
                  min  mean[+/-sd] median   max
    Connect:      483 8982 3326.6  11090   14031
    Processing:    16 2255 3313.0     43   11399
    Waiting:       14 2186 3253.3     35   11252
    Total:       5648 11237 879.1  11212   22732

    Percentage of the requests served within a certain time (ms)
      50%  11212
      66%  11274
      75%  11308
      80%  11321
      90%  11395
      95%  11641
      98%  11847
      99%  14063
     100%  22732 (longest request)

这是在 HAProxy VM 上进行的 OpenSSL 测试。

    $ openssl speed rsa

                      sign    verify    sign/s verify/s
    rsa  512 bits 0.000081s 0.000006s  12314.6 179042.8
    rsa 1024 bits 0.000277s 0.000017s   3603.7  60563.8
    rsa 2048 bits 0.001852s 0.000058s    539.8  17231.3
    rsa 4096 bits 0.013793s 0.000221s     72.5   4517.4

因此,我认为 HAProxy 无法超越 openssl 速度测试的 72.5 sign/s、4517.4 verify/s。但是,带有 SSL 终止的 HAProxy 执行速度约为 17 request/s。当然,我们可以获得较小的密钥来提高整体性能,但这并不能解决从 openssl 速度测试到 HAProxy 的速度提高约 4.5 倍的问题(如果存在问题的话)。

那么,根据这些信息,是否存在可以提高性能的最佳 HAProxy 配置?我是否遗漏了某些内容,例如:当用户第一次访问某个页面时,他们只需“签名”一次,并且对该页面的所有并发请求都只需“验证”。如果是这样,那么 AB 测试就无法适当地衡量这一点(如果我错了,请纠正我)。并且,要实现这一点,用户是否必须访问同一个 Nginx 服务器?如果是这样,是否需要保持会话?

为了回答我自己的问题,我尝试从这篇文章中添加粘性会话:带有 SSL 和粘性会话的 HAProxy并使用 Siege 对多个 URL 进行了测试。然而,性能仍然没有提升。

    $ siege -c 100 -r 10 -b -f urls.txt

    Transactions:               1000 hits
    Availability:             100.00 %
    Elapsed time:              22.56 secs
    Data transferred:           2.84 MB
    Response time:              2.17 secs
    Transaction rate:          44.33 trans/sec
    Throughput:             0.13 MB/sec
    Concurrency:               96.06
    Successful transactions:        1000
    Failed transactions:               0
    Longest transaction:            8.96
    Shortest transaction:           0.16

urls.txt 的位置

    URL=https://192.168.1.10/
    $(URL)
    $(URL)page1.html
    $(URL)page2.html

那么,我只能接受这种性能吗?有些地方提到,4096 位密钥的请求率也类似,约为 75 毫秒/请求。 https://certsimple.com/blog/measuring-ssl-rsa-keys

或者,我的 HAProxy 配置不当,在某处处理 SSL 2x?ServerFault:/questions/574582/nginx-ssl-termination-slow

答案1

需要考虑的一点是,许多 HTTP 客户端(包括浏览器)都试图将 SSL 握手的成本分摊到多个 HTTP 请求中。也就是说,它们与服务器建立一个 TCP 连接,执行 SSL 握手,然后将该 TCP 连接(及其 SSL 会话)重新用于多个请求/响应,而不是每个请求都执行一次 SSL 握手。

为了在您的设置中启用这种场景/测试,您可以在-k命令行中包含 选项ab,以便前端HTTP 请求。

另一个考虑因素是您对option http-server-closeHAproxy 设置的使用。这会告诉haproxy您针对每个前端 HTTP 请求建立一个新的后端 TCP 连接;这可能会增加 40-100 毫秒(甚至更多),具体取决于后端网络。如果您允许 HAproxy 保持这些后端 TCP 连接打开,那么这也可能会减少 报告的每个请求延迟ab

根据您预期的 SSL 会话数量,增加 SSL 会话缓存的内存分配(HAproxy 的tune.ssl.cachesize设置,可能与增加缓存超时结合tune.ssl.lifetime,从而增加会话缓存重用的可能性)也可能会允许更多恢复的 SSL 会话(以及更快/计算强度更低的 SSL 握手)。

ab但是我认为,当使用 keep-alive( )时,报告的数字-k将更好地证明对许多 HTTP 请求重新使用相同的 SSL 会话(通过相同的 TCP 连接)的有效性。

希望这可以帮助!

答案2

进行苹果与苹果之间的比较。

您的基准测试openssl speed rsa可能不会测量 DHE 时间,因为它不使用临时密钥。这意味着您测试的是安全性较低的算法与 DHE 算法。后者速度较慢,但​​另一方面它提供了完美的前向保密性 (PFS)。

但是 DHE 相当古老且效率低下,现代浏览器通常使用更好的 ECDHE(甚至是 ECDSA)。

我认为您应该设置 ab 基准以强制执行 ECDHE-RSA-AES128-SHA256。我认为您应该对 openssl 基准进行编程以使用循环openssl s_client -cipher ECDHE-RSA-AES128-SHA256(而不是简单的openssl speed)。

相关内容