cuncurrent-map优化共享map内存问题

api gateway主体逻辑load etcd中的config到内存中,配置被应用到处理各backend service抽离出来的逻辑中。配置大多是全局的map,涉及到频繁的get操作和偶尔的set操作。因为是共享内存,所以一定要是threadsafe的。
threadsafe的原因可以参考: go内存模型 中的描述

首先想到的是利用读写锁sync.RWMutex,控制整个config struct,处理request时RLock,处理修改config时Lock,config的loader在设计时,考虑到尽量减小每次修改内存的影响范围,所以是区分api、client等对象进行更新的。但是上到测试环境的时候发现,在有比较大量的请求时,如果后台触发reload整体配置,读写锁会相互影响,大量读导致获取写锁很慢,在写时,又会累积大量的请求,在写锁释放时同时invoke,为了防止将来在线上出现极端情况,决定还是要优化一下。

本来看到traefik中safe.go中代码,想直接因为,并且针对map封装一下即可,后续读traefik的server.go时发现他用了一个叫 concurrent-map 的第三方库,所以读了一下这个库的代码,该库做了意见和innodb行锁相似的事,把整个map根据key分片,针对每个分片构建读写锁。如果当前服务涉及到大量的并发读,且量比较大的写,那么shard lock能有效的缓解这种情况。

就当前服务而言,map中key可能只有几百个,那么是否分片可能效果就不那么明显了。因为shard引入的hash性能损耗,和shard带来的性能优化涉及到权衡问题,这个只能根据当前map规模和使用场景进行benchmark测试了。

map相关文档:
https://blog.golang.org/go-maps-in-action
https://golang.org/doc/faq#atomic_maps

cuncurrent-map优化共享map内存问题
Share this