Bound Gateway cache lifetime and capacity - #516
Conversation
|
PR Title: Bound Gateway cache lifetime and capacity Commit: 本变更在 Gateway 中为 整体方向正确(此前缓存无界且实例失效不清缓存)。但实现存在几个值得关注的点:(1) 每次 |
| } | ||
| cacheKey := mcpToolsCacheKey(capsetID, items) | ||
| g.mu.Lock() | ||
| g.evictExpiredCachesLocked(time.Now()) |
There was a problem hiding this comment.
每次缓存访问都在全局锁下全量扫描缓存做过期淘汰,热路径由 O(1) 退化为 O(n)
mcpTools(887 行)与 connectHandler(1268 行)在每次调用、持有全局 g.mu 时都执行 evictExpiredCachesLocked,该函数会完整遍历 mcpCacheAt 与 connectCacheAt 两张 map(每张最多 gatewayCacheMaxEntries=1024 项)。即使缓存全部命中、没有任何过期项,每次请求也要做最多约 2048 次时间比较并串行化在全局互斥锁内。改动前热路径只是 O(1) 的 map 读取;改动后所有网关请求在全局锁下承担 O(cache) 的清扫成本,高 QPS 下会放大锁竞争与请求延迟,且该成本与缓存命中与否无关。
Problem code:
Changed code at internal/protocol/gateway.go:887
Recommendation:
将过期淘汰从每次访问的全量 O(n) 扫描改为摊销/懒淘汰:读取时只检查目标 cacheKey 自身的过期时间,命中即返回;仅在写入新条目或周期性(每 N 次访问/后台定时器)时才做全量清扫。若保留全量扫描,至少将其移出读路径。
|
PR Title: Bound Gateway cache lifetime and capacity Commit: 本次变更优化了 Gateway 的 schema/handler 缓存淘汰策略,并修复了此前 prune 路径可能死循环的缺陷。 改动要点:
总体评估:本次改动针对性地解决了两个历史高风险问题(热路径 O(n) 扫描、prune 死循环)。经核查,gateway.go 内 mcpToolsCache/connectCache 的全部读写点均在 mcpTools/connectHandler 内且于同一把 g.mu 下成对维护,读路径定向淘汰保证了任何 key 都不会被命中返回过期值,未发现新的高置信正确性/并发/安全/回归缺陷。历史问题 InvalidateInstance 清空全量缓存导致的跨实例缓存雪崩不在本次 diff 范围内,维持原样。无新增可操作发现。 |
|
Follow-up fixes after performance/reliability review:
Verification: targeted Gateway cache tests pass. |
问题
Gateway 的 MCP Tool、Connect Handler 缓存按版本 key 累积,缺少容量和生命周期限制;实例失效时也没有清除 schema/handler 缓存。
影响
服务反复导入、descriptor 变化或暴露配置变化时,旧 handler、schema 和 descriptor 关联对象会长期驻留,造成可持续的内存增长。
修复内容
验证
go test ./internal/protocol -run 'TestGatewayCacheEntriesExpireAndInvalidateTogether|TestGatewayInstanceInvalidationClearsSchemaCaches'通过。