天天看點

blkio cgroup

blkio cgroup 基本功能

blkio 是 cgroup v1 中的一個子系統,使用 cgroup v1 blkio 子系統主要是為了減少程序之間共同讀寫同一塊磁盤時互相幹擾的問題。

cgroup v1 blkio 控制子系統可以限制程序讀寫的 IOPS 和吞吐量,但它隻能對 Direct I/O 的檔案讀寫進行限速,對 Buffered I/O 的檔案讀寫無法限制。

Buffered I/O 指會經過 PageCache 然後再寫入到儲存設備中。這裡面的 Buffered 的含義跟記憶體中 buffer cache 不同,這裡的 Buffered 含義相當于記憶體中的buffer cache+page cache。

在 blkio cgroup 中,主要有以下四個參數來限制磁盤 I/O:

blkio.throttle.read_bps_device
blkio.throttle.read_iops_device
blkio.throttle.write_bps_device
blkio.throttle.write_iops_device           

如果要限制某個控制組對磁盤的寫入吞吐量不超過 10M/s,我們可以對blkio.throttle.write_bps_device參數進行配置:

echo "8:0 10485760" > /sys/fs/cgroup/blkio/blkio.throttle.write_bps_device           

在 Linux 中,檔案預設讀寫方式為 Buffered I/O,應用程式一般将檔案寫入到 PageCache 後就直接傳回了,然後核心線程會異步将資料從記憶體同步到磁盤中。而 Direct I/O 不會和記憶體打交道,而是直接寫入到儲存設備中。

要了解 blkio cgroup 的限速邏輯,需要先了解下 Linux 的寫檔案流程。

Linux 寫檔案流程

blkio cgroup

上圖是 Linux 寫檔案的一個流程圖,圖中主要包含三塊,使用者層、核心層、硬體層,Linux 在寫檔案時要經過系統調用、VFS、PageCache、檔案系統、通用塊管理層、IO排程層等多個流程後最終會将檔案寫入到磁盤中。而 blkio cgroup 作用在通用塊管理層。Buffered I/O 是先寫入到 PageCache 再走後面的流程将資料寫入磁盤,而 Direct I/O 會繞過 PageCache 直接走後面的流程。

Linux 中應用程式對檔案讀寫時預設是以 Buffered I/O 的形式寫入的,此時并不需要經過通用塊管理層,隻需寫入到 PageCache 即可,是以無法被限速,但 PageCache 中的資料總是要經過通用塊管理層寫入到磁盤的,原則上說也有影響,但是對于應用程式來說感受可能不一樣,這與 PageCache 寫入磁盤的機制也有關系。

在一般 I/O 的情況下,應用程式很可能很快的就寫完了資料(在資料量小于緩存空間的情況下),然後去做其他事情了。這時應用程式感受不到自己被限速了,而核心在将資料從 PageCache 同步到磁盤階段,由于 PageCache 中沒有具體 cgroup 關聯資訊,是以所有 PageCache 的回寫隻能放到 cgroup 的 root 組中進行限制,而不能在其他cgroup 中進行限制,root cgroup 一般也是不做限制的。而在Direct IO的情況下,由于應用程式寫的資料是不經過緩存層的,是以能直接感受到速度被限制,一定要等到整個資料按限制好的速度寫完或者讀完,才能傳回。這就是目前 cgroup 的 blkio 限制所能起作用的環境限制。

PageCache 中髒頁回寫機制:

(1)髒頁太多,Page Cache 中的髒頁比例達到一定門檻值時回寫,主要有下面兩個參數來控制髒頁比例:

  • dirty_background_ratio 表示當髒頁占總記憶體的的百分比超過這個值時,背景線程開始重新整理髒頁。這個值如果設定得太小,可能不能很好地利用記憶體加速檔案操作。如果設定得太大,則會周期性地出現一個寫 I/O 的峰值,預設為 10;
  • dirty_background_bytes:和 dirty_background_ratio 實作相同的功能,該參數依據髒頁位元組數來判斷,但兩個參數隻會有其中一個生效,預設為 0;
  • dirty_ratio 當髒頁占用的記憶體百分比超過此值時,核心會阻塞掉寫操作,并開始重新整理髒頁,預設為 20;
  • dirty_bytes:和參數 dirty_ratio 實作相同功能,該參數依據髒頁位元組數來判斷,但兩個參數隻會有其中一個生效,預設為 0;

(2)髒頁存在太久,核心線程會周期性回寫,髒頁存在時間主要由以下幾個參數控制:

  • dirty_writeback_centisecs 表示多久喚醒一次重新整理髒頁的背景線程,這個參數會和參數 dirty_background_ratio 一起來作用,一個表示大小比例,一個表示時間;即滿足其中任何一個的條件都達到刷盤的條件,預設為 500;
  • dirty_expire_centisecs 表示髒頁超過多長時間就會被核心線程認為需要寫回到磁盤,預設為 3000;

為什麼 cgroup v1 不支援非 Buffer IO 的限制

cgroup v1 通常是每個層級對應一個子系統,子系統需要挂載使用,而每個子系統之間都是獨立的,很難協同工作,比如 memory cgroup 和 blkio cgroup 能分别控制某個程序的資源使用量,但是blkio cgroup 對程序資源限制的時候無法感覺 memory cgroup 中程序資源的使用量,導緻對 Buffered I/O 的限制一直沒有實作。

cgroup v1 結構如下所示:

blkio cgroup

cgroup v1 因為有很多缺陷也導緻了 linux 的開發者重新設計了 cgroup,也就有了 cgroup v2,在 cgroup v2 中就可以解決 Buffered I/O 限制的問題。cgroup v2 使用了統一層級(unified hierarchy),各個子系統都可以挂載在統一層級下,一個程序屬于一個控制組,每個控制組裡可以定義自己需要的多個子系統。cgroup v2 中 io 子系統等同于 v1 中的 blkio 子系統。

cgroup v2 結構如下所示:

blkio cgroup

參考:

https://www.kernel.org/doc/Documentation/cgroup-v1/blkio-controller.txt http://kernel.pursuitofcloud.org/1780636

繼續閱讀