加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

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()
}

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读