如何利用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. C#获取文件和文件夹大小

    代码如下: /// <summary> /// 获取文件夹大小 /// </summary> /// <param name="dirPath"> ...

  2. Error when launching Quest Central for DB2: "QCC10000E - Unable to allocate environment handle fo

    标题 Error when launching Quest Central for DB2: "QCC10000E - Unable to allocate environment hand ...

  3. My way on Linux - 知识梳理计划

    知识梳理计划图 近期计划把自己学习的工作中用到的Linux知识梳理下,敬请期待.

  4. python-文件操作(1)

    本文内容涉及python打开/创建文件对象,文件的读写.文件指针位置的移动.获取命令行参数. 1. open() open函数以指定模式返回一个file对象,如: file_object = open ...

  5. 需求管理(REQM,Requirements Management)工具(转)

    需求管理(REQM,Requirements Management)属于成熟度2级(受管理级)的过程域,是其他许多过程域实施的前提.对于暂未实施CMMI的企业,同样也可以借鉴CMMI的原则,实施和优化 ...

  6. Geodatabase - 删除要素

    //删除要素类. //例如:workspacePath=@"G:\doc\gis\1.400\data\pdb.mdb", featureClassPath="res2_ ...

  7. table超过30个字段如何处理呢? bootstrap

    样式: @media (max-width: 768px) { .table-supplier { width: 100%; height: 100%; margin-bottom: 12.75px; ...

  8. Apache URL转发

    httpd.conf 尾巴加 Alias /web "F:\xampp\htdocs\test/" <Directory "F:\xampp\htdocs\test ...

  9. 5 输出的properties文件按照key进行排序

    import java.io.BufferedWriter; import java.io.FileInputStream; import java.io.FileNotFoundException; ...

  10. JSP 实现 之 调用java方法实现MySQL数据库备份和恢复

    package cn.qm.db; import java.io.BufferedReader; import java.io.DataInputStream; import java.io.IOEx ...