NGINX、HAProxy和Traefik负载均衡能力对比

网上有很多讨论Nginx和HAProxy的文章,很多文章基本都是说这样子的内容:

一、Nginx优点:
1、工作在网络7层之上,可针对http应用做一些分流的策略,如针对域名、目录结构,它的正规规则比HAProxy更为强大和灵活,所以,目前为止广泛流行。
2、Nginx对网络稳定性的依赖非常小,理论上能ping通就能进……

二、HAProxy优点:
1、HAProxy是支持虚拟主机的,可以工作在4、7层(支持多网段)
2、HAProxy的优点能够补充Nginx的一些缺点,比如支持Session的保持,Cookie的引导;同时支持通过获取指定的url来检测……

详细我就不全部贴了,大家也可以自己在google出来,很多一边倒都说HAProxy的负载均衡能力比Nginx的要强,但是这些文章,很大一部分没有一个真实的数据反映出HAProxy和Nginx哪一个能力更强,而且就算有,都是基于比较旧的版本去测试了。

这次我就亲自测试Nginx和HAProxy的负载均衡能力上的区别,等着,标题不是还有一个Traefik吗?嗯,在我搜索过程,我发现有外国的小伙也在讨论Traefik,Traefik是一个反向代理器,是一个比较年轻的项目,对容器支持十分友好,早就2017年,我就在项目使用过,不过仅是在反向代理这一块,在负载均衡上面没有太多深入研究,中文社区中,对他的测评并不多,但很多说法都是说这货的能力比较弱,事实真的如此吗?

故事背景

公司在一个项目上需要用到负载均衡,但在我工作这么多年上,我仅在测试环境上自己部署过Nginx的负载均衡,在生产环境上面,一直都是用云平台提供的负载均衡服务,所以目前为止,对负载均衡的能力掌握比较小,所以我透过这次的测试来了解目前市面常用的负载均衡器的对比。

测试要求

  1. 负载均衡使用的是7层模型(所以这里没有提到LVS的原因)
  2. 需要解析HTTPS,在负载均衡直接解析HTTPS,到达后面服务后直接用HTTP,避免后续服务重新解析,消耗性能

前期准备

本次用到服务器5台,配置均为4 CPUs,8G内存,40G存储空间,centOS 7.4 系统。

服务器1 IP:172.18.128.254

服务器2 IP:172.18.128.255

服务器3 IP:172.18.129.0

服务器4 IP:172.18.129.1

服务器5 IP:172.18.129.2

服务器1、2、3用作部署Web服务,服务器4用作部署负载均衡服务,服务器5用作Web客户端。

开始部署

首先部署服务器1、2、3的Web服务,Web服务是一个由go编写的服务,代码如下:

package main

import (
    "log"
    "fmt"
    "net/http"
    "runtime"
    "io/ioutil"
)

//Define the port used for this web application
var SERVER_PORT = ":8000"

//Read the content of a file
func serveContent(file string) string {
    b, err := ioutil.ReadFile(file)
    if err != nil {
        log.Print(err)
        return "{error:\"Resource not found\"}"
    }
    str := string(b)
    return str
}

//REST handler
func handler(w http.ResponseWriter, r *http.Request) {
    log.Print("Processing request: ", r.URL.Path[1:])
    str := serveContent(r.URL.Path[1:])
    fmt.Fprintf(w, str)
}

//Main program
func main() {
    runtime.GOMAXPROCS(runtime.NumCPU())
    log.Print("Starting webserver on Port", SERVER_PORT)
    http.HandleFunc("/", handler)
    http.ListenAndServe(SERVER_PORT, nil)
}

我再编写一个文件用于接下来请求用的:

# hello.txt
{output:"I Love Spring Cloud"}

部署服务器4的负载均衡服务,由于我比较懒,所有测试服务我都是用Docker来部署,至于HTTPS的证书,是通过Let's Encrypt去申请的,具体申请方法我再另一篇文章会有所提到。

首先,我们来编写各个服务用到的配置文件,

Nginx的配置文件:

# /opt/app/nginx/config/minsheng.conf 
upstream minsheng.ms {
      server 172.18.128.254:8000;
      server 172.18.129.0:8000;
      server 172.18.128.255:8000;
}

server{ 
    listen 80; 
    listen 443 ssl;
    server_name test.ruishanio.net;

    ssl_certificate /etc/nginx/ssl/test.ruishanio.net/fullchain.cer;
    ssl_certificate_key /etc/nginx/ssl/test.ruishanio.net/test.ruishanio.net.key;
    ssl_trusted_certificate /etc/nginx/ssl/test.ruishanio.net/ca.cer;

    location / { 
        proxy_pass         http://minsheng.ms; 
        proxy_set_header   Host             $host; 
        proxy_set_header   X-Real-IP        $remote_addr; 
        proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for; 
    } 
}

HAProxy的配置文件:

# /opt/app/haproxy/conf/haproxy.cfg
frontend https_frontend
  bind *:443 ssl crt /etc/ssl/test.ruishanio.net/test.ruishanio.net.pem
  mode http
  option httpclose
  option forwardfor
  reqadd X-Forwarded-Proto:\ https
  default_backend web_server

backend web_server
  mode http
  balance roundrobin
  server s1 172.18.128.254:8000 inter 2000 fall 3
  server s2 172.18.129.0:8000 inter 2000 fall 3
  server s3 172.18.128.255:8000 inter 2000 fall 3

Traefik的配置文件:

# /opt/app/traefik/conf/traefik.toml
[entryPoints]
  [entryPoints.http]
    address = ":80"
  [entryPoints.https]
    address = ":443"
    [entryPoints.https.tls]
      [[entryPoints.https.tls.certificates]]
      certFile = "/etc/ssl/test.ruishanio.net/fullchain.cer"
      keyFile = "/etc/ssl/test.ruishanio.net/test.ruishanio.net.key"

[file]

[backends]
  [backends.backend1]
    [backends.backend1.servers]
      [backends.backend1.servers.server0]
        url = "http://172.18.128.254:8000"
        weight = 1
      [backends.backend1.servers.server1]
        url = "http://172.18.129.0:8000"
        weight = 1
      [backends.backend1.servers.server2]
        url = "http://172.18.128.255:8000"
        weight = 1

[frontends]
  [frontends.frontend1]
    entryPoints = ["http", "https"]
    backend = "backend1"
    passHostHeader = true


[[tls]]
  entryPoints = ["https"]
  [tls.certificate]
    certFile = "/etc/ssl/test.ruishanio.net/fullchain.cer"
    keyFile = "/etc/ssl/test.ruishanio.net/test.ruishanio.net.key"

部署命令分别是:

# Nginx
docker run -d --net=host -v /opt/app/nginx/config/:/etc/nginx/conf.d/ -v /opt/app/ssl:/etc/nginx/ssl --name nginx nginx

# HAProxy
docker run -d --net=host -v /opt/app/haproxy/conf/:/usr/local/etc/haproxy -v /opt/app/ssl:/etc/ssl --name=haproxy haproxy

# Traefik
docker run -d --net=host -v /opt/app/traefik/conf/:/etc/traefik -v /opt/app/ssl/:/etc/ssl --name=traefik traefik

最后,我们部署测试机的环境,我们选用 wrk 作为测试工具,CentOS安装wrk参考这里:Installing wrk on Linux

进行测试

现在我们开始进行测试,首先我们分别裸跑三个服务的性能会到哪里。

$ wrk  -t 10 -c 200 -d 60s -T 30s --latency http://172.18.128.254:8000/hello.txt
Running 1m test @ http://172.18.128.254:8000/hello.txt
  10 threads and 200 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     3.47ms    3.26ms  48.20ms   76.78%
    Req/Sec     6.75k   445.49    21.86k    86.84%
  Latency Distribution
     50%    3.44ms
     75%    5.26ms
     90%    7.68ms
     99%   13.68ms
  4030219 requests in 1.00m, 568.84MB read
Requests/sec:  67058.69
Transfer/sec:      9.46MB

$ wrk  -t 10 -c 200 -d 60s -T 30s --latency http://172.18.128.255:8000/hello.txt
Running 1m test @ http://172.18.128.255:8000/hello.txt
  10 threads and 200 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    15.04ms   80.06ms   1.06s    97.78%
    Req/Sec     5.39k   532.13    12.06k    93.46%
  Latency Distribution
     50%    4.38ms
     75%    7.02ms
     90%   11.02ms
     99%  492.93ms
  3139915 requests in 1.00m, 443.18MB read
Requests/sec:  52309.88
Transfer/sec:      7.38MB

$ wrk  -t 10 -c 200 -d 60s -T 30s --latency http://172.18.129.0:8000/hello.txt
Running 1m test @ http://172.18.129.0:8000/hello.txt
  10 threads and 200 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     3.51ms    3.35ms  42.92ms   80.40%
    Req/Sec     6.75k   800.56    64.34k    99.15%
  Latency Distribution
     50%    3.46ms
     75%    5.33ms
     90%    7.84ms
     99%   14.01ms
  4027949 requests in 1.00m, 568.52MB read
Requests/sec:  67021.06
Transfer/sec:      9.46MB

除了 172.18.128.255 这台机弱一点外,其余两台机的性能都能达到67000请求/秒的能力。

接下来我们首先测试Nginx的负载均衡的能力。

$ wrk  -t 10 -c 200 -d 60s -T 30s --latency https://test.ruishanio.net/hello.txt
Running 1m test @ https://test.ruishanio.net/hello.txt
  10 threads and 200 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    18.26ms    1.71ms  44.14ms   71.24%
    Req/Sec     1.09k   108.54     1.84k    80.41%
  Latency Distribution
     50%   18.14ms
     75%   19.37ms
     90%   20.49ms
     99%   22.33ms
  647237 requests in 1.00m, 119.72MB read
Requests/sec:  10782.14
Transfer/sec:      1.99MB

可以看到,Nginx最终能够去到10000请求/秒的能力。

然后,我们测试HAProxy的负载均衡能力。

$ wrk  -t 10 -c 200 -d 60s -T 30s --latency https://test.ruishanio.net/hello.txt
Running 1m test @ https://test.ruishanio.net/hello.txt
  10 threads and 200 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    39.50ms    3.21ms 106.74ms   71.21%
    Req/Sec   415.63     42.95     1.43k    79.00%
  Latency Distribution
     50%   39.43ms
     75%   41.54ms
     90%   43.43ms
     99%   46.43ms
  247707 requests in 1.00m, 39.45MB read
Requests/sec:   4122.57
Transfer/sec:    672.33KB

测试结果表明,HAProxy的测试只达到了4100请求/秒的能力。

最后,我们来进行测试Traefik的负载均衡能力。

$ wrk  -t 10 -c 200 -d 60s -T 30s --latency https://test.ruishanio.net/hello.txt
Running 1m test @ https://test.ruishanio.net/hello.txt
  10 threads and 200 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     9.24ms    4.16ms 192.86ms   73.97%
    Req/Sec     2.18k   280.31    19.41k    94.82%
  Latency Distribution
     50%    9.57ms
     75%   10.81ms
     90%   14.70ms
     99%   18.67ms
  1300778 requests in 1.00m, 183.60MB read
Requests/sec:  21644.33
Transfer/sec:      3.05MB

很难想象,这货居然达到了21000请求/秒的能力。

最后,贴一下这几个负载均衡在测试过程中的CPU占用率。

第一个峰值是Nginx 32%左右,第二个峰值是HAProxy 20%左右,最后一个是Traefik 76%左右,三个服务都没有把整台机的CPU利用完。

从利用率来看,Nginx 每1%的CPU占用率 312请求,HAProxy为 每1%请求占用率 205 请求,Traefik 每1%的CPU占用率 276 请求。从CPU利用率来看,Nginx的利用率最高。

总结

这是一个开放题,最后我选择了哪一个服务,我不在此处阐述。但我对这次的测试总结一下。

关于HAProxy,互联网对它的负载均衡能力评价是最高的,但测试结果表明,它的负载均衡能力表现最差,也不知道是我测试方法有问题还有配置不合理造成,但我修改了几次配置再测试,结果也不会相差太远。

而Nginx,请求结果上它不是最高,但是在CPU利用比上面,它占了最大优势。

最后是Traefik,这个后起之秀简直刮目相看,它尽可能地压榨了整体CPU的性能,CPU的利用率它是最高的,请求数也到达了Nginx的两倍,HAProxy的5倍,唯一遗憾的是CPU利用比上,它不如Nginx。

大家如何选择负载均衡的话,可以参考我这篇文章,有疑问,有问题,也可以留言讨论。

编辑于 2018-08-06