本文首發於 vivo互聯網技術 微信公眾號
鏈接: https://mp.weixin.qq.com/s/MaeXn-kmgLUah78brglFkg
作者:Yang Yijun
本文主要描述Linux Page Cache優化的背景、Page Cache的基本概念、列舉之前針對Kafka的 IO 性能瓶頸采取的一些解決方案、如何進行Page Cache相關參數調整以及性能優化前后效果對比。
一、優化背景
當業務快速增長,每天需要處理萬億記錄級數據量時。在讀寫數據方面,Kafka 集群的壓力將變得巨大,而磁盤 IO 成為了 Kafka 集群最大的性能瓶頸。
當出現入流量突增或者出流量突增情況,磁盤 IO 持續處於被打滿狀態,導致無法處理新的讀寫請求,甚至造成部分broker節點雪崩而影響集群的穩定。
如下圖所示,磁盤 IO 被持續打滿:
這嚴重的影響了集群的穩定,從而影響業務的穩定運行。對此,我們做出了一些針對性的優化方案:
- 對Linux操作系統的Page Cache參數進行優化;【本文主要講解內容】
- 對kafka集群用戶的出入流量進行限制,避免出入流量突增給磁盤IO帶來的壓力;【本文對此方案不做講解】
- 按業務對集群進行資源組隔離(集群broker的物理隔離),避免不同業務間因為共享磁盤IO相互影響;【本文對此方案不做講解】
- 對Kafka集群broker節點服務參數進行優化;【本文對此方案不做講解】
- 改造Kafka副本遷移源碼,實現增量並發副本遷移,減少副本遷移給集群broker節點磁盤IO帶來的壓力;【本文對此方案不做講解】
- 開發一套Kafka集群自動負載均衡服務,定期對集群進行負載均衡;【本文對此方案不做講解】
- 采用IO性能更好的SSD固態硬盤替換普通的機械硬盤;進行磁盤RAID讓broker內部多塊磁盤間IO負載更加均衡【本文對此方案不做講解】
- 改造Kafka源碼,對Kafka集群單個broker及單個topic進行出入流量限制,實現流量對最細粒度控制;當單個broker流量突增時可以對其進行上限限制,避免節點被異常流量打掛;【本文對此方案不做講解】
- 改造Kafka源碼,修復副本遷移任務啟動后不可手動終止的缺陷,實現當因遷移導致負載過高卻無法停止的問題;【本文對此方案不做講解】
- 機房網絡帶寬的競爭也將間接的影響到follower同步leader的數據,最終將導致follower同步拉取歷史數據而增加IO負載,因此需要對網絡帶寬進行優先級打標,當有競爭時提高Kafka集群的優先級,避免kafka集群的broker和其他大量消耗網絡帶寬的業務共用機房交換機。【本文對此方案不做講解】
以上只是列舉了幾點主要的優化方案,還有一些其他的內容這里不再贅述。本文我們主要來講解一下 Linux操作系統的Page Cache參數調優。
二、基本概念
1、什么是Page Cache?
Page Cache是針對文件系統的緩存,通過將磁盤中的文件數據緩存到內存中,從而減少磁盤I/O操作提高性能。
對磁盤的數據進行緩存從而提高性能主要是基於兩個因素:
- 磁盤訪問的速度比內存慢好幾個數量級(毫秒和納秒的差距);
- 被訪問過的數據,有很大概率會被再次訪問。
文件讀寫流程如下所示:
2、讀Cache
當內核發起一個讀請求時(例如進程發起read()請求),首先會檢查請求的數據是否緩存到了Page Cache中。
如果有,那么直接從內存中讀取,不需要訪問磁盤,這被稱為cache命中(cache hit);
如果cache中沒有請求的數據,即cache未命中(cache miss),就必須從磁盤中讀取數據。然后內核將讀取的數據緩存到cache中,這樣后續的讀請求就可以命中cache了。
page可以只緩存一個文件部分的內容,不需要把整個文件都緩存進來。
3、寫Cache
當內核發起一個寫請求時(例如進程發起write()請求),同樣是直接往cache中寫入,后備存儲中的內容不會直接更新(當服務器出現斷電關機時,存在數據丟失風險)。
內核會將被寫入的page標記為dirty,並將其加入dirty list中。內核會周期性地將dirty list中的page寫回到磁盤上,從而使磁盤上的數據和內存中緩存的數據一致。
當滿足以下兩個條件之一將觸發臟數據刷新到磁盤操作:
- 數據存在的時間超過了dirty_expire_centisecs(默認300厘秒,即30秒)時間;
- 臟數據所占內存 > dirty_background_ratio,也就是說當臟數據所占用的內存占總內存的比例超過dirty_background_ratio(默認10,即系統內存的10%)的時候會觸發pdflush刷新臟數據。
4、Page Cache緩存查看工具
我們如何查看緩存命中率呢?在這里我們可以借助一個緩存命中率查看工具 cachestat。
(1)下載安裝
(2)啟動執行
(3)輸出內容說明
5、如何回收Page Cache
執行腳本:echo 1 > /proc/sys/vm/drop_caches 這里可能需要等待一會,因為有應用程序正在寫數據。
回收前:
回收后:
緩存回收后,正常情況下,buff/cache應該是0的,我這里之所以不為0是因為有數據正在不停的寫入。
三、參數調優
備注:不同硬件配置的服務器可能效果不同,所以,具體的參數值設置需要考慮自己集群硬件配置。
考慮的因素主要包括:CPU核數、內存大小、硬盤類型、網絡帶寬等。
1、如何查看Page Cache參數
執行命令 sysctl -a|grep dirty
2、操作系統Page Cache相關參數默認值
vm.dirty_background_bytes = 0 # 和參數vm.dirty_background_ratio實現相同功能,但兩個參數只會有其中一個生效,表示臟頁大小達到多少字節后開始觸發刷磁盤 vm.dirty_background_ratio = 10 vm.dirty_bytes = 0 # 和參數vm.dirty_ratio實現相同功能,但兩個參數只會有其中一個生效,表示臟頁達到多少字節后停止接收寫請求,開始觸發刷磁盤 vm.dirty_ratio = 20 vm.dirty_expire_centisecs = 3000 #這里表示30秒(時間單位:厘秒) vm.dirty_writeback_centisecs = 500 #這里表示5秒(時間單位:厘秒)
3、如果系統中cached大量數據可能存在的問題
- 緩存的數據越多,丟數據的風險越大。
- 會定期出現IO峰值,這個峰值時間會較長,在這期間所有新的寫IO性能會很差(極端情況直接被hang住)。
后一個問題對寫負載很高的應用會產生很大影響。
4、如何調整內核參數來優化IO性能?
(1)vm.dirty_background_ratio參數優化
當cached中緩存當數據占總內存的比例達到這個參數設定的值時將觸發刷磁盤操作。
把這個參數適當調小,這樣可以把原來一個大的IO刷盤操作變為多個小的IO刷盤操作,從而把IO寫峰值削平。
對於內存很大和磁盤性能比較差的服務器,應該把這個值設置的小一點。
#設置方法1: sysctl -w vm.dirty_background_ratio=1(臨時生效,重啟服務器后失效) #設置方法2(永久生效): echo vm.dirty_background_ratio=1 >> /etc/sysctl.conf sysctl -p /etc/sysctl.conf #設置方法3(永久生效): #當然你還可以在/etc/sysctl.d/目錄下創建一個自己的參數優化文件,把系統優化參數進行歸類存放,然后設置生效,如: touch /etc/sysctl.d/kafka-optimization.conf echo vm.dirty_background_ratio=1 >> /etc/sysctl.d/kafka-optimization.conf sysctl --system
(2)vm.dirty_ratio參數優化
對於寫壓力特別大的,建議把這個參數適當調大;對於寫壓力小的可以適當調小;如果cached的數據所占比例(這里是占總內存的比例)超過這個設置,
系統會停止所有的應用層的IO寫操作,等待刷完數據后恢復IO。所以萬一觸發了系統的這個操作,對於用戶來說影響非常大的。
(3)vm.dirty_expire_centisecs參數優化
這個參數會和參數vm.dirty_background_ratio一起來作用,一個表示大小比例,一個表示時間;即滿足其中任何一個的條件都達到刷盤的條件。
為什么要這么設計呢?我們來試想一下以下場景:
- 如果只有參數 vm.dirty_background_ratio ,也就是說cache中的數據需要超過這個閥值才會滿足刷磁盤的條件;
- 如果數據一直沒有達到這個閥值,那相當於cache中的數據就永遠無法持久化到磁盤,這種情況下,一旦服務器重啟,那么cache中的數據必然丟失。
結合以上情況,所以添加了一個數據過期時間參數。當數據量沒有達到閥值,但是達到了我們設定的過期時間,同樣可以實現數據刷盤。
這樣可以有效的解決上述存在的問題,其實這種設計在絕大部分框架中都有。
(4)vm.dirty_writeback_centisecs參數優化
理論上調小這個參數,可以提高刷磁盤的頻率,從而盡快把臟數據刷新到磁盤上。但一定要保證間隔時間內一定可以讓數據刷盤完成。
(5)vm.swappiness參數優化
禁用swap空間,設置vm.swappiness=0
5、參數調優前后效果對比
(1)寫入流量對比
從下圖可以看出,優化前寫入流量出現大量突刺,波動非常大,優化后寫入流量更加平滑。
(2)磁盤IO UTIL對比
從下圖可以看出,優化前IO出現大量突刺,波動非常大,優化后IO更加平滑。
(3)網絡入流量對比
從下圖可以看出,優化前后對網絡入流量並無影響。
四、總結
這里不同機型,不同硬件配置可能最終優化效果也不一樣,但是參數變化的趨勢應該是一致的。
1、當vm.dirty_background_ratio、vm.dirty_expire_centisecs變大時
- 出入流量抖動變大,出現大量突刺;
- IO抖動變大,出現大量突刺,磁盤有連續打滿的情況;
- 出入流量平均大小不受影響;
2、當vm.dirty_background_ratio、vm.dirty_expire_centisecs變小時
- 出入流量抖動變小,趨於平滑穩定,無突刺;
- 磁盤IO抖動變小,無突刺,磁盤IO無打滿情況;
- 出入流量平均大小不受影響;
3、當vm.dirty_ratio變小(低於10)
- 出入流量隔一段時間出現一個明顯的波谷;這是因為cache數據量超過vm.dirty_ratio設定的值將阻塞寫請求,進行刷盤操作。
4、當vm.dirty_ratio變大時(高於40),出入流量無明顯的波谷,流量平滑;
5、當以下三個參數分別為對應值時,出入流量非常平滑,趨於一條直線;
- vm.dirty_background_ratio=1
- vm.dirty_ratio=80
- vm.dirty_expire_centisecs=1000
6、如下圖所示,整個調整過程平均流量不受影響
更多內容敬請關注 vivo 互聯網技術 微信公眾號
注:轉載文章請先與微信號:Labs2020 聯系