关于falcon-graph内存调试 - Tinsley's blog

/ 0评 / 0

graph组件由于大量与数据打交道(内存磁盘使用大户), 而且使用了我不怎么熟悉的rrdtool, 一直属于open-falcon后端中不怎么让人省心的一部分. 这里分享一些调试心得.

由EBS引发的内存问题

之前遇到过好几次内存突增, 后查明原因是AWS的EBS磁盘突发余额(Burst Balance)耗尽, IO骤降至基准性能导致内存中的数据点无法按正常速度落盘, 从而积压在内存中, 内存占用急剧上涨. 可以通过观察AWS控制台中EBS突发余额(Burst Balance), 读写延迟(Average Read/Write Latency), 空闲花费时间(Average Write Latency), 平均队列长度(Average Write Latency)等metric来定位该问题.

对于上述情况, 最简单的解决办法是扩容EBS磁盘提升IOPS. 如果是io1类型, 可直接调大IOPS数值; 如果是gp2类型的EBS, 由于IOPS与磁盘容量成正比:

1GB -> 3IOPS

所以直接适量调大EBS容量即可.

另外从几次扩容的经验来看, 扩容EBS磁盘这一操作应该会重置突发余额为最大可用值, 可以迅速摆脱因相当有限的基准IO性能导致的内存积压情况, 效果不错.

但是这样做也不是没有缺点. 在此种情况的扩容操作中, 扩充EBS容量花费的成本, 实际上大部分是用来购买"重置突发余额为最大值", 小部分用来购买"多一丢丢的IOPS性能", 真正表面上买到的磁盘容量, 反而是作用最小的. 而动态扩充EBS容量这一操作不可逆, 即我们没有办法动态缩减EBS容量. 所以从成本上考虑, 这样的操作是否划算见仁见智, 如果能把这部分磁盘容量利用起来, 那自然最好.


引入pprof分析graph内存

前几日又碰上graph内存上涨, 不同的是, 这次不是内存突增, 而是缓慢上涨到了95%, 由于增长趋势不太符合业务上涨情况, 所以先排除这个原因.

想用上面相同的办法来定位问题, 发现EBS表现正常, 突发余额也是够用的, 但还是报着侥幸心理扩容了磁盘, 结果当然是并没有解决问题. 接着是从程序本身找答案.

由于之前确实没有分析go程序内存的经验, 甚至想直接上主机dump一份内存下来. 之后了解了go官方的pprof工具, 发现这东西必须得先引入到代码中开放接口, 才能用web或者cli来访问服务监听http端口的/debug/pprof路径来分析内存.

看了下graph的源码, 确实在代码中引入了net/http/pprof, 但是由于其使用了gin作为http框架, 由框架接管所有的路由, 所以/debug/pprof这个path的路由并没有生效. 想要在gin中使用pprof, 需要引入https://github.com/gin-contrib/pprof这个包才行.

接下来就是连环踩坑流程:

上述环境问题全部解决之后, 在modules/graph/http/http.go文件中, import部分注释掉原本的"net/http/pprof", 加上"github.com/gin-contrib/pprof":

import (
        "encoding/json"
        "fmt"
        log "github.com/Sirupsen/logrus"
        "net"
        "net/http"
        //_ "net/http/pprof"   注释掉这一行
        "time"

        "github.com/gin-contrib/pprof"  //加上这一行
        "github.com/gin-gonic/gin"
        "github.com/open-falcon/falcon-plus/modules/graph/g"
        "github.com/open-falcon/falcon-plus/modules/graph/rrdtool"
)

然后在init()函数中添加pprof注册:

func init() {
        router = gin.Default()
        pprof.Register(router)   //加上这一行
        configCommonRoutes()
        configProcRoutes()
        configIndexRoutes()
        Close_chan = make(chan int, 1)
        Close_done_chan = make(chan int, 1)
}

现在运行重新编译过的graph, 日志中可以发现增加了debug相关的api:

之后就可以使用pprof分析内存了.

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注