DEV Community 中文 关注 Go 中的 singleflight:在高负载下合并重复工作 缓存雪崩发生在缓存过期时,大量请求同时未命中,导致重复执行昂贵操作。Go 的 golang.org/x/sync/singleflight 包通过确保针对给定键仅执行一次函数来解决此问题。并发调用者若使用相同键,将等待并从该单次执行中获取结果。Do 方法接收一个键和一个函数,仅对第一个调用者执行该函数;后续调用者会阻塞直至函数完成,然后共享其结果。shared 布尔值指示结果是否已分发给多个调用者,可用于指标统计。Singleflight 本身并非缓存;它仅在调用时间重叠时合并请求。典型模式包括:先检查缓存,若未命中则使用 group.Do,最后将结果写回缓存。一个关键注意事项是返回值是共享的,因此可变类型(如指针、切片和映射)若被多个 goroutine 修改,可能导致数据竞争。为避免此问题,应将返回值视为不可变,或返回副本供调用者独立拥有和修改。对于非阻塞行为,DoChan 返回一个 channel,允许调用者响应上下文取消。然而,函数运行在第一个调用者的上下文中,因此对于共享操作,建议将工作从特定请求的上下文中解耦。Forget 方法可用于清除键,使后续调用能够启动新的执行,这有助于限制失败操作的传播范围。Singleflight 应置于重复工作代价高昂的边界处,例如缓存加载或缓慢的上游调用,而非领域逻辑内部。两个主要陷阱是共享值和第一个调用者的上下文。 singleflight in Go: Collapsing Duplicate Work Under Load dev.to DEV Community 中文 RSS thenote.app
golang.org/x/sync/singleflight包通过确保针对给定键仅执行一次函数来解决此问题。并发调用者若使用相同键,将等待并从该单次执行中获取结果。Do方法接收一个键和一个函数,仅对第一个调用者执行该函数;后续调用者会阻塞直至函数完成,然后共享其结果。shared布尔值指示结果是否已分发给多个调用者,可用于指标统计。Singleflight 本身并非缓存;它仅在调用时间重叠时合并请求。典型模式包括:先检查缓存,若未命中则使用group.Do,最后将结果写回缓存。一个关键注意事项是返回值是共享的,因此可变类型(如指针、切片和映射)若被多个 goroutine 修改,可能导致数据竞争。为避免此问题,应将返回值视为不可变,或返回副本供调用者独立拥有和修改。对于非阻塞行为,DoChan返回一个 channel,允许调用者响应上下文取消。然而,函数运行在第一个调用者的上下文中,因此对于共享操作,建议将工作从特定请求的上下文中解耦。Forget方法可用于清除键,使后续调用能够启动新的执行,这有助于限制失败操作的传播范围。Singleflight 应置于重复工作代价高昂的边界处,例如缓存加载或缓慢的上游调用,而非领域逻辑内部。两个主要陷阱是共享值和第一个调用者的上下文。