
Go API网关项目复盘从nginx到自研网关的迁移经验与性能对比一、nginx有什么不够用的一个微服务架构使用nginx做反向代理和负载均衡。nginx配置了120个location规则随着服务数量增长出现了三个痛点动态路由困难。新增一个微服务需要在nginx配置中添加location块reload需要约50ms——期间所有新连接排队。每天reload 3-5次。服务发现不原生。nginx不会自动感知Kubernetes中Pod的变化。需要额外的nginx-ingress或外部DNS方案。可观测性不足。nginx的access_log虽然完整但缺少请求级别的追踪和自定义指标——需要嵌入Lua脚本或OpenResty扩展。自研网关的目标不是做一个比nginx更快的网关而是做一个运维成本更低的网关——动态路由、服务发现、可观测性、零reload。二、自研网关的核心设计动态路由表——自动感知Kubernetes服务变化type Gateway struct { router *DynamicRouter proxy *httputil.ReverseProxy k8sWatcher *K8sServiceWatcher } type DynamicRouter struct { mu sync.RWMutex routes map[string]*Route // path → route } type Route struct { Path string ServiceName string Endpoints []Endpoint // 动态更新 Middleware []Middleware } // K8sWatcher监听Service/Endpoints变化 type K8sServiceWatcher struct { clientset *kubernetes.Clientset onUpdate func(serviceName string, endpoints []Endpoint) } func (w *K8sServiceWatcher) Watch(ctx context.Context) error { watcher, err : w.clientset.CoreV1().Endpoints().Watch(ctx, metav1.ListOptions{}) if err ! nil { return err } for event : range watcher.ResultChan() { endpoints : event.Object.(*v1.Endpoints) serviceName : endpoints.Name // 解析Endpoints到网关内部路由表 var eps []Endpoint for _, subset : range endpoints.Subsets { for _, addr : range subset.Addresses { for _, port : range subset.Ports { eps append(eps, Endpoint{ Host: addr.IP, Port: int(port.Port), }) } } } w.onUpdate(serviceName, eps) } return nil }零reload的配置热更新func (g *Gateway) ServeHTTP(w http.ResponseWriter, r *http.Request) { // 1. 动态路由查找——不需要reload route : g.router.Match(r.URL.Path) if route nil { http.NotFound(w, r) return } // 2. 负载均衡——轮询健康检查 endpoint : g.selectEndpoint(route) if endpoint nil { http.Error(w, Service Unavailable, 503) return } // 3. 中间件链 handler : g.buildMiddlewareChain(route.Middleware, g.proxy.ServeHTTP) handler(w, r) } // 健康检查——自动剔除不健康的Pod func (g *Gateway) healthCheckLoop() { ticker : time.NewTicker(10 * time.Second) for range ticker.C { g.router.mu.Lock() for _, route : range g.router.routes { healthy : make([]Endpoint, 0) for _, ep : range route.Endpoints { if g.isHealthy(ep) { healthy append(healthy, ep) } } route.Endpoints healthy } g.router.mu.Unlock() } }三、性能对比数据基于同一台4C8G服务器使用wrk压测100并发30秒指标nginx自研网关差异请求数/秒48,20042,300-12%P50延迟1.2ms1.5ms25%P99延迟4.8ms5.2ms8%内存使用15MB32MB113%配置变更reload 50ms实时生效-吞吐量比nginx低12%延迟略高。但差异在微服务场景下可接受——后端服务本身的延迟通常在50-200ms网关的1-2ms差异不构成瓶颈。真正的收益不在性能在运维新增服务零配置nginx需要添加location块upstreamreload自研网关自动感知K8s Endpoints灰度发布支持基于Header的流量路由X-Canary: true→ 路由到canary版本自定义指标每个路由的QPS、延迟、错误率的Prometheus指标自动生成四、何时不要自研网关nginx经过15年的开发和优化在纯反向代理场景下经过充分的安全审计CVE修复及时内存安全C编写但通过严格测试验证丰富的模块生态限流、缓存、WAF自研网关的劣势安全性需要团队自己保证内存管理依赖Go GC——在极高QPS下10万/sGC停顿可能造成延迟尖峰需要持续维护和功能迭代自研适用微服务数量20个nginx配置管理复杂、需要动态路由服务发现、团队有Go开发能力自研不适用小规模部署5个服务、团队无Go能力、安全审计要求高金融/医疗五、总结从nginx到自研网关的迁移经验自研网关的吞吐量比nginx低12%——在微服务场景下可接受真正的收益是运维效率——零reload、自动服务发现、自定义可观测性K8s环境下的Watch机制让动态路由实现非常自然健康检查自动剔除不健康Pod避免请求失败不应该追求做一个更快的nginx——追求做一个运维成本更低的网关当前网关稳定运行8个月代理15个微服务日均处理约3000万请求。零次配置变更导致的事故。唯一的运维痛点是Go GC在极高负载下的停顿——通过GOGC200调参后已控制在可接受范围。如果未来性能成为瓶颈QPS10万可能考虑用Rust重写热路径但当前Go实现已满足需求的10倍余量。