Linux優化之IO子系統監控與調優

Linux優化之IO子系統node

做爲服務器主機來說,最大的兩個IO類型 :linux

1.磁盤IO ios

2.網絡IOweb

這是咱們調整最多的兩個部分所在算法

 

磁盤IO是如何實現的數據庫

在內存調優中,一直在講到爲了加速性能,linux內核通常狀況下都會嘗試將磁盤上的慢速設備上的文件緩存至內存中,從而達到加速效果;編程

虛擬內存的概念:緩存

讀寫都在內存中完成,當某一進程在cpu運行的時候,進程要訪問本身地址空間中的某一內存頁,當進程須要訪問頁面中的數據,而這個頁面最終是要對應在物理內存中的某個物理頁面,而進程只能看到本身的線性地址空間,而這個地址並不存在,一旦訪問這個地址,那麼會經過MMU(內存管理單元)機制中的存儲當前進程的線性地址到物理地址的映射表服務器

由此經過MMU實現對應的地址查詢因而獲得了其映射的地址,最終進程雖然訪問的數據是來自於映射過的地址,這種訪問訪問咱們被稱爲虛擬地址或虛擬內存網絡

 

若是因爲咱們使用交換內存或其餘方式有可能這個進程所打開的文件長時間沒有被訪問,這個文件所對應的內存已經被清出去了,因此使用mmu地址轉換後的地址對應的數據在內存中不存在了,這時候會產生頁錯誤,咱們也被稱爲缺頁異常

 

缺頁異常

缺頁異常分爲大異常和小異常:

    若是數據不存在使得不得不在磁盤中載入頁面文件,這時CPU就會進入內核模式,訪問磁盤,每次CPU訪問內存就要3個週期,訪問磁盤須要N個週期,首先須要定位數據的準確位置,然後定位物理內存中開闢數據空間,最後將數據總線貫通,從而將數據從磁盤轉入到內存--blockin

 

    當咱們找一個空閒空間,而事實上當進程訪問這段數據就須要訪問新位置的數據,因此咱們要更新這個映射表,明確說明所要訪問的邏輯地址所要對應的空間的轉換的位置,而且讓進程從新發起一次訪問,這時須要先查找TLB(緩存緩衝器),再次進行查表

    而將磁盤裝入內存的過程就會發生IO,若是進程修改了數據,最終數據還須要寫到磁盤中去,而寫到磁盤中去,過程使得數據比原來的文件更大了

具體是由文件系統模塊根據進程發起的請求,內核指揮文件系統模塊開闢更多的存儲塊然後將數據存儲,這種過程被稱爲 block out

 

#緩衝器負責將以前緩衝過的緩存下來,那麼若是N個條目,而緩衝器只能緩存有限的幾個,那麼命中率可能會很低,若是咱們使用大頁面的話,那麼命中率能夠大大提升。

 

 

機械硬盤的特性

同一方向的操做是合併起來完成的,然後在這個方向結束以後則是另一方向的

對硬盤來說,讀寫是不一樣類型的操做,讀寫是不能同時進行的

 

磁盤是如何操做的

將一個或多個進程的讀操做合併到一塊兒讀

將一個或多個進程的寫操做合併到一塊兒寫

 

因此讀寫操做是兩類不一樣的操做並且是同一方向合併的

若是是讀文件,這個文件必定是來自於磁盤的

若是是寫文件,那麼寫入到內存中,對於進程來說是已經完成的,那麼用戶對計算機性能感知是來自於讀,由於讀必定是與IO相交互

 

1.讀是在同方向合併的

2.寫也是須要合併的,並且二者是不一樣方向的操做

由於在同一方向能夠節省不少資源

讀必須優先知足,而寫也不能等過久,所以必須有一種良好的算法讓其儘量都獲得知足,而又不能讓用戶感到性能降低  

所以在IO系統上有個很是重要的模塊---IO調度器

 

IO調度器

用來實現合併同一方向的讀寫操做而且將讀寫操做盡量理想的這種情況

IO調度器自己的完成,最終用戶實現寫的時候進程級別所看到的數據是文件接口

那麼文件接口輸出的時候就意味着將磁盤空間以文件接口的方式輸出,其須要文件系統

也就意味着進程與磁盤上的數據打交道是依賴文件系統的

 

因此用戶的請求先到文件系統,而文件系統經過內核輸出是虛擬文件接口(VFS) 經過VFS找到各特定文件系統相關模塊,固然對應的文件是哪一個那麼則經過vfs轉換成什麼便可

文件系統將數據接下來以後,最終存儲爲磁盤塊的方式保存在磁盤上,所以這些文件系統最終還要轉換數據爲磁盤塊,因此接下來還要有塊層

塊層主要是將數據轉換爲磁盤塊格式,然後再由磁盤塊格式轉換成調度之後存儲在磁盤上

以下圖所示:

wKiom1QdhnPy6EQQAAH_P6Mmz0A257.jpg

(1)用戶進程實現寫操做 實現系統調用

(2)用戶的寫操做必定是跟VFS進行交互的

(3)VFS須要將其換換爲特定的文件系統

(4)單個文件在虛擬文件系統存放都會轉換成頁面方式(page cache)

(5)寫完以後經過block buffer快緩衝(知因此進行緩衝是由於磁盤太慢了,因此寫的時候須要緩衝下來

(6)而後由bio將每一個page cache轉換成塊,而且在塊緩衝這個層次上緩存下來

這就是緩衝隊列,而在塊層實現緩衝以後每一個塊最終都要交給塊層來處理,塊層中最重要的一個組件就是IO調度器,IO調度器接收blockbuffer中所發送過來的多個請求塊,這多個請求塊須要排序的:同方向合併,圖中都是寫操做的 

至於如何排序,必定是最靠近寫請求的最優先知足

 

而IO調度器主要功能就是將隨機IO儘量合併爲順序IO  本文來自http://yijiu.blog.51cto.com 轉載請說明,翻版可恥

可是咱們有說過,儘量同一方向合併儘量會隨機變爲順序,可是咱們又不得不讀飢餓也不能寫飢餓,因此要交替進行的

因此:

(10)由IO調度器調度完成以後,提交給Device Driver ,由Device Driver控制磁盤控制器,由控制器將電器信號轉換爲磁信號寫入到磁盤中去

 

爲什麼隨機讀寫比順序讀寫要慢:

·隨機讀寫:

咱們可能寫任意一個磁道的任意一個扇區,那麼硬盤磁頭可能來回晃動才能完成一次寫

·順序讀寫:

在一個方向轉動便可完成,不用再去移動磁臂的

磁頭操做是電磁運動,而磁臂操做是機械運動,因此任什麼時候候隨機讀寫性能都比順序讀寫都要差的不少

 

 

調度算法

IO調度器事實上是用程序完成的調度算法,對linux來說,2.6的內核一共有4個

1、CFQ

  徹底公平隊列,比較適合於交互式場景      

2、Deadline

   最後期限,任何一個讀寫請求,都有本身的知足期限,當期限到來時以前,必須達到需求的知足(通常建議在數據庫服務器上使用此調度算法)

3、anticpatory

   預期的,任何一個數據讀完以後,有可能與其相鄰的數據也可能被讀到,因此它大體所實現的方法就是,讀完以後先不知足,則不處理,需等一段時間後查看是否有相近數據訪問過,若是有立刻先知足,因此這隻能在行爲預估的場景下可用

4、Noop

    不排隊不合並,先到先得

    #像固態硬盤,由於它不是機械硬盤,它的讀寫就算是隨機IO那麼它的性能跟順序IO差異也不是很大,反而若是想讓調度器去調取它的算法,那麼調度器自己運行會佔用很高的CPU的時鐘週期,有可能會得不償失,因此noop在這種場景下是最好的算法

    #有些RAID設備控制器在硬件設備上本身就有讀寫操做排序的,也就意味着在硬件級別排好序以後在操做系統級別會將其打散從新排序,得不償失,因此RAID設備有本身的調度器的話,最好也使用noop

通常來說,默認是CFQ的

 本文來自http://yijiu.blog.51cto.com 轉載請說明,翻版可恥

有時候在不一樣場景下,他們所最佳所適用的算法可能不同,好比:

若是是web服務器,這裏只是訪問放web上的分區的頁面數據

若是是db數據庫,訪問的是db數據庫的文件,他們最適用的算法未必會同樣,由於他們的訪問風格不一樣,因此這時候咱們就須要修改他們的調度器算法

CFQ比較適合於交互式場景,因而在不少時候會將服務器設置爲Deadline,固然只是一種假定,具體須要本身測試而後作決定

 

觀測當前磁盤IO活動

通常 ethstatus iotio pt-ioprofile sar等查工具看哪些進程引發的io比較高等

這裏咱們使用sar來觀察其狀態信息  本文 來自http://yijiu.blog.51cto.com 轉載 請說明,翻版 可恥

例:

[root@node3 ~]# sar  -d 1 5

Linux2.6.32-431.20.3.el6.x86_64 (node3.test.com) 09/20/2014   _x86_64_(4 CPU)

 

09:16:00 PM       DEV      tps  rd_sec/s  wr_sec/s avgrq-sz  avgqu-sz     await    svctm     %util

09:16:01 PM  dev252-0    46.46      0.00  46795.96  1007.13      2.65    580.00     2.26     10.51

 

09:16:01 PM       DEV      tps  rd_sec/s  wr_sec/s avgrq-sz  avgqu-sz     await    svctm     %util

09:16:02 PM  dev252-0     3.00      0.00    144.00    48.00      0.00      1.33     1.00      0.30

 

09:16:02 PM       DEV      tps  rd_sec/s  wr_sec/s avgrq-sz  avgqu-sz     await    svctm     %util

09:16:03 PM  dev252-0     0.00      0.00      0.00     0.00      0.00      0.00     0.00      0.00

 

09:16:03 PM       DEV      tps  rd_sec/s  wr_sec/s avgrq-sz  avgqu-sz     await    svctm     %util

09:16:04 PM  dev252-0     0.00      0.00      0.00     0.00      0.00      0.00     0.00      0.00

 

09:16:04 PM       DEV      tps  rd_sec/s  wr_sec/s avgrq-sz  avgqu-sz     await    svctm     %util

09:16:05 PM  dev252-0    72.73      0.00  59967.68   824.56      2.61     35.88     1.21      8.79

用參數-p能夠打印出sda,hdc等磁盤設備名稱,若是不用參數-p,設備節點則有多是dev8-0,dev22-0

參數解釋:

tps:每秒從物理磁盤I/O的次數.多個邏輯請求會被合併爲一個I/O磁盤請求,一次傳輸的大小是不肯定的

rd_sec/s:每秒讀扇區的次數. 

avgrq-sz:平均每次設備I/O操做的數據大小(扇區). 

avgqu-sz:磁盤請求隊列的平均長度.

await:從請求磁盤操做到系統完成處理,每次請求的平均消耗時間,包括請求隊列等待時間,單位是毫秒(1秒=1000毫秒).(一次完成的任務,它的IO完成的平均耗時)

svctm:系統處理每次請求的平均時間,不包括在請求隊列中消耗的時間,

%util:I/O請求佔CPU的百分比,比率越大,說明越飽,通常到95左右可能要引發關注

咱們一般經驗值是:

svctm不超過0.5;

await不超過5;

主要看當前設備


核心要點:
一、tps(iops)越高,但%util越低,說明io能力容量越大
二、await、svctm越低越好,說明io響應延遲很低,iops能力很高

 

調整buffer,提升性能

無非就是調整隊列數,以及增長預讀數,下面咱們來手動作一下

·增長隊列長度

格式:

/sys/block/vda(特定某設備)/queue/nr_requests

因爲我這裏跑的是kvm虛機,因此設備號默認都以vdx開頭

默認隊列爲128個長度

[root@node3 ~]#  cat /sys/block/vda/queue/nr_requests

128

這個值是能夠調大一點的

 

2.增長預讀數

  /sys/block/vda(特定某設備)/queue/read_ahead_kb

表示事先預讀數據的kb數,默認也是128

[root@node3 ~]# cat /sys/block/vda/queue/read_ahead_kb
128

這個值也是能夠調大的,具體多少自行而定

 本文 來自http://yijiu.blog.51cto.com 轉載 請說明,翻版 可恥

 

CFQ徹底公平隊列

IO調度是在各進程之間平均分配的,主要是根據進程的IO需求來說IO能力平均分配調度

因此在交互式環境中,這種方式是比較實用的

 

可是在RHEL6.4上 它又提供了三個不一樣的調度等級:

1.實時 RT

2.最佳效果 BE

3.閒置

 

咱們可使用ionice命令手動分配調度等級,或者使用iopro_set系統調用編程分配,固然涉及到開發層面了

在實時調度等級和最佳效果兩個級別都有8個IO等級,

數字越小優先級越高,最佳效果是默認調度等級 也就是4,不用更改

 

修改CFQ,以調節其性能

涉及參數文件:/sys/block/vda/queue/iosched/

修改默認調度器算法:

[root@node3 ~]# cd /sys/block/vda/queue/

[root@node3 queue]# ls

add_random           hw_sector_size      max_hw_sectors_kb  minimum_io_size  physical_block_size  scheduler

discard_granularity  iosched             max_sectors_kb     nomerges         read_ahead_kb        unpriv_sgio

discard_max_bytes    iostats             max_segments       nr_requests      rotational

discard_zeroes_data  logical_block_size  max_segment_size   optimal_io_size  rq_affinity

而在其上層目錄裏,有一scheduler文件

查看scheduler文件

[root@node3 queue]# cat scheduler

noop anticipatory deadline [cfq]

所以更改磁盤IO調度器則去找這個目錄下所對應的scheduler,注意的是,它只是針對每一個磁盤進行調整的,若是有多塊磁盤的話則須要對應每一個磁盤進行修改

它沒有辦法使用sysctl進行控制,若是想開機生效,只能寫到rc.local 或init腳本中

 

一旦更改調度算法以後,再來查看目錄中的文件

[root@node3 queue]# ls /sys/block/vda/queue/iosched/

back_seek_max      fifo_expire_async  group_idle       low_latency  slice_async     slice_idle

back_seek_penalty  fifo_expire_sync   group_isolation  quantum     slice_async_rq  slice_sync

修改算法

[root@node3 queue]# echo deadline > scheduler

[root@node3 queue]# cat scheduler

noop anticipatory [deadline] cfq

再次觀察iosched目錄,並查看其是否有變化

[root@node3 queue]# ls/sys/block/vda/queue/iosched/

fifo_batch  front_merges read_expire  write_expire  writes_starved

因此咱們更改調度算法後,每一個調度算法在此目錄都有不少可調整參數,每一個參數都有值,只不過都表現爲其文件內容而已,而每一個調度器的值經過修改是能夠優化調度器的工做特性的

 

好比對CFQ來說,有如下幾個值能夠調整:

back_seek_max

    反向尋道可能有負面影響,負載小的時候能夠啓用,不然不要使用反向尋道太多值

 

back_seek_penal

    反向尋道作懲罰,若是不得不使用反向尋道的話,那麼必須對其作出必定懲罰,一旦作完懲罰以後,必需要正向尋道更屢次數

 

fifo_expire_async

    用來控制異步請求等待時間長度,默認是250毫秒,過時以後沒法知足的異步請求將會被移動到調度隊列中,也就意味着要從新調度。一般這些值不須要調整

 

fifo_expire_sync

    用於同步請求的,

嚴格來說寫操做都是在內存中完成 過週期以後纔會同步至硬盤中,站在計算機角度來講這種操做都被稱爲異步,而同步則是爲了儘量保證數據會被第一時間寫到磁盤上來,數據不會在內存上逗留,直接寫入磁盤

 

low_latecy

    低延遲,簡單來說,每一個進程都有可能發起讀寫請求,也就意味着最終知足用戶讀寫請求是按進程爲單位劃分,在知足這個前提下,須要考慮每一個進程都須要獲得知足,因此必須關注每一個進程發起IO請求以後最多等待多長時間,若是啓動此值就意味着每一個進程只要發起讀寫請求都要儘量快速獲得知足,默認就啓用了低延遲

    在桌面系統環境,低延遲是很是有必要的

 

quantum

    CFQ一次能夠發出的IO請求數,一批最大能夠調度的IO數,限制IO隊列深度的,簡單來講就是定義設備一次能夠接收的IO請求的隊列長度,默認爲8

    增長反而會有負面影響,所以謹慎調整

    若是隨機IO請求數很是的多,這個值能夠適當調大,若是順序寫很是多,那麼不建議調整

 

設置IO容許消耗的時間

一次IO請求的操做,一次執行多久,應該執行多久,按理說硬盤只要是沒有損壞,能正常運做,在正常範圍內,那麼它就應該寫完、讀完因此咱們要定義好每次讀寫請求所最大容許消耗的時間,那麼就是如下幾個參數的意義了:

slice_async

    定義異步寫入的超時值,每次異步寫操做最長時長是多少,默認值爲40秒

slice_idle

    等待IO請求的閒置時長

slice_sync

    定義同步寫入操做超時值,由於同步比較慢,因此其默認值是100秒,由於是從進程直接到磁盤的,因此超時時間會長一點

在桌面環境和在服務環境下,他們若是都使用CFQ調度器,他們工做特性不必定,也就意味着咱們關注其背後工做機制參數也不同,因此要調整某些值作一些測試的評判

 

 

Deadline最後期限調度

最後期限

wKiom1Qdhp2A5fkHAACT0L3TiWU207.jpg

如圖所示,其分爲了3個隊列,分別是:

·讀隊列

·寫對列

·排序隊列

然後這些隊列都被整合到派發隊列中去然後由磁盤獲得知足,咱們從中任何一隊列中選出一個操做獲得知足以前必需要保證這類操做不能超期

簡單來說deadline就是將每一個讀寫操做放到隊列的時候都給他一個倒計時的計時器,將倒計時的計時器消耗完以前須要趕忙放到派發隊列中,然後再同步至硬盤

而對服務器來說,這種方式是比較理想的

 

經常使用可調參數

fifo_batch

    單批發出的讀寫數,在其最後期限知足以前將隊列中的數據拿出並知足,但有寫操做是須要排序的;默認爲16,設置更多的值會得到更好的流量,可是會增長延遲

    好比一批讀爲16個,那麼咱們講其改成32個,那意味着寫的時間會更高

    固然全部都取決於測試數據,不管怎麼調都不如換一塊SSD硬盤

 

front_merges

    能夠將多個請求合併在一塊兒,可是有些請求壓根不連續,不可能被合併在一塊兒,那麼咱們能夠禁止在知足IO以前進行合併的,禁止合併有可能會帶來隨機讀寫的特性的

    但容許合併也有必定的反作用,就是必須花時間去排序

 

read_expire

    每一個讀操做必須在多少期限內獲得知足,默認爲半秒鐘

 

write_expire

    每一個寫操做必須在多久內獲得知足,默認爲5秒鐘

 

#寫操做是能夠延遲知足的

 

writes_starved

    定義一批能夠處理多少個讀取批,這個值越高,讀的效果就越好。默認爲2,意味着2批讀,一批寫。若是服務器讀多寫少,內存緩衝足夠大,那麼能夠將其調大

 

Noop

若是系統與cpu綁定,且使用高速存儲(SSD),這就是最佳的IO調度程序

只要使用固態硬盤就要將其改成noop

 

若是調參數的話則須要直接去挑戰/sys/block/vda/queue下的參數,而不是調度器的參數

 

add_random

    其做用是否使用商池

 

max_sectors_kb

    默認發送到磁盤的最大請求是多少,默認爲512kb。咱們知道每一個扇區是512字節,那麼每次發送512kb 意味着發送N個扇區,咱們能夠調整或增大減少該值,對於固態硬盤來說不是所謂的扇區概念,由此可調。

    在此類狀況下建議將max_hw_sectors_kb下降刪除塊大小

咱們可使用壓力測試工具對其作測試,記錄大小從512kb到1MB不等,哪一個值的效果好就設置爲哪一個值,固然壓力測試跟實際場景有出入的,因此要充分考慮環境儘量模擬真實場景,儘量要模擬隨機讀寫

 

nr_request

    請求的隊列的值,能夠下降其值

rotational

    若是是SSD硬盤要將此值設置爲0,禁用輪轉模式

 

rq_affinity

    在觸發IO不一樣的CPU中處理IO,通常來說在同CPU上處理同IO是最好的

    由於CPU處理的僅僅是中斷而已

 

所以對於SSD環境中經常使用的調整參數有:

max_sectors_kb

nr_requests

optimal_io_size

rotational

 

調整後如何測試性能是否提升

比較經常使用的硬盤壓力測試工具

·aio-stress

·iozone

·fio

 

瞭解磁盤IO活動情況分析工具

blktrace

 

磁盤IO瓶頸分析工具

blkparse

gnuplot

 本文 來自http://yijiu.blog.51cto.com 轉載 請說明,翻版 可恥

 

總結:IO優化大體思路

·最好換SSD

·調整raid級別

·選擇IO調度器

·根據場景選擇合適的文件系統

·配置選定調度器的參數

·優化結果是否理想,則使用工具進行分析

·寫在開機啓動項裏

相關文章
相關標籤/搜索