Golang解决缓存miss后的刷新缓存带来的数据库读取压力

前端之家收集整理的这篇文章主要介绍了Golang解决缓存miss后的刷新缓存带来的数据库读取压力前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

工作中碰到缓存失败时,数据库的惊群,本来之前用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()
}
原文链接:https://www.f2er.com/go/189320.html

猜你在找的Go相关文章