AlexStocks opened a new issue, #3569:
URL: https://github.com/apache/dubbo-go/issues/3569
## 问题描述
`registry/servicediscovery/store/cache_manager.go` 中的 `CacheManager` 持有
`lock sync.Mutex`(L39),但**只在 `dumpCache`(L132)和 `StopDump`(L179)中加锁**。热路径 `Get`
/ `Set` / `Delete` / `GetAll`(L78–103)完全没有加锁:
```go
func (cm *CacheManager) Get(key string) (any, bool) { return
cm.cache.Get(key) } // 无锁
func (cm *CacheManager) Set(key string, value any) { cm.cache.Add(key,
value) } // 无锁
func (cm *CacheManager) Delete(key string) { cm.cache.Remove(key) }
// 无锁
func (cm *CacheManager) GetAll() map[string]any { ...
cm.cache.Keys()/Get() } // 无锁
```
底层缓存是 `github.com/hashicorp/golang-lru v0.5.4`(`go.mod`),该库**不是并发安全的**。而
`metaCache` 是包级全局变量,被所有 `ServiceInstancesChangedListenerImpl` 在消费端读取路径(如
`GetMetadataInfo`)并发访问;同时 `runDumpTask` 的定时 goroutine 也直接读写 `cm.cache`。`lock`
字段对 `Get/Set/Delete/GetAll` 实际无效,是死代码。
## 影响
高并发下(多 consumer 并发订阅同一 app 的实例变更)会出现真实的 **data race**:LRU
双向链表被并发修改,可能返回脏缓存甚至 panic。`go test -race` 可复现。
## 建议修复
- 方案 A(推荐):将 `hashicorp/golang-lru` 升级到
`github.com/hashicorp/golang-lru/v2`,使用 `lru.NewSynced(maxCacheSize)`。
- 方案 B:保留 v0.5.4,但在 `Get/Set/Delete/GetAll` 中也加同一把 `lock`,并确保
`dumpCache`/`loadCache` 对 `cm.cache` 的访问都走加锁路径。
## 参考
- `registry/servicediscovery/store/cache_manager.go` L33–41, L78–103,
L129–155
- 全局变量
`metaCache`:`registry/servicediscovery/service_instances_changed_listener_impl.go`
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]