最近在Splunk工作不久,一個同事在Slack上找到我,問起我之前一篇關于《Kubernetes指標》的博文。
他的問題是關于OOMKiller使用是容器里哪個 "memory usage “的指標來決定是否應該殺死一個容器。我在那篇文章中提出的論斷是。
你可能認為用
container_memory_usage_bytes
來跟蹤內(nèi)存利用率很容易,但是,這個指標也包括緩存(想想文件系統(tǒng)緩存)數(shù)據(jù),這些數(shù)據(jù)在內(nèi)存壓力下可能會被驅逐。更好的指標是container_memory_working_set_bytes
,因為這是OOM殺手關注的。
這是這篇文章中最核心的論述,所以我決定我需要模擬這次行為。讓我們看看OOMKiller在觀察哪些指標。
我做了一個小東西,它會不斷地分配內(nèi)存,直到OOMKiller參與進來并殺死pod中的容器。
package main
import (
"fmt"
"net/http"
"time"
"github.com/prometheus/client_golang/prometheus/promhttp"
)
func main() {
memoryTicker := time.NewTicker(time.Millisecond * 5)
leak := make(map[int][]byte)
i := 0
go func() {
for range memoryTicker.C {
leak[i] = make([]byte, 1024)
i++
}
}()
http.Handle("/metrics", promhttp.Handler())
http.ListenAndServe(":8081", nil)
}
見它部署在minikube中,并將內(nèi)存請求和限制都設置為128MB,我們可以看到container_memory_usage_bytes
和container_memory_working_set_bytes
幾乎1:1地相互跟蹤。當它們都達到容器上設置的極限時,OOMKiller就會殺死容器,進程重新開始。
由于container_memory_usage_bytes
也跟蹤進程所使用的文件系統(tǒng)緩存,所以我又優(yōu)化了下小工具,以便將數(shù)據(jù)直接寫到文件系統(tǒng)上的一個文件。
package main
import (
"fmt"
"net/http"
"time"
"github.com/prometheus/client_golang/prometheus/promhttp"
)
func main() {
memoryTicker := time.NewTicker(time.Millisecond * 5)
leak := make(map[int][]byte)
i := 0
go func() {
for range memoryTicker.C {
leak[i] = make([]byte, 1024)
i++
}
}()
fileTicker := time.NewTicker(time.Millisecond * 5)
go func() {
os.Create("/tmp/file")
buffer := make([]byte, 1024)
defer f.Close()
for range fileTicker.C {
f.Write(buffer)
f.Sync()
}
}()
http.Handle("/metrics", promhttp.Handler())
http.ListenAndServe(":8081", nil)
}
在引入文件系統(tǒng)緩存后,我們開始看到 container_memory_usage_bytes
和 container_memory_working_set_bytes
開始出現(xiàn)分叉
現(xiàn)在有趣的是,容器仍然不允許使用超過容器極限的內(nèi)存量,但是OOMKiller container_memory_working_set_bytes
達到內(nèi)存極限時才會殺死容器。
這種行為的另一個有趣的方面是,
container_memory_usage_bytes
在容器的內(nèi)存極限時達到了頂點,但是數(shù)據(jù)還是繼續(xù)在往磁盤寫入。
如果我們再看一下container_memory_cache
,我們會發(fā)現(xiàn),在container_memory_usage_bytes
達到極限之前,使用的緩存量持續(xù)增加,然后開始減少。
從這個實驗中,我們可以看到,container_memory_usage_bytes
確實占用了一些正在被緩存的文件系統(tǒng)頁面。我們還可以看到,OOMKiller正在追蹤container_memory_working_set_bytes
。這是有道理的,因為共享文件系統(tǒng)的緩存頁可以在任何時候在內(nèi)存中被驅逐。我們僅僅因為使用磁盤I/O而殺死進程是沒有意義的。
****
本文由博客群發(fā)一文多發(fā)等運營工具平臺 OpenWrite 發(fā)布