TiDB 多 Socket 服务器性能扩展问题分析 - 续
作者: Hacker_URrvEGHH 原文来源:https://tidb.net/blog/fcbee15e
【是否原创】是
【首发渠道】TiDB 社区
【首发渠道链接】
【正文】
在上一篇 TiDB 多 Socket 服务器性能扩展问题分析中提到,我们通过 Perf C2C 工具分析,认为这个问题很可能是由于 CPU Cache line 的 false share 造成的。 并定位到对同一 cache line 上不同数据的读写冲突的函数分别是:
runtime.heapBitsSetType
runtime.(*mspan).sweep
runtime.sweepone
runtime.(*mheap).reclaim
但由于 Perf C2C 工具并不支持关联到 Go 代码的位置,因此我们还无法定位到发生冲突的对应的结构、变量定义。
最近,在工作中我们发现英特尔的性能分析神器vtune是可以支持 go 应用的。我们就使用 vtune 工具来进一步分析这个问题。我们首先使用 vtune 的 hotspot 分析功能来对 TiDB 进行的 profiling。和之前 Perf 的结果略有区别,vTune 给出最热点的函数是 runtime.heapBitsForAddr,占比 23.4%。不过由于这个函数是被 runtime.heapBitsSetType 调用的,所以算在 runtime.heapBitsSetType 中也没问题。热点函数如下面这张图所示:
点击 runtime.heapBitsForAddr,就可以关联到该函数对应的 go 源代码。特别强大的是,我们还能关联到这个函数对应的汇编代码。就像这张图:
由于在上一篇的分析中,我们借助 perf c2c 工具已经可以找到发生 HITM 时的代码地址。比如对 runtime.heapBitsSetType 函数来说,代码地址是 0x10d786a。利用 vtune 的汇编代码视图,我们根据这个代码地址,就可以找到对应的汇编代码位置。比如,对于 0x10d786a 地址来说,就对应这样一条汇编指令。
在我们找到这条汇编指令后,vtune 能够帮助我们找到这条汇编指令对应的 go 源代码,就是下面这行代码。
通过这个方法,我们可以分别找到:
runtime.(*mspan).sweep 函数中的代码是:
“atomic.Xadd64(&mheap_.pagesSwept, int64(s.npages))”,
runtime.sweepone 函数对应的代码是
“atomic.Xadduintptr(&mheap_.reclaimCredit, npages)”,runtime.
(*mheap).relcaim 函数对应的代码是
“if atomic.Casuintptr(&h.reclaimCredit, credit, credit-take) {”。
用这个办法,我们可以很容易地确定 cache line 假共享和 mheap 结构中的 pagesSwept、reclaimCredit 以及 arenas 变量有关。如果,假设 pagesSwept 在 cache line 中的 offset 是 0x00 的话,则 reclaimCredit 位于 0x30,arenas 位于 0x38。这刚好和上一篇中,Perf c2c 工具输出发生 HITM 的 cache line 上的偏移对应。
到这里,我们比较确定地找到了 TiDB 在 2 路服务器上性能下降的根源在于 Go 中 mheap 结构的定义方式。一般解决 cache line 假共享问题的方法是在出现假共享的变量间增加一些 padding,或改变变量的定义顺序,使发生冲突的变量分配到不同的 Cache line 上。
由于这个问题的根源是出现在 go runtime 中,我们向 go 社区提交了一个 issuehttps://github.com/golang/go/issues/47831。让我们拭目以待这个问题的最终解决,以及 TiDB 最终能在 2 路的环境上获得多少的性能提升。
版权声明: 本文为 InfoQ 作者【TiDB 社区干货传送门】的原创文章。
原文链接:【http://xie.infoq.cn/article/ebbed82f8518c83f95c051807】。文章转载请联系作者。
评论