参与开发的系统对外部部分API请求需要进行一个鉴权,而鉴权过程中需要利用公钥拿到用户的账户信息,从而利用账户信息中的私钥对请求签名进行一个验证。
为了避免大量请求对account服务(用户账户信息服务)进行轮询,系统对账户信息利用LRU进行了缓存,这样可以做到:1控制缓存数量,2提高命中率。对LRU的更新,会获取所有的键,然后新建LRU,替换原有的LRU。考虑到account服务长时间不可用的情况,需要LRU有降级策略,只有当用于更新的LRU创建成功(即利用所有key访问account服务成功率大于设定值)才会进行替换更新。
LRU的实现:
typeCachestruct{MaxEntriesint//最大缓存数目//当key被从缓存中清除时所执行的回调函数OnEvictedfunc(keyCacheKey,valueinterface{})lllist.ListcacheMap[interface{}]*list.Element}tyepCacheKeyinterface{}typeentrystruct{keyCacheKeyvalueinterface{}}
重要方法实现:Add:
func(c*Cache)Add(keyCacheKey,valueinterface{}){ifc.cache==nil{c.cache=make(map[interface{}]*list.Element)c.ll=list.New()}ifee,ok:=c.cache[key];ok{c.ll.MoveToFront(ee)ee.Value.(*entry).value=valuereturn}ele:=c.ll.PushFront(&entry{key,value})c.cache[key]=eleifc.MaxEntries!=0&&c.ll.Len()>c.MaxEntries{c.MoveOldest()}}
Get:
func(c*Cache)Get(keyCacheKey)(valueinterface{},okbool){ifc.cache==nil{return}ifele,ok:=c.cache[key];ok{c.ll.MoveToFront(ele)returnele.value.(*entry).value,true}return}
RemoveOldest:
func(c*Cache)removeOldest(){ifc.cache==nil{return}ele:=c.ll.Back()ifele!=nil{c.RemoveElement(ele)}}func(c*Cache)removeElement(ee*list.Element){c.ll.Remove(ee)kv:=e.Value.(*entry)delete(c.cache,kv.key)ifc.OnEvicted!=nil{c.OnEvicted(kv.key,kv.value)}}
利用LRU构建账户缓存
typeDoubleBufferKeyInfo{lru*Cachecli*account.Client//账户服务的代理sync.RWMutex}func(dbk*DoubleBufferKeyInfo)Get(akString)*KeyInfo{dbk.Lock()v,ok:=dbk.lru.Get(ak)dbk.UnLock()ifok{returnv.(KeyInfo)}ctx:=context.Background()account,err:=dbk.cli.GetAccount(ctx,ak)iferr!=nil{......}extra:=make(map[string]interface{})iferr:=json.Unmarshal([]byte(account.Extra,&extra);err!=nil{......}keyInfo:=&KeyInfo{SecretKey:account.SecretKeyExtra:extra}dbk.Lock()dbk.lru.Add(ak,keyInfo)dbk.UnLock()returnkeyInfo}
构建鉴权认证中心:
typeAuthCenterstruct{keyInfors*DoubleBufferKeyInfoverifyFunsmap[string]VerifyFunc}
对缓存进行更新
funcInitAuthCenter(config*util.AuthCenterConfig)(*AuthCenter,error){center.KeyInfos=NewKeyInfoCache(....)//对缓存进行更新gofunc(){//为了避免我们系统所有服务(系统会有多个实例,部署在不同的数据中心)会在同一时间对账户系统//服务进行访问rand.Seed(int64(time.Now().NanoSecond()))interval:=time.Duration(rand.IntN(60)*time.Second+config.TimeInterval)ticker:=time.Ticker(interval)forrangeticker{keys:=center.keyInfors.GetAllKeys()ifnext_lru,ok:=updateKeyInfo(keys,config);err!=nil{......}else{center.keyInfos.Update(next_lru)}}}}funcupdateKeyInfo(key[]CacheKey,conf*util.AuthCenterConfig)(*Cache,error){//对所有key通过账户服务获取账户信息,统计访问成功率,当成功率大于设定值,生成新的LRU.......}二cache
cache更新策略参考