如何利用golang自带的profile工具进行应用程序的性能调优,前一段时间我做的日志分析系统在线上遇到了一个问题,就是分任务的系统down机了,日志处理延迟了10几个小时,这个时候任务分发系统重启之后开始分发任务,但是一下子就承受了十几个并发任务,导致内存消耗过快,直接吃掉了16G的内存,这可急坏了我啊。所以赶紧开始做性能优化。

性能优化我主要从以下几个方面进行了测试和调优:

  • CPU Profiling
  • Mem Profiling
  • GC & HEAP

我采用了如下的profile工具代码:

package main

import (

"fmt"

"log"

"os"

"runtime"

"runtime/debug"

"runtime/pprof"

"strconv"

"sync/atomic"

"syscall"

"time"

)

var heapProfileCounter int32

var startTime = time.Now()

var pid int

func init() {

pid = os.Getpid()

}

func StartCPUProfile() {

f, err := os.Create("cpu-" + strconv.Itoa(pid) + ".pprof")

if err != nil {

log.Fatal(err)

}

pprof.StartCPUProfile(f)

}

func StopCPUProfile() {

pprof.StopCPUProfile()

}

func StartBlockProfile(rate int) {

runtime.SetBlockProfileRate(rate)

}

func StopBlockProfile() {

filename := "block-" + strconv.Itoa(pid) + ".pprof"

f, err := os.Create(filename)

if err != nil {

log.Fatal(err)

}

if err = pprof.Lookup("block").WriteTo(f, 0); err != nil {

log.Fatalf(" can't write %s: %s", filename, err)

}

f.Close()

}

func SetMemProfileRate(rate int) {

runtime.MemProfileRate = rate

}

func GC() {

runtime.GC()

}

func DumpHeap() {

filename := "heap-" + strconv.Itoa(pid) + "-" + strconv.Itoa(int(atomic.AddInt32(&heapProfileCounter, 1))) + ".pprof"

f, err := os.Create(filename)

if err != nil {

fmt.Fprintf(os.Stderr, "testing: %s", err)

return

}

if err = pprof.WriteHeapProfile(f); err != nil {

fmt.Fprintf(os.Stderr, "testing: can't write %s: %s", filename, err)

}

f.Close()

}

func showSystemStat(interval time.Duration, count int) {

usage1 := &syscall.Rusage{}

var lastUtime int64

var lastStime int64

counter := 0

for {

//http://man7.org/linux/man-pages/man3/vtimes.3.html

syscall.Getrusage(syscall.RUSAGE_SELF, usage1)

utime := usage1.Utime.Sec*1000000000 + usage1.Utime.Usec

stime := usage1.Stime.Sec*1000000000 + usage1.Stime.Usec

userCPUUtil := float64(utime-lastUtime) * 100 / float64(interval)

sysCPUUtil := float64(stime-lastStime) * 100 / float64(interval)

memUtil := usage1.Maxrss * 1024

lastUtime = utime

lastStime = stime

if counter > 0 {

fmt.Printf("cpu: %3.2f%% us  %3.2f%% sy, mem:%s \n", userCPUUtil, sysCPUUtil, toH(uint64(memUtil)))

}

counter += 1

if count >= 1 && count < counter {

return

}

time.Sleep(interval)

}

}

func ShowSystemStat(seconds int) {

go func() {

interval := time.Duration(seconds) * time.Second

showSystemStat(interval, 0)

}()

}

func PrintSystemStats() {

interval := time.Duration(1) * time.Second

showSystemStat(interval, 1)

}

func ShowGCStat() {

go func() {

var numGC int64

interval := time.Duration(100) * time.Millisecond

gcstats := &debug.GCStats{PauseQuantiles: make([]time.Duration, 100)}

memStats := &runtime.MemStats{}

for {

debug.ReadGCStats(gcstats)

if gcstats.NumGC > numGC {

runtime.ReadMemStats(memStats)

printGC(memStats, gcstats)

numGC = gcstats.NumGC

}

time.Sleep(interval)

}

}()

}

func PrintGCSummary() {

memStats := &runtime.MemStats{}

runtime.ReadMemStats(memStats)

gcstats := &debug.GCStats{PauseQuantiles: make([]time.Duration, 100)}

debug.ReadGCStats(gcstats)

printGC(memStats, gcstats)

}

func printGC(memStats *runtime.MemStats, gcstats *debug.GCStats) {

if gcstats.NumGC > 0 {

lastPause := gcstats.Pause[0]

elapsed := time.Now().Sub(startTime)

overhead := float64(gcstats.PauseTotal) / float64(elapsed) * 100

allocatedRate := float64(memStats.TotalAlloc) / elapsed.Seconds()

fmt.Printf("NumGC:%d Pause:%s Pause(Avg):%s Overhead:%3.2f%% Alloc:%s Sys:%s Alloc(Rate):%s/s Histogram:%s %s %s \n",

gcstats.NumGC,

toS(lastPause),

toS(avg(gcstats.Pause)),

overhead,

toH(memStats.Alloc),

toH(memStats.Sys),

toH(uint64(allocatedRate)),

toS(gcstats.PauseQuantiles[94]),

toS(gcstats.PauseQuantiles[98]),

toS(gcstats.PauseQuantiles[99]))

} else {

// while GC has disabled

elapsed := time.Now().Sub(startTime)

allocatedRate := float64(memStats.TotalAlloc) / elapsed.Seconds()

fmt.Printf("Alloc:%s Sys:%s Alloc(Rate):%s/s\n",

toH(memStats.Alloc),

toH(memStats.Sys),

toH(uint64(allocatedRate)))

}

}

func avg(items []time.Duration) time.Duration {

var sum time.Duration

for _, item := range items {

sum += item

}

return time.Duration(int64(sum) / int64(len(items)))

}

// human readable format

func toH(bytes uint64) string {

switch {

case bytes < 1024:

return fmt.Sprintf("�", bytes)

case bytes < 1024*1024:

return fmt.Sprintf("%.2fK", float64(bytes)/1024)

case bytes < 1024*1024*1024:

return fmt.Sprintf("%.2fM", float64(bytes)/1024/1024)

default:

return fmt.Sprintf("%.2fG", float64(bytes)/1024/1024/1024)

}

}

// short string format

func toS(d time.Duration) string {

u := uint64(d)

if u < uint64(time.Second) {

switch {

case u == 0:

return "0"

case u < uint64(time.Microsecond):

return fmt.Sprintf("%.2fns", float64(u))

case u < uint64(time.Millisecond):

return fmt.Sprintf("%.2fus", float64(u)/1000)

default:

return fmt.Sprintf("%.2fms", float64(u)/1000/1000)

}

} else {

switch {

case u < uint64(time.Minute):

return fmt.Sprintf("%.2fs", float64(u)/1000/1000/1000)

case u < uint64(time.Hour):

return fmt.Sprintf("%.2fm", float64(u)/1000/1000/1000/60)

default:

return fmt.Sprintf("%.2fh", float64(u)/1000/1000/1000/60/60)

}

}

}

Golang性能调优入门的更多相关文章

  1. golang 性能调优分析工具 pprof(下)

    golang 性能调优分析工具 pprof(上)篇, 这是下篇. 四.net/http/pprof 4.1 代码例子 1 go version go1.13.9 把上面的程序例子稍微改动下,命名为 d ...

  2. golang 性能调优分析工具 pprof (上)

    一.golang 程序性能调优 在 golang 程序中,有哪些内容需要调试优化? 一般常规内容: cpu:程序对cpu的使用情况 - 使用时长,占比等 内存:程序对cpu的使用情况 - 使用时长,占 ...

  3. JVM性能调优入门

    1. 背景 虽然大多数应用程序使用JVM的默认设置就能很好地工作,仍然有不少应用程序需要对JVM进行额外的配置才能达到其期望的性能要求. 现在JVM为了满足各种应用的需要,为程序运行提供了大量的JVM ...

  4. 【GoLang】golang垃圾回收 & 性能调优

    golang垃圾回收 & 性能调优 参考资料: 如何监控 golang 程序的垃圾回收_Go语言_第七城市 golang的垃圾回收(GC)机制 - 两只羊的博客 - 博客频道 - CSDN.N ...

  5. Golang 的 协程调度机制 与 GOMAXPROCS 性能调优

    作者:林冠宏 / 指尖下的幽灵 掘金:https://juejin.im/user/587f0dfe128fe100570ce2d8 博客:http://www.cnblogs.com/linguan ...

  6. 关于iOS性能调优

    性能调优一直都是作为高阶iOS开发者的一个入门门槛,下面我搜集了日常查阅资料中见到的各种高质量调优博文,仅供参考 UIKit性能调优实战讲解 iOS 高效添加圆角效果实战讲解

  7. Spark Streaming性能调优详解

    Spark Streaming性能调优详解 Spark  2015-04-28 7:43:05  7896℃  0评论 分享到微博   下载为PDF 2014 Spark亚太峰会会议资料下载.< ...

  8. Go性能调优

    文章引用自   Go性能调优 在计算机性能调试领域里,profiling 是指对应用程序的画像,画像就是应用程序使用 CPU 和内存的情况. Go语言是一个对性能特别看重的语言,因此语言中自带了 pr ...

  9. Spark性能调优-高级篇

    前言 继基础篇讲解了每个Spark开发人员都必须熟知的开发调优与资源调优之后,本文作为<Spark性能优化指南>的高级篇,将深入分析数据倾斜调优与shuffle调优,以解决更加棘手的性能问 ...

随机推荐

  1. [ES6] ITERATORS

    Iterables return an iterator object. This object knows how to access items from a collection 1 at a ...

  2. QT实现透明效果的按钮

    QPushButton { color: rgb(0,88,152) background-color: rgba(97%,80%,9%,50%)}

  3. stat(),lstat(),fstat() 获取文件/目录的相关信息

    stat 的使用 Linux有个命令,ls -l,效果如下: 这个命令能显示文件的类型.操作权限.硬链接数量.属主.所属组.大小.修改时间.文件名.它是怎么获得这些信息的呢,请看下面的讲解. stat ...

  4. SpinLock(自旋锁)

    SpinLock(自旋锁) SpinLock 结构是一个低级别的互斥同步基元,它在等待获取锁时进行旋转. 在多核计算机上,当等待时间预计较短且极少出现争用情况时,SpinLock 的性能将高于其他类型 ...

  5. (转)CommandArgument用法

    1.绑定数据库中一个主键前台代码:<ItemTemplate>                        <asp:ImageButton ID="ibtnUpdate ...

  6. 阐述Lambada表达式

    在C#2.0引入匿名方法之前,声明委托的唯一方法就是使用命名方法,C#2.0之后的C#3.0中开始引入了Lambda表达式取代了匿名方法. 匿名方法 要说Lambda必然离不开匿名方法,实际上,Lam ...

  7. jQuery input -> file change事件bug

    由jQuery绑定类型为file的input控件的change事件,发现只能被触发一次,修改方法 --> 原始代码: $input.change(function() { // somethin ...

  8. DOM 节点实例操作

    涉及知识点包括节点的所有知识 目的: 自动为文档创建一个目录表 自动创建目录

  9. jade的基本语法

    - for (var i=0;i<3;i++) li scnu-learn //这里的=,默认会转义内容 p= "Welcome scnu <strong>good< ...

  10. apache将请求转发到到tomcat应用

    映射: 1.开启apache中的proxy模块(proxy.conf,proxy.load,proxy_http.load) 2.配置apache配置文件,<VirtualHost *:80&g ...