前言

go-zero 群里常常有同学问:

服务监控是通过什么算法实现的?

滑动窗口是怎么工作的?是否讲讲这块的原理?

熔断算法是怎么设计的?为啥没有半开半闭状态呢?

go-zero

指标怎么统计

breaker
type googleBreaker struct {
  k     float64
  stat  *collection.RollingWindow
  proba *mathx.Proba
}
go-zerobreaker
breaker
func (b *googleBreaker) doReq(req func() error, fallback func(err error) error, acceptable Acceptable) error {
  ...
  // 执行理论申请函数
  err := req()
  if acceptable(err) {
    // 理论执行:b.stat.Add(1)
    // 也就是说:外部指标统计胜利+1
    b.markSuccess()
  } else {
    // 原理同上
    b.markFailure()
  }

  return err
}

所以其实底层说白了就是:申请执行结束,会依据谬误产生次数,外部的统计数据结构会相应地加上统计值(可正可负)。同时随着工夫迁徙,统计值也须要随工夫进化。

简略来说:工夫序列内存数据库【也没数据库这么猛,就是一个存储,只是一个内存版的】

上面就来说说这个工夫序列用什么数据结构组织的。

滑动窗口

rollingwindow
type RollingWindow struct {
    lock          sync.RWMutex
    size          int
    win           *window
    interval      time.Duration
    offset        int
    ignoreCurrent bool
    lastTime      time.Duration
  }
window
rollingwindow
SumCountbreakeracceptstotal

滑动是怎么产生的

breakerbucketbucket
Bucket
bucketbucket
bucketbucketbucket
rollingwindowbucket
breakerb.stat.Add(1)
func (rw *RollingWindow) Add(v float64) {
  rw.lock.Lock()
  defer rw.lock.Unlock()
  // 滑动的动作产生在此
  rw.updateOffset()
  rw.win.add(rw.offset, v)
}

func (rw *RollingWindow) updateOffset() {
  span := rw.span()
  if span <= 0 {
    return
  }

  offset := rw.offset
  // 重置过期的 bucket
  for i := 0; i < span; i++ {
    rw.win.resetBucket((offset + i + 1) % rw.size)
  }

  rw.offset = (offset + span) % rw.size
  now := timex.Now()
  // 更新工夫
  rw.lastTime = now - (now-rw.lastTime)%rw.interval
}

func (w *window) add(offset int, v float64) {
  // 往执行的 bucket 退出指定的指标
  w.buckets[offset%w.size].add(v)
}
Add(delta)bucket
updateOffsetbucketbucketbucketbucket intervalbucketresetoffsetbucketlastTimeoffsetbucket
bucket
bucketlastTimebuckettimex.Since(rw.lastTime) / rw.interval

Add()lastTimenowTime

总结

go-zerorollingWindowstore/redis

滑动窗口实用于流控中对指标进行计算,同时也能够做到控流。

go-zero

我的项目地址

https://github.com/tal-tech/go-zero

欢送应用 go-zero 并 star 反对咱们!

微信交换群

关注『微服务实际』公众号并点击 交换群 获取社区群二维码。

go-zero 系列文章见『微服务实际』公众号