Golang HTTP API 服务性能瓶颈分析与优化指南

Golang HTTP API 服务性能瓶颈分析与优化指南 我在中国阿里云部署了API服务器。使用台湾的PC机通过2个Hyper-V虚拟机进行测试。

测试配置如下: ab -n 3000 -c 3000 http://ip:7000/api/0.2/weather(2个虚拟机,总计6000请求)

服务器配置为1核CPU(使用率10%),4G内存(使用率10%) 带宽最高3.5 Mbps,3K pps,TCP连接数6K

但是当我使用-c 4000参数时,出现错误: “apr_socket_recv: Connection timed out (110)” 由于所有资源使用率都很低,为什么无法处理更高的请求?

我使用了以下包:

go get github.com/robfig/cron
go get github.com/go-gorp/gorp
go get github.com/julienschmidt/httprouter
go get github.com/go-sql-driver/mysql
go get github.com/mssola/user_agent
go get github.com/astaxie/beego/session

天气功能不使用数据库。当函数被调用时,只是简单返回内存中的数据结构。

服务器端配置: $vi /etc/sysctl.conf

net.core.somaxconn = 1024
net.core.netdev_max_backlog = 2000
net.ipv4.tcp_max_syn_backlog=2048
net.ipv4.tcp_max_tw_buckets = 5000
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_max_syn_backlog = 1024
net.ipv4.tcp_synack_retries = 2
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1
net.ipv6.conf.lo.disable_ipv6 = 1
kernel.sysrq = 1

// 额外命令

ulimit -n 102400
$ifconfig eth0 txqueuelen 5000
$echo "/sbin/ifconfig eth0 txqueuelen 5000" >> /etc/rc.local

我使用 $watch -n 1 “netstat -anp|grep 7000|wc -l” 服务器上有6000个连接。

提前感谢。


更多关于Golang HTTP API 服务性能瓶颈分析与优化指南的实战教程也可以访问 https://www.itying.com/category-94-b0.html

10 回复

你期望什么?你的TCP连接耗尽了

更多关于Golang HTTP API 服务性能瓶颈分析与优化指南的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


嗨 acim:
有可能是阿里云有一些限制,但我就是找不到说明这个问题的文档地址。

谢谢你,vitr。

我试过了,没有发现区别。但我使用5个客户端进行ab测试,我的服务器最多能处理13K请求。这是我目前能达到的最佳性能。

感谢vitr。

每个IP的最大TCP连接数应该在3万左右,我使用了两个客户端(一个在中国,一个在台湾)进行ab测试,得到了相同的结果。您能告诉我哪个Linux命令可以显示TCP连接已耗尽吗? 谢谢。

感谢acim。

我正在使用Go 1.10.1 您建议我使用Prometheus来监控我的简单API服务器吗?我有阿里云监控工具和一些Linux命令。是否有某些特定参数需要我关注?

func main() {
    fmt.Println("hello world")
}

Prometheus 很酷,一旦开始跟踪指标,你就能发现很多信息。我们用它来监控我们的 HTTP 客户端,所以这是从另一个角度来看的。即使你不跟踪任何特殊内容,Prometheus 也会显示一些预设指标,然后你可以添加更多自定义内容。会不会是某些防火墙限制了你的连接或其他原因?我的意思是在阿里巴巴的基础设施中,他们肯定有这类措施。

感谢vitr。

我没有关于"nf_conntrack"的错误信息,但我有这个错误:“request_sock_TCP: 端口7000可能出现SYN泛洪攻击。正在发送cookies”。 我的/etc/sysctl.conf配置如下: vm.swappiness = 0 net.ipv4.neigh.default.gc_stale_time=120

详见 https://help.aliyun.com/knowledge_detail/39428.html

net.ipv4.conf.all.rp_filter=0 net.ipv4.conf.default.rp_filter=0 net.ipv4.conf.default.arp_announce = 2 net.ipv4.conf.lo.arp_announce=2 net.ipv4.conf.all.arp_announce=2

详见 https://help.aliyun.com/knowledge_detail/41334.html

net.ipv4.tcp_max_tw_buckets = 5000 net.ipv4.tcp_syncookies = 1 net.ipv4.tcp_max_syn_backlog = 1024 net.ipv4.tcp_synack_retries = 2 net.ipv6.conf.all.disable_ipv6 = 1 net.ipv6.conf.default.disable_ipv6 = 1 net.ipv6.conf.lo.disable_ipv6 = 1 kernel.sysrq = 1

用于Http Api服务器

net.core.somaxconn = 2048 net.core.netdev_max_backlog = 5000 net.ipv4.tcp_max_syn_backlog = 5000

net.core.wmem_max = 12582912 net.core.rmem_max = 12582912

net.ipv4.tcp_rmem = 10240 87380 12582912 net.ipv4.tcp_wmem = 10240 87380 12582912

net.netfilter.nf_conntrack_max = 1048576 net.netfilter.nf_conntrack_buckets = 16384

从你的描述来看,服务器资源使用率很低但无法处理更高并发请求,这通常表明存在连接处理或网络配置相关的瓶颈。以下是几个关键优化方向:

1. Go HTTP 服务器配置优化

package main

import (
    "net/http"
    "time"
    "github.com/julienschmidt/httprouter"
)

func main() {
    router := httprouter.New()
    router.GET("/api/0.2/weather", weatherHandler)
    
    server := &http.Server{
        Addr:         ":7000",
        Handler:      router,
        ReadTimeout:  10 * time.Second,    // 增加读取超时
        WriteTimeout: 10 * time.Second,    // 增加写入超时
        IdleTimeout:  30 * time.Second,    // 空闲连接超时
    }
    
    // 设置连接限制
    server.SetKeepAlivesEnabled(true)
    server.ListenAndServe()
}

func weatherHandler(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
    // 直接从内存返回数据
    data := map[string]interface{}{
        "temperature": 25,
        "humidity":    60,
        "condition":   "sunny",
    }
    
    w.Header().Set("Content-Type", "application/json")
    // 直接写入响应,避免不必要的序列化开销
    w.Write([]byte(`{"temperature":25,"humidity":60,"condition":"sunny"}`))
}

2. 系统级优化配置

# 优化 /etc/sysctl.conf 配置
net.core.somaxconn = 65535
net.core.netdev_max_backlog = 10000
net.ipv4.tcp_max_syn_backlog = 65536
net.ipv4.tcp_max_tw_buckets = 2000000
net.ipv4.ip_local_port_range = 1024 65535
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_fin_timeout = 30
net.ipv4.tcp_keepalive_time = 1200
net.ipv4.tcp_keepalive_intvl = 30
net.ipv4.tcp_keepalive_probes = 3

# 应用配置
sysctl -p

3. 连接池和 Goroutine 优化

import (
    "net"
    "net/http"
    "time"
)

func createOptimizedClient() *http.Client {
    transport := &http.Transport{
        MaxIdleConns:        1000,
        MaxIdleConnsPerHost: 1000,
        IdleConnTimeout:     90 * time.Second,
        DialContext: (&net.Dialer{
            Timeout:   30 * time.Second,
            KeepAlive: 30 * time.Second,
        }).DialContext,
        TLSHandshakeTimeout: 10 * time.Second,
        ExpectContinueTimeout: 1 * time.Second,
    }
    
    return &http.Client{
        Transport: transport,
        Timeout:   30 * time.Second,
    }
}

4. 监控和诊断代码

import (
    "expvar"
    "net/http"
    "runtime"
)

func init() {
    // 暴露运行时指标
    expvar.Publish("goroutines", expvar.Func(func() interface{} {
        return runtime.NumGoroutine()
    }))
}

// 添加性能监控中间件
func monitoringMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        start := time.Now()
        next.ServeHTTP(w, r)
        duration := time.Since(start)
        
        // 记录请求耗时
        // 可以集成到监控系统中
        _ = duration
    })
}

5. 压力测试优化参数

# 使用 wrk 进行更准确的测试
wrk -t12 -c4000 -d30s http://ip:7000/api/0.2/weather

# 或者使用优化后的 ab 参数
ab -n 10000 -c 1000 -k http://ip:7000/api/0.2/weather

主要问题可能在于:

  1. TCP 连接队列溢出
  2. 文件描述符限制
  3. 客户端端口耗尽
  4. 网络延迟导致的连接超时

建议先应用系统级优化,然后使用保持连接的测试方法(-k 参数)来验证性能改进。

回到顶部