Golang性能调优入门
如何利用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性能调优入门的更多相关文章
- golang 性能调优分析工具 pprof(下)
golang 性能调优分析工具 pprof(上)篇, 这是下篇. 四.net/http/pprof 4.1 代码例子 1 go version go1.13.9 把上面的程序例子稍微改动下,命名为 d ...
- golang 性能调优分析工具 pprof (上)
一.golang 程序性能调优 在 golang 程序中,有哪些内容需要调试优化? 一般常规内容: cpu:程序对cpu的使用情况 - 使用时长,占比等 内存:程序对cpu的使用情况 - 使用时长,占 ...
- JVM性能调优入门
1. 背景 虽然大多数应用程序使用JVM的默认设置就能很好地工作,仍然有不少应用程序需要对JVM进行额外的配置才能达到其期望的性能要求. 现在JVM为了满足各种应用的需要,为程序运行提供了大量的JVM ...
- 【GoLang】golang垃圾回收 & 性能调优
golang垃圾回收 & 性能调优 参考资料: 如何监控 golang 程序的垃圾回收_Go语言_第七城市 golang的垃圾回收(GC)机制 - 两只羊的博客 - 博客频道 - CSDN.N ...
- Golang 的 协程调度机制 与 GOMAXPROCS 性能调优
作者:林冠宏 / 指尖下的幽灵 掘金:https://juejin.im/user/587f0dfe128fe100570ce2d8 博客:http://www.cnblogs.com/linguan ...
- 关于iOS性能调优
性能调优一直都是作为高阶iOS开发者的一个入门门槛,下面我搜集了日常查阅资料中见到的各种高质量调优博文,仅供参考 UIKit性能调优实战讲解 iOS 高效添加圆角效果实战讲解
- Spark Streaming性能调优详解
Spark Streaming性能调优详解 Spark 2015-04-28 7:43:05 7896℃ 0评论 分享到微博 下载为PDF 2014 Spark亚太峰会会议资料下载.< ...
- Go性能调优
文章引用自 Go性能调优 在计算机性能调试领域里,profiling 是指对应用程序的画像,画像就是应用程序使用 CPU 和内存的情况. Go语言是一个对性能特别看重的语言,因此语言中自带了 pr ...
- Spark性能调优-高级篇
前言 继基础篇讲解了每个Spark开发人员都必须熟知的开发调优与资源调优之后,本文作为<Spark性能优化指南>的高级篇,将深入分析数据倾斜调优与shuffle调优,以解决更加棘手的性能问 ...
随机推荐
- C#获取文件和文件夹大小
代码如下: /// <summary> /// 获取文件夹大小 /// </summary> /// <param name="dirPath"> ...
- 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 ...
- My way on Linux - 知识梳理计划
知识梳理计划图 近期计划把自己学习的工作中用到的Linux知识梳理下,敬请期待.
- python-文件操作(1)
本文内容涉及python打开/创建文件对象,文件的读写.文件指针位置的移动.获取命令行参数. 1. open() open函数以指定模式返回一个file对象,如: file_object = open ...
- 需求管理(REQM,Requirements Management)工具(转)
需求管理(REQM,Requirements Management)属于成熟度2级(受管理级)的过程域,是其他许多过程域实施的前提.对于暂未实施CMMI的企业,同样也可以借鉴CMMI的原则,实施和优化 ...
- Geodatabase - 删除要素
//删除要素类. //例如:workspacePath=@"G:\doc\gis\1.400\data\pdb.mdb", featureClassPath="res2_ ...
- table超过30个字段如何处理呢? bootstrap
样式: @media (max-width: 768px) { .table-supplier { width: 100%; height: 100%; margin-bottom: 12.75px; ...
- Apache URL转发
httpd.conf 尾巴加 Alias /web "F:\xampp\htdocs\test/" <Directory "F:\xampp\htdocs\test ...
- 5 输出的properties文件按照key进行排序
import java.io.BufferedWriter; import java.io.FileInputStream; import java.io.FileNotFoundException; ...
- JSP 实现 之 调用java方法实现MySQL数据库备份和恢复
package cn.qm.db; import java.io.BufferedReader; import java.io.DataInputStream; import java.io.IOEx ...