“使用的内存”度量标准:转到工具pprof与docker统计信息

我写了一个golang应用程序,运行在我的每个docker容器中。 它通过tcp和udp使用protobufs相互通信,并使用Hashicorp的成员列表库来发现我的networking中的每个容器。 在docker统计我看到内存使用情况线性增加,所以我试图find我的应用程序中的任何泄漏。

由于它是一个持续运行的应用程序,我使用http pprof来检查任何一个容器中的实时应用程序。 我看到runtime.MemStats.sys是常量,即使docker统计是线性增加。 我的使用空间在1MB左右,而且随着时间的推移,课程的空间不断增加。 这是一个alloc_space的示例:

root@n3:/app# go tool pprof --alloc_space main http://localhost:8080/debug/pprof/heap Fetching profile from http://localhost:8080/debug/pprof/heap Saved profile in /root/pprof/pprof.main.localhost:8080.alloc_objects.alloc_space.005.pb.gz Entering interactive mode (type "help" for commands) (pprof) top --cum 1024.11kB of 10298.19kB total ( 9.94%) Dropped 8 nodes (cum <= 51.49kB) Showing top 10 nodes out of 34 (cum >= 1536.07kB) flat flat% sum% cum cum% 0 0% 0% 10298.19kB 100% runtime.goexit 0 0% 0% 6144.48kB 59.67% main.Listener 0 0% 0% 3072.20kB 29.83% github.com/golang/protobuf/proto.Unmarshal 512.10kB 4.97% 4.97% 3072.20kB 29.83% github.com/golang/protobuf/proto.UnmarshalMerge 0 0% 4.97% 2560.17kB 24.86% github.com/hashicorp/memberlist.(*Memberlist).triggerFunc 0 0% 4.97% 2560.10kB 24.86% github.com/golang/protobuf/proto.(*Buffer).Unmarshal 0 0% 4.97% 2560.10kB 24.86% github.com/golang/protobuf/proto.(*Buffer).dec_struct_message 0 0% 4.97% 2560.10kB 24.86% github.com/golang/protobuf/proto.(*Buffer).unmarshalType 512.01kB 4.97% 9.94% 2048.23kB 19.89% main.SaveAsFile 0 0% 9.94% 1536.07kB 14.92% reflect.New (pprof) list main.Listener Total: 10.06MB ROUTINE ======================== main.Listener in /app/listener.go 0 6MB (flat, cum) 59.67% of Total . . 24: l.SetReadBuffer(MaxDatagramSize) . . 25: defer l.Close() . . 26: m := new(NewMsg) . . 27: b := make([]byte, MaxDatagramSize) . . 28: for { . 512.02kB 29: n, src, err := l.ReadFromUDP(b) . . 30: if err != nil { . . 31: log.Fatal("ReadFromUDP failed:", err) . . 32: } . 512.02kB 33: log.Println(n, "bytes read from", src) . . 34: //TODO remove later. For testing Fetcher only . . 35: if rand.Intn(100) < MCastDropPercent { . . 36: continue . . 37: } . 3MB 38: err = proto.Unmarshal(b[:n], m) . . 39: if err != nil { . . 40: log.Fatal("protobuf Unmarshal failed", err) . . 41: } . . 42: id := m.GetHead().GetMsgId() . . 43: log.Println("CONFIG-UPDATE-RECEIVED { \"update_id\" =", id, "}") . . 44: //TODO check whether value already exists in store? . . 45: store.Add(id) . 2MB 46: SaveAsFile(id, b[:n], StoreDir) . . 47: m.Reset() . . 48: } . . 49:} (pprof) 

我已经能够使用http://:8080 / debug / pprof / goroutine?debug = 1来validation没有goroutine泄漏

请评论为什么docker统计显示不同的图片(线性增加内存)

 CONTAINER CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS n3 0.13% 19.73 MiB / 31.36 GiB 0.06% 595 kB / 806 B 0 B / 73.73 kB 14 

如果我运行它过夜,这个内存膨胀到250MB左右。 我没有跑多久,但我觉得这应该达到了高原,而不是线性增加

docker stats显示了cgroup的内存使用情况统计信息。 (请参阅: https : //docs.docker.com/engine/admin/runmetrics/ )

如果你阅读“过时但有用”的文档( https://www.kernel.org/doc/Documentation/cgroup-v1/memory.txt ),它说

5.5 usage_in_bytes

为了提高效率,与其他内核组件一样,内存cgroup使用一些优化来避免不必要的cacheline错误共享。 usage_in_bytes受该方法的影响,并不显示内存(和交换)使用的“确切”值,这是高效访问的模糊值。 (当然,必要时,它是同步的)。如果你想知道更准确的内存使用情况,你应该在memory.stat中使用RSS + CACHE(+ SWAP)值(见5.2)。

页面caching和RES包含在内存usage_in_bytes数量中。 所以如果容器有文件I / O,内存使用情况会增加。 但是,对于一个容器来说,如果使用量达到了最大限度,它将回收一些未使用的内存。 因此,当我添加一个内存限制到我的容器,我可以观察到内存回收和使用时,限制命中。 容器进程不会被杀死,除非没有内存回收和OOM错误发生。 对于任何关心docker统计中显示的数字的人来说,简单的方法是检查cgroup中可用的详细统计信息,path为:/ sys / fs / cgroup / memory / docker //这将在内存中详细显示所有内存度量。统计信息或其他内存*文件。

如果要在“docker run”命令中限制docker容器使用的资源,可以按照以下参考进行操作: https : //docs.docker.com/engine/admin/resource_constraints/

由于我使用的是docker-compose,所以我在docker-compose.yml文件中添加了一行,这个文件位于我想限制的服务之下:

mem_limit:32米

其中m代表兆字节。