缓存的使用(2)

在rpc框架中,kitc客户端中需要对访问的服务IP进行缓存与更新,本章谈一谈kitc对服务信息的缓存与更新机制。
kitc获取服务信息是通过请求的方式向 consul服务来获取特定服务的IP地址,为了避免kitc在启动时对同一个Key并发地访问,这里引入一个结构来对重复函数调用进行限制:

type call struct {
	wg sync.WaitGroup
	val interface{}
	err error
}

type Group struct {
	mu sync.Mutex
	m map[string]*call
}

func (g *Group) Do(key string, fn func() (interface{}, error) {
	g.mu.lock()
	if g.m == nil {
	....
	}
	if c, ok := g.m[key]; ok {
		g.mu.Unlock()
		c.Wg.Wait()
		return c.val, c,.err
	}
	c := new(call)
	c.wg.Add(1)
	g.m[key] = c 
	g.mu.Unlock()
	c.val, c.err = fn()
	c.wg.Done()
	g.mu.Lock()
	delete(g.m, key)
	g.mu.Unlock()
}

对信息进行缓存的结构如下:

type Asyncache struct {
	sfg *Group
	opt *Options
	data sync.Map
	exit chan struct{}
}
type Options struct {
	BlockFirest bool
	RefreshDuration time.Duration
	Fetcher func(key string) ( interface{}, error)
	ErrorHandler func(key string, err error)
	ChangeHandler func(key string, oldData, newData interface{})
	IsSame func(key string, oldDate, newData interface{}) bool
}

当生成一个Asyncache的时候,就会同时生成一个协程执行对应的更新函数

func ( c *Asyncache) refresher() {
	ch := time.Tick(c.opt.RefreshDuration)
	for {
		select {
			case <- c.exit:
				return
			case <- ch:
				c.Refresh()
		}
	}
}
func (c *Asynccache) refresh() {
	oldDate := c.Dump()
	for key, oldVal := range oldDate {
		newVal, err := c.opt.Fetcher(key)
		if err != nil {
			c.opt.ErrHandler(key, err)
			continue
		}
		if c.opt.IsSame != nil && !c.opt.IsSame(key, oldVal, newVal) {
			if c.opt.ChangeHandler != nil {
				go c.opt.ChangeHandler(key, oldVal, newVal)
			}
		}
		c.data.Store(key, newVal)
	}
}

重要的get函数:

func (c *AsyncCache) Get(key string, defaultVal interface{}) interface{} {
	val, ok := c.data.load(key)
	if ok {
		return val
	}
	if !c.opt.BlockFirst {
		c.data.Stroe(key, defaultVal)
		return defaultVal
	}
	// 避免启动时,对一个key进行大量的并发请求
	val, err := c.sfg.Do(key, func()(interface{], error) {
		return c.opt.Fetcher(key)
	})
	if err != nil { ......}
	c.data.Store(key, val)
	return val
}

kitc 的服务发现使用了一种消息传播结构体,对系统内的消息进行注册与执行:

type Handler func(event *KitEvent)
// 标示kitc内部一些自动化触发的事件
type KitEvent struct {
	Name string
	time Time
	Detail string
	Extra map[string]interface{}
}
type EventBus interface{
	Watch(event string, handler Handler)
	UnWatch(evnet string, handler Handler)
	Dispatch(event *KitEvent)
}
type eventBus struct {
	callBacks sync.Map
}
func (c *evenBus) Watch(event string, handler Handler) {
	var handlers []Handler
	if actual, ok := c.callBacks.Load(event); ok {
		handlers = actual.([]Handler)
	}
	handlers = append(handlers, handler)
	s.callBacks.Store(event, handlers)
}
func ( c *EventBus) Dispatch(event *KitcEvent) {
	if acutal, ok := c.callBacks.Load(event); ok {
		for _, h := range actual.([]Handler) {
			go h(event)
		}
	}
}

kitc 的服务发现中对服务信息进行缓存:

type KitcDiscover struct {
	eventBus KitEvent.EventBus
	discover discovery.ServiceDiscover
	cache *cache.Asyncache
	policy *discvery.DiscoversyPolicy
}

KitcDiscver 实现了Options中的Fetcher等函数,这些函数设定了缓存Asyncache的行为:

func (c *KitcDiscover) fetch(key string) (interface{}, error) {
	tmp := string.Split(key, ":")
	if len(tem) != 4 {...}
	service, idc, cluster, env := tmp[0],tmp[1],tmp[2],tmp[3]
	ins, err := c.discover.Discover(service, idc)
	if err != nil {...}
	filtered := c.policy.Filter(ins, cluster, env)
	......
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值