Linux 的 IO 隔離


跟內存管理那部分複雜度類似, IO 的資源隔離要講清楚也是比較麻煩的。這部分內容都是這樣,配置起來簡單,但是要理解清楚確沒那麼簡單。這次是跟 Linux 內核的 IO 實現有關係。對於 IO 的速度限制,實現思路跟 CPU 和內存都不一樣。 CPU 是針對進程佔用時間的比例限制,內存是空間限制,而當我們討論 IO 資源隔離的時候,實際上有兩個資源需要考慮,一個是空間,另一個是速度。對於空間來說,這個很簡單,大不了分區就是了。現實手段中,分區、 LVM 、磁盤配額、目錄配額等等,不同的分區管理方式,不同的文件系統都給出了很多不同的解決方案。所以,空間的限制實際上不是 cgroup 要解決的問題,那就是說,我們在這裏要解決的問題是:如何進行 IO 數據傳輸的速度限制。

限速這件事情,現實中有很多模型、算法去解決這個問題。比如,如果我們想控制高速公路上的汽車單位時間通過率,就讓收費站每隔固定時間週期只允許通過固定個數的車就好了。這是一種非常有效的控制手段--漏斗算法。現實中這種算法可能在特定情況下會造成資源浪費以及用戶的體驗不好,於是又演化出令牌桶算法。這裏我們不去詳細分析這些算法,但是我們要知道,對 io 的限速基本是一個漏斗算法的限速效果。無論如何,這種限速都要有個“收費站”這樣的設施來執行限速,那麼對於 Linux 的 IO 體系來說,這個”收費站”建在哪裏呢?於是我們就必須先來了解一下:

Linux 的 IO 體系

Linux 的 IO 體系是個層級還算清晰的結構,它基本上分成了如圖示這樣幾層:

Linux 的 IO 體系層次結構

Linux 的 IO 體系層次

我們可以通過追蹤一個 read()系統調用來一窺這些層次的結構,當 read()系統調用發生,內核首先會通過彙編指令引發一個軟中斷,然後根據中斷傳入的參數查詢系統調用影射表,找到 read()對應的內核調用方法名,並去執行相關調用,這個系統調用名一般情況下就是 sys_read()。從此,便開始了調用在內核中處理的過程的第一步:

  1. VFS 層:虛擬文件系統層。由於內核要跟多種文件系統打交道,而每一種文件系統所實現的數據結構和相關方法都可能不盡相同,所以,內核抽象了這一層,專門用來適配各種文件系統,並對外提供統一操作接口。
  2. 文件系統層:不同的文件系統實現自己的操作過程,提供自己特有的特徵,具體不多說了,大家願意的話自己去看代碼即可。
  3. 頁緩存層:我們的老朋友了,如果不瞭解緩存是什麼的,可以先來看看Linux 內存資源管理部分。
  4. 通用塊層:由於絕大多數情況的 io 操作是跟塊設備打交道,所以 Linux 在此提供了一個類似 vfs 層的塊設備操作抽象層。下層對接各種不同屬性的塊設備,對上提供統一的 Block IO 請求標準。
  5. IO 調度層:因爲絕大多數的塊設備都是類似磁盤這樣的設備,所以有必要根據這類設備的特點以及應用的不同特點來設置一些不同的調度算法和隊列。以便在不同的應用環境下有針對性的提高磁盤的讀寫效率,這裏就是大名鼎鼎的 Linux 電梯所起作用的地方。針對機械硬盤的各種調度方法就是在這實現的。
  6. 塊設備驅動層:驅動層對外提供相對比較高級的設備操作接口,往往是 C 語言的,而下層對接設備本身的操作方法和規範。
  7. 塊設備層:這層就是具體的物理設備了,定義了各種真對設備操作方法和規範。

根據這幾層的特點,如果你是設計者,你會在哪裏實現真對塊設備的限速策略呢? 6 、 7 都是相關具體設備的,如果在這個層次提供,那就不是內核全局的功能,而是某些設備自己的 feture 。文件系統層也可以實現,但是如果要全局實現也是不可能的,需要每種文件系統中都實現一遍,成本太高。所以,可以實現限速的地方比較合適的是 VFS 、緩存層、通用塊層和 IO 調度層。而 VFS 和 page cache 這樣的機制並不是面向塊設備設計的,都是做其他事情用的,雖然也在 io 體系中,但是並不適合用來做 block io 的限速。所以這幾層中,最適合並且成本最低就可以實現的地方就是 IO 調度層和通用塊層。 IO 調度層本身已經有隊列了,我們只要在隊列裏面實現一個限速機制即可,但是在 IO 調度層實現的限速會因爲不同調度算法的側重點不一樣而有很多侷限性,從通用塊層實現的限速,原則上就可以對幾乎所有的塊設備進行帶寬和 iops 的限制。截止目前( 4.3.3 內核), IO 限速主要實現在這兩層中。

根據 IO 調度層和通用塊層的特點,這兩層分別實現了兩種不同策略的 IO 控制策略,也是目前 blkio 子系統提供的兩種控制策略,一個是權重比例方式的控制,另一個是針對 IO 帶寬和 IOPS 的控制。

IO 調度層

我們需要先來認識一下 IO 調度層。這一層要解決的核心問題是,如何提高塊設備 IO 的整體性能?這一層也主要是針對用途最廣泛的機械硬盤結構而設計的。衆所周知,機械硬盤的存儲介質是磁介質,並且是盤狀,用磁頭在盤片上移動進行數據的尋址,這類似播放一張唱片。這種結構的特點是,順序的數據讀寫效率比較理想,但是如果一旦對盤片有隨機讀寫,那麼大量的時間都會浪費在磁頭的移動上,這時候就會導致每次 IO 的響應時間很長,極大的降低 IO 的響應速度。磁頭在盤片上尋道的操作,類似電梯調度,如果在尋道的過程中,能把路過的相關磁道的數據請求都“順便”處理掉,那麼就可以在比較小影響響應速度的前提下,提高整體 IO 的吞吐量。所以,一個好的 IO 調度算法的需求就此產生。在最開始的階段, Linux 就把這個算法命名爲 Linux 電梯算法。目前在內核中默認開啓了三種算法,其實嚴格算應該是兩種,因爲第一種叫做 noop ,就是空操作調度算法,也就是沒有任何調度操作,並不對 io 請求進行排序,僅僅做適當的 io 合併的一個 fifo 隊列。

目前內核中默認的調度算法應該是 cfq ,叫做完全公平隊列調度。這個調度算法人如其名,它試圖給所有進程提供一個完全公平的 IO 操作環境。它爲每個進程創建一個同步 IO 調度隊列,並默認以時間片和請求數限定的方式分配 IO 資源,以此保證每個進程的 IO 資源佔用是公平的, cfq 還實現了針對進程級別的優先級調度,這裏我們不去細節解釋。我們在此只需要知道,既然時間片分好了,優先級實現了,那麼 cfq 肯定是實現進程級別的權重比例分配的最好方案。內核就是這麼做的, cgroup blkio 的權重比例限制就是基於 cfq 調度器實現的。如果你要使用權重比例分配,請先確定對應的塊設備的 IO 調度算法是 cfq 。

查看和修改的方法是:

[zorro@zorrozou-pc0 ~]$ cat /sys/block/sda/queue/scheduler 
noop deadline [cfq] 
[zorro@zorrozou-pc0 ~]$ echo cfq > /sys/block/sda/queue/scheduler

cfq 是通用服務器比較好的 IO 調度算法選擇,對桌面用戶也是比較好的選擇。但是對於很多 IO 壓力較大的場景就並不是很適應,尤其是 IO 壓力集中在某些進程上的場景。因爲這種場景我們需要更多的滿足某個或者某幾個進程的 IO 響應速度,而不是讓所有的進程公平的使用 IO ,比如數據庫應用。

deadline 調度(最終期限調度)就是更適應這樣的場景的解決方案。 deadline 實現了四個隊列,其中兩個分別處理正常 read 和 write ,按扇區號排序,進行正常 io 的合併處理以提高吞吐量.因爲 IO 請求可能會集中在某些磁盤位置,這樣會導致新來的請求一直被合併,於是可能會有其他磁盤位置的 io 請求被餓死。於是實現了另外兩個處理超時 read 和 write 的隊列,按請求創建時間排序,如果有超時的請求出現,就放進這兩個隊列,調度算法保證超時(達到最終期限時間)的隊列中的請求會優先被處理,防止請求被餓死。由於 deadline 的特點,無疑在這裏無法區分進程,也就不能實現針對進程的 io 資源控制。

其實不久前,內核還是默認標配四種算法,還有一種叫做 as 的算法( Anticipatory scheduler ),預測調度算法。一個高大上的名字,搞得我一度認爲 Linux 內核都會算命了。結果發現,無非是在基於 deadline 算法做 io 調度的之前等一小會時間,如果這段時間內有可以合併的 io 請求到來,就可以合併處理,提高 deadline 調度的在順序讀寫情況下的數據吞吐量。其實這根本不是啥預測,我覺得不如叫撞大運調度算法。估計結果是不僅沒有提高吞吐量,還降低了響應速度,所以內核乾脆把它從默認配置裏刪除了。畢竟 Linux 的宗旨是實用。

根據以上幾種 io 調度算法的簡單分析,我們也能對各種調度算法的使用場景有一些大致的思路了。從原理上看, cfq 是一種比較通用的調度算法,是一種以進程爲出發點考慮的調度算法,保證大家儘量公平。 deadline 是一種以提高機械硬盤吞吐量爲思考出發點的調度算法,只有當有 io 請求達到最終期限的時候才進行調度,非常適合業務比較單一併且 IO 壓力比較重的業務,比如數據庫。而 noop 呢?其實如果我們把我們的思考對象拓展到固態硬盤,那麼你就會發現,無論 cfq 還是 deadline ,都是針對機械硬盤的結構進行的隊列算法調整,而這種調整對於固態硬盤來說,完全沒有意義。對於固態硬盤來說, IO 調度算法越複雜,效率就越低,因爲額外要處理的邏輯越多。所以,固態硬盤這種場景下,使用 noop 是最好的, deadline 次之,而 cfq 由於複雜度的原因,無疑效率最低。但是,如果你想對你的固態硬盤做基於權重比例的 IO 限速的話,那就沒啥辦法了,畢竟這時候,效率並不是你的需求,要不你限速幹嘛?

通用塊設備層

這層的作用我這裏就不再複述了,本節其實主要想解釋的是,既然這裏實現了對 blkio 的帶寬和 iops 的速度限制,那麼有沒有什麼需要注意的地方?這自然是有的。首先我們還是要先來搞清楚 IO 中的幾個概念。

一般 IO

一個正常的文件 io ,需要經過 vfs -> buffer\page cache -> 文件系統 -> 通用塊設備層 -> IO 調度層 -> 塊設備驅動 -> 硬件設備這所有幾個層次。其實這就是一般 IO 。當然,不同的狀態可能會有變化,比如一個進程正好 open 並 read 一個已經存在於 page cache 中的數據。這樣的事情我們排出在外不分析。那麼什麼是比較特別的 io 呢?

Direct IO

中文也可以叫直接 IO 操作,其特點是, VFS 之後跳過 buffer\page cache 層,直接從文件系統層進行操作。那麼就意味着,無論讀還是寫,都不會進行 cache 。我們基本上可以理解這樣的 io 看起來效率要低很多,直接看到的速度就是設備的速度,並且缺少了 cache 層對數據的緩存之後,文件系統和數據塊的操作效率直接暴露給了應用程序,塊的大小會直接影響 io 速度。

Sync IO & write-through:

中文叫做同步 IO 操作,如果是寫操作的話也叫 write-through ,這個操作往往容易跟上面的 DIO 搞混,因爲看起來他們速度上差不多,但是是有本質區別的。這種方式寫的數據要等待存儲寫入返回才能成功返回,所以跟 DIO 效率差不多,但是,寫的數據仍然是要在 cache 中寫入的,這樣其他一般 IO 的程度仍然可以使用 cache 機制加速 IO 操作。所以,這裏的 sync 的意思就是,在執行 write 操作的時候,讓 cache 和存儲上的數據一致。那麼他跟一般 IO 其實一樣,數據是要經過 cache 層的。

write-back:

既然明白了 write-thuough ,那麼 write-back 就好理解了,無非就是將目前在 cache 中還沒寫回存儲的髒數據寫回到存儲。這個名詞一般指的是一個獨立的過程,這個過程不是隨着應用的寫而發生,這往往是內核自己找個時間來單獨操作的。說白了就是,應用寫文件,感覺自己很快寫完了,其實內核都把數據放倒 cache 裏了,然後內核自己找時間再去寫回到存儲上。實際上 write-back 只是在一般 IO 的情況下,保證數據一致性的一種機制而已。

有人將 IO 過程中,以是否使用緩衝(緩存)的區別,將 IO 分成了緩存 IO ( Buffered IO )和直接 IO ( Direct io )。其實就是名詞上的不同而已。這裏面的 buffer 的含義跟內存中 buffer cache 有概念上的不同。實際上這裏 Buffered IO 的含義,相當於內存中的 buffer cache+page cache ,就是 IO 經過緩存的意思。到這我們思考一個問題,如果 cgroup 針對 IO 的資源限制實現在了通用塊設備層,那麼將會對哪些 IO 操作有影響呢?其實原則上說都有影響,因爲絕大多數數據都是要經過通用塊設備層寫入存儲的,但是對於應用程序來說感受可能不一樣。在一般 IO 的情況下,應用程序很可能很快的就寫完了數據(在數據量小於緩存空間的情況下),然後去做其他事情了。這時應用程序感受不到自己被限速了,而內核在處理 write-back 的階段,由於沒有相關 page cache 中的 inode 是屬於那個 cgroup 的信息記錄,所以所有的 page cache 的回寫只能放到 cgroup 的 root 組中進行限制,而不能在其他 cgroup 中進行限制,因爲 root 組的 cgroup 一般是不做限制的,所以就相當於目前的 cgroup 的 blkio 對 buffered IO 是沒有限速支持的。這個功能將在使用了 unified-hierarchy 體系的 cgroup v2 中的部分文件系統( ext 系列)已經得到得到支持,目前這個功能還在開發中,據說將在 4.5 版本的內核中正式發佈。

而在 Sync IO 和 Direct IO 的情況下,由於應用程序寫的數據是不經過緩存層的,所以能直接感受到速度被限制,一定要等到整個數據按限制好的速度寫完或者讀完,才能返回。這就是當前 cgroup 的 blkio 限制所能起作用的環境限制。瞭解了這個之後,我們就可以來看:

blkio 配置方法

權重比例分配

我們這次直接使用命令行的方式對 cgroup 進行操作。在我們的系統上,我們現在想創建兩個 cgroup 組,一個叫 test1 ,一個叫 test2 。我們想讓這兩個組的進程在對 /dev/sdb ,設備號爲 8:16 的這個磁盤進行讀寫的時候按權重比例進行 io 資源的分配。具體配置方法如下:

首先確認系統上已經 mount 了相關的 cgroup 目錄:

[root@zorrozou-pc0 ~]# ls /sys/fs/cgroup/blkio/
blkio.io_merged        blkio.io_service_bytes_recursive  blkio.io_wait_time        blkio.sectors            blkio.throttle.read_iops_device   blkio.weight       tasks
blkio.io_merged_recursive  blkio.io_serviced             blkio.io_wait_time_recursive  blkio.sectors_recursive      blkio.throttle.write_bps_device   blkio.weight_device
blkio.io_queued        blkio.io_serviced_recursive       blkio.leaf_weight         blkio.throttle.io_service_bytes  blkio.throttle.write_iops_device  cgroup.clone_children
blkio.io_queued_recursive  blkio.io_service_time         blkio.leaf_weight_device      blkio.throttle.io_serviced       blkio.time                cgroup.procs
blkio.io_service_bytes     blkio.io_service_time_recursive   blkio.reset_stats         blkio.throttle.read_bps_device   blkio.time_recursive          notify_on_release

然後創建兩個針對 blkio 的 cgroup

[root@zorrozou-pc0 ~]# mkdir /sys/fs/cgroup/blkio/test1
[root@zorrozou-pc0 ~]# mkdir /sys/fs/cgroup/blkio/test2

相關目錄下會自動產生相關配置項:

[root@zorrozou-pc0 ~]# ls /sys/fs/cgroup/blkio/test{1,2}
/sys/fs/cgroup/blkio/test1:
blkio.io_merged        blkio.io_service_bytes_recursive  blkio.io_wait_time        blkio.sectors            blkio.throttle.read_iops_device   blkio.weight       tasks
blkio.io_merged_recursive  blkio.io_serviced             blkio.io_wait_time_recursive  blkio.sectors_recursive      blkio.throttle.write_bps_device   blkio.weight_device
blkio.io_queued        blkio.io_serviced_recursive       blkio.leaf_weight         blkio.throttle.io_service_bytes  blkio.throttle.write_iops_device  cgroup.clone_children
blkio.io_queued_recursive  blkio.io_service_time         blkio.leaf_weight_device      blkio.throttle.io_serviced       blkio.time                cgroup.procs
blkio.io_service_bytes     blkio.io_service_time_recursive   blkio.reset_stats         blkio.throttle.read_bps_device   blkio.time_recursive          notify_on_release

/sys/fs/cgroup/blkio/test2:
blkio.io_merged        blkio.io_service_bytes_recursive  blkio.io_wait_time        blkio.sectors            blkio.throttle.read_iops_device   blkio.weight       tasks
blkio.io_merged_recursive  blkio.io_serviced             blkio.io_wait_time_recursive  blkio.sectors_recursive      blkio.throttle.write_bps_device   blkio.weight_device
blkio.io_queued        blkio.io_serviced_recursive       blkio.leaf_weight         blkio.throttle.io_service_bytes  blkio.throttle.write_iops_device  cgroup.clone_children
blkio.io_queued_recursive  blkio.io_service_time         blkio.leaf_weight_device      blkio.throttle.io_serviced       blkio.time                cgroup.procs
blkio.io_service_bytes     blkio.io_service_time_recursive   blkio.reset_stats         blkio.throttle.read_bps_device   blkio.time_recursive          notify_on_release

之後我們就可以進行限制了。針對 cgroup 進行權重限制的配置有blkio.weight,是單純針對 cgroup 進行權重配置的,還有blkio.weight_device可以針對設備單獨進行限制,我們都來試試。首先我們想設置 test1 和 test2 使用任何設備的 io 權重比例都是 1:2 :

[root@zorrozou-pc0 zorro]# echo 100 > /sys/fs/cgroup/blkio/test1/blkio.weight
[root@zorrozou-pc0 zorro]# echo 200 > /sys/fs/cgroup/blkio/test2/blkio.weight

注意權重設置的取值範圍爲: 10-1000 。然後我們來寫一個測試腳本:

#!/bin/bash

testfile1=/home/test1
testfile2=/home/test2

if [ -e $testfile1 ]
then
    rm -rf $testfile1
fi

if [ -e $testfile2 ]
then
    rm -rf $testfile2
fi

sync
echo 3 > /proc/sys/vm/drop_caches

cgexec -g blkio:test1 dd if=/dev/zero of=$testfile1 oflag=direct bs=1M count=1023 &

cgexec -g blkio:test2 dd if=/dev/zero of=$testfile2 oflag=direct bs=1M count=1023 &

我們 dd 的時候使用的是 direct 標記,在這使用 sync 和不加任何標記的話都達不到效果。因爲權重限制是基於 cfq 實現, cfq 要標記進程,而 buffered IO 都是內核同步,無法標記進程。使用 iotop 查看限制效果:

[root@zorrozou-pc0 zorro]# iotop -b -n1|grep direct
 1519 be/4 root        0.00 B/s  110.00 M/s  0.00 % 99.99 % dd if=/dev/zero of=/home/test2 oflag=direct bs=1M count=1023
 1518 be/4 root        0.00 B/s   55.00 M/s  0.00 % 99.99 % dd if=/dev/zero of=/home/test1 oflag=direct bs=1M count=1023

卻是達到了 1:2 比例限速的效果。此時對於磁盤讀取的限制效果也一樣,具體測試用例大家可以自己編寫。讀取的時候要注意,仍然要保證讀取的文件不在 page cache 中,方法就是: echo 3 > /proc/sys/vm/drop_caches 。因爲在 page cache 中的數據已經在內存裏了,直接修改是直接改內存中的內容,只有 write-back 的時候纔會經過 cfq 。

我們再來試一下針對設備的權重分配,請注意設備號的填寫格式:

[root@zorrozou-pc0 zorro]# echo "8:16 400" > /sys/fs/cgroup/blkio/test1/blkio.weight_device 
[root@zorrozou-pc0 zorro]# echo "8:16 200" > /sys/fs/cgroup/blkio/test2/blkio.weight_device 

[root@zorrozou-pc0 zorro]# iotop -b -n1|grep direct
 1800 be/4 root        0.00 B/s  102.24 M/s  0.00 % 99.99 % dd if=/dev/zero of=/home/test1 oflag=direct bs=1M count=1023
 1801 be/4 root        0.00 B/s   51.12 M/s  0.00 % 99.99 % dd if=/dev/zero of=/home/test2 oflag=direct bs=1M count=1023

我們會發現,這時權重確實是按照最後一次的設置, test1 和 test2 變成了 2:1 的比例,而不是 1:2 了。這裏要說明的就是,注意 blkio.weight_device 的設置會覆蓋 blkio.weight 的設置,因爲前者的設置精確到了設備, Linux 在這裏的策略是,越精確越優先。

讀寫帶寬和 iops 限制

針對讀寫帶寬和 iops 的限制都是絕對值限制,所以我們不用兩個 cgroup 做對比了。我們就設置 test1 的寫帶寬速度爲 1M/s:

[root@zorrozou-pc0 zorro]# echo "8:16  1048576" > /sys/fs/cgroup/blkio/test1/blkio.throttle.write_bps_device

[root@zorrozou-pc0 zorro]# sync
[root@zorrozou-pc0 zorro]# echo 3 > /proc/sys/vm/drop_caches

[root@zorrozou-pc0 zorro]# cgexec -g blkio:test1 dd if=/dev/zero of=/home/test oflag=direct count=1024 bs=1M
^C21+0 records in
21+0 records out
22020096 bytes (22 MB) copied, 21.012 s, 1.0 MB/s

此時不用 dd 命令執行完,稍等一下中斷執行就能看到速度確實限制在了 1M / s 。寫的同時, iostat 顯示爲:

[zorro@zorrozou-pc0 ~]$ iostat -x 1
Linux 4.3.3-2-ARCH (zorrozou-pc0.tencent.com)   2016 年 01 月 15 日  _x86_64_    (4 CPU)


avg-cpu:  %user   %nice %system %iowait  %steal   %idle
       0.50    0.00    0.50   25.13    0.00   73.87

Device:         rrqm/s   wrqm/s     r/s     w/s    rkB/s    wkB/s avgrq-sz avgqu-sz   await r_await w_await  svctm  %util
sda               0.00     0.00    0.00    0.00     0.00     0.00     0.00     0.00    0.00    0.00    0.00   0.00   0.00
sdb               0.00     0.00    0.00    1.00     0.00  1024.00  2048.00     0.00    0.00    0.00    0.00   0.00   0.00
dm-0              0.00     0.00    0.00    1.00     0.00  1024.00  2048.00     1.00 1000.00    0.00 1000.00 1000.00 100.00
dm-1              0.00     0.00    0.00    0.00     0.00     0.00     0.00     0.00    0.00    0.00    0.00   0.00   0.00
dm-2              0.00     0.00    0.00    0.00     0.00     0.00     0.00     0.00    0.00    0.00    0.00   0.00   0.00
dm-3              0.00     0.00    0.00    0.00     0.00     0.00     0.00     0.00    0.00    0.00    0.00   0.00   0.00

avg-cpu:  %user   %nice %system %iowait  %steal   %idle

可以看到寫的速度確實爲 1024wkB/s 左右。我們再來試試讀,先創建一個大文件,此處沒有限速:

[root@zorrozou-pc0 zorro]# dd if=/dev/zero of=/home/test oflag=direct count=1024 bs=1M
1024+0 records in
1024+0 records out
1073741824 bytes (1.1 GB) copied, 10.213 s, 105 MB/s

然後進行限速設置並確認:

[root@zorrozou-pc0 zorro]# sync
[root@zorrozou-pc0 zorro]# echo 3 > /proc/sys/vm/drop_caches 
[root@zorrozou-pc0 zorro]# echo "8:16  1048576" > /sys/fs/cgroup/blkio/test1/blkio.throttle.read_bps_device
[root@zorrozou-pc0 zorro]# cgexec -g blkio:test1 dd if=/home/test of=/dev/null iflag=direct count=1024 bs=1M
^C15+0 records in
14+0 records out
14680064 bytes (15 MB) copied, 15.0032 s, 978 kB/s

iostat 結果:

avg-cpu:  %user   %nice %system %iowait  %steal   %idle
       0.75    0.00    0.75   24.63    0.00   73.88

Device:         rrqm/s   wrqm/s     r/s     w/s    rkB/s    wkB/s avgrq-sz avgqu-sz   await r_await w_await  svctm  %util
sda               0.00     0.00    0.00    0.00     0.00     0.00     0.00     0.00    0.00    0.00    0.00   0.00   0.00
sdb               0.00     0.00    2.00    0.00  1024.00     0.00  1024.00     0.00    0.00    0.00    0.00   0.00   0.00
dm-0              0.00     0.00    2.00    0.00  1024.00     0.00  1024.00     1.65  825.00  825.00    0.00 500.00 100.00
dm-1              0.00     0.00    0.00    0.00     0.00     0.00     0.00     0.00    0.00    0.00    0.00   0.00   0.00
dm-2              0.00     0.00    0.00    0.00     0.00     0.00     0.00     0.00    0.00    0.00    0.00   0.00   0.00
dm-3              0.00     0.00    0.00    0.00     0.00     0.00     0.00     0.00    0.00    0.00    0.00   0.00   0.00

最後是 iops 的限制,我就不廢話了,直接上命令執行結果:

[root@zorrozou-pc0 zorro]# echo "8:16  20" > /sys/fs/cgroup/blkio/test1/blkio.throttle.write_iops_device 
[root@zorrozou-pc0 zorro]# rm /home/test 
[root@zorrozou-pc0 zorro]# sync
[root@zorrozou-pc0 zorro]# echo 3 > /proc/sys/vm/drop_caches
[root@zorrozou-pc0 zorro]# cgexec -g blkio:test1 dd if=/dev/zero of=/home/test oflag=direct count=1024 bs=1M
^C121+0 records in
121+0 records out
126877696 bytes (127 MB) copied, 12.0576 s, 10.5 MB/s

[zorro@zorrozou-pc0 ~]$ iostat -x 1
avg-cpu:  %user   %nice %system %iowait  %steal   %idle
       0.50    0.00    0.25   24.81    0.00   74.44

Device:         rrqm/s   wrqm/s     r/s     w/s    rkB/s    wkB/s avgrq-sz avgqu-sz   await r_await w_await  svctm  %util
sda               0.00     0.00    0.00    0.00     0.00     0.00     0.00     0.00    0.00    0.00    0.00   0.00   0.00
sdb               0.00     0.00    0.00   20.00     0.00 10240.00  1024.00     0.00    0.00    0.00    0.00   0.00   0.00
dm-0              0.00     0.00    0.00   20.00     0.00 10240.00  1024.00     2.00  100.00    0.00  100.00  50.00 100.00
dm-1              0.00     0.00    0.00    0.00     0.00     0.00     0.00     0.00    0.00    0.00    0.00   0.00   0.00
dm-2              0.00     0.00    0.00    0.00     0.00     0.00     0.00     0.00    0.00    0.00    0.00   0.00   0.00
dm-3              0.00     0.00    0.00    0.00     0.00     0.00     0.00     0.00    0.00    0.00    0.00   0.00   0.00

iops 的讀限制我就不在廢話了,大家可以自己做實驗測試一下。

其他相關文件

針對權重比例限制的相關文件

blkio.leaf_weight[_device]

其意義等同於 blkio.weight[_device],主要表示當本 cgroup 中有子 cgroup 的時候,本 cgroup 的進程和子 cgroup 中的進程所分配的資源比例是怎麼樣的。舉個例子說吧,假設有一組 cgroups 的關係是這樣的:

root
       /    |   \
      A     B    leaf
     400   200   200

leaf 就表示 root 組下的進程所佔 io 資源的比例。
此時 A 組中的進程可以佔用的比例爲: 400/( 400+200+200 ) * 100% = 50%
B 爲: 200/( 400+200+200 ) * 100% = 25%
而 root 下的進程爲: 200/( 400+200+200 ) * 100% = 25%

blkio.time

統計相關設備的分配給本組的 io 處理時間,單位爲 ms 。權重就是依據此時間比例進行分配的。

blkio.sectors

統計本 cgroup 對設備的讀寫扇區個數。

blkio.io_service_bytes

統計本 cgroup 對設備的讀寫字節個數。

blkio.io_serviced

統計本 cgroup 對設備的讀寫操作個數。

blkio.io_service_time

統計本 cgroup 對設備的各種操作時間。時間單位是 ns 。

blkio.io_wait_time

統計本 cgroup 對設備的各種操作的等待時間。時間單位是 ns 。

blkio.io_merged

統計本 cgroup 對設備的各種操作的合併處理次數。

blkio.io_queued

統計本 cgroup 對設備的各種操作的當前正在排隊的請求個數。

blkio.*_recursive

這一堆文件是相對應的不帶_recursive 的文件的遞歸顯示版本,所謂遞歸的意思就是,它會顯示出包括本 cgroup 在內的衍生 cgroup 的所有信息的總和。

針對帶寬和 iops 限制的相關文件

blkio.throttle.io_serviced

統計本 cgroup 對設備的讀寫操作個數。

blkio.throttle.io_service_bytes

統計本 cgroup 對設備的讀寫字節個數。

blkio.reset_stats

對本文件寫入一個 int 可以對以上所有文件的值置零,重新開始累計。

最後

其實一直糾結要不要寫這部分 IO 隔離的文檔,因爲看上去意義不大。一則因爲目前 IO 隔離似乎工作場景裏用的不多,二則因爲目前內核中這部分代碼還在進行較大變化的調整,還要繼續加入其它功能。從內核 Linux 3.16 版本之後, cgroup 調整方向,開始了基於 unified hierarchy 架構的 cgroup v2 。 IO 部分在 write-back 部分進行了較大調整,加入了對 buffered IO 的資源限制。我們這次系統環境爲 ArchLinux ,內核版本爲 Linux 4.3.3 ,雖然環境中的 unified hierarchy 的開發版本功能已經部分支持了,但是思考再三還是暫時不加入到此文檔中。新架構的 cgoup v2 預計會跟隨 Linux 4.5 一起推出,到時候我們再做詳細分析好了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章