• golang使用pprof检查goroutine泄露


    有一段时间,我们的推送服务socket占用非常不正常,我们自己统计的同一时候在线就10w的用户,可是占用的socket居然达到30w,然后查看goroutine的数量,发现已经60w+。

    每一个用户占用一个socket,而一个socket,有read和write两个goroutine,简化的代码例如以下:

    c, _ := listerner.Accept()
    
    go c.run()
    
    func (c *conn) run() {
        go c.onWrite()
        c.onRead()
    }
    
    func (c *conn) onRead() {
        stat.AddConnCount(1)
    
        //on something
    
        stat.AddConnCount(-1)
    
        //clear
        //notify onWrite to quit
    }
    

    当时我就怀疑,用户同一时候在线的统计是正确的,也就是之后的clear阶段出现了问题,导致两个goroutine都无法正常结束。在检查代码之后,我们发现了一个可疑的地方,由于我们不光有自己的统计,还会将一些统计信息发送到我们公司的统计平台,代码例如以下:

    ch = make([]byte, 100000)
    func send(msg []byte) {
        ch <- msg
    }
    
    //在还有一个goroutine的地方,
    msg <- msg
    httpsend(msg)
    

    我们channel的缓存分配了10w,假设公司统计平台出现了问题,可能会导致channel堵塞。但究竟是不是这个原因呢?

    幸运的是,我们先前已经在代码里面内置了pprof的功能,通过pprof goroutine的信息,发现大量的goroutine的当前执行函数在httpsend里面,也就是说,公司的统计平台在大并发以下服务不可用,尽管我们有http超时的处理,可是由于发送的数据量太频繁,导致总体堵塞。

    暂时的解决的方法就是关闭了统计信息的发送,兴许我们会考虑将其发送到自己的mq上面,尽管也可能会出现mq服务不可用的问题,可是说句实话,比起自己实现的mq,公司的统计平台更让我不可信。

    这同一时候也给了我一个教训,訪问外部服务一定要好优点理外部服务不可用的情况,即使可用,也要考虑压力问题。

    对于pprof怎样查看了goroutine的问题,能够通过一个简单的样例说明:

    package main
    
    import (
        "net/http"
        "runtime/pprof"
    )
    
    var quit chan struct{} = make(chan struct{})
    
    func f() {
        <-quit
    }
    
    func handler(w http.ResponseWriter, r *http.Request) {
        w.Header().Set("Content-Type", "text/plain")
    
        p := pprof.Lookup("goroutine")
        p.WriteTo(w, 1)
    }
    
    func main() {
        for i := 0; i < 10000; i++ {
            go f()
        }
    
        http.HandleFunc("/", handler)
        http.ListenAndServe(":11181", nil)
    }
    

    这上面的样例中,我们启动了10000个goroutine,并堵塞,然后通过訪问http://localhost:11181/,我们就能够得到整个goroutine的信息,仅列出关键信息:

    goroutine profile: total 10004
    
    10000 @ 0x186f6 0x616b 0x6298 0x2033 0x188c0
    #   0x2033  main.f+0x33 /Users/siddontang/test/pprof.go:11
    

    能够看到,在main.f这个函数中,有10000个goroutine正在运行,符合我们的预期。

    在go里面,还有非常多执行时查看机制,能够非常方便的帮我们定位程序问题,不得不赞一下。

  • 相关阅读:
    String.Format使用方法
    在gfs2中关闭selinux
    开发板怎样开启telnet服务
    Google App Engine 学习和实践
    Ewebeditor最新漏洞及漏洞大全
    为HttpStatusCodeResult加入customErrors
    【android】下载文件至本应用程序的file文件夹或者sdcard
    java entry
    关闭对话框,OnClose和OnCancel
    主成分分析(PCA)
  • 原文地址:https://www.cnblogs.com/mfrbuaa/p/3914792.html
Copyright © 2020-2023  润新知