ããã«ã¡ã¯ããã¯ã©ã¯ãã¸ãã¹ã«ã¼ãã§ã¨ã³ã¸ãã¢ããã¦ãã @onsd_ ã§ããæè¿ã¯ã©ã³ãã³ã°ãå§ãã¦ãçå± å¨ãã ã£ããå±±ã ã£ããããããèµ°ã£ã¦ããã¾ããStrava åéåéä¸ã§ãã
ãã®è¨äºã¯Â LayerXããã¯ã¢ãã«ã¬ 31æ¥ç®ã®è¨äºã§ãã ååã¯kikuchyããã«ãã ãªããã¯ã©ã¯ç³è«ã»çµè²»ç²¾ç®ã¯Flutterã§ã¢ããªã®ä½ãç´ãããã¦ããã®ã ã§ãããã¢ããªãä½ãç´ãçç±ãLayerXããããªãã¨æãã¾ãããèå³ãããæ¹ã¯ãã²ãã¡ããã覧ãã ããï¼ æ¬¡å㯠ar_tamaãããæ å½ããã¾ããã楽ãã¿ã«ï¼
ãã®è¨äºã§ã¯ãã¢ããªã±ã¼ã·ã§ã³ãµã¼ãã§èµ·ããåé¡ã«ã¤ãã¦èª¿æ»ããæé ãæ®ãã¾ãããã¼ã«ã使ã£ã¦èª¿æ»ãé²ããæ¹æ³ã«ã¤ãã¦åèã«ãªãã°å¬ããã§ãã
éçºç°å¢ã§ã®ã¿èµ·ããOOM
ã¢ããªã±ã¼ã·ã§ã³ã®å¦çã¨ãã¦ããã¡ã¤ã«ãåãåã S3 ã«ã¢ãããã¼ãããã¨ããå¦çãããã¾ãã
ãã®å¦çã«ã¤ãã¦ãã¾ãåãåãããã¡ã¤ã«ãµã¤ãºã®ä¸éãå¼ãä¸ãã対å¿ããã¾ããã ï¼â» GraphQLãµã¼ããå®è£ ããããã«ãgqlgen ãå©ç¨ãã¦ãã¾ãï¼
srv.AddTransport(transport.MultipartForm{ - MaxUploadSize: 50 * 1 << 20, // 50MB, - MaxMemory: 50 * 1 << 20, // 50MB, + MaxUploadSize: 80 * 1 << 20, // 80MB, + MaxMemory: 80 * 1 << 20, // 80MB, })
ä¸éãå¼ãä¸ããæå ã§ãã¡ã¤ã«ãã¢ãããã¼ãããã¨ããæ£å¸¸ã«åä½ãã¦ãããã§ããã ãã®ããããã¼ã¸ãã¦æ§åãè¦ã¦ããã¨ããããã¾ã«ECSã®ã¿ã¹ã¯ãæ»ãã§ããäºã«æ°ã¥ãã¾ããã
éçºç°å¢ã§ãã¡ã¤ã«ãã¢ãããã¼ããã¦ã¿ãã¨ã50MBã®ãã¡ã¤ã«ã§ã¯åé¡ãªãã®ã§ããã80MBã®ãã¡ã¤ã«ãã¢ãããã¼ããã㨠500 ãè¿ã£ã¦ãããã¨ãã£ãæåã示ãã¦ãã¾ããã
ã³ã³ããã®ãã°ãã¿ã¦ã¿ãã¨OOMã§ã¿ã¹ã¯ãçµäºããã¦ããäºãããã£ãã®ã§ã調æ»ãã¦ã¿ããã¨ã«ãã¾ããã
調æ»ï¼èª°ãã¡ã¢ãªã使ã£ã¦ããï¼
ã¡ã¢ãªã®ä½¿ç¨çãè¨æ¸¬ãããããä»å㯠profile ã使ã£ã¦ã¡ã¢ãªã®ãããã¡ã¤ãªã³ã°ããããã¨ã«ãã¾ããã
profile ã¯ãè¨æ¸¬ã§ãã使ããã pprof ã使ããããããã«ã©ããããã©ã¤ãã©ãªã§ãã
次ã®ããã«ãimport ã㦠mainé¢æ°ã®ä¸çªä¸ã§å¼ã³åºãã¾ãã
diff --git a/cmd/api/main.go b/cmd/api/main.go index 024d3e37..7609ffa3 100644 --- a/cmd/api/main.go +++ b/cmd/api/main.go @@ -24,6 +24,7 @@ import ( + "github.com/pkg/profile" ) @@ -32,6 +33,8 @@ import ( func main() { + defer profile.Start(profile.MemProfile).Stop() // ã¡ã¢ãªã®è¨æ¸¬ããã
ãã®ç¶æ ã§ã¢ããªã±ã¼ã·ã§ã³ãåä½ãããã¨ã次ã®ããã«ä½ã®è¨æ¸¬ãæå¹ã«ãªã£ã¦ãããã¨ããããã¡ã¤ãªã³ã°çµæã®ãã¹ã表示ããã¾ãã
$ go build ./cmd/api/...
$ ./api
2023/06/21 09:49:12 profile: memory profiling enabled (rate 4096), /var/folders/w4/hsgyyx5508b60xcvtnzhk1hr0000gn/T/profile4014285411/mem.pprof
ããã§ã80MB ã®ãã¡ã¤ã«ãã¢ãããã¼ããã¦ããããããã¡ã¤ãªã³ã°çµæãã¿ã¦ã¿ããã¨ã«ãã¾ããã
çµæã®è§£æã«ã¯ã go tool pprof
ã³ãã³ããå©ç¨ã§ãã¾ãã
# go tool pprof <path-to-binary> <path-to-profile-output> $ go tool pprof api /var/folders/w4/hsgyyx5508b60xcvtnzhk1hr0000gn/T/profile369504276/mem.pprof File: api Type: inuse_space Time: Jun 21, 2023 at 9:53am (JST) Entering interactive mode (type "help" for commands, "o" for options) (pprof) top Showing nodes accounting for 154.14MB, 99.61% of 154.75MB total Dropped 388 nodes (cum <= 0.77MB) Showing top 10 nodes out of 37 flat flat% sum% cum cum% 154.14MB 99.61% 99.61% 154.14MB 99.61% io.ReadAll 0 0% 99.61% 60.19MB 38.89% github.com/99designs/gqlgen/graphql/executor.(*Executor).DispatchOperation.func1.1 0 0% 99.61% 60.19MB 38.89% github.com/99designs/gqlgen/graphql/executor.(*Executor).DispatchOperation.func1.1.1 0 0% 99.61% 60.19MB 38.89% github.com/99designs/gqlgen/graphql/executor.aroundRespFunc.InterceptResponse 0 0% 99.61% 60.19MB 38.89% github.com/99designs/gqlgen/graphql/executor.processExtensions.func2 0 0% 99.61% 60.21MB 38.91% github.com/99designs/gqlgen/graphql/executor.processExtensions.func3 0 0% 99.61% 60.21MB 38.91% github.com/99designs/gqlgen/graphql/executor.processExtensions.func4 0 0% 99.61% 60.19MB 38.89% github.com/99designs/gqlgen/graphql/executor.processExtensions.func6 0 0% 99.61% 60.19MB 38.89% github.com/99designs/gqlgen/graphql/executor.processExtensions.func6.1 0 0% 99.61% 154.20MB 99.64% github.com/99designs/gqlgen/graphql/handler.(*Server).ServeHTTP
ãããã¿ãã¨ã io.ReadAll
ãã¡ã¢ãªã使ã£ã¦ãããã¨ããããã¾ããã
io.ReadAll ã¯ã対象ã®ãã¡ã¤ã«ãã¡ã¢ãªã«ãã¹ã¦èªã¿è¾¼ã¿ã¾ããã§ã¯ã80MBå¼±ã®ãã¡ã¤ã«ãèªã¿è¾¼ãã ã ãã§ãªã 154.14MB 使ç¨ãããã¨ã«ãªã£ã¦ãã¾ãã®ã§ããããã
ã½ã¼ã¹ã³ã¼ãã io.ReadAll
ã§æ¤ç´¢ããã¨ãS3 ã«ã¢ãããã¼ãããå¦çã§å©ç¨ãã¦ãããã¨ããããã¾ãããä»åã¯ãs3Manager ãå©ç¨ãã¦ã io.Reader
ã®ã¾ã¾å¦çããæ¹åã§ä¿®æ£ãã¾ããã
// ã³ã¼ãä¾ func Upload(ctx Context.Context, body io.Reader) (string, error) { id := ulid.MustNew() s3Key := "some-path-s3-" + id - bodyBytes, err := io.ReadAll(body) + uploader := s3manager.NewUploaderWithClient(app.GetS3()) + _, err := uploader.Upload(&s3manager.UploadInput{ + Body: body, + Bucket: &bucket, + Key: &s3Key, + }) if err != nil { return "", err } - if err := aws.PutS3Object(bucket, s3Key, bytes.NewReader(bodyBytes), contentType); err != nil { - app.LogError(ctx, err).Send() - return "", err - } return s3Key, nil } }
ãã®å¤æ´ãé©å¿ããå¾ãå度ãã¡ã¤ã«ã¢ãããã¼ããè¡ããè¨æ¸¬ãè¡ãã¾ããã
$ go tool pprof api /var/folders/w4/hsgyyx5508b60xcvtnzhk1hr0000gn/T/profile3099273002/mem.pprof File: api Type: inuse_space Time: Jun 21, 2023 at 10:03am (JST) Entering interactive mode (type "help" for commands, "o" for options) (pprof) top Showing nodes accounting for 75.19MB, 99.44% of 75.61MB total Dropped 271 nodes (cum <= 0.38MB) Showing top 10 nodes out of 17 flat flat% sum% cum cum% 75.19MB 99.44% 99.44% 75.19MB 99.44% io.ReadAll 0 0% 99.44% 75.19MB 99.45% github.com/99designs/gqlgen/graphql/handler.(*Server).ServeHTTP 0 0% 99.44% 75.19MB 99.44% github.com/99designs/gqlgen/graphql/handler/transport.MultipartForm.Do
ã©ããããä»ã«ã io.ReadAll
ã使ã£ã¦ããç®æãããããã§ãã
調æ»ï¼èª°ã io.ReadAll
ãå¼ãã§ããï¼
ãã®æ®µéã§ãã½ã¼ã¹ã³ã¼ãä¸ã§ io.ReadAll
ãå©ç¨ããã¦ããç®æã¯ããã¾ããã§ããã
ãããã£ãå ´åã®èª¿æ»ã«å½¹ç«ã¤ã®ããpprof ã® -png
ãªãã·ã§ã³ã§ãã
ãã®ãªãã·ã§ã³ãã¤ãã¦å®è¡ãããã¨ã§ãé¢æ°ã®å¼ã³åºãé ãå³ã§è¡¨ç¤ºããã¾ãã
$ go tool pprof -png api /var/folders/w4/hsgyyx5508b60xcvtnzhk1hr0000gn/T/profile3099273002/mem.pprof > pprof2.png
ãã®å³ãè¦ãã¨ãServeHTTP ãå¼ãã§ãã MultipartForm.Do ã®ãªã㧠io.ReadAll
ãå¼ã°ãã¦ãããã¨ããããã¾ãã
MultipartForm.Doã®å®è£
ãèªãã¨ã MultipartForm.maxMemory
ã¨ã¢ãããã¼ãããããã¡ã¤ã«ã® Content-Length
ãæ¯è¼ãã¦æåãå¤ããããã«ãªã£ã¦ãã¾ããã
- Content-Length ã®æ¹ã大ããå ´åã¯ãä¸æãã¡ã¤ã«ãä½æãã¦ããã«æ¸ãè¾¼ã¾ãã¾ãã
- Content-Length ã®æ¹ãå°ããå ´åã¯ãio.ReadAll ãå©ç¨ãã¦ã¡ã¢ãªã«ã³ãã¼ããã¾ãã
ä»åã80MiB ã¾ã§åãä»ãã対å¿ãããæã«ãmaxMemory
ãå¢ãã対å¿ããã¦ãã¾ããã
ãã®ããã大ãããã¡ã¤ã«ãã¡ã¢ãªã¸ã³ãã¼ãããããã«ãªãã¾ããããå®ç¾©ããã¦ããECSã®ã¿ã¹ã¯ã®ã¡ã¢ãªã§ã¯å°ããã£ãã¨ããã®ãOOMã®åå ã®ããã§ããã
ããã¾ã§ããã£ãã®ã§ãã¿ã¹ã¯ã®ã¡ã¢ãªãå¢ãã対å¿ãè¡ãã¾ããã
ãããã«
OOMãèµ·ããï¼ã¨ããã¨ãã«ããªãOOMãèµ·ããã®ãï¼ããããã¡ã¤ãªã³ã°ãã¼ã«ãå©ç¨ãããã¨ã§æ ¹æ ãæã£ã¦æ¹åãã§ããã®ã¯è¯ãä½é¨ã§ããã ã¾ããã³ã¼ãã追ã£ã¦è¡ããã¨ã§ç解ãæ·±ã¾ã£ããããä¸ç³äºé³¥ã§ããã
ã¡ãªã¿ã« Fact Base ã¨ã¯ãå¼ç¤¾ã®è¡åæéã§ãã ãã¡ãã«ãèå³ãããæ¹ã¯ããã² LayerX ç¾ éç¤ ã御覧ãã ããã
ãã¿ã©ã¯ããã¯ã©ã¯ã«ãããããã¯ããä¸ç·ã«éçºãã¦ãããã人ã大åéä¸ã§ãï¼ ãããèå³ããã¾ãããããã²ã«ã¸ã¥ã¢ã«é¢è«ããã話ããã¦ãã ããï¼
LayerX Casual Night ã¨ãããé ã飲ã¿ãªããã«ã¸ã¥ã¢ã«é¢è«ããã«ã¸ã¥ã¢ã«ã«ããï½ã話ããã¤ãã³ããéå¬ãã¦ããã¾ãã®ã§ããã²ãåå ãã ããï¼