在go-lang中分析http处理程序

在go-lang中分析http处理程序,go,profiling,pprof,Go,Profiling,Pprof,我正在尝试分析我用go编写的http处理程序。它在每个http请求中从S3下载一个图像,调整它的大小/裁剪它,并作为响应写入它 我遵循了这一点,并尝试使用easy方法和hard方法分析我的代码。现在,当我使用代码中提到的以下行时 defer profile.Start(profile.CPUProfile).Stop() 它不会在/tmp/profie[some number]/cpu.pprof文件中写入任何内容 此外,当我在serveHTTP中使用defer profile.Startp

我正在尝试分析我用go编写的http处理程序。它在每个http请求中从S3下载一个图像,调整它的大小/裁剪它,并作为响应写入它

我遵循了这一点,并尝试使用easy方法和hard方法分析我的代码。现在,当我使用代码中提到的以下行时

defer profile.Start(profile.CPUProfile).Stop() 
它不会在/tmp/profie[some number]/cpu.pprof文件中写入任何内容

此外,当我在serveHTTP中使用defer profile.Startprofile.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:
第2部分:

                                   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行存在内存泄漏,对吗?此外,我找不到任何关闭/销毁s3Client和blobGiff字节[]的选项

要在http服务器运行时对其进行评测,可以使用该包

加上

import _ "net/http/pprof"

到您的导入和打开http://localhost:8081/debug/pprof/ 在浏览器中。

要在http服务器运行时对其进行评测,可以使用该软件包

加上

import _ "net/http/pprof"
到您的导入和打开http://localhost:8081/debug/pprof/ 在浏览器中。

首先使用import-net/http/pprof而不是import-net/http/pprof。后来,在下面的路线中,人们没有认出pprof

我使用的是默认的serveMux/多路复用器。但后来我创造了我自己的,因为人们认为它具有性能含义

myMux := http.NewServeMux()
然后为请求添加路由

myMux.HandleFunc("/", serveHTTP)
此外,我还添加了使http://localhost:8081/debug/pprof/ 工作

因此,最终代码是:

导入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)
    }       

}
首先使用import-net/http/pprof而不是import-net/http/pprof。后来,在下面的路线中,人们没有认出pprof

我使用的是默认的serveMux/多路复用器。但后来我创造了我自己的,因为人们认为它具有性能含义

myMux := http.NewServeMux()
然后为请求添加路由

myMux.HandleFunc("/", serveHTTP)
此外,我还添加了使http://localhost:8081/debug/pprof/ 工作

因此,最终代码是:

导入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)
    }       

}

main中的延迟永远不会运行,因为http.ListenAndServe会永远阻塞。当您将处理程序放入请求处理程序时,会得到多个文件,因为该处理程序会被多次调用,每次都会创建一个新的配置文件。它不会在文件中写入任何内容。您不能在main中使用defer profile.Startprofile.CPUProfile.Stop行,因为defer永远不会被调用ListendServe块并永远等待。在serveHTTP函数中调用defer profile.Startprofile.CPUProfile.Stop时,探查器已从main运行,因此不会写入任何内容,因为探查器一次不能运行多次。您不能单独分析单个处理程序。pprof是一个采样探查器,因此除非处理程序运行很长时间,否则将无法获取任何样本。配置整个应用程序,并在处理程序上生成足够的负载。如果导入并分析正在运行的二进制文件,这会更容易。主文件中的延迟永远不会运行,因为http.ListenAndServe会永远阻塞。当您将处理程序放入请求处理程序时,会得到多个文件,因为该处理程序会被多次调用,每次都会创建一个新的配置文件。它不会在文件中写入任何内容。您不能在main中使用defer profile.Startprofile.CPUProfile.Stop行,因为defer永远不会被调用ListendServe块并永远等待。在serveHTTP函数中调用defer profile.Startprofile.CPUProfile.Stop时,探查器已从main运行,因此不会写入任何内容,因为探查器一次不能运行多次。您不能单独分析单个处理程序。pprof是一个采样探查器,因此除非处理程序运行很长时间,否则将无法获取任何样本。配置整个应用程序,并在处理程序上生成足够的负载。如果您导入并分析正在运行的二进制文件,+1,这就更容易了。如果确实要使用标准探查器,请使用os/signal实现正常关机或正常关机库,以便在需要时调用您的延迟。@fl0cke我将尝试此方法。请你也告诉我。我附加的行肯定有内存泄漏,它清楚地表明这是由于[]字节和S3客户端。那么,有没有办法在围棋中摧毁或关闭它们lang@Naresh:这不是这种分析的目的,这些行本身并不意味着任何内存泄漏。Go是垃圾收集的,因此没有彻底销毁[]字节的方法,*S3也没有close方法。我们无法从代码片段中分辨出来,但看起来您没有检查
正在检查从GetObject返回的错误时,请始终检查错误,也不要关闭从GetObject返回的响应正文。@JimB谢谢。我处理了错误并关闭了响应主体。你能告诉我如果我不处理这个错误会不会导致内存泄漏吗?此外,如果内存探查器没有给出真正的内存泄漏点,那么我们如何找出内存泄漏发生的位置。@fl0cke正如您所建议的,我导入了net/http/pprof并尝试浏览相同的Url。但它给出了一个错误:没有提供足够的参数。传递给s3客户端的密钥的原因将为空。仅供参考,正如您所见,我在我的代码+1中使用默认mux。如果确实要使用标准探查器,请使用os/signal实现正常关机或正常关机库,以便在需要时调用您的延迟。@fl0cke我将尝试此方法。请你也告诉我。我附加的行肯定有内存泄漏,它清楚地表明这是由于[]字节和S3客户端。那么,有没有办法在围棋中摧毁或关闭它们lang@Naresh:这不是这种分析的目的,这些行本身并不意味着任何内存泄漏。Go是垃圾收集的,因此没有彻底销毁[]字节的方法,*S3也没有close方法。我们无法从代码片段中分辨出来,但看起来您没有检查从GetObject always check errors返回的错误,也没有关闭GetObject的响应正文。@JimB谢谢您。我处理了错误并关闭了响应主体。你能告诉我如果我不处理这个错误会不会导致内存泄漏吗?此外,如果内存探查器没有给出真正的内存泄漏点,那么我们如何找出内存泄漏发生的位置。@fl0cke正如您所建议的,我导入了net/http/pprof并尝试浏览相同的Url。但它给出了一个错误:没有提供足够的参数。传递给s3客户端的密钥的原因将为空。仅供参考,正如您所见,我在代码中使用了默认的mux