您好,欢迎来到12图资源库!分享精神,快乐你我!我们只是素材的搬运工!!
  • 首 页
  • 当前位置:首页 > 开发 > WEB开发 >
    几个Go系统能够遇到的锁成绩
    时间:2019-01-07 21:10 来源:网络整理 作者:网络 浏览:收藏 挑错 推荐 打印

    之前一致特征系统在 QA 同窗的协助下停止了一些压测,发现了一些成绩,这些成绩是较为通用的成绩,收回来给其他同窗参考一下,避免踩异样的坑。

    几个Go系统能够遇到的锁成绩

    底层依赖 sync.Pool 的场景

    有一些开源库,为了优化功用,运用了官方提供的 sync.Pool,比如我们运用的 https://github.com/valyala/fasttemplate 这个库,每当你执行下面这样的代码的时分:

    template := "{{host}}/?q={{query}}&foo={{bar}}{{bar}}" 

        t := fasttemplate.New(template, "{{""}}"

        s := t.ExecuteString(map[string]interface{}{ 

            "host":  "谷歌.com"

            "query": url.QueryEscape("hello=world"), 

            "bar":   "foobar"

        }) 

        fmt.Printf("%s", s) 

    外部都会生成一个 fasttemplate.Template 对象,并带有一个 byteBufferPool 字段:

    type Template struct { 

        template string 

        startTag string 

        endTag   string 

     

        texts          [][]byte 

        tags           []string 

        byteBufferPool bytebufferpool.Pool   ==== 就是这个字段 

    byteBufferPool 底层就是经过封装的 sync.Pool:

    type Pool struct { 

        calls       [steps]uint64 

        calibrating uint64 

     

        defaultSize uint64 

        maxSize     uint64 

     

        pool sync.Pool 

    这种设计会带来一个成绩,假设运用方每次央求都 New 一个 Template 对象。并停止求值,比如我们最后的用法,在每次拿到了用户的央求之后,都会用参数填入到模板:

    func fromTplToStr(tpl string, params map[string]interface{}) string { 

      tplVar := fasttemplate.New(tpl, `{{`, `}}`) 

      res := tplVar.ExecuteString(params) 

      return res 

    在模板求值的时分:

    func (t *Template) ExecuteFuncString(f TagFunc) string { 

        bb := t.byteBufferPool.Get() 

        if _, err := t.ExecuteFunc(bb, f); err != nil { 

            panic(fmt.Sprintf("unexpected error: %s", err)) 

        } 

        s := string(bb.Bytes()) 

        bb.Reset() 

        t.byteBufferPool.Put(bb) 

        return s 

    会对该 Template 对象的 byteBufferPool 停止 Get,在运用完之后,把 ByteBuffer Reset 再放回到对象池中。但成绩在于,我们的 Template 对象本身并没有停止复用,所以这里的 byteBufferPool 本身的作用其实并没有发扬出来。

    相反的,由于每一个央求都需求重生成一个 sync.Pool,在高并发场景下,执行时会卡在 bb := t.byteBufferPool.Get() 这一句上,经过压测可以比较快地发现成绩,到达一定 QPS 压力时,会有少量的 Goroutine 堆积,比如下面有 18910 个 G 堆积在抢锁代码上:

    goroutine profile: total 18910 

    18903 @ 0x102f20b 0x102f2b3 0x103fa4c 0x103f77d 0x10714df 0x1071d8f 0x1071d26 0x1071a5f 0x12feeb8 0x13005f0 0x13007c3 0x130107b 0x105c931 

    (责任编辑:admin)