摘要:診斷修復不穩定的關鍵詞社區相關問題起源薛定諤平臺是我司開發的基于建立的一套自動化測試框架,提供各種能力,同時也提供自動化的測試,各類異常監控告警以及自動輸出測試報告等功能。
作者:張文博
Kubernetes(K8s)是一個開源容器編排系統,可自動執行應用程序部署、擴展和管理。它是云原生世界的操作系統。 K8s 或操作系統中的任何缺陷都可能使用戶進程存在風險。作為 PingCAP EE(效率工程)團隊,我們在 K8s 中測試 TiDB Operator(一個創建和管理 TiDB 集群的工具)時,發現了兩個 Linux 內核錯誤。這些錯誤已經困擾我們很長一段時間,并沒有在整個 K8s 社區中徹底修復。
經過廣泛的調查和診斷,我們已經確定了處理這些問題的方法。在這篇文章中,我們將與大家分享這些解決方法。不過,盡管這些方法很有用,但我們認為這只是權宜之策,相信未來會有更優雅的解決方案,也期望 K8s 社區、RHEL 和 CentOS 可以在不久的將來徹底修復這些問題。
Bug #1: 診斷修復不穩定的 Kmem Accounting關鍵詞:SLUB: Unable to allocate memory on node -1
社區相關 Issue:
github.com/kubernetes/…
github.com/opencontain…
support.mesosphere.com/s/article/C…
問題起源薛定諤平臺是我司開發的基于 K8s 建立的一套自動化測試框架,提供各種 Chaos 能力,同時也提供自動化的 Bench 測試,各類異常監控、告警以及自動輸出測試報告等功能。我們發現 TiKV 在薛定諤平臺上做 OLTP 測試時偶爾會發生 I/O 性能抖動,但從下面幾項來看未發現異常:
TiKV 和 RocksDB 的日志
CPU 使用率
內存和磁盤等負載信息
只能偶爾看到 dmesg 命令執行的結果中包含一些 “SLUB: Unable to allocate memory on node -1” 信息。
問題分析我們使用 perf-tools 中的 funcslower trace 來執行較慢的內核函數并調整內核參數 hung_task_timeout_secs 閾值,抓取到了一些 TiKV 執行寫操作時的內核路徑信息:
從上圖的信息中可以看到 I/O 抖動和文件系統執行 writepage 有關。同時捕獲到性能抖動的前后,在 node 內存資源充足的情況下,dmesg 返回的結果也會出現大量 “SLUB: Unable to allocate memory on node -1” 的信息。
從 hung_task 輸出的 call stack 信息結合內核代碼發現,內核在執行 bvec_alloc 函數分配 bio_vec 對象時,會先嘗試通過 kmem_cache_alloc 進行分配,kmem_cache_alloc 失敗后,再進行 fallback 嘗試從 mempool 中進行分配,而在 mempool 內部會先嘗試執行 pool->alloc 回調進行分配,pool->alloc 分配失敗后,內核會將進程設置為不可中斷狀態并放入等待隊列中進行等待,當其他進程向 mempool 歸還內存或定時器超時(5s) 后,進程調度器會喚醒該進程進行重試 ,這個等待時間和我們業務監控的抖動延遲相符。
但是我們在創建 Docker 容器時,并沒有設置 kmem limit,為什么還會有 kmem 不足的問題呢?為了確定 kmem limit 是否被設置,我們進入 cgroup memory controller 對容器的 kmem 信息進行查看,發現 kmem 的統計信息被開啟了, 但 limit 值設置的非常大。
我們已知 kmem accounting 在 RHEL 3.10 版本內核上是不穩定的,因此懷疑 SLUB 分配失敗是由內核 bug 引起的,搜索 kernel patch 信息我們發現確實是內核 bug, 在社區高版本內核中已修復:
slub: make dead caches discard free slabs immediately
同時還有一個 namespace 泄漏問題也和 kmem accounting 有關:
mm: memcontrol: fix cgroup creation failure after many small jobs
那么是誰開啟了 kmem accounting 功能呢?我們使用 bcc 中的 opensnoop 工具對 kmem 配置文件進行監控,捕獲到修改者 runc 。從 K8s 代碼上可以確認是 K8s 依賴的 runc 項目默認開啟了 kmem accounting。
解決方案通過上述分析,我們要么升級到高版本內核,要么在啟動容器的時候禁用 kmem accounting 功能,目前 runc 已提供條件編譯選項,可以通過 Build Tags 來禁用 kmem accounting,關閉后我們測試發現抖動情況消失了,namespace 泄漏問題和 SLUB 分配失敗的問題也消失了。
操作步驟我們需要在 kubelet 和 docker 上都將 kmem account 功能關閉。
kubelet 需要重新編譯,不同的版本有不同的方式。
如果 kubelet 版本是 v1.14 及以上,則可以通過在編譯 kubelet 的時候加上 Build Tags 來關閉 kmem account:
$ git clone --branch v1.14.1 --single-branch --depth 1 [https://github.com/kubernetes/kubernetes](https://github.com/kubernetes/kubernetes)
$ cd kubernetes
$ KUBE_GIT_VERSION=v1.14.1 ./build/run.sh make kubelet GOFLAGS="-tags=nokmem"
但如果 kubelet 版本是 v1.13 及以下,則無法通過在編譯 kubelet 的時候加 Build Tags 來關閉,需要重新編譯 kubelet,步驟如下。
首先下載 Kubernetes 代碼:
$ git clone --branch v1.12.8 --single-branch --depth 1 https://github.com/kubernetes/kubernetes
$ cd kubernetes
然后手動將開啟 kmem account 功能的 兩個函數 替換成 下面這樣:
func EnableKernelMemoryAccounting(path string) error {
return nil
}
func setKernelMemory(path string, kernelMemoryLimit int64) error {
return nil
}
之后重新編譯 kubelet:
$ KUBE_GIT_VERSION=v1.12.8 ./build/run.sh make kubelet
編譯好的 kubelet 在 ./_output/dockerized/bin/$GOOS/$GOARCH/kubelet 中。
同時需要升級 docker-ce 到 18.09.1 以上,此版本 docker 已經將 runc 的 kmem account 功能關閉。
最后需要重啟機器。
驗證方法是查看新創建的 pod 的所有 container 已關閉 kmem,如果為下面結果則已關閉:
$ cat /sys/fs/cgroup/memory/kubepods/burstable/podBug #2:診斷修復網絡設備引用計數泄漏問題/ /memory.kmem.slabinfo cat: memory.kmem.slabinfo: Input/output error
關鍵詞:kernel:unregister_netdevice: waiting for eth0 to become free. Usage count = 1
社區相關 Issue:
github.com/kubernetes/…
github.com/projectcali…
github.com/moby/moby/i…
問題起源我們的薛定諤分布式測試集群運行一段時間后,經常會持續出現“kernel:unregister_netdevice: waiting for eth0 to become free. Usage count = 1” 問題,并會導致多個進程進入不可中斷狀態,只能通過重啟服務器來解決。
問題分析通過使用 crash 工具對 vmcore 進行分析,我們發現內核線程阻塞在 netdev_wait_allrefs 函數,無限循環等待 dev->refcnt 降為 0。由于 pod 已經釋放了,因此懷疑是引用計數泄漏問題。我們查找 K8s issue 后發現問題出在內核上,但這個問題沒有簡單的穩定可靠復現方法,且在社區高版本內核上依然會出現這個問題。
為避免每次出現問題都需要重啟服務器,我們開發一個內核模塊,當發現 net_device 引用計數已泄漏時,將引用計數清 0 后移除此內核模塊(避免誤刪除其他非引用計數泄漏的網卡)。為了避免每次手動清理,我們寫了一個監控腳本,周期性自動執行這個操作。但此方案仍然存在缺陷:
引用計數的泄漏和監控發現之間存在一定的延遲,在這段延遲中 K8s 系統可能會出現其他問題;
在內核模塊中很難判斷是否是引用計數泄漏,netdev_wait_allrefs 會通過 Notification Chains 向所有的消息訂閱者不斷重試發布 NETDEV_UNREGISTER 和 NETDEV_UNREGISTER_FINAL 消息,而經過 trace 發現消息的訂閱者多達 22 個,而去弄清這 22 個訂閱者注冊的每個回調函數的處理邏輯來判斷是否有辦法避免誤判也不是一件簡單的事。
解決方案在我們準備深入到每個訂閱者注冊的回調函數邏輯的同時,我們也在持續關注 kernel patch 和 RHEL 的進展,發現 RHEL 的 solutions:3659011 有了一個更新,提到 upstream 提交的一個 patch:
route: set the deleted fnhe fnhe_daddr to 0 in ip_del_fnhe to fix a race
在嘗試以 hotfix 的方式為內核打上此補丁后,我們持續測試了 1 周,問題沒有再復現。我們向 RHEL 反饋測試信息,得知他們已經開始對此 patch 進行 backport。
操作步驟推薦內核版本 Centos 7.6 kernel-3.10.0-957 及以上。
安裝 kpatch 及 kpatch-build 依賴:
UNAME=$(uname -r)
sudo yum install gcc kernel-devel-${UNAME%.*} elfutils elfutils-devel
sudo yum install pesign yum-utils zlib-devel
binutils-devel newt-devel python-devel perl-ExtUtils-Embed
audit-libs audit-libs-devel numactl-devel pciutils-devel bison
# enable CentOS 7 debug repo
sudo yum-config-manager --enable debug
sudo yum-builddep kernel-${UNAME%.*}
sudo debuginfo-install kernel-${UNAME%.*}
# optional, but highly recommended - enable EPEL 7
sudo yum install ccache
ccache --max-size=5G
安裝 kpatch 及 kpatch-build:
git clone https://github.com/dynup/kpatch && cd kpatch
make
sudo make install
systemctl enable kpatch
下載并構建熱補丁內核模塊:
curl -SOL https://raw.githubusercontent.com/pingcap/kdt/master/kpatchs/route.patch
kpatch-build -t vmlinux route.patch (編譯生成內核模塊)
mkdir -p /var/lib/kpatch/${UNAME}
cp -a livepatch-route.ko /var/lib/kpatch/${UNAME}
systemctl restart kpatch (Loads the kernel module)
kpatch list (Checks the loaded module)
雖然我們修復了這些內核錯誤,但是未來應該會有更好的解決方案。對于 Bug#1,我們希望 K8s 社區可以為 kubelet 提供一個參數,以允許用戶禁用或啟用 kmem account 功能。對于 Bug#2,最佳解決方案是由 RHEL 和 CentOS 修復內核錯誤,希望 TiDB 用戶將 CentOS 升級到新版后,不必再擔心這個問題。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/7861.html
摘要:經過廣泛的調查和診斷,我們已經確定了處理這些問題的方法。我們發現在薛定諤平臺上做測試時偶爾會發生性能抖動,但從下面幾項來看未發現異常和的日志使用率內存和磁盤等負載信息只能偶爾看到命令執行的結果中包含一些信息。 作者:張文博 Kubernetes(K8s)是一個開源容器編排系統,可自動執行應用程序部署、擴展和管理。它是云原生世界的操作系統。 K8s 或操作系統中的任何缺陷都可能使用戶進程...
摘要:經過廣泛的調查和診斷,我們已經確定了處理這些問題的方法。我們發現在薛定諤平臺上做測試時偶爾會發生性能抖動,但從下面幾項來看未發現異常和的日志使用率內存和磁盤等負載信息只能偶爾看到命令執行的結果中包含一些信息。 作者:張文博 Kubernetes(K8s)是一個開源容器編排系統,可自動執行應用程序部署、擴展和管理。它是云原生世界的操作系統。 K8s 或操作系統中的任何缺陷都可能使用戶進程...
摘要:中國論壇提案征集月日截止論壇讓用戶開發人員從業人員匯聚一堂,面對面進行交流合作。贊助方案出爐多元化獎學金現正接受申請即將首次合體落地中國 PingCAP將其TiDB數據庫平臺押注在云原生上 showImg(https://segmentfault.com/img/bVbogKp?w=508&h=477); 公司:PingCAP地點:中國北京和加利福尼亞州圣馬特奧行業:軟件 挑戰 流行的...
摘要:中國論壇提案征集月日截止論壇讓用戶開發人員從業人員匯聚一堂,面對面進行交流合作。贊助方案出爐多元化獎學金現正接受申請即將首次合體落地中國 PingCAP將其TiDB數據庫平臺押注在云原生上 showImg(https://segmentfault.com/img/bVbogKp?w=508&h=477); 公司:PingCAP地點:中國北京和加利福尼亞州圣馬特奧行業:軟件 挑戰 流行的...
閱讀 2883·2021-09-22 15:20
閱讀 2958·2021-09-22 15:19
閱讀 3448·2021-09-22 15:15
閱讀 2382·2021-09-08 09:35
閱讀 2373·2019-08-30 15:44
閱讀 3004·2019-08-30 10:50
閱讀 3707·2019-08-29 16:25
閱讀 1586·2019-08-26 13:55