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