场景
高并发写多读少的场景下,对 map 的写需要加锁,急剧影响性能.
解决方案
方案1 | 单库变多库.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| package main
import ( "sync" )
type driverInfo struct { id int age int }
type company struct { lock []sync.RWMutex driver map[int]map[int]*driverInfo count int }
func newCompany(count int) *company { lock := make([]sync.RWMutex, count) driver := make(map[int]map[int]*driverInfo, count) for i := 0; i < count; i++ { lock[i] = sync.RWMutex{} driver[i] = make(map[int]*driverInfo) }
return &company{ lock: lock, count: count, driver: driver, } }
func (c *company) getDriver(id int) (derive *driverInfo) { i := id % c.count c.lock[i].RLock() defer c.lock[i].RUnlock() return c.driver[i][id] }
func (c *company) setDriver(driver *driverInfo) { i := driver.id % c.count c.lock[i].Lock() defer c.lock[i].Unlock() c.driver[i][driver.id] = driver }
|
方案 2 | 库变表
跟方案 1 类似,减小锁的粒度到字段.潜在的问题是当数据量过大的,锁需要占用大量内存.
方案 3 | 不加锁, 加签名校验数据的合法性
在并发场景下,对同一个值的修改,数据的完整性不能保证.对 key 的 val1,val2 的写入,可能写入val1 成功一半,val2 成功一半,即 val1 half+ val2 half.为了保证数据的正确性.可以在数据的末尾增加 crc32 校验,计算数据的签名.取出数据时,需要校验签名是否正确.签名不正确,直接丢弃,从数据库拉取.
参考链接