Golang解决缓存miss后的刷新缓存带来的数据库读取压力
发布时间:2020-12-16 18:26:07 所属栏目:大数据 来源:网络整理
导读:工作中碰到缓存失败时,数据库的惊群,本来之前用Redis的SETNX来做锁处理,后来想想,既然用golang写了服务,当然可以把锁直接做在内存里,就自己写了一小段代码。 package resourceslockimport ("errors""sync")var (Lock resourcesLock = resourcesLock{lo
|
工作中碰到缓存失败时,数据库的惊群,本来之前用Redis的SETNX来做锁处理,后来想想,既然用golang写了服务,当然可以把锁直接做在内存里,就自己写了一小段代码。 package resourceslock
import (
"errors"
"sync"
)
var (
Lock resourcesLock = resourcesLock{
lockerMapMtx: new(sync.Mutex),lockerMap: make(map[ResourceTopic]chan void),topicWaitlistMtx: make(map[ResourceTopic]*sync.Mutex),topicWaitlist: make(map[ResourceTopic][]chan bool),} // universal lock
voidMsg void = void{}
)
type ResourceTopic string
type ProtectCondition func() bool
type ReloadFunc func() (interface{},error)
type void struct{}
type resourcesLock struct {
lockerMapMtx *sync.Mutex
topicWaitlistMtx map[ResourceTopic]*sync.Mutex
lockerMap map[ResourceTopic](chan void)
topicWaitlist map[ResourceTopic][](chan bool)
}
func (self *resourcesLock) Protect(topic ResourceTopic,cond *ProtectCondition,reload *ReloadFunc) error {
if (*cond)() == true {
return nil
}
var err error
self.createLockChn(topic)
select {
case <-self.lockerMap[topic]:
_,err = (*reload)()
if err != nil {
self.notifyError(topic)
} else {
self.notifySuccess(topic)
}
self.lockerMap[topic] <- voidMsg
default:
if !<-self.addToWaitlist(topic) {
err = errors.New("Resource is not refreshed.")
}
}
return err
}
func (self *resourcesLock) createLockChn(topic ResourceTopic) {
self.lockerMapMtx.Lock()
_,ok := self.lockerMap[topic]
if !ok {
ch := make(chan void,1)
ch <- voidMsg
self.lockerMap[topic] = ch
self.topicWaitlistMtx[topic] = new(sync.Mutex)
}
self.lockerMapMtx.Unlock()
}
func (self *resourcesLock) addToWaitlist(topic ResourceTopic) <-chan bool {
ch := make(chan bool)
self.topicWaitlistMtx[topic].Lock()
self.topicWaitlist[topic] = append(self.topicWaitlist[topic],ch)
self.topicWaitlistMtx[topic].Unlock()
return ch
}
func (self *resourcesLock) notifyError(topic ResourceTopic) {
self.notify(topic,false)
}
func (self *resourcesLock) notifySuccess(topic ResourceTopic) {
self.notify(topic,true)
}
func (self *resourcesLock) notify(topic ResourceTopic,suc bool) {
self.topicWaitlistMtx[topic].Lock()
for i,c := range self.topicWaitlist[topic] {
if suc {
c <- true
} else {
c <- false
}
self.topicWaitlist[topic][i] = nil
}
self.topicWaitlist[topic] = self.topicWaitlist[topic][:0]
self.topicWaitlistMtx[topic].Unlock()
} (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
