在Go语言中对HTTP处理程序进行性能分析

huangapple go评论71阅读模式
英文:

profiling http handler in go lang

问题

我正在尝试对我的Go语言编写的HTTP处理程序进行性能分析。每次HTTP请求时,它会从S3下载图像,对其进行调整/裁剪,并将其写入响应中。

我按照这个链接1中提到的方法进行了操作,并尝试使用简单方法和困难方法来对我的代码进行性能分析。现在,当我在代码中使用以下行时:

defer profile.Start(profile.CPUProfile).Stop()

它不会将任何内容写入/tmp/profie[some number]/cpu.pprof文件中。

此外,当我在serveHTTP方法中使用defer profile.Start(profile.CPUProfile).Stop()行时:

func serveHTTP(w http.ResponseWriter, r *http.Request) {

    defer profile.Start(profile.CPUProfile).Stop()
    ......
}

它会在/tmp/profile[some number]文件夹中创建多个文件。所以,第一个问题是为什么它不会写入文件,第二个问题是它不应该放在serveHTTP方法中吗?因为服务器只会启动一次。因此,main()只会被调用一次,而serveHTTP将在每个请求上被调用。

第一部分:

 .               124:	s3Client := s3.New(session.New(), &aws.Config{Region: aws.String(region)})
 .          .    125:        params := &s3.GetObjectInput{
 .          .    126:		Bucket: aws.String(masterBucketName),
 .          .    127:		Key: aws.String(keyName),
 .    32.01kB    128:	    }
 .          .    129:
 .          .    130:	mw := imagick.NewMagickWand()
 .          .    131:	defer mw.Destroy()
 .          .    132:	
 .          .    133:	out, err := s3Client.GetObject(params)			
 .          .    134:
 .          .    135:	if strings.EqualFold(keyName[strings.LastIndex(keyName,".")+1:len(keyName)], "gif") {
 .          .    136:
 .    40.11kB    137:		blobGiff, err := ioutil.ReadAll(out.Body)
 .          .    138:		w.Header().Set("Content-Type", "image/gif")
 .          .    139:		w.Header().Set("Cache-Control", "max-age: 604800, public")	
 .          .    140:		w.Header().Set("Last-Modified", time.Now().Format(http.TimeFormat))
 .          .    141:		w.Header().Set("Expires", time.Now().AddDate(1, 0, 0).Format(http.TimeFormat))	
 .          .    142:

第二部分:

                                   else {
         .          .    167:		img, err := ioutil.ReadAll(out.Body)
         .          .    168:		if err != nil {
         .          .    169:		   
         .          .    170:		   w.WriteHeader(http.StatusNotFound) 
         .     1.56MB    171:	 	   return	   
         .          .    172:		}   

此外,在上述两个部分中,第128、137和171行存在内存泄漏,对吗?此外,我没有找到关闭/销毁s3ClientblobGiff(字节数组)的选项。

英文:

I am trying to profile my http handler written in go. Which on every http request download an image from S3, resize it/crop it and write it in response.

I have followed this link and tried to profile my code as mentioned using easy method as well as hard method. Now, when i use the following line as mentioned in the code.

defer profile.Start(profile.CPUProfile).Stop() 

It doesn't write anything in the /tmp/profie[some number]/cpu.pprof file

func main() {       			         		 

	   defer profile.Start(profile.CPUProfile).Stop()	
	  
      if err := http.ListenAndServe(":8081", http.HandlerFunc(serveHTTP)); err != nil {
	   logFatal("Error when starting or running http server: %v", err)
	}       
}

func serveHTTP(w http.ResponseWriter, r *http.Request) {
        keyName := r.URL.Path[1:]
        s3Client := s3.New(session.New(), &aws.Config{Region: aws.String(region)})
        params := &s3.GetObjectInput{
		Bucket: aws.String(bucketName),
		Key: aws.String(keyName),
	    }

	mw := imagick.NewMagickWand()
	defer mw.Destroy()
    ...
}

Moreover, when i used the defer profile.Start(profile.CPUProfile).Stop() line inside the serveHTTP like :

func serveHTTP(w http.ResponseWriter, r *http.Request) {

    defer profile.Start(profile.CPUProfile).Stop()
    ......
}

It creates multiple files in the /tmp/profile[some number] folder. So, first question is why it is not writing in the file and secondly shouldn't it be places inside the serveHTTP method because server will get started only once. Hence main() will be called once wheres serveHTTP wil be called on every request.

Part 1

 .               124:	s3Client := s3.New(session.New(), &aws.Config{Region: aws.String(region)})
 .          .    125:        params := &s3.GetObjectInput{
 .          .    126:		Bucket: aws.String(masterBucketName),
 .          .    127:		Key: aws.String(keyName),
 .    32.01kB    128:	    }
 .          .    129:
 .          .    130:	mw := imagick.NewMagickWand()
 .          .    131:	defer mw.Destroy()
 .          .    132:	
 .          .    133:	out, err := s3Client.GetObject(params)			
 .          .    134:
 .          .    135:	if strings.EqualFold(keyName[strings.LastIndex(keyName,".")+1:len(keyName)], "gif") {
 .          .    136:
 .    40.11kB    137:		blobGiff, err := ioutil.ReadAll(out.Body)
 .          .    138:		w.Header().Set("Content-Type", "image/gif")
 .          .    139:		w.Header().Set("Cache-Control", "max-age: 604800, public")	
 .          .    140:		w.Header().Set("Last-Modified", time.Now().Format(http.TimeFormat))
 .          .    141:		w.Header().Set("Expires", time.Now().AddDate(1, 0, 0).Format(http.TimeFormat))	
 .          .    142:

Part 2 :

                                   else {
         .          .    167:		img, err := ioutil.ReadAll(out.Body)
         .          .    168:		if err != nil {
         .          .    169:		   
         .          .    170:		   w.WriteHeader(http.StatusNotFound) 
         .     1.56MB    171:	 	   return	   
         .          .    172:		}   

Also, in the above two parts line 128, 137 and 171 has memory leaks, right? Also, I don't find any option to close/destroy the s3Client and blobGiff (byte []).

答案1

得分: 6

要在运行中对一个 HTTP 服务器进行性能分析,你可以使用 net/http/pprof 包。

只需在你的导入中添加:

import _ "net/http/pprof"

然后在浏览器中打开 http://localhost:8081/debug/pprof/

英文:

To profile a http server while it's running you can use the net/http/pprof package.

Just add

import _ "net/http/pprof"

to your imports and open http://localhost:8081/debug/pprof/ in your browser.

答案2

得分: 5

首先,使用import "net/http/pprof"而不是import _ "net/http/pprof"。后者无法识别下面路由中的pprof

我之前使用的是默认的serveMux/multiplexer。但后来我创建了自己的,因为有人建议说它会对性能产生影响。

myMux := http.NewServeMux()

然后添加请求的路由:

myMux.HandleFunc("/", serveHTTP)

此外,我还添加了以下路由以使http://localhost:8081/debug/pprof/工作:

myMux.HandleFunc("/debug/pprof/", pprof.Index)
myMux.HandleFunc("/debug/pprof/{action}", pprof.Index)
myMux.HandleFunc("/debug/pprof/symbol", pprof.Symbol)

因此,最终的代码如下:

import "net/http/pprof"

func main() {
    myMux := http.NewServeMux()
    myMux.HandleFunc("/", serveHTTP)
    myMux.HandleFunc("/debug/pprof/", pprof.Index)
    myMux.HandleFunc("/debug/pprof/{action}", pprof.Index)
    myMux.HandleFunc("/debug/pprof/symbol", pprof.Symbol)

    if err := http.ListenAndServe(":8081", myMux); err != nil {
        logFatal("Error when starting or running http server: %v", err)
    }
}
英文:

First of all use import "net/http/pprof" NOT import _ "net/http/pprof. later one didn't recognize the pprof in the below routes.

I was using the default serveMux/multiplexer. But then I created my own as people suggested it has performance implication.

myMux := http.NewServeMux()

Then added the route for the request

myMux.HandleFunc("/", serveHTTP)

Morever, I also added the routes for to make the http://localhost:8081/debug/pprof/ work

        myMux.HandleFunc("/debug/pprof/", pprof.Index)
        myMux.HandleFunc("/debug/pprof/{action}", pprof.Index)
        myMux.HandleFunc("/debug/pprof/symbol", pprof.Symbol)

So, final code would be :

import "net/http/pprof

func main() {       			         		 
		
	    myMux := http.NewServeMux()
	    myMux.HandleFunc("/", serveHTTP)

 	    myMux.HandleFunc("/debug/pprof/", pprof.Index)
        myMux.HandleFunc("/debug/pprof/{action}", pprof.Index)
        myMux.HandleFunc("/debug/pprof/symbol", pprof.Symbol)	

	if err := http.ListenAndServe(":8081", myMux); err != nil {
		logFatal("Error when starting or running http server: %v", err)
	}       

}

huangapple
  • 本文由 发表于 2016年2月12日 18:22:12
  • 转载请务必保留本文链接:https://go.coder-hub.com/35360089.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定