Go | First Response Pattern
Aug 7, 2025
// Avoid timeout - Replicate servers and use first response
type Result string
type Search func(query string) Result
func fakeSearch(kind string) Search
func First(query string, replicas ...Search) Result
func main()
这是 Go 并发经典实践之一:“用副本竞速的方式避免超时,返回最早的可用结果”——常见于高可用分布式系统的请求快速返回(比如多个搜索副本、微服务副本集请谁先响应)。
主要思想
- 业务背景:你有好几个“备用服务器/副本/搜索实现”,哪个响应最快用哪个,“慢的都不用等”,避免整个请求因单点慢或偶发延迟变慢。
- 这是现实世界中 Google、Amazon 等公司搜索引擎“边缘副本”、“异地容灾高可用”大量使用的技术方案。
现实应用场景
- 微服务多活:多个服务副本响应同一请求,优先拿到第一个并快速返回,极大降低99.99延迟。
- CDN/边缘计算:拉取数据时向多节点并发请求,客户端只拿第一个响应的内容。
- 多家供应商比价/辅助搜索聚合:哪个接口快就显示谁的内容。
使用context控制goroutine leak
这个简单写法确实会导致 goroutine 泄露(goroutine leak)的问题。
- 你发起了多个副本 goroutine,每个都会做完自己的“搜索”然后把结果写入同一个 channel
c
。 - 但
First
只从 channel 取第一个结果:return <-c
- 其它 goroutine 后续写入 channel 时,如果没人读,它们会永远阻塞在
c <- ...
这一行上——此时这些 goroutine 无法退出,即内存泄露。
func First(query string, replicas ...Search) Result
主流程一旦拿到第一个结果,cancel() 会通知其他所有 goroutine 退出。
复杂情况下可配合 context、WaitGroup 做到无资源泄露。
- https://www.concurrency.rocks/