2021-01-13 關(guān)于線上redis和k8s的幾個(gè)事故復(fù)盤

image.png

如圖,你覺得當(dāng)前系統(tǒng)可用內(nèi)存還有多少?實(shí)際上剩余內(nèi)存不是 1.5gb,而是 2.5Gb。

你需要知道這個(gè)命令展示的 buffer/cache 實(shí)際上指的是緩沖區(qū)數(shù)據(jù)大小,是被操作系統(tǒng)分配了但還未使用的內(nèi)存空間。

  • buffer 全稱 buffer cache,是塊設(shè)備的緩沖區(qū),即磁盤緩沖區(qū)。操作系統(tǒng)會(huì)先把磁盤塊讀取到 buffer cache 中,cache 空間不夠時(shí)會(huì)通過一定的策略清除部分 cache 數(shù)據(jù)。
  • cache 全稱 page cache,是文件系統(tǒng)的緩沖區(qū),即內(nèi)存緩沖區(qū)。幾個(gè)塊組成一個(gè)頁,只緩存文件的內(nèi)容,比 buffer cache 更優(yōu)先提供給應(yīng)用程序使用。
  • swap 線上一般關(guān)閉,使用了交換空間意味著應(yīng)用性能會(huì)較大幅度下降。

如果 cache 的值比較大,說明被緩存的文件數(shù)量比較多,這樣的話磁盤的讀取IO壓力就會(huì)相對(duì)小。

redis 一旦開啟持久化,尤其是 aof 持久化方式,這個(gè) buffer/cache 就會(huì)增長的比較快。但實(shí)際上這個(gè)參數(shù)變大并不會(huì)影響系統(tǒng)使用,應(yīng)用需要的內(nèi)存還是可以分配。

但容器環(huán)境可就不一樣了哦。容器部署的情況下,無論是 docker stat 還是 cadvisor 統(tǒng)計(jì)方式,都會(huì)將 buffer/cache 計(jì)算到已使用的內(nèi)存中,所以配套的指標(biāo)閾值告警也會(huì)存在問題。這個(gè)問題在 docker17.06 版本得到解決,但還是建議實(shí)際測試下自己的 docker 和監(jiān)控方案。

redis 創(chuàng)建子進(jìn)程做 aofrewrite 時(shí),如果內(nèi)存資源不足,會(huì)導(dǎo)致 fork 失敗,fd 不會(huì)被釋放,報(bào)錯(cuò)提示不能申請(qǐng)內(nèi)存??梢酝ㄟ^ /proc/${pid}/fd 下看某 redis 線程具體的 fd 數(shù)量。

通過 redis-cli 查看 info memory 內(nèi)存使用大概了23Gb,機(jī)器本身有 32Gb 可用,buffer/cache 目前使用約 2Gb,意味著剩余可分配內(nèi)存約 8Gb。

關(guān)于 redis 啟動(dòng)時(shí)日志提醒了三個(gè)配置項(xiàng)優(yōu)化點(diǎn):

30914:M 03 Jan 16:30:34.425 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
30914:M 03 Jan 16:30:34.425 # Server started, Redis version 3.2.11
30914:M 03 Jan 16:30:34.425 # WARNING overcommit_memory is set to 0! Background save may fail under low memory condition. To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect.
30914:M 03 Jan 16:30:34.425 # WARNING you have Transparent Huge Pages (THP) support enabled in your kernel. This will create latency and memory usage issues with Redis. To fix this issue run the command 'echo never > /sys/kernel/mm/transparent_hugepage/enabled' as root, and add it to your /etc/rc.local in order to retain the setting after a reboot. Redis must be restarted after THP is disabled.
  1. tcp 連接問題

意思就是這個(gè)參數(shù)系統(tǒng)設(shè)置為 128,但你的 redis配置設(shè)置的 511 超過了系統(tǒng)值。解決方式是通過修改內(nèi)核配置文件 sysctl.conf,添加 net.core.somaxconn= 1024,即將這個(gè)系統(tǒng)參數(shù)設(shè)置大一點(diǎn),這叫操作系統(tǒng)性能優(yōu)化。

  1. 內(nèi)存分配策略設(shè)置不當(dāng)

應(yīng)用程序向操作系統(tǒng)申請(qǐng)內(nèi)存時(shí),內(nèi)存不足內(nèi)核會(huì)怎么處理?

  • overcommit_memory=0,系統(tǒng)默認(rèn)值,即系統(tǒng)剩余內(nèi)存不能滿足你這次的申請(qǐng)需要,就返回報(bào)錯(cuò)信息;
  • overcommit_memory=1redis.conf 建議值,即允許分配所有的物理內(nèi)存,就是先給你再說,最終還是不夠就直接 oom。
  • overcommit_memory=2,允許分配一定量的物理內(nèi)存(overcommit_ratio)和交換空間的內(nèi)存值,一般不會(huì)使用,除非你的 redis 內(nèi)存硬件資源不足,又不能關(guān)機(jī)加內(nèi)存,臨時(shí)可以用這種方式。

所以啊,老老實(shí)實(shí)設(shè)置 vm.overcommit=1 吧。

  1. 系統(tǒng)默認(rèn)設(shè)置的 透明大頁 可能會(huì)存在性能問題

還是頁式存儲(chǔ)的問題,每個(gè)內(nèi)存頁默認(rèn)為 4kb8kb 大小。如果要在內(nèi)存中運(yùn)行比較大的應(yīng)用程序,那么操作系統(tǒng)以 4kb 為單位進(jìn)行物理地址映射時(shí)就會(huì)產(chǎn)生比較多的缺頁中斷和 TLBMiss,從而大大影響性能。
為了能夠動(dòng)態(tài)的修改虛擬內(nèi)存單位的大小,linux 引入了 hugetlbfs 文件系統(tǒng),最大支持設(shè)置每頁 2Mb 內(nèi)存空間。
對(duì)于目前大多數(shù)做了 4k 優(yōu)化的應(yīng)用程序而言,一旦動(dòng)態(tài)修改了這個(gè)參數(shù),分配系統(tǒng)內(nèi)存時(shí)就會(huì)涉及各種內(nèi)存鎖,應(yīng)用程序性能隨機(jī)就會(huì)下降,所以我們要禁用這個(gè)參數(shù)。

/etc/rc.local 文件添加兩行即可:

echo never > /sys/kernel/mm/redhat_transparent_hugepage/defrag
echo never > /sys/kernel/mm/redhat_transparent_hugepage/enabled

線上環(huán)境 k8s 集群安裝成功后,服務(wù)拉鏡像部署的過程中機(jī)房斷電了。你們猜猜會(huì)影響了什么?

  1. xfs 文件系統(tǒng)損壞
  2. etcd 心跳檢測斷連

etcd 斷連的話,從集群摘除再重新加入集群就好了? 但是 systemctl restart etcd 依然不生效,必須先 systemctl stop etcdsystemctl start etcd 才行。之前 dockernginx 也出現(xiàn)過這種問題,執(zhí)行 systemctl reload nginxsystemctl restart docker 也都有過無效的情況,必須先停止再啟動(dòng),更底層的原因就沒有去深究了。

重點(diǎn)的 xfs 文件系統(tǒng)損壞的問題。容器啟動(dòng)失敗,查看日志可以很明顯看到文件系統(tǒng)相關(guān)的報(bào)錯(cuò)。先使用 xfs_repair -n 檢查確定某臺(tái)節(jié)點(diǎn)的文件系統(tǒng)損壞。再檢查了一下故障實(shí)例所在的節(jié)點(diǎn),確實(shí)都在這臺(tái)機(jī)器上,且這臺(tái)機(jī)器上的部分實(shí)例是能正常運(yùn)行的。

xfs_repair 命令就可以修復(fù)損壞的 xfs 文件系統(tǒng)(垃圾浪潮磁盤真的經(jīng)常出問題),但是執(zhí)行這個(gè)命令之前你要umount 相關(guān)的磁盤。如果這個(gè)磁盤掛載的目錄正在使用中怎么辦呢?你 umount -f 都沒用,永遠(yuǎn)都是 device is busy,這可怎么辦?

通過 fuser 這個(gè)工具可以找出某個(gè)目錄被哪些進(jìn)程占用著,也可以殺這些進(jìn)程(線上環(huán)境小心操作,建議先把服務(wù)調(diào)度到其他節(jié)點(diǎn)),知道了進(jìn)程就可以通過 lsof、netstat 查看端口,猜測哪些服務(wù)使用,能否先 kill 掉。但 yum install fuser 發(fā)現(xiàn)沒這個(gè)包?百度一下 yum install -y psmisc 就行了,這種問題在 centos 里是很常見的坑了。rhel8 改成 dnf 命令后就會(huì)提示你這個(gè)命令在哪個(gè)包里能使用,但估計(jì)還要一兩年才能普及 centos8 吧。

結(jié)果 fuser -cu 看占用,fuser -ck 殺相關(guān)進(jìn)程。沒錯(cuò)能殺掉,但得多次執(zhí)行后這目錄又會(huì)被占用,因?yàn)橛形募丛床粩嗟卦趯懭氚?,即使?fuser -ck /xxoo && umount 還是不行哦。

我和運(yùn)維當(dāng)時(shí)都懵逼了,我們頻繁執(zhí)行幾次,特么居然成功了,別問我為什么,我也不知道為什么。和 systemctl 有時(shí)候 restart 失敗一樣:未知力量。然后修復(fù) xfs,重點(diǎn)是修復(fù)后,之前被 k8s 調(diào)度到這臺(tái)節(jié)點(diǎn)的容器有好幾個(gè)都無法啟動(dòng),pod 狀態(tài)為:ImageInspectError

這個(gè)狀態(tài)是鏡像校驗(yàn)過程發(fā)生錯(cuò)誤,第一,我們部署包關(guān)于鏡像校驗(yàn)?zāi)_本都沒改動(dòng)啊,第二,k8s集群本身是不是有對(duì)鏡像的檢驗(yàn),第三,上傳到docker-registy的鏡像是否完整(第二次意識(shí)到harbor的重要性,第一次是跨集群鏡像同步需求),第四,本地拉到的鏡像是不是出問題了。

然后簡單問了一下運(yùn)維這次的部署包有變更嗎,最近沒有改動(dòng)。k8s本身我記得是沒有對(duì)docker image做什么判斷改動(dòng)的,就算有也應(yīng)該最后去看(主要是其他服務(wù)正常,散列類型的出錯(cuò)不太可能是集群本身環(huán)境問題)然后docker-registry都倉庫了我也沒去驗(yàn)證啊,那我只能認(rèn)為是下拉鏡像過程sha1變了,或者拉下來后斷電導(dǎo)致磁盤壞道,導(dǎo)致某些服務(wù)的overlayfs壞了,通過systemctl status docker和journalctl -f日志確實(shí)看到overlayfs報(bào)錯(cuò)(etcd斷連同樣這樣看到的,這是基操),返回狀態(tài)碼-2,谷歌一下都說文件系統(tǒng)損壞,可我特么剛修復(fù)xfs文件系統(tǒng)啊。然后我認(rèn)為是原因是后者,文件系統(tǒng)是當(dāng)時(shí)出問題了,拉下來的鏡像在repair后不完整了,這時(shí)候你想到了如何解決嗎?

我先手動(dòng)改yaml nodeName強(qiáng)制服務(wù)調(diào)度到非斷電機(jī)器,結(jié)果服務(wù)正常了。(你要是K8s上萬臺(tái)就GG了)我查看某個(gè)ImageInspectErr服務(wù),-owide查看鏡像名和調(diào)度節(jié)點(diǎn)發(fā)現(xiàn)出問題的都在斷電機(jī)器上。然后ssh去那個(gè)機(jī)器(你要是沒權(quán)限就GG了),嘗試性的在這個(gè)k8s節(jié)點(diǎn)docker命令刪除本地鏡像,結(jié)果特么打死都刪除不了(因?yàn)橛腥萜髋苤。?,我特么遲疑了3s才想起來k8s deployment確保一直有一個(gè)容器服務(wù)啟動(dòng),然后還要edit deploy replicas=0。然后刪啊刪,然后又改回來replicas=1,ok一切都成功啦?。?!

結(jié)果特么還有個(gè)末尾,有個(gè)服務(wù)正常Running,0/1,logs查看一直都是sleep。這尼瑪?shù)疤垡槐龋M(jìn)去服務(wù)里看日志,尼瑪Nodejs服務(wù),提示丟失ippxxoo mudule,what??我特么寫Nodejs的也沒發(fā)現(xiàn)我們用了這個(gè)模塊啊,問了運(yùn)維他說上午這個(gè)服務(wù)運(yùn)行是正常的。事后解決才想起,可能底層overlayfs丟失的磁盤數(shù)據(jù)里包含了這個(gè)modules吧。同樣的道理操作解決(這個(gè)問題在上一條之前發(fā)現(xiàn),困擾了十分鐘)。本來只是因?yàn)殚_發(fā)網(wǎng)玩壞了codis導(dǎo)致找運(yùn)維上物理機(jī),結(jié)果全程2小時(shí)操蛋。另外目前docker更推薦的存儲(chǔ)是overlay2,但建議內(nèi)核 >4.0(我們是3.10跑著容器服務(wù),才過很多坑了,如果你的大規(guī)模使用k8s,其實(shí)有坑也不用踩,最終一致性的集群,OOM之前也會(huì)給你重啟,很多時(shí)候卻是臨時(shí)解決了可用性問題)

其實(shí)這個(gè)開發(fā)網(wǎng)codis問題后面還引發(fā)了半小時(shí)zk注冊(cè)節(jié)點(diǎn)和codis-dashboard問題,就不說了,心累

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容