一、TCP层:高性能服务器的基石
Go的net包封装了BSD Socket API,提供了优雅的并发模型。所有HTTP服务本质上都是TCP服务器。理解TCP层参数调优,是构建高性能Go服务的关键第一步。
1.1 TCP连接建立与backlog
package main
import (
"fmt"
"net"
"net/http"
"runtime"
"time"
)
// TCP连接建立的三个队列(理解backlog的关键):
/*
客户端 服务器内核 应用层(listen fd)
| | |
|-- SYN (seq=x) --------->| |
| (客户端进入SYN_SENT) |-- 进入半连接队列(1) ---------> listen fd
|<-- SYN+ACK (seq=y,ack=x+1)-- |
|-- ACK (ack=y+1) -------->| |
| |-- 移到全连接队列(2) ---------> listen fd
| | |---[ ][ ][ ]
|<------------------------- accept()拿走 ------------------| ↑ ↑ ↑
Linux 2.2之前:backlog控制两个队列的总和
Linux 2.2之后:分别控制
- 半连接队列: /proc/sys/net/ipv4/tcp_max_syn_backlog
- 全连接队列: min(backlog, /proc/sys/net/core/somaxconn)
Go默认backlog = 0 → 使用默认值128
*/
// 高性能HTTP服务器配置
func newHighPerfServer() *http.Server {
return &http.Server{
Addr: ":8080",
ReadTimeout: 30 * time.Second,
ReadHeaderTimeout: 10 * time.Second, // 防Slow Loris攻击
WriteTimeout: 30 * time.Second,
IdleTimeout: 120 * time.Second,
MaxHeaderBytes: 1 << 20,
}
}
// TCP keepalive配置
func configureKeepAlive(conn net.Conn) error {
if tcpConn, ok := conn.(*net.TCPConn); ok {
return tcpConn.SetKeepAlive(true)
}
return nil
}
backlog实践经验:在Kubernetes环境中,
somaxconn默认只有128。推荐生产环境设置:sysctl -w net.core.somaxconn=65535。如果需要精确控制Go服务的backlog,建议使用net.Listen配合系统调用,或在nginx层做代理。
1.2 连接池与复用
package netpool
import (
"net"
"sync"
"time"
)
type ConnPool struct {
addr string
pool chan net.Conn
mu sync.Mutex
active int
maxOpen int
maxIdle int
}
type PoolConfig struct {
MaxOpen int
MaxIdle int
}
func NewConnPool(addr string, cfg PoolConfig) *ConnPool {
return &ConnPool{
addr: addr,
pool: make(chan net.Conn, cfg.MaxIdle),
maxOpen: cfg.MaxOpen,
maxIdle: cfg.MaxIdle,
}
}
func (p *ConnPool) Get() (net.Conn, error) {
select {
case conn := <-p.pool:
return conn, nil
default:
}
p.mu.Lock()
if p.active >= p.maxOpen {
p.mu.Unlock()
conn, err := <-p.pool
return conn, err
}
p.active++
p.mu.Unlock()
return net.DialTimeout("tcp", p.addr, 5*time.Second)
}
func (p *ConnPool) Put(conn net.Conn) {
if conn == nil {
p.mu.Lock()
p.active--
p.mu.Unlock()
return
}
select {
case p.pool <- conn:
return
default:
p.mu.Lock()
p.active--
p.mu.Unlock()
conn.Close()
}
}
二、HTTP/2:现代Web性能的核心
HTTP/2通过多路复用、头部压缩、服务器推送等特性,彻底改变了Web性能。Go的net/http包从Go 1.6开始完整支持HTTP/2,是目前最成熟的HTTP/2实现之一。
2.1 HTTP/2核心特性与Go实现
package main
import (
"crypto/tls"
"fmt"
"golang.org/x/net/http2"
"net/http"
)
// HTTP/2必须通过HTTPS运行(ALPN协商)
// Go自动为HTTPS Server启用HTTP/2(无需额外配置)
func newHTTP2Server() *http.Server {
return &http.Server{
Addr: ":8443",
TLSConfig: &tls.Config{
MinVersion: tls.VersionTLS12,
CurvePreferences: []tls.CurveID{
tls.CurveP256,
tls.X25519,
},
CipherSuites: []uint16{
tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
},
},
}
}
// HTTP/2服务器配置(使用http2包精细控制)
func newHTTP2ServerWithConfig() *http.Server {
srv := &http.Server{
Addr: ":8443",
}
// 显式配置HTTP/2(对于h2c明文HTTP/2必须)
http2srv := &http2.Server{
MaxConcurrentStreams: 250, // 单连接最大并发流(默认250)
MaxReadFrameSize: 1 << 20, // 最大帧大小(默认16KB)
IdleTimeout: 5 * 60e9, // 空闲超时(纳秒)
MaxUploadBufferPerConnection: 1 << 20,
MaxUploadBufferPerStream: 1 << 18,
}
http2 ConfigureServer(srv, http2srv)
return srv
}
// 手动配置HTTP/2 ClientTransport
func newHTTP2Client() *http.Client {
return &http.Client{
Transport: &http2.Transport{
// 禁用 CONNECT 请求(用于代理)
AllowHTTP: false,
// 为每个主机名建立独立连接池
// (同主机多请求复用同一个TCP连接上的多个流)
PingIdleTimeout: 30 * 1e9,
},
}
}
// HTTP/2 vs HTTP/1.1性能对比(关键指标)
/*
┌──────────────────┬──────────────────┬──────────────────┐
│ 特性 │ HTTP/1.1 │ HTTP/2 │
├──────────────────┼──────────────────┼──────────────────┤
│ 多路复用 │ 无(pipelining不可靠)│ ✓ (stream) │
│ 头部压缩 │ 无 │ ✓ (HPACK) │
│ 服务器推送 │ 无 │ ✓ (PUSH_PROMISE) │
│ 流控制 │ 无 │ ✓ │
│ 单连接多请求 │ 需开多连接 │ ✓ │
│ 首部阻塞 │ HOLB问题 │ ✓ (帧级别优化) │
│ 握手延迟 │ 1 RTT │ ✓ (ALPN协商) │
└──────────────────┴──────────────────┴──────────────────┘
HPACK头部压缩原理:
- 静态表:61个预定义头部字段(如:method: GET)
- 动态表:记录当前连接中出现过的头部值
- 霍夫曼编码:高频字符使用更短编码
- 效果:重复头部(如cookie、authorization)只传索引
*/
2.2 gRPC中的HTTP/2应用
package main
import (
"context"
"log"
"net"
"time"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
"google.golang.org/grpc/encoding/gzip"
"google.golang.org/grpc/keepalive"
)
// gRPC建立在HTTP/2之上,充分利用了HTTP/2的所有特性
// Protobuf序列化比JSON更紧凑,解析更快
func newGRPCServer() *grpc.Server {
kaep := keepalive.EnforcementPolicy{
MinTime: 5 * time.Minute,
PermitWithoutStream: true,
}
kasp := keepalive.ServerParameters{
MaxConnectionIdle: 10 * time.Minute,
MaxConnectionAge: 2 * time.Hour,
MaxConnectionAgeGrace: 1 * time.Minute,
Time: 1 * time.Hour,
Timeout: 20 * time.Second,
}
// gRPC server配置
srv := grpc.NewServer(
grpc.KeepaliveEnforcementPolicy(kaep),
grpc.KeepaliveParams(kasp),
grpc.NumStreamWorkers(32), // 并发处理流的数量
)
return srv
}
// gRPC客户端连接池(高并发场景必需)
type GRPCPool struct {
addrs []string
conns []*grpc.ClientConn
idx int
lb RoundRobin
}
type RoundRobin struct {
mu sync.Mutex
idx int
n int
}
func (r *RoundRobin) Next() int {
r.mu.Lock()
v := r.idx
r.idx = (r.idx + 1) % r.n
r.mu.Unlock()
return v
}
func DialGRPCPool(addrs []string) (*GRPCPool, error) {
pool := &GRPCPool{addrs: addrs, n: len(addrs)}
for _, addr := range addrs {
conn, err := grpc.Dial(addr,
grpc.WithTransportCredentials(insecure.NewCredentials()),
grpc.WithDefaultServiceConfig(`{"loadBalancingPolicy":"round_robin"}`),
grpc.WithCompression(gzip.Name),
)
if err != nil {
return nil, err
}
pool.conns = append(pool.conns, conn)
}
return pool, nil
}
import "sync"
HTTP/2 gRPC实战经验:在生产环境中,gRPC的HTTP/2优势在微服务间通信中体现得最明显——单连接多流避免了连接建立开销,HPACK大幅压缩重复header,Protobuf序列化比JSON快5-10倍且体积更小。建议:内部服务通信全部迁移到gRPC,对外API使用HTTP/2+JSON(兼容性考虑)。
三、ReverseProxy:构建高性能代理
Go的net/http/httputil.ReverseProxy是构建API网关、负载均衡器的核心工具。它设计精巧,支持流式转发、请求修改、负载均衡等场景。
3.1 ReverseProxy核心用法
package proxy
import (
"fmt"
"net/http"
"net/http/httputil"
"net/url"
"strings"
"time"
)
// 基础反向代理
func NewReverseProxy(target string) *httputil.ReverseProxy {
targetURL, _ := url.Parse(target)
director := func(req *http.Request) {
req.URL.Scheme = targetURL.Scheme
req.URL.Host = targetURL.Host
req.Host = targetURL.Host
// 修改请求路径(去除前缀)
req.URL.Path = strings.TrimPrefix(req.URL.Path, "/api")
}
return &httputil.ReverseProxy{
Director: director,
Transport: &http.Transport{MaxIdleConns: 1000},
FlushInterval: 200 * time.Millisecond, // 流式响应刷新间隔
ModifyResponse: nil, // 可修改响应
ErrorHandler: errorHandler, // 自定义错误处理
}
}
func errorHandler(w http.ResponseWriter, r *http.Request, err error) {
// 优雅降级:后端服务不可用时返回友好错误
w.WriteHeader(http.StatusBadGateway)
fmt.Fprintf(w, `{"code":502,"message":"upstream error"}`)
}
// 带负载均衡的反向代理
type LoadBalancer struct {
backends []*url.URL
index int
mu sync.Mutex
}
func (lb *LoadBalancer) Next() *url.URL {
lb.mu.Lock()
defer lb.mu.Unlock()
backend := lb.backends[lb.index]
lb.index = (lb.index + 1) % len(lb.backends)
return backend
}
func (lb *LoadBalancer) NewProxy() *httputil.ReverseProxy {
director := func(req *http.Request) {
backend := lb.Next()
req.URL.Scheme = backend.Scheme
req.URL.Host = backend.Host
req.Host = backend.Host
}
return &httputil.ReverseProxy{Director: director}
}
// 带健康检查的负载均衡
type HealthChecker struct {
backends map[string]*BackendInfo
mu sync.RWMutex
}
type BackendInfo struct {
URL *url.URL
Healthy bool
FailCount int
Latency time.Duration
}
func (hc *HealthChecker) Check() {
hc.mu.Lock()
defer hc.mu.Unlock()
for _, b := range hc.backends {
start := time.Now()
resp, err := http.Head(b.URL.String())
latency := time.Since(start)
if err != nil || resp.StatusCode >= 500 {
b.FailCount++
if b.FailCount >= 3 {
b.Healthy = false
}
} else {
b.FailCount = 0
b.Healthy = true
b.Latency = latency
}
}
}
import "sync"
3.2 Zero-Copy优化
package zcopy
import (
"io"
"net"
"net/http"
"os"
"strings"
)
// 传统方式:ReadAll + Write → 两次内存拷贝
func copyTraditional(w http.ResponseWriter, r *http.Request) {
// 读取全部内容到内存(一次分配+拷贝)
body, _ := io.ReadAll(r.Body)
// 写回(又一次拷贝)
w.Write(body)
}
// Zero-Copy方式:bytes.Buffer + io.Copy → 内核空间拷贝
// 最佳实践:静态文件使用http.ServeFile(使用sendfile系统调用)
func serveFileZeroCopy(w http.ResponseWriter, r *http.Request, path string) {
http.ServeFile(w, r, path)
// 内部使用os.Open + io.Copy
// io.Copy在Linux上使用sendfile(2)系统调用
// → 数据从磁盘缓存直接→socket,不经过用户态
}
// 高性能静态文件服务器配置
func newStaticFileServer() http.Handler {
return http.FileServer(http.Dir("/var/www/static"))
}
// 管道式代理(最小化内存拷贝)
// httputil.ReverseProxy内部使用io.Copy实现零额外拷贝的流转发
func newStreamingProxy(target string) *httputil.ReverseProxy {
targetURL, _ := url.Parse(target)
return &httputil.ReverseProxy{
Director: func(req *http.Request) {
req.URL.Scheme = targetURL.Scheme
req.URL.Host = targetURL.Host
},
// BufferPool减少buffer分配(Go 1.6+)
BufferPool: newBufferPool(),
// FlushInterval: -1 禁用自动flush(提高大文件传输性能)
FlushInterval: -1,
}
}
import (
"net/url"
"sync"
)
type bufferPool struct {
pool sync.Pool
}
func newBufferPool() *bufferPool {
return &bufferPool{
pool: sync.Pool{
New: func() interface{} {
b := make([]byte, 32*1024) // 32KB buffer
return &b
},
},
}
}
// Linux sendfile系统调用路径(了解即可):
/*
用户态: Go io.Copy
↓
内核态: tcp_sendmsg (inet_sendmsg)
↓
虚拟文件层: do_sendfile → vfs_read → ext4/xfs_read_page
↓
磁盘/SSD → DMA → 内存
↓
网卡驱动 → DMA描述符
↓
网络线缆
Zero-Copy关键:步骤4-6中,数据不经过用户态CPU,由DMA直接搬运
对比传统IO: 磁盘→内核页缓存→用户态buffer→内核socket buffer→网卡
(需要CPU参与中间每一步)
*/
// Unix Domain Socket代理(极高性能进程间通信)
func newUDSProxy(socketPath string) *httputil.ReverseProxy {
return &httputil.ReverseProxy{
Director: func(req *http.Request) {
req.URL.Scheme = "http"
req.URL.Host = "localhost" // 被UDS覆盖
},
Transport: &http.Transport{
DialContext: func(ctx interface{}, addr string) (net.Conn, error) {
var d net.Dialer
return d.DialContext(ctx, "unix", socketPath)
},
},
}
}
ReverseProxy调优注意事项:默认的ReverseProxy会修改请求Host头(从Director中设置),如果目标服务依赖X-Forwarded-For等头信息,需要显式转发原始头。
proxy.Headers()方法(Go 1.11+)可以精细控制哪些头被转发。流式响应场景下,FlushInterval设置要权衡——太短影响性能,太长导致SSE/长轮询延迟。
四、rate.Limiter:精细化流量控制
高并发系统必须具备流量控制能力。Go标准库的golang.org/x/time/rate是生产级的令牌桶实现,支持单速率和双速率限流。
4.1 令牌桶算法与rate.Limiter
package ratelimit
import (
"context"
"fmt"
"net/http"
"time"
"golang.org/x/time/rate"
)
// 令牌桶核心概念:
/*
令牌桶 = 一个固定大小的桶,以固定速率r放入令牌
每个请求消耗1个令牌,桶满时拒绝
桶容量b = 突发大小(burst)
┌─────────────────────────────────────────────────────┐
│ QPS = r(每秒r个请求) │
│ Burst = b(可一次性处理b个并发请求) │
│ │
│ 例如: limiter := NewLimiter(rate.Every(100ms), 10) │
│ → 每100ms补充1个令牌,最多持有10个令牌 │
└─────────────────────────────────────────────────────┘
*/
// 单节点限流器
type RateLimiter struct {
limiter *rate.Limiter
burst int
}
func NewRateLimiter(qps float64, burst int) *RateLimiter {
return &RateLimiter{
limiter: rate.NewLimiter(rate.Limit(qps), burst),
burst: burst,
}
}
func (rl *RateLimiter) Allow() bool {
return rl.limiter.Allow()
}
func (rl *RateLimiter) Wait(ctx context.Context) error {
return rl.limiter.Wait(ctx)
}
// WaitN:一次消耗N个令牌(用于批处理场景)
func (rl *RateLimiter) WaitN(ctx context.Context, n int) error {
return rl.limiter.WaitN(ctx, n)
}
// HTTP中间件:全局限流
func (rl *RateLimiter) Middleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if err := rl.Wait(r.Context()); err != nil {
http.Error(w, "rate limit exceeded", http.StatusTooManyRequests)
return
}
next.ServeHTTP(w, r)
})
}
// 分布式限流:Redis + Lua(多节点共享限流)
/*
Redis令牌桶实现(Lua保证原子性):
local key = KEYS[1]
local rate = tonumber(ARGV[1]) -- 每秒补充速率
local capacity = tonumber(ARGV[2]) -- 桶容量
local now = tonumber(ARGV[3]) -- 当前时间戳(毫秒)
local fill_time = capacity / rate
local ttl = math.floor(fill_time * 2)
local last = tonumber(redis.call("HGET", key, "last") or now)
local tokens = tonumber(redis.call("HGET", key, "tokens") or capacity)
local delta = math.max(0, now - last)
local filled = delta * rate / 1000
tokens = math.min(capacity, tokens + filled)
local allowed = 0
if tokens >= 1 then
tokens = tokens - 1
allowed = 1
end
redis.call("HSET", key, "last", now)
redis.call("HSET", key, "tokens", tokens)
redis.call("EXPIRE", key, ttl)
return allowed
*/
// 分层限流策略(推荐生产使用)
type TieredRateLimiter struct {
global *rate.Limiter // 全局限流(保护后端)
perIP map[string]*rate.Limiter
perIPMu sync.Mutex
perIPRate rate.Limit
}
func NewTieredLimiter(qps, perIPQps float64, burst int) *TieredRateLimiter {
return &TieredRateLimiter{
global: rate.NewLimiter(rate.Limit(qps), burst),
perIP: make(map[string]*rate.Limiter),
perIPRate: rate.Limit(perIPQps),
}
}
func (t *TieredRateLimiter) Allow(ip string) bool {
// 第一层:全局限流
if !t.global.Allow() {
return false
}
// 第二层:IP维限流(防止单IP打爆)
t.perIPMu.Lock()
limiter, exists := t.perIP[ip]
if !exists {
limiter = rate.NewLimiter(t.perIPRate, 10)
t.perIP[ip] = limiter
}
t.perIPMu.Unlock()
return limiter.Allow()
}
import "sync"
4.2 双速率限流:允许突发但限制平均
package ratelimit
import (
"context"
"fmt"
"golang.org/x/time/rate"
)
// 双速率限流(Token Bucket + Leaky Bucket的混合)
// 也称为"允许突发但限制平均速率"
type BurstLimiter struct {
limiter *rate.Limiter
}
func NewBurstLimiter(qps float64, burst int) *BurstLimiter {
return &BurstLimiter{
limiter: rate.NewLimiter(rate.Limit(qps), burst),
}
}
// Reserve:预约令牌,返回等待时间
// 比Allow更精确,适用于需要知道等待多久的场景
func (rl *BurstLimiter) Reserve(ctx context.Context, n int) (wait time.Duration, allowed bool) {
r := rl.limiter.ReserveN(time.Now(), n)
if !r.OK() {
return 0, false
}
wait = r.Delay()
return wait, true
}
// 限流指标(用于监控和告警)
type RateLimitStats struct {
allowed int64
rejected int64
}
func (s *RateLimitStats) Record(allowed bool) {
if allowed {
s.allowed++
} else {
s.rejected++
}
}
func (s *RateLimitStats) RejectRate() float64 {
total := s.allowed + s.rejected
if total == 0 {
return 0
}
return float64(s.rejected) / float64(total)
}
// 限流重试策略:使用retry-after头告知客户端
func RateLimitHandler(w http.ResponseWriter, r *http.Request, limiter *rate.Limiter) error {
ctx := r.Context()
if err := limiter.Wait(ctx); err != nil {
retryAfter := 1 // 秒
w.Header().Set("Retry-After", fmt.Sprintf("%d", retryAfter))
http.Error(w, "rate limit exceeded", http.StatusTooManyRequests)
return err
}
return nil
}
import "time"
限流策略选择:对于API网关,令牌桶(rate.Limiter)是最佳选择——允许短暂突发以应对流量尖刺,同时保证长期平均速率不超过阈值。对于消息队列消费者,漏桶更合适——以恒定速率消费,防止压垮下游。对于爬虫/外部调用,滑动窗口(Redis sorted set实现)提供最公平的限流体验。
五、完整高性能HTTP服务示例
综合以上所有技术,构建一个生产级高性能HTTP服务器。
package main
import (
"context"
"crypto/tls"
"fmt"
"log"
"net/http"
"net/http/httputil"
"net/url"
"os"
"os/signal"
"runtime"
"syscall"
"time"
"golang.org/x/net/http2"
"golang.org/x/time/rate"
)
// 生产级高性能服务器
type HighPerfServer struct {
httpSrv *http.Server
httpsSrv *http.Server
proxy *httputil.ReverseProxy
rateLimit *rate.Limiter
}
func NewHighPerfServer() *HighPerfServer {
// 后端服务地址
backend, _ := url.Parse("http://127.0.0.1:8081")
proxy := &httputil.ReverseProxy{
Director: func(req *http.Request) {
req.URL.Scheme = backend.Scheme
req.URL.Host = backend.Host
req.Header.Set("X-Forwarded-Host", req.Host)
req.Header.Set("X-Real-IP", getClientIP(req))
},
BufferPool: newBufferPool(),
Transport: &http.Transport{
MaxConnsPerHost: 100,
MaxIdleConns: 200,
MaxIdleConnsPerHost: 10,
IdleConnTimeout: 90 * time.Second,
TLSHandshakeTimeout: 10 * time.Second,
},
FlushInterval: 200 * time.Millisecond,
ErrorHandler: func(w http.ResponseWriter, r *http.Request, err error) {
http.Error(w, "Bad Gateway", http.StatusBadGateway)
},
}
return &HighPerfServer{
proxy: proxy,
rateLimit: rate.NewLimiter(10000, 1000), // 10k QPS, burst 1000
}
}
func getClientIP(r *http.Request) string {
if fwd := r.Header.Get("X-Real-IP"); fwd != "" {
return fwd
}
return r.RemoteAddr[:len(r.RemoteAddr)-len(":xxxx")]
}
type bufferPool struct{ pool chan []byte }
func newBufferPool() *bufferPool {
pool := &bufferPool{make(chan []byte, 100)}
for i := 0; i < 100; i++ {
pool.pool <- make([]byte, 32*1024)
}
return pool
}
func (p *bufferPool) Get(size int) []byte {
select {
case b := <-p.pool:
if cap(b) >= size {
return b[:size]
}
return make([]byte, size)
default:
return make([]byte, size)
}
}
func (p *bufferPool) Put(b []byte) {
select {
case p.pool <- b:
default:
}
}
func (s *HighPerfServer) Serve() error {
runtime.GOMAXPROCS(runtime.NumCPU())
// HTTP/1.1 + HTTP/2混合服务器
s.httpSrv = &http.Server{
Addr: ":8080",
Handler: s.routes(),
ReadTimeout: 30 * time.Second,
ReadHeaderTimeout: 10 * time.Second,
WriteTimeout: 60 * time.Second,
IdleTimeout: 120 * time.Second,
MaxHeaderBytes: 1 << 20,
}
// HTTPS/HTTP2服务器(同一端口,ALPN协商)
tlsConfig := &tls.Config{
MinVersion: tls.VersionTLS12,
CurvePreferences: []tls.CurveID{
tls.CurveP256, tls.X25519,
},
GetConfigForClient: func(hello *tls.ClientHelloInfo) (*tls.Config, error) {
// HTTP/2的ALPN协商在这里生效
return tlsConfig, nil
},
}
s.httpsSrv = &http.Server{
Addr: ":8443",
TLSConfig: tlsConfig,
Handler: s.routes(),
}
// 配置HTTP/2
http2.ConfigureServer(s.httpsSrv, &http2.Server{
MaxConcurrentStreams: 250,
IdleTimeout: 5 * time.Minute,
})
// 启动服务器
go func() {
log.Printf("HTTP server: http://:8080")
log.Printf("HTTPS server: https://:8443")
}()
// 优雅关闭
quit := make(chan os.Signal, 1)
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
go func() {
if err := s.httpSrv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
log.Fatalf("HTTP server error: %v", err)
}
}()
go func() {
if err := s.httpsSrv.ListenAndServeTLS("cert.pem", "key.pem"); err != nil && err != http.ErrServerClosed {
log.Fatalf("HTTPS server error: %v", err)
}
}()
<-quit
log.Println("Shutting down...")
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
s.httpSrv.Shutdown(ctx)
s.httpsSrv.Shutdown(ctx)
return nil
}
func (s *HighPerfServer) routes() http.Handler {
mux := http.NewServeMux()
// 限流端点
mux.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
if !s.rateLimit.Allow() {
http.Error(w, "Rate limit", http.StatusTooManyRequests)
return
}
fmt.Fprintln(w, "OK")
})
// 反向代理
mux.HandleFunc("/api/", func(w http.ResponseWriter, r *http.Request) {
if !s.rateLimit.Allow() {
http.Error(w, "Rate limit", http.StatusTooManyRequests)
return
}
s.proxy.ServeHTTP(w, r)
})
return mux
}
import "crypto/tls"
性能优化checklist:HTTP服务器优化顺序——(1)先用压测工具
wrk/hey确认瓶颈;(2)关注CPU还是IO;(3)CPU-bound加GOMAXPROCS、减少GC压力;(4)IO-bound加连接池、使用HTTP/2、启用keep-alive;(5)瓶颈在后端→优化代理层+限流;(6)瓶颈在Go→检查sync.Pool是否正确使用。切忌:未测量的优化是徒劳的。