阿里云-云小站(无限量代金券发放中)
【腾讯云】云服务器、云数据库、COS、CDN、短信等热卖云产品特惠抢购

使用 Go 对 Nginx 进行性能测试

428次阅读
没有评论

共计 8068 个字符,预计需要花费 21 分钟才能阅读完成。

目前有很多提供 Go 语言 HTTP 应用服务的方法,但其中最好的选择取决于每个应用的实际情况。目前,Nginx 看起来是每个新项目的标准 Web 服务器,即使在有其他许多不错 Web 服务器的情况下。然而,在 Nginx 上提供 Go 应用服务的开销是多少呢?我们需要一些 nginx 的特性参数(vhosts,负载均衡,缓存,等等)或者直接使用 Go 提供服务?如果你需要 nginx,最快的连接机制是什么?这就是在这我试图回答的问题。 该基准测试的目的不是要验证 Go 比 nginx 的快或慢。那将会很愚蠢。

下面是我们要比较不同的设置:

  • Go HTTP standalone (as the control group)
  • Nginx proxy to Go HTTP
  • Nginx fastcgi to Go TCP FastCGI
  • Nginx fastcgi to Go Unix Socket FastCGI

硬件

因为我们将在相同的硬件下比较所有设置,硬件选择的是廉价的一个。这不应该是一个大问题。

  • Samsung 笔记本 NP550P5C-AD1BR
  • Intel Core i7 3630QM @2.4GHz (quad core, 8 threads)
  • CPU caches: (L1: 256KiB, L2: 1MiB, L3: 6MiB)
  • RAM 8GiB DDR3 1600MHz

软件

  • Ubuntu 13.10 amd64 Saucy Salamander (updated)
  • Nginx 1.4.4 (1.4.4-1~saucy0 amd64)
  • Go 1.2 (linux/amd64)
  • wrk 3.0.4

设置

内核

只需很小的一点调整,将内核的 limits 调高。如果你对这一变量有更好的想法,请在写在下面评论处:

fs.file-max                    9999999
fs.nr_open                    9999999
net.core.netdev_max_backlog    4096
net.core.rmem_max              16777216
net.core.somaxconn            65535
net.core.wmem_max              16777216
net.ipv4.ip_forward            0
net.ipv4.ip_local_port_range  1025      65535
net.ipv4.tcp_fin_timeout      30
net.ipv4.tcp_keepalive_time    30
net.ipv4.tcp_max_syn_backlog  20480
net.ipv4.tcp_max_tw_buckets    400000
net.ipv4.tcp_no_metrics_save  1
net.ipv4.tcp_syn_retries      2
net.ipv4.tcp_synack_retries    2
net.ipv4.tcp_tw_recycle        1
net.ipv4.tcp_tw_reuse          1
vm.min_free_kbytes            65536
vm.overcommit_memory          1

Limits

供 root 和 www-data 打开的最大文件数限制被配置为 200000。

Nginx

有几个必需得 Nginx 调整。有人跟我说过,我禁用了 gzip 以保证比较公平。下面是它的配置文件 /etc/nginx/nginx.conf:

user www-data;
worker_processes auto;
worker_rlimit_nofile 200000;
pid /var/run/nginx.pid;

events {
    worker_connections 10000;
    use epoll;
    multi_accept on;
}

http {
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    keepalive_timeout 300;
    keepalive_requests 10000;
    types_hash_max_size 2048;

    open_file_cache max=200000 inactive=300s;
    open_file_cache_valid 300s;
    open_file_cache_min_uses 2;
    open_file_cache_errors on;

    server_tokens off;
    dav_methods off;

    include /etc/nginx/mime.types;
    default_type application/octet-stream;

    access_log /var/log/nginx/access.log combined;
    error_log /var/log/nginx/error.log warn;

    gzip off;
    gzip_vary off;

    include /etc/nginx/conf.d/*.conf;
    include /etc/nginx/sites-enabled/*.conf;
}

Nginx vhosts

upstream go_http {
    server 127.0.0.1:8080;
    keepalive 300;
}

server {
    listen 80;
    server_name go.http;
    access_log off;
    error_log /dev/null crit;

    location / {
        proxy_pass http://go_http;
        proxy_http_version 1.1;
        proxy_set_header Connection “”;
    }
}

upstream go_fcgi_tcp {
    server 127.0.0.1:9001;
    keepalive 300;
}

server {
    listen 80;
    server_name go.fcgi.tcp;
    access_log off;
    error_log /dev/null crit;

    location / {
        include fastcgi_params;
        fastcgi_keep_conn on;
        fastcgi_pass go_fcgi_tcp;
    }
}

upstream go_fcgi_unix {
    server unix:/tmp/go.sock;
    keepalive 300;
}

server {
    listen 80;
    server_name go.fcgi.unix;
    access_log off;
    error_log /dev/null crit;

    location / {
        include fastcgi_params;
        fastcgi_keep_conn on;
        fastcgi_pass go_fcgi_unix;
    }
}

Go 源码

package main

import (
    “fmt”
    “log”
    “net”
    “net/http”
    “net/http/fcgi”
    “os”
    “os/signal”
    “syscall”
)

var (
    abort bool
)

const (
    SOCK = “/tmp/go.sock”
)

type Server struct {
}

func (s Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    body := “Hello World\n”
    // Try to keep the same amount of headers
    w.Header().Set(“Server”, “gophr”)
    w.Header().Set(“Connection”, “keep-alive”)
    w.Header().Set(“Content-Type”, “text/plain”)
    w.Header().Set(“Content-Length”, fmt.Sprint(len(body)))
    fmt.Fprint(w, body)
}

func main() {
    sigchan := make(chan os.Signal, 1)
    signal.Notify(sigchan, os.Interrupt)
    signal.Notify(sigchan, syscall.SIGTERM)

    server := Server{}

    go func() {
        http.Handle(“/”, server)
        if err := http.ListenAndServe(“:8080”, nil); err != nil {
            log.Fatal(err)
        }
    }()

    go func() {
        tcp, err := net.Listen(“tcp”, “:9001”)
        if err != nil {
            log.Fatal(err)
        }
        fcgi.Serve(tcp, server)
    }()

    go func() {
        unix, err := net.Listen(“unix”, SOCK)
        if err != nil {
            log.Fatal(err)
        }
        fcgi.Serve(unix, server)
    }()

    <-sigchan

    if err := os.Remove(SOCK); err != nil {
        log.Fatal(err)
    }
}

检查 HTTP header

为公平起见,所有的请求必需大小相同。

$ curl -sI http://127.0.0.1:8080/
HTTP/1.1 200 OK
Connection: keep-alive
Content-Length: 12
Content-Type: text/plain
Server: gophr
Date: Sun, 15 Dec 2013 14:59:14 GMT

$ curl -sI http://127.0.0.1:8080/ | wc -c
141

 

$ curl -sI http://go.http/
HTTP/1.1 200 OK
Server: nginx
Date: Sun, 15 Dec 2013 14:59:31 GMT
Content-Type: text/plain
Content-Length: 12
Connection: keep-alive

$ curl -sI http://go.http/ | wc -c
141

 

$ curl -sI http://go.fcgi.tcp/
HTTP/1.1 200 OK
Content-Type: text/plain
Content-Length: 12
Connection: keep-alive
Date: Sun, 15 Dec 2013 14:59:40 GMT
Server: gophr

$ curl -sI http://go.fcgi.tcp/ | wc -c
141

 

$ curl -sI http://go.fcgi.unix/
HTTP/1.1 200 OK
Content-Type: text/plain
Content-Length: 12
Connection: keep-alive
Date: Sun, 15 Dec 2013 15:00:15 GMT
Server: gophr

$ curl -sI http://go.fcgi.unix/ | wc -c
141

 

启动引擎

  • 使用 sysctl 配置内核
  • 配置 Nginx
  • 配置 Nginx vhosts
  • 用 www-data 启动服务
  • 运行基准测试

基准测试

GOMAXPROCS = 1

Go standalone

# wrk -t100 -c5000 -d30s http://127.0.0.1:8080/
Running 30s test @ http://127.0.0.1:8080/
  100 threads and 5000 connections
  Thread Stats  Avg      Stdev    Max  +/- Stdev
    Latency  116.96ms  17.76ms 173.96ms  85.31%
    Req/Sec  429.16    49.20  589.00    69.44%
  1281567 requests in 29.98s, 215.11MB read
Requests/sec:  42745.15
Transfer/sec:      7.17MB

Nginx + Go through HTTP

# wrk -t100 -c5000 -d30s http://go.http/
Running 30s test @ http://go.http/
  100 threads and 5000 connections
  Thread Stats  Avg      Stdev    Max  +/- Stdev
    Latency  124.57ms  18.26ms 209.70ms  80.17%
    Req/Sec  406.29    56.94    0.87k    89.41%
  1198450 requests in 29.97s, 201.16MB read
Requests/sec:  39991.57
Transfer/sec:      6.71MB

Nginx + Go through FastCGI TCP

# wrk -t100 -c5000 -d30s http://go.fcgi.tcp/
Running 30s test @ http://go.fcgi.tcp/
  100 threads and 5000 connections
  Thread Stats  Avg      Stdev    Max  +/- Stdev
    Latency  514.57ms  119.80ms  1.21s    71.85%
    Req/Sec    97.18    22.56  263.00    79.59%
  287416 requests in 30.00s, 48.24MB read
  Socket errors: connect 0, read 0, write 0, timeout 661
Requests/sec:  9580.75
Transfer/sec:      1.61MB

Nginx + Go through FastCGI Unix Socket

# wrk -t100 -c5000 -d30s http://go.fcgi.unix/
Running 30s test @ http://go.fcgi.unix/
  100 threads and 5000 connections
  Thread Stats  Avg      Stdev    Max  +/- Stdev
    Latency  425.64ms  80.53ms 925.03ms  76.88%
    Req/Sec  117.03    22.13  255.00    81.30%
  350162 requests in 30.00s, 58.77MB read
  Socket errors: connect 0, read 0, write 0, timeout 210
Requests/sec:  11670.72
Transfer/sec:      1.96MB

GOMAXPROCS = 8

Go standalone

# wrk -t100 -c5000 -d30s http://127.0.0.1:8080/
Running 30s test @ http://127.0.0.1:8080/
  100 threads and 5000 connections
  Thread Stats  Avg      Stdev    Max  +/- Stdev
    Latency    39.25ms    8.49ms  86.45ms  81.39%
    Req/Sec    1.29k  129.27    1.79k    69.23%
  3837995 requests in 29.89s, 644.19MB read
Requests/sec: 128402.88
Transfer/sec:    21.55MB

Nginx + Go through HTTP

# wrk -t100 -c5000 -d30s http://go.http/
Running 30s test @ http://go.http/
  100 threads and 5000 connections
  Thread Stats  Avg      Stdev    Max  +/- Stdev
    Latency  336.77ms  297.88ms 632.52ms  60.16%
    Req/Sec    2.36k    2.99k  19.11k    84.83%
  2232068 requests in 29.98s, 374.64MB read
Requests/sec:  74442.91
Transfer/sec:    12.49MB

Nginx + Go through FastCGI TCP

# wrk -t100 -c5000 -d30s http://go.fcgi.tcp/
Running 30s test @ http://go.fcgi.tcp/
  100 threads and 5000 connections
  Thread Stats  Avg      Stdev    Max  +/- Stdev
    Latency  217.69ms  121.22ms  1.80s    75.14%
    Req/Sec  263.09    102.78  629.00    62.54%
  721027 requests in 30.01s, 121.02MB read
  Socket errors: connect 0, read 0, write 176, timeout 1343
Requests/sec:  24026.50
Transfer/sec:      4.03MB

Nginx + Go through FastCGI Unix Socket

# wrk -t100 -c5000 -d30s http://go.fcgi.unix/
Running 30s test @ http://go.fcgi.unix/
  100 threads and 5000 connections
  Thread Stats  Avg      Stdev    Max  +/- Stdev
    Latency  694.32ms  332.27ms  1.79s    62.13%
    Req/Sec  646.86    669.65    6.11k    87.80%
  909836 requests in 30.00s, 152.71MB read
Requests/sec:  30324.77
Transfer/sec:      5.09MB

结论

第一组基准测试时一些 Nginx 的设置还没有很好的优化(启用 gzip,Go 的后端没有使用 keep-alive 连接)。当改为 wrk 以及按建议优化 Nginx 后结果有较大差异。

当 GOMAXPROCS= 1 时,Nginx 的开销不是那么大,但当 OMAXPROCS= 8 时差异就很大了。以后可能会再试一下其他设置。如果你需要使用 Nginx 像虚拟主机,负载均衡,缓存等特性,使用 HTTP proxy,别使用 FastCGI。有些人说 Go 的 FastCGI 还没有被很好优化,这也许就是测试结果中巨大差异的原因。

推荐阅读

 

Nginx 实现反向代理和负载均衡的配置及优化 http://www.linuxidc.com/Linux/2013-11/92909.htm

 

Nginx 做负载均衡报:nginx: [emerg] could not build the types_hash http://www.linuxidc.com/Linux/2013-10/92063.htm

 

Nginx 负载均衡模块 ngx_http_upstream_module 详述 http://www.linuxidc.com/Linux/2013-10/91907.htm

 

Nginx+Firebug 让浏览器告诉你负载均衡将请求分到了哪台服务器 http://www.linuxidc.com/Linux/2013-10/91824.htm

 

Ubuntu 安装 Nginx php5-fpm MySQL(LNMP 环境搭建) http://www.linuxidc.com/Linux/2012-10/72458.htm

 

Nginx 的详细介绍 :请点这里
Nginx 的下载地址 :请点这里

正文完
星哥玩云-微信公众号
post-qrcode
 0
星锅
版权声明:本站原创文章,由 星锅 于2022-01-20发表,共计8068字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
【腾讯云】推广者专属福利,新客户无门槛领取总价值高达2860元代金券,每种代金券限量500张,先到先得。
阿里云-最新活动爆款每日限量供应
评论(没有评论)
验证码
【腾讯云】云服务器、云数据库、COS、CDN、短信等云产品特惠热卖中

星哥玩云

星哥玩云
星哥玩云
分享互联网知识
用户数
4
文章数
19351
评论数
4
阅读量
7994014
文章搜索
热门文章
星哥带你玩飞牛NAS-6:抖音视频同步工具,视频下载自动下载保存

星哥带你玩飞牛NAS-6:抖音视频同步工具,视频下载自动下载保存

星哥带你玩飞牛 NAS-6:抖音视频同步工具,视频下载自动下载保存 前言 各位玩 NAS 的朋友好,我是星哥!...
星哥带你玩飞牛NAS-3:安装飞牛NAS后的很有必要的操作

星哥带你玩飞牛NAS-3:安装飞牛NAS后的很有必要的操作

星哥带你玩飞牛 NAS-3:安装飞牛 NAS 后的很有必要的操作 前言 如果你已经有了飞牛 NAS 系统,之前...
我把用了20年的360安全卫士卸载了

我把用了20年的360安全卫士卸载了

我把用了 20 年的 360 安全卫士卸载了 是的,正如标题你看到的。 原因 偷摸安装自家的软件 莫名其妙安装...
再见zabbix!轻量级自建服务器监控神器在Linux 的完整部署指南

再见zabbix!轻量级自建服务器监控神器在Linux 的完整部署指南

再见 zabbix!轻量级自建服务器监控神器在 Linux 的完整部署指南 在日常运维中,服务器监控是绕不开的...
飞牛NAS中安装Navidrome音乐文件中文标签乱码问题解决、安装FntermX终端

飞牛NAS中安装Navidrome音乐文件中文标签乱码问题解决、安装FntermX终端

飞牛 NAS 中安装 Navidrome 音乐文件中文标签乱码问题解决、安装 FntermX 终端 问题背景 ...
阿里云CDN
阿里云CDN-提高用户访问的响应速度和成功率
随机文章
星哥带你玩飞牛NAS硬件 01:捡垃圾的最爱双盘,暴风二期矿渣为何成不老神话?

星哥带你玩飞牛NAS硬件 01:捡垃圾的最爱双盘,暴风二期矿渣为何成不老神话?

星哥带你玩飞牛 NAS 硬件 01:捡垃圾的最爱双盘,暴风二期矿渣为何成不老神话? 前言 在选择 NAS 用预...
支付宝、淘宝、闲鱼又双叕崩了,Cloudflare也瘫了连监控都挂,根因藏在哪?

支付宝、淘宝、闲鱼又双叕崩了,Cloudflare也瘫了连监控都挂,根因藏在哪?

支付宝、淘宝、闲鱼又双叕崩了,Cloudflare 也瘫了连监控都挂,根因藏在哪? 最近两天的互联网堪称“故障...
手把手教你,购买云服务器并且安装宝塔面板

手把手教你,购买云服务器并且安装宝塔面板

手把手教你,购买云服务器并且安装宝塔面板 前言 大家好,我是星哥。星哥发现很多新手刚接触服务器时,都会被“选购...
每年0.99刀,拿下你的第一个顶级域名,详细注册使用

每年0.99刀,拿下你的第一个顶级域名,详细注册使用

每年 0.99 刀,拿下你的第一个顶级域名,详细注册使用 前言 作为长期折腾云服务、域名建站的老玩家,星哥一直...
我用AI做了一个1978年至2019年中国大陆企业注册的查询网站

我用AI做了一个1978年至2019年中国大陆企业注册的查询网站

我用 AI 做了一个 1978 年至 2019 年中国大陆企业注册的查询网站 最近星哥在 GitHub 上偶然...

免费图片视频管理工具让灵感库告别混乱

一言一句话
-「
手气不错
还在找免费服务器?无广告免费主机,新手也能轻松上手!

还在找免费服务器?无广告免费主机,新手也能轻松上手!

还在找免费服务器?无广告免费主机,新手也能轻松上手! 前言 对于个人开发者、建站新手或是想搭建测试站点的从业者...
安装Black群晖DSM7.2系统安装教程(在Vmware虚拟机中、实体机均可)!

安装Black群晖DSM7.2系统安装教程(在Vmware虚拟机中、实体机均可)!

安装 Black 群晖 DSM7.2 系统安装教程(在 Vmware 虚拟机中、实体机均可)! 前言 大家好,...
星哥带你玩飞牛NAS-11:咪咕视频订阅部署全攻略

星哥带你玩飞牛NAS-11:咪咕视频订阅部署全攻略

星哥带你玩飞牛 NAS-11:咪咕视频订阅部署全攻略 前言 在家庭影音系统里,NAS 不仅是存储中心,更是内容...
150元打造低成本NAS小钢炮,捡一块3865U工控板

150元打造低成本NAS小钢炮,捡一块3865U工控板

150 元打造低成本 NAS 小钢炮,捡一块 3865U 工控板 一块二手的熊猫 B3 工控板 3865U,搭...
手把手教你,购买云服务器并且安装宝塔面板

手把手教你,购买云服务器并且安装宝塔面板

手把手教你,购买云服务器并且安装宝塔面板 前言 大家好,我是星哥。星哥发现很多新手刚接触服务器时,都会被“选购...