热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Golang性能调优入门

如何利用golang自带的profile工具进行应用程序的性能调优,前一段时间我做的日志分析系统在线上遇到了一个问题,就是分任务的系统down机了,日志处理延迟了10几个小时,这个时候任务分发系统重启

如何利用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

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

switch {

case u == 0:

return "0"

case u

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

case u

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

default:

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

}

} else {

switch {

case u

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

case u

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

default:

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

}

}

 

}


推荐阅读
  • go channel 缓冲区最大限制_Golang学习笔记之并发.协程(Goroutine)、信道(Channel)
    原文作者:学生黄哲来源:简书Go是并发语言,而不是并行语言。一、并发和并行的区别•并发(concurrency)是指一次处理大量事情的能力 ... [详细]
  • 本文主要解析了Open judge C16H问题中涉及到的Magical Balls的快速幂和逆元算法,并给出了问题的解析和解决方法。详细介绍了问题的背景和规则,并给出了相应的算法解析和实现步骤。通过本文的解析,读者可以更好地理解和解决Open judge C16H问题中的Magical Balls部分。 ... [详细]
  • 本文讨论了如何使用IF函数从基于有限输入列表的有限输出列表中获取输出,并提出了是否有更快/更有效的执行代码的方法。作者希望了解是否有办法缩短代码,并从自我开发的角度来看是否有更好的方法。提供的代码可以按原样工作,但作者想知道是否有更好的方法来执行这样的任务。 ... [详细]
  • 欢乐的票圈重构之旅——RecyclerView的头尾布局增加
    项目重构的Git地址:https:github.comrazerdpFriendCircletreemain-dev项目同步更新的文集:http:www.jianshu.comno ... [详细]
  • Android系统源码分析Zygote和SystemServer启动过程详解
    本文详细解析了Android系统源码中Zygote和SystemServer的启动过程。首先介绍了系统framework层启动的内容,帮助理解四大组件的启动和管理过程。接着介绍了AMS、PMS等系统服务的作用和调用方式。然后详细分析了Zygote的启动过程,解释了Zygote在Android启动过程中的决定作用。最后通过时序图展示了整个过程。 ... [详细]
  • 目录在Go语言项目中使用Zap日志库介绍默认的GoLogger日志库实现GoLogger设置Logger使用LoggerLogger的运行GoLogger的优势和劣势优势劣势Ube ... [详细]
  • [Redis 系列]redis 学习六,redis 事务处理和监控事务
    【Redis系列】redis学习六,redis事务处理和监控事务写在前面我们学过的事务都是保证原子性的,但是redis的事务中执行多个指令,是不保证原子性的redis事务的本质就是 ... [详细]
  • Go 快速入门指南命令行参数
    命令行参数个数调用os包即可。获取参数个数,遍历参数packagemainimport(fmtos)funcmain(){fmt.Printf(Numberofargsi ... [详细]
  • CSS3选择器的使用方法详解,提高Web开发效率和精准度
    本文详细介绍了CSS3新增的选择器方法,包括属性选择器的使用。通过CSS3选择器,可以提高Web开发的效率和精准度,使得查找元素更加方便和快捷。同时,本文还对属性选择器的各种用法进行了详细解释,并给出了相应的代码示例。通过学习本文,读者可以更好地掌握CSS3选择器的使用方法,提升自己的Web开发能力。 ... [详细]
  • 阿,里,云,物,联网,net,core,客户端,czgl,aliiotclient, ... [详细]
  • FeatureRequestIsyourfeaturerequestrelatedtoaproblem?Please ... [详细]
  • 3.223.28周学习总结中的贪心作业收获及困惑
    本文是对3.223.28周学习总结中的贪心作业进行总结,作者在解题过程中参考了他人的代码,但前提是要先理解题目并有解题思路。作者分享了自己在贪心作业中的收获,同时提到了一道让他困惑的题目,即input details部分引发的疑惑。 ... [详细]
  • 本文详细介绍了如何使用MySQL来显示SQL语句的执行时间,并通过MySQL Query Profiler获取CPU和内存使用量以及系统锁和表锁的时间。同时介绍了效能分析的三种方法:瓶颈分析、工作负载分析和基于比率的分析。 ... [详细]
  • Java 11相对于Java 8,OptaPlanner性能提升有多大?
    本文通过基准测试比较了Java 11和Java 8对OptaPlanner的性能提升。测试结果表明,在相同的硬件环境下,Java 11相对于Java 8在垃圾回收方面表现更好,从而提升了OptaPlanner的性能。 ... [详细]
  • Annotation的大材小用
    为什么80%的码农都做不了架构师?最近在开发一些通用的excel数据导入的功能,由于涉及到导入的模块很多,所以开发了一个比较通用的e ... [详细]
author-avatar
林泳_钿
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有