javaee论坛

普通会员

225648

帖子

338

回复

352

积分

楼主
发表于 2019-11-01 17:09:04 | 查看: 133 | 回复: 2

参与开发的系统对外部部分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更新策略参考


普通会员

0

帖子

311

回复

326

积分
沙发
发表于 2019-11-05 16:42:30

我喜欢

普通会员

0

帖子

257

回复

259

积分
板凳
发表于 2024-04-17 15:51:17

我喜欢

您需要登录后才可以回帖 登录 | 立即注册

触屏版| 电脑版

技术支持 历史网 V2.0 © 2016-2017