㈠ 技術問題
Code maturity level options
代碼成熟度選項
Prompt for development and/or incomplete code/drivers
顯示尚在開發中或尚未完成的代碼與驅動.除非你是測試人員或者開發者,否則請勿選擇
General setup
常規設置
Local version - append to kernel release
在內核版本後面加上自定義的版本字元串(小於64字元),可以用"uname -a"命令看到
Automatically append version information to the version string
自動在版本字元串後面添加版本信息,編譯時需要有perl以及git倉庫支持
Support for paging of anonymous memory (swap)
使用交換分區或者交換文件來做為虛擬內存
System V IPC
System V進程間通信(IPC)支持,許多程序需要這個功能.必選,除非你知道自己在做什麼
IPC Namespaces
IPC命名空間支持,不確定可以不選
POSIX Message Queues
POSIX消息隊列,這是POSIX IPC中的一部分
BSD Process Accounting
將進程的統計信息寫入文件的用戶級系統調用,主要包括進程的創建時間/創建者/內存佔用等信息
BSD Process Accounting version 3 file format
使用新的第三版文件格式,可以包含每個進程的PID和其父進程的PID,但是不兼容老版本的文件格式
Export task/process statistics through netlink
通過netlink介面向用戶空間導出任務/進程的統計信息,與BSD Process Accounting的不同之處在於這些統計信息在整個任務/進程生存期都是可用的
Enable per-task delay accounting
在統計信息中包含進程等候系統資源(cpu,IO同步,內存交換等)所花費的時間
UTS Namespaces
UTS名字空間支持,不確定可以不選
Auditing support
審計支持,某些內核模塊(例如SElinux)需要它,只有同時選擇其子項才能對系統調用進行審計
Enable system-call auditing support
支持對系統調用的審計
Kernel .config support
把內核的配置信息編譯進內核中,以後可以通過scripts/extract-ikconfig腳本來提取這些信息
Enable access to .config through /proc/config.gz
允許通過/proc/config.gz訪問內核的配置信息
Cpuset support
只有含有大量CPU(大於16個)的SMP系統或NUMA(非一致內存訪問)系統才需要它
Kernel->user space relay support (formerly relayfs)
在某些文件系統上(比如debugfs)提供從內核空間向用戶空間傳遞大量數據的介面
Initramfs source file(s)
initrd已經被initramfs取代,如果你不明白這是什麼意思,請保持空白
Optimize for size (Look out for broken compilers!)
編譯時優化內核尺寸(使用"-Os"而不是"-O2"參數編譯),有時會產生錯誤的二進制代碼
Enable extended accounting over taskstats
收集額外的進程統計信息並通過taskstats介面發送到用戶空間
Configure standard kernel features (for small systems)
配置標準的內核特性(為小型系統)
Enable 16-bit UID system calls
允許對UID系統調用進行過時的16-bit包裝
Sysctl syscall support
不需要重啟就能修改內核的某些參數和變數,如果你也選擇了支持/proc,將能從/proc/sys存取可以影響內核行為的參數或變數
Load all symbols for debugging/kksymoops
裝載所有的調試符號表信息,僅供調試時選擇
Include all symbols in kallsyms
在kallsyms中包含內核知道的所有符號,內核將會增大300K
Do an extra kallsyms pass
除非你在kallsyms中發現了bug並需要報告這個bug才打開該選項
Support for hot-pluggable devices
支持熱插拔設備,如usb與pc卡等,Udev也需要它
Enable support for printk
允許內核向終端列印字元信息,在需要診斷內核為什麼不能運行時選擇
BUG() support
顯示故障和失敗條件(BUG和WARN),禁用它將可能導致隱含的錯誤被忽略
Enable ELF core mps
內存轉儲支持,可以幫助調試ELF格式的程序
Enable full-sized data structures for core
在內核中使用全尺寸的數據結構.禁用它將使得某些內核的數據結構減小以節約內存,但是將會降低性能
Enable futex support
快速用戶空間互斥體可以使線程串列化以避免競態條件,也提高了響應速度.禁用它將導致內核不能正確的運行基於glibc的程序
Enable eventpoll support
支持事件輪循的系統調用
Use full shmem filesystem
啟用shmem支持.shmem是基於共享內存的文件系統(可能用到swap),在啟用TMPFS後可以掛載為tmpfs供用戶空間使用,它比簡單的ramfs先進許多
Use full SLAB allocator
使用SLAB完全取代SLOB進行內存分配,SLAB是一種優秀的內存分配管理器,推薦使用
Enable VM event counters for /proc/vmstat
允許在/proc/vmstat中包含虛擬內存事件記數器
Loadable mole support
可載入模塊支持
Enable loadable mole support
打開可載入模塊支持,如果打開它則必須通過"make moles_install"把內核模塊安裝在/lib/moles/中
Mole unloading
允許卸載已經載入的模塊
Forced mole unloading
允許強制卸載正在使用中的模塊(比較危險)
Mole versioning support
允許使用其他內核版本的模塊(可能會出問題)
Source checksum for all moles
為所有的模塊校驗源碼,如果你不是自己編寫內核模塊就不需要它
Automatic kernel mole loading
讓內核通過運行modprobe來自動載入所需要的模塊,比如可以自動解決模塊的依賴關系
Block layer
塊設備層
Enable the block layer
塊設備支持,使用硬碟/USB/SCSI設備者必選
Support for Large Block Devices
僅在使用大於2TB的塊設備時需要
Support for tracing block io actions
塊隊列IO跟蹤支持,它允許用戶查看在一個塊設備隊列上發生的所有事件,可以通過blktrace程序獲得磁碟當前的詳細統計數據
Support for Large Single Files
僅在可能使用大於2TB的文件時需要
IO Schelers
IO調度器
Anticipatory I/O scheler
適用於大多數環境,但不太合適資料庫應用
Deadline I/O scheler
通常與Anticipatory相當,但更簡潔小巧,更適合於資料庫應用
CFQ I/O scheler
為所有進程分配等量的帶寬,適合於桌面多任務及多媒體應用
Default I/O scheler
默認IO調度器
Processor type and features
中央處理器(CPU)類型及特性
Symmetric multi-processing support
對稱多處理器支持,如果你有多個CPU或者使用的是多核CPU就選上.此時"Enhanced Real Time Clock Support"選項必須開啟,"Advanced Power Management"選項必須關閉
Subarchitecture Type
處理器的子架構,大多數人都應當選擇"PC-compatible"
Processor family
處理器系列,請按照你實際使用的CPU選擇
Generic x86 support
通用x86支持,如果你的CPU能夠在上述"Processor family"中找到就別選
HPET Timer Support
HPET是替代8254晶元的新一代定時器,i686及以上級別的主板都支持,可以安全的選上
Maximum number of CPUs
支持的最大CPU數,每增加一個內核將增加8K體積
SMT (Hyperthreading) scheler support
支持Intel的超線程(HT)技術
Multi-core scheler support
針對多核CPU進行調度策略優化
Preemption Model
內核搶占模式
No Forced Preemption (Server)
適合伺服器環境的禁止內核搶占
Voluntary Kernel Preemption (Desktop)
適合普通桌面環境的自願內核搶占
Preemptible Kernel (Low-Latency Desktop)
適合運行實時程序的主動內核搶占
Preempt The Big Kernel Lock
可以搶佔大內核鎖,應用於實時要求高的場合,不適合伺服器環境
Machine Check Exception
讓CPU檢測到系統故障時通知內核,以便內核採取相應的措施(如過熱關機等)
Check for non-fatal errors on AMD Athlon/Duron / Intel Pentium 4
每5秒檢測一次這些cpu的非致命錯誤並糾正它們,同時記入日誌
check for P4 thermal throttling interrupt
當P4的cpu過熱時顯示一條警告消息
Enable VM86 support
虛擬X86支持,在DOSEMU下運行16-bit程序或XFree86通過BIOS初始化某些顯卡的時候才需要
Toshiba Laptop support
Toshiba筆記本模塊支持
Dell laptop support
Dell筆記本模塊支持
Enable X86 board specific fixups for reboot
修正某些舊x86主板的重起bug,這種主板基本絕種了
/dev/cpu/microcode - Intel IA32 CPU microcode support
使用不隨Linux內核發行的IA32微代碼,你必需有IA32微代碼二進制文件,僅對Intel的CPU有效
/dev/cpu/*/msr - Model-specific register support
在多cpu系統中讓特權CPU訪問x86的MSR寄存器
/dev/cpu/*/cpuid - CPU information support
能從/dev/cpu/x/cpuid獲得CPU的唯一標識符(CPUID)
Firmware Drivers
固件驅動程序
BIOS Enhanced Disk Drive calls determine boot disk
有些BIOS支持從某塊特定的硬碟啟動(如果BIOS不支持則可能無法啟動),目前大多數BIOS還不支持
BIOS update support for DELL systems via sysfs
僅適用於DELL機器
Dell Systems Management Base Driver
僅適用於DELL機器
High Memory Support
最高內存支持,總內存小於等於1G的選"off",大於4G的選"64G"
Memory split
如果你不是絕對清楚自己在做什麼,不要改動這個選項
Memory model
一般選"Flat Memory",其他選項涉及內存熱插拔
64 bit Memory and IO resources
使用64位的內存和IO資源
Allocate 3rd-level pagetables from highmem
在內存很多(大於4G)的機器上將用戶空間的頁表放到高位內存區,以節約寶貴的低端內存
Math emulation
數學協處理器模擬,486DX以上的cpu就不要選它了
MTRR (Memory Type Range Register) support
打開它可以提升PCI/AGP匯流排上的顯卡2倍以上的速度,並且可以修正某些BIOS錯誤
Boot from EFI support
EFI是一種可代替傳統BIOS的技術(目前的Grub/LILO尚不能識別它),但是現在遠未普及
Enable kernel irq balancing
讓內核將irq中斷平均分配給多個CPU以進行負載均衡,但是要配合irqbanlance守護進程才行
Use register arguments
使用"-mregparm=3"參數編譯內核,將前3個參數以寄存器方式進行參數調用,可以生成更緊湊和高效的代碼
Enable seccomp to safely compute untrusted bytecode
只有嵌入式系統可以不選
Timer frequency
內核時鍾頻率,桌面推薦"1000 HZ",伺服器推薦"100 HZ"或"250 HZ"
kexec system call
提供kexec系統調用,可以不必重啟而切換到另一個內核
kernel crash mps
被kexec啟動後產生內核崩潰轉儲
Physical address where the kernel is loaded
內核載入的物理地址,除非你知道自己在做什麼,否則不要修改.在提供kexec系統調用的情況下可能要修改它
Support for hot-pluggable CPUs
對熱插拔CPU提供支持
Compat VDSO support
如果Glibc版本大於等於2.3.3就不選,否則就選上
更多問題請點這里:http://www.chinaunix.net/jh/4/885597.html
㈡ 如何提高Linux下塊設備IO的整體性能
前言:本文主要講解Linux IO調度層的三種模式:cfp、deadline和noop,並給出各自的優化和適用場景建議。
IO調度發生在Linux內核的IO調度層。這個層次是針對Linux的整體IO層次體系來說的。從read()或者write()系統調用的角度來說,Linux整體IO體系可以分為七層,它們分別是:
VFS層: 虛擬文件系統層。由於內核要跟多種文件系統打交道,而每一種文件系統所實現的數據結構和相關方法都可能不盡相同,所以,內核抽象了這一層,專門用來適配各種文件系統,並對外提供統一操作介面。
文件系統層: 不同的文件系統實現自己的操作過程,提供自己特有的特徵,具體不多說了,大家願意的話自己去看代碼即可。
頁緩存層: 負責真對page的緩存。
通用塊層: 由於絕大多數情況的io操作是跟塊設備打交道,所以Linux在此提供了一個類似vfs層的塊設備操作抽象層。下層對接各種不同屬性的塊設備,對上提供統一的Block IO請求標准。
IO調度層 :因為絕大多數的塊設備都是類似磁碟這樣的設備,所以有必要根據這類設備的特點以及應用的不同特點來設置一些不同的調度演算法和隊列。以便在不同的應用環境下有針對性的提高磁碟的讀寫效率,這里就是大名鼎鼎的Linux電梯所起作用的地方。針對機械硬碟的各種調度方法就是在這實現的。
塊設備驅動層: 驅動層對外提供相對比較高級的設備操作介面,往往是C語言的,而下層對接設備本身的操作方法和規范。
塊設備層: 這層就是具體的物理設備了,定義了各種真對設備操作方法和規范。
有一個已經整理好的[Linux IO結構圖],非常經典,一圖勝千言:
我們今天要研究的內容主要在IO調度這一層。
它要解決的核心問題是,如何提高塊設備IO的整體性能?這一層也主要是針對機械硬碟結構而設計的。
眾所周知,機械硬碟的存儲介質是磁碟,磁頭在碟片上移動進行磁軌定址,行為類似播放一張唱片。
這種結構的特點是,順序訪問時吞吐量較高,但是如果一旦對碟片有隨機訪問,那麼大量的時間都會浪費在磁頭的移動上,這時候就會導致每次IO的響應時間變長,極大的降低IO的響應速度。
磁頭在碟片上尋道的操作,類似電梯調度,實際上在最開始的時期,Linux把這個演算法命名為Linux電梯演算法,即:
如果在尋道的過程中,能把順序路過的相關磁軌的數據請求都「順便」處理掉,那麼就可以在比較小影響響應速度的前提下,提高整體IO的吞吐量。
這就是我們為什麼要設計IO調度演算法的原因。
目前在內核中默認開啟了三種演算法/模式:noop,cfq和deadline。嚴格算應該是兩種:
因為第一種叫做noop,就是空操作調度演算法,也就是沒有任何調度操作,並不對io請求進行排序,僅僅做適當的io合並的一個fifo隊列。
目前內核中默認的調度演算法應該是cfq,叫做完全公平隊列調度。這個調度演算法人如其名,它試圖給所有進程提供一個完全公平的IO操作環境。
註:請大家一定記住這個詞語,cfq,完全公平隊列調度,不然下文就沒法看了。
cfq為每個進程創建一個同步IO調度隊列,並默認以時間片和請求數限定的方式分配IO資源,以此保證每個進程的IO資源佔用是公平的,cfq還實現了針對進程級別的優先順序調度,這個我們後面會詳細解釋。
查看和修改IO調度演算法的方法是:
cfq是通用伺服器比較好的IO調度演算法選擇,對桌面用戶也是比較好的選擇。
但是對於很多IO壓力較大的場景就並不是很適應,尤其是IO壓力集中在某些進程上的場景。
因為這種場景我們需要更多的滿足某個或者某幾個進程的IO響應速度,而不是讓所有的進程公平的使用IO,比如資料庫應用。
deadline調度(最終期限調度)就是更適合上述場景的解決方案。deadline實現了四個隊列:
其中兩個分別處理正常read和write,按扇區號排序,進行正常io的合並處理以提高吞吐量。因為IO請求可能會集中在某些磁碟位置,這樣會導致新來的請求一直被合並,可能會有其他磁碟位置的io請求被餓死。
另外兩個處理超時read和write的隊列,按請求創建時間排序,如果有超時的請求出現,就放進這兩個隊列,調度演算法保證超時(達到最終期限時間)的隊列中的請求會優先被處理,防止請求被餓死。
不久前,內核還是默認標配四種演算法,還有一種叫做as的演算法(Anticipatory scheler),預測調度演算法。一個高大上的名字,搞得我一度認為Linux內核都會算命了。
結果發現,無非是在基於deadline演算法做io調度的之前等一小會時間,如果這段時間內有可以合並的io請求到來,就可以合並處理,提高deadline調度的在順序讀寫情況下的數據吞吐量。
其實這根本不是啥預測,我覺得不如叫撞大運調度演算法,當然這種策略在某些特定場景差效果不錯。
但是在大多數場景下,這個調度不僅沒有提高吞吐量,還降低了響應速度,所以內核乾脆把它從默認配置里刪除了。畢竟Linux的宗旨是實用,而我們也就不再這個調度演算法上多費口舌了。
1、cfq:完全公平隊列調度
cfq是內核默認選擇的IO調度隊列,它在桌面應用場景以及大多數常見應用場景下都是很好的選擇。
如何實現一個所謂的完全公平隊列(Completely Fair Queueing)?
首先我們要理解所謂的公平是對誰的公平?從操作系統的角度來說,產生操作行為的主體都是進程,所以這里的公平是針對每個進程而言的,我們要試圖讓進程可以公平的佔用IO資源。
那麼如何讓進程公平的佔用IO資源?我們需要先理解什麼是IO資源。當我們衡量一個IO資源的時候,一般喜歡用的是兩個單位,一個是數據讀寫的帶寬,另一個是數據讀寫的IOPS。
帶寬就是以時間為單位的讀寫數據量,比如,100Mbyte/s。而IOPS是以時間為單位的讀寫次數。在不同的讀寫情境下,這兩個單位的表現可能不一樣,但是可以確定的是,兩個單位的任何一個達到了性能上限,都會成為IO的瓶頸。
從機械硬碟的結構考慮,如果讀寫是順序讀寫,那麼IO的表現是可以通過比較少的IOPS達到較大的帶寬,因為可以合並很多IO,也可以通過預讀等方式加速數據讀取效率。
當IO的表現是偏向於隨機讀寫的時候,那麼IOPS就會變得更大,IO的請求的合並可能性下降,當每次io請求數據越少的時候,帶寬表現就會越低。
從這里我們可以理解,針對進程的IO資源的主要表現形式有兩個: 進程在單位時間內提交的IO請求個數和進程佔用IO的帶寬。
其實無論哪個,都是跟進程分配的IO處理時間長度緊密相關的。
有時業務可以在較少IOPS的情況下佔用較大帶寬,另外一些則可能在較大IOPS的情況下佔用較少帶寬,所以對進程佔用IO的時間進行調度才是相對最公平的。
即,我不管你是IOPS高還是帶寬佔用高,到了時間咱就換下一個進程處理,你愛咋樣咋樣。
所以,cfq就是試圖給所有進程分配等同的塊設備使用的時間片,進程在時間片內,可以將產生的IO請求提交給塊設備進行處理,時間片結束,進程的請求將排進它自己的隊列,等待下次調度的時候進行處理。這就是cfq的基本原理。
當然,現實生活中不可能有真正的「公平」,常見的應用場景下,我們很肯能需要人為的對進程的IO佔用進行人為指定優先順序,這就像對進程的CPU佔用設置優先順序的概念一樣。
所以,除了針對時間片進行公平隊列調度外,cfq還提供了優先順序支持。每個進程都可以設置一個IO優先順序,cfq會根據這個優先順序的設置情況作為調度時的重要參考因素。
優先順序首先分成三大類:RT、BE、IDLE,它們分別是實時(Real Time)、最佳效果(Best Try)和閑置(Idle)三個類別,對每個類別的IO,cfq都使用不同的策略進行處理。另外,RT和BE類別中,分別又再劃分了8個子優先順序實現更細節的QOS需求,而IDLE只有一個子優先順序。
另外,我們都知道內核默認對存儲的讀寫都是經過緩存(buffer/cache)的,在這種情況下,cfq是無法區分當前處理的請求是來自哪一個進程的。
只有在進程使用同步方式(sync read或者sync wirte)或者直接IO(Direct IO)方式進行讀寫的時候,cfq才能區分出IO請求來自哪個進程。
所以,除了針對每個進程實現的IO隊列以外,還實現了一個公共的隊列用來處理非同步請求。
當前內核已經實現了針對IO資源的cgroup資源隔離,所以在以上體系的基礎上,cfq也實現了針對cgroup的調度支持。
總的來說,cfq用了一系列的數據結構實現了以上所有復雜功能的支持,大家可以通過源代碼看到其相關實現,文件在源代碼目錄下的block/cfq-iosched.c。
1.1 cfq設計原理
在此,我們對整體數據結構做一個簡要描述:首先,cfq通過一個叫做cfq_data的數據結構維護了整個調度器流程。在一個支持了cgroup功能的cfq中,全部進程被分成了若干個contral group進行管理。
每個cgroup在cfq中都有一個cfq_group的結構進行描述,所有的cgroup都被作為一個調度對象放進一個紅黑樹中,並以vdisktime為key進行排序。
vdisktime這個時間紀錄的是當前cgroup所佔用的io時間,每次對cgroup進行調度時,總是通過紅黑樹選擇當前vdisktime時間最少的cgroup進行處理,以保證所有cgroups之間的IO資源佔用「公平」。
當然我們知道,cgroup是可以對blkio進行資源比例分配的,其作用原理就是,分配比例大的cgroup佔用vdisktime時間增長較慢,分配比例小的vdisktime時間增長較快,快慢與分配比例成正比。
這樣就做到了不同的cgroup分配的IO比例不一樣,並且在cfq的角度看來依然是「公平「的。
選擇好了需要處理的cgroup(cfq_group)之後,調度器需要決策選擇下一步的service_tree。
service_tree這個數據結構對應的都是一系列的紅黑樹,主要目的是用來實現請求優先順序分類的,就是RT、BE、IDLE的分類。每一個cfq_group都維護了7個service_trees,其定義如下:
其中service_tree_idle就是用來給IDLE類型的請求進行排隊用的紅黑樹。
而上面二維數組,首先第一個維度針對RT和BE分別各實現了一個數組,每一個數組中都維護了三個紅黑樹,分別對應三種不同子類型的請求,分別是:SYNC、SYNC_NOIDLE以及ASYNC。
我們可以認為SYNC相當於SYNC_IDLE並與SYNC_NOIDLE對應。idling是cfq在設計上為了盡量合並連續的IO請求以達到提高吞吐量的目的而加入的機制,我們可以理解為是一種「空轉」等待機制。
空轉是指,當一個隊列處理一個請求結束後,會在發生調度之前空等一小會時間,如果下一個請求到來,則可以減少磁頭定址,繼續處理順序的IO請求。
為了實現這個功能,cfq在service_tree這層數據結構這實現了SYNC隊列,如果請求是同步順序請求,就入隊這個service tree,如果請求是同步隨機請求,則入隊SYNC_NOIDLE隊列,以判斷下一個請求是否是順序請求。
所有的非同步寫操作請求將入隊ASYNC的service tree,並且針對這個隊列沒有空轉等待機制。
此外,cfq還對SSD這樣的硬碟有特殊調整,當cfq發現存儲設備是一個ssd硬碟這樣的隊列深度更大的設備時,所有針對單獨隊列的空轉都將不生效,所有的IO請求都將入隊SYNC_NOIDLE這個service tree。
每一個service tree都對應了若干個cfq_queue隊列,每個cfq_queue隊列對應一個進程,這個我們後續再詳細說明。
cfq_group還維護了一個在cgroup內部所有進程公用的非同步IO請求隊列,其結構如下:
非同步請求也分成了RT、BE、IDLE這三類進行處理,每一類對應一個cfq_queue進行排隊。
BE和RT也實現了優先順序的支持,每一個類型有IOPRIO_BE_NR這么多個優先順序,這個值定義為8,數組下標為0-7。
我們目前分析的內核代碼版本為Linux 4.4,可以看出,從cfq的角度來說,已經可以實現非同步IO的cgroup支持了,我們需要定義一下這里所謂非同步IO的含義,它僅僅表示從內存的buffer/cache中的數據同步到硬碟的IO請求,而不是aio(man 7 aio)或者linux的native非同步io以及lio機制,實際上這些所謂的「非同步」IO機制,在內核中都是同步實現的(本質上馮諾伊曼計算機沒有真正的「非同步」機制)。
我們在上面已經說明過,由於進程正常情況下都是將數據先寫入buffer/cache,所以這種非同步IO都是統一由cfq_group中的async請求隊列處理的。
那麼為什麼在上面的service_tree中還要實現和一個ASYNC的類型呢?
這當然是為了支持區分進程的非同步IO並使之可以「完全公平」做准備嘍。
實際上在最新的cgroup v2的blkio體系中,內核已經支持了針對buffer IO的cgroup限速支持,而以上這些可能容易混淆的一堆類型,都是在新的體系下需要用到的類型標記。
新體系的復雜度更高了,功能也更加強大,但是大家先不要著急,正式的cgroup v2體系,在Linux 4.5發布的時候會正式跟大家見面。
我們繼續選擇service_tree的過程,三種優先順序類型的service_tree的選擇就是根據類型的優先順序來做選擇的,RT優先順序最高,BE其次,IDLE最低。就是說,RT里有,就會一直處理RT,RT沒了再處理BE。
每個service_tree對應一個元素為cfq_queue排隊的紅黑樹,而每個cfq_queue就是內核為進程(線程)創建的請求隊列。
每一個cfq_queue都會維護一個rb_key的變數,這個變數實際上就是這個隊列的IO服務時間(service time)。
這里還是通過紅黑樹找到service time時間最短的那個cfq_queue進行服務,以保證「完全公平」。
選擇好了cfq_queue之後,就要開始處理這個隊列里的IO請求了。這里的調度方式基本跟deadline類似。
cfq_queue會對進入隊列的每一個請求進行兩次入隊,一個放進fifo中,另一個放進按訪問扇區順序作為key的紅黑樹中。
默認從紅黑樹中取請求進行處理,當請求的延時時間達到deadline時,就從紅黑樹中取等待時間最長的進行處理,以保證請求不被餓死。
這就是整個cfq的調度流程,當然其中還有很多細枝末節沒有交代,比如合並處理以及順序處理等等。
1.2 cfq的參數調整
理解整個調度流程有助於我們決策如何調整cfq的相關參數。所有cfq的可調參數都可以在/sys/class/block/sda/queue/iosched/目錄下找到,當然,在你的系統上,請將sda替換為相應的磁碟名稱。我們來看一下都有什麼:
這些參數部分是跟機械硬碟磁頭尋道方式有關的,如果其說明你看不懂,請先補充相關知識:
back_seek_max:磁頭可以向後定址的最大范圍,默認值為16M。
back_seek_penalty:向後定址的懲罰系數。這個值是跟向前定址進行比較的。
以上兩個是為了防止磁頭尋道發生抖動而導致定址過慢而設置的。基本思路是這樣,一個io請求到來的時候,cfq會根據其定址位置預估一下其磁頭尋道成本。
設置一個最大值back_seek_max,對於請求所訪問的扇區號在磁頭後方的請求,只要定址范圍沒有超過這個值,cfq會像向前定址的請求一樣處理它。
再設置一個評估成本的系數back_seek_penalty,相對於磁頭向前定址,向後定址的距離為1/2(1/back_seek_penalty)時,cfq認為這兩個請求定址的代價是相同。
這兩個參數實際上是cfq判斷請求合並處理的條件限制,凡事復合這個條件的請求,都會盡量在本次請求處理的時候一起合並處理。
fifo_expire_async:設置非同步請求的超時時間。
同步請求和非同步請求是區分不同隊列處理的,cfq在調度的時候一般情況都會優先處理同步請求,之後再處理非同步請求,除非非同步請求符合上述合並處理的條件限制范圍內。
當本進程的隊列被調度時,cfq會優先檢查是否有非同步請求超時,就是超過fifo_expire_async參數的限制。如果有,則優先發送一個超時的請求,其餘請求仍然按照優先順序以及扇區編號大小來處理。
fifo_expire_sync:這個參數跟上面的類似,區別是用來設置同步請求的超時時間。
slice_idle:參數設置了一個等待時間。這讓cfq在切換cfq_queue或service tree的時候等待一段時間,目的是提高機械硬碟的吞吐量。
一般情況下,來自同一個cfq_queue或者service tree的IO請求的定址局部性更好,所以這樣可以減少磁碟的定址次數。這個值在機械硬碟上默認為非零。
當然在固態硬碟或者硬RAID設備上設置這個值為非零會降低存儲的效率,因為固態硬碟沒有磁頭定址這個概念,所以在這樣的設備上應該設置為0,關閉此功能。
group_idle:這個參數也跟上一個參數類似,區別是當cfq要切換cfq_group的時候會等待一段時間。
在cgroup的場景下,如果我們沿用slice_idle的方式,那麼空轉等待可能會在cgroup組內每個進程的cfq_queue切換時發生。
這樣會如果這個進程一直有請求要處理的話,那麼直到這個cgroup的配額被耗盡,同組中的其它進程也可能無法被調度到。這樣會導致同組中的其它進程餓死而產生IO性能瓶頸。
在這種情況下,我們可以將slice_idle = 0而group_idle = 8。這樣空轉等待就是以cgroup為單位進行的,而不是以cfq_queue的進程為單位進行,以防止上述問題產生。
low_latency:這個是用來開啟或關閉cfq的低延時(low latency)模式的開關。
當這個開關打開時,cfq將會根據target_latency的參數設置來對每一個進程的分片時間(slice time)進行重新計算。
這將有利於對吞吐量的公平(默認是對時間片分配的公平)。
關閉這個參數(設置為0)將忽略target_latency的值。這將使系統中的進程完全按照時間片方式進行IO資源分配。這個開關默認是打開的。
我們已經知道cfq設計上有「空轉」(idling)這個概念,目的是為了可以讓連續的讀寫操作盡可能多的合並處理,減少磁頭的定址操作以便增大吞吐量。
如果有進程總是很快的進行順序讀寫,那麼它將因為cfq的空轉等待命中率很高而導致其它需要處理IO的進程響應速度下降,如果另一個需要調度的進程不會發出大量順序IO行為的話,系統中不同進程IO吞吐量的表現就會很不均衡。
就比如,系統內存的cache中有很多臟頁要寫回時,桌面又要打開一個瀏覽器進行操作,這時臟頁寫回的後台行為就很可能會大量命中空轉時間,而導致瀏覽器的小量IO一直等待,讓用戶感覺瀏覽器運行響應速度變慢。
這個low_latency主要是對這種情況進行優化的選項,當其打開時,系統會根據target_latency的配置對因為命中空轉而大量佔用IO吞吐量的進程進行限制,以達到不同進程IO佔用的吞吐量的相對均衡。這個開關比較合適在類似桌面應用的場景下打開。
target_latency:當low_latency的值為開啟狀態時,cfq將根據這個值重新計算每個進程分配的IO時間片長度。
quantum:這個參數用來設置每次從cfq_queue中處理多少個IO請求。在一個隊列處理事件周期中,超過這個數字的IO請求將不會被處理。這個參數只對同步的請求有效。
slice_sync:當一個cfq_queue隊列被調度處理時,它可以被分配的處理總時間是通過這個值來作為一個計算參數指定的。公式為:time_slice = slice_sync + (slice_sync/5 * (4 - prio))。這個參數對同步請求有效。
slice_async:這個值跟上一個類似,區別是對非同步請求有效。
slice_async_rq:這個參數用來限制在一個slice的時間范圍內,一個隊列最多可以處理的非同步請求個數。請求被處理的最大個數還跟相關進程被設置的io優先順序有關。
1.3 cfq的IOPS模式
我們已經知道,默認情況下cfq是以時間片方式支持的帶優先順序的調度來保證IO資源佔用的公平。
高優先順序的進程將得到更多的時間片長度,而低優先順序的進程時間片相對較小。
當我們的存儲是一個高速並且支持NCQ(原生指令隊列)的設備的時候,我們最好可以讓其可以從多個cfq隊列中處理多路的請求,以便提升NCQ的利用率。
此時使用時間片的分配方式分配資源就顯得不合時宜了,因為基於時間片的分配,同一時刻最多能處理的請求隊列只有一個。
這時,我們需要切換cfq的模式為IOPS模式。切換方式很簡單,就是將slice_idle=0即可。內核會自動檢測你的存儲設備是否支持NCQ,如果支持的話cfq會自動切換為IOPS模式。
另外,在默認的基於優先順序的時間片方式下,我們可以使用ionice命令來調整進程的IO優先順序。進程默認分配的IO優先順序是根據進程的nice值計算而來的,計算方法可以在man ionice中看到,這里不再廢話。
2、deadline:最終期限調度
deadline調度演算法相對cfq要簡單很多。其設計目標是:
在保證請求按照設備扇區的順序進行訪問的同時,兼顧其它請求不被餓死,要在一個最終期限前被調度到。
我們知道磁頭對磁碟的尋道是可以進行順序訪問和隨機訪問的,因為尋道延時時間的關系,順序訪問時IO的吞吐量更大,隨機訪問的吞吐量小。
如果我們想為一個機械硬碟進行吞吐量優化的話,那麼就可以讓調度器按照盡量復合順序訪問的IO請求進行排序,之後請求以這樣的順序發送給硬碟,就可以使IO的吞吐量更大。
但是這樣做也有另一個問題,就是如果此時出現了一個請求,它要訪問的磁軌離目前磁頭所在磁軌很遠,應用的請求又大量集中在目前磁軌附近。
導致大量請求一直會被合並和插隊處理,而那個要訪問比較遠磁軌的請求將因為一直不能被調度而餓死。
deadline就是這樣一種調度器,能在保證IO最大吞吐量的情況下,盡量使遠端請求在一個期限內被調度而不被餓死的調度器。
㈢ 怎樣在 Ubuntu 上安裝 Linux Kernel 4.4
Android (x86)項目致力於移植Android系統到X86處理器上,使用戶可以更容易的在任何電腦上安裝Android。他們通過使用android源碼,增加補丁來使Android能夠在X86處理器,筆記本電腦和平板電腦下工作。
前一段時間,項目組發布了最新的「Android KitKat 4.4 r1」,下面,我將說明如何在VirtualBox上安裝。
第一步:在Linux上安裝VirtualBox
1、大多數的Linux發行版中,官方源都有VirtualBox,例如在Ubuntu中安裝
$ sudo apt-get install virtualbox
第二步:下載並在VirtualBox中安裝Android 4.4 kitkat
2、這步挺簡單的,只是需要去androud Sourceforge.net項目下載Android 4.4 x86 Kit Kat文件(地址)
3、要想安裝Android 4.4 kitkat,首先,你需要啟動剛剛下載.iso文件,打開VirtualBox,創建一個新的虛擬機,然後按照下面圖片設置:
4、接下來,它會詢問你新設備的內存大小,Android 4.4 kikat需要1G內存才能完美運行,但是由於我的電腦只有1G內存,我只能選擇512MB。
5、選擇「現在創建虛擬硬碟」(「Create a virtual hard drive now」)來創建一個新的硬碟。
6、它現在會詢問你新虛擬硬碟的類型,選擇VDI
7、現在設置虛擬硬碟大小,你可以按照你的所需來設置任何大小,但是除了將來安裝Apps所用的空間,至少需要4G來保證系統正確安裝。
8、現在你的新虛擬設備創建好了,可以啟動下載的.iso文件了,從左邊的列表選擇創建的虛擬機,點擊設置->存儲,如下圖,選擇android 4.4 kitkat RC2的鏡像文件。
9、點擊OK,打開機器,啟動.iso鏡像,選擇「安裝」開始在虛擬機上安裝系統。
10、請選擇一個分區來安裝Android-x86
11、如下圖,你可以看見cfdisk界面,cfdisk是一個分區工具,我們將要使用它來創建一個新的硬碟分區,用來安裝Android 4.4,現在,點擊「New」
12、選擇「Primary」作為分區類型
㈣ 怎麼給ubuntu 內核打補丁 成為實時操作系統
linux有實時內核的。
有四種內核,分別為:
-generic
kernel - this is the stock kernel that is provided by
default in Ubuntu.
-preempt
kernel - this kernel is based on the -generic kernel source
tree but is built with different configurations (settings) to rece
latency. Also known as a soft
real-time kernel.
-rt
kernel - is based on the Ubuntu kernel source tree with Ingo
Molnar maintained PREEMPT_RT patch applied to
it. Also known as a hard
real-time kernel.
-lowlatency
kernel - very similar to the -preempt kernel and based on
the -generic kernel source tree, but uses a more aggressive
configuration to further rece latency. Also known as a soft
real-time kernel.
-realtime
kernel - is based on the vanilla kernel source tree with
Ingo
Molnar maintained PREEMPT_RT patch applied to
it. Also known as a hard
real-time kernel.
×*******************************如何選擇適合你的內核************************************
Choosing
a Kernel for Your Use Case
These
are some simple guidelines provided to help you understand which
kernel, and in which order, you should test to fit your use case.
If
you do not require low latency for your system then please use the
-generic kernel.
If
you need a low latency system (e.g. for recording audio) then please
use the -preempt kernel as a first choice. This reces latency but
doesn't sacrifice power saving features. It is available only for 64
bit systems (also called amd64).
If
the -preempt kernel does not provide enough low latency for your
needs (or you have an 32 bit system) then you should try the
-lowlatency kernel.
If
the -lowlatency kernel isn't enough then you should try the -rt
kernel
If
the -rt kernel isn't enough stable for you then you should try the
-realtime kernel
××*********************************************去哪裡下載內核********************************************8
kernel點ubuntu點com/~kernel-ppa/mainline/
㈤ 如何為Ubuntu升級Linux Kernel 4.4內核
64位系統
wget kernel.ubuntu.com/~kernel-ppa/mainline/v4.4.1-wily/linux-headers-4.4.1-040401_4.4.1-040401.201601311534_all.deb
wget kernel.ubuntu.com/~kernel-ppa/mainline/v4.4.1-wily/linux-headers-4.4.1-040401-generic_4.4.1-040401.201601311534_amd64.deb
wget kernel.ubuntu.com/~kernel-ppa/mainline/v4.4.1-wily/linux-image-4.4.1-040401-generic_4.4.1-040401.201601311534_amd64.deb
32位系統
wget kernel.ubuntu.com/~kernel-ppa/mainline/v4.4.1-wily/linux-headers-4.4.1-040401_4.4.1-040401.201601311534_all.deb
wget kernel.ubuntu.com/~kernel-ppa/mainline/v4.4.1-wily/linux-headers-4.4.1-040401-generic_4.4.1-040401.201601311534_i386.deb
wget kernel.ubuntu.com/~kernel-ppa/mainline/v4.4.1-wily/linux-image-4.4.1-040401-generic_4.4.1-040401.201601311534_i386.deb
下載完成之後請使用如下命令安裝 Kernel 4.4.1:
sudo dpkg -i *.deb
安裝完成之後使用如下命令更新 Grub boot loader:
sudo update-grub
升級完之後請重啟系統。
Ubuntu卸載Linux Kernel 4.4.1
如果你不想用 Linux Kernel 4.4.1 了,可以隨時使用如下命令刪除:
sudo apt-get remove linux-headers-4.4* linux-image-4.4*
sudo update-grub
㈥ linux進程調度的三種策略是什麼
linux內核的三種主要調度策略:
1,SCHED_OTHER 分時調度策略,
2,SCHED_FIFO實時調度策略,先到先服務
3,SCHED_RR實時調度策略,時間片輪轉
實時進程將得到優先調用,實時進程根據實時優先順序決定調度權值。分時進程則通過nice和counter值決定權值,nice越小,counter越大,被調度的概率越大,也就是曾經使用了cpu最少的進程將會得到優先調度。
SHCED_RR和SCHED_FIFO的不同:
當採用SHCED_RR策略的進程的時間片用完,系統將重新分配時間片,並置於就緒隊列尾。放在隊列尾保證了所有具有相同優先順序的RR任務的調度公平。
SCHED_FIFO一旦佔用cpu則一直運行。一直運行直到有更高優先順序任務到達或自己放棄。
如果有相同優先順序的實時進程(根據優先順序計算的調度權值是一樣的)已經准備好,FIFO時必須等待該進程主動放棄後才可以運行這個優先順序相同的任務。而RR可以讓每個任務都執行一段時間。
相同點:
RR和FIFO都只用於實時任務。
創建時優先順序大於0(1-99)。
按照可搶占優先順序調度演算法進行。
就緒態的實時任務立即搶占非實時任務。
所有任務都採用linux分時調度策略時:
1,創建任務指定採用分時調度策略,並指定優先順序nice值(-20~19)。
2,將根據每個任務的nice值確定在cpu上的執行時間(counter)。
3,如果沒有等待資源,則將該任務加入到就緒隊列中。
4,調度程序遍歷就緒隊列中的任務,通過對每個任務動態優先順序的計算權值(counter+20-nice)結果,選擇計算結果最大的一個去運行,當這個時間片用完後(counter減至0)或者主動放棄cpu時,該任務將被放在就緒隊列末尾(時間片用完)或等待隊列(因等待資源而放棄cpu)中。
5,此時調度程序重復上面計算過程,轉到第4步。
6,當調度程序發現所有就緒任務計算所得的權值都為不大於0時,重復第2步。
所有任務都採用FIFO時:
1,創建進程時指定採用FIFO,並設置實時優先順序rt_priority(1-99)。
2,如果沒有等待資源,則將該任務加入到就緒隊列中。
3,調度程序遍歷就緒隊列,根據實時優先順序計算調度權值(1000+rt_priority),選擇權值最高的任務使用cpu,該FIFO任務將一直佔有cpu直到有優先順序更高的任務就緒(即使優先順序相同也不行)或者主動放棄(等待資源)。
4,調度程序發現有優先順序更高的任務到達(高優先順序任務可能被中斷或定時器任務喚醒,再或被當前運行的任務喚醒,等等),則調度程序立即在當前任務堆棧中保存當前cpu寄存器的所有數據,重新從高優先順序任務的堆棧中載入寄存器數據到cpu,此時高優先順序的任務開始運行。重復第3步。
5,如果當前任務因等待資源而主動放棄cpu使用權,則該任務將從就緒隊列中刪除,加入等待隊列,此時重復第3步。
所有任務都採用RR調度策略時:
1,創建任務時指定調度參數為RR,並設置任務的實時優先順序和nice值(nice值將會轉換為該任務的時間片的長度)。
2,如果沒有等待資源,則將該任務加入到就緒隊列中。
3,調度程序遍歷就緒隊列,根據實時優先順序計算調度權值(1000+rt_priority),選擇權值最高的任務使用cpu。
4,如果就緒隊列中的RR任務時間片為0,則會根據nice值設置該任務的時間片,同時將該任務放入就緒隊列的末尾。重復步驟3。
5,當前任務由於等待資源而主動退出cpu,則其加入等待隊列中。重復步驟3。
系統中既有分時調度,又有時間片輪轉調度和先進先出調度:
1,RR調度和FIFO調度的進程屬於實時進程,以分時調度的進程是非實時進程。
2,當實時進程准備就緒後,如果當前cpu正在運行非實時進程,則實時進程立即搶占非實時進程。
3,RR進程和FIFO進程都採用實時優先順序做為調度的權值標准,RR是FIFO的一個延伸。FIFO時,如果兩個進程的優先順序一樣,則這兩個優先順序一樣的進程具體執行哪一個是由其在隊列中的未知決定的,這樣導致一些不公正性(優先順序是一樣的,為什麼要讓你一直運行?),如果將兩個優先順序一樣的任務的調度策略都設為RR,則保證了這兩個任務可以循環執行,保證了公平。
Ingo Molnar-實時補丁
為了能並入主流內核,Ingo Molnar的實時補丁也採用了非常靈活的策略,它支持四種搶占模式:
1.No Forced Preemption (Server),這種模式等同於沒有使能搶占選項的標准內核,主要適用於科學計算等伺服器環境。
2.Voluntary Kernel Preemption (Desktop),這種模式使能了自願搶占,但仍然失效搶占內核選項,它通過增加搶占點縮減了搶占延遲,因此適用於一些需要較好的響應性的環境,如桌面環境,當然這種好的響應性是以犧牲一些吞吐率為代價的。
3.Preemptible Kernel (Low-Latency Desktop),這種模式既包含了自願搶占,又使能了可搶占內核選項,因此有很好的響應延遲,實際上在一定程度上已經達到了軟實時性。它主要適用於桌面和一些嵌入式系統,但是吞吐率比模式2更低。
4.Complete Preemption (Real-Time),這種模式使能了所有實時功能,因此完全能夠滿足軟實時需求,它適用於延遲要求為100微秒或稍低的實時系統。
實現實時是以犧牲系統的吞吐率為代價的,因此實時性越好,系統吞吐率就越低。
㈦ 安裝Linux kernel 5.4
下載Linux kernel 5.4的主線包。根據您的操作系統類型,按順序下載並安裝軟體包:
linux-headers-5.4.0-xxxxxx_all.deb
linux-headers-5.4.0-xxx-generic(/lowlatency)_xxx_amd64.deb
linux-moles-5.4.0-xxx-generic(/lowlatency)_xxx_amd64.deb
linux-image-xxx-5.4.0-xxx-generic(/lowlatency)_xxx_amd64.deb
安裝Linux Kernel 5.4
㈧ Linux 磁碟IO
磁碟結構與數據存儲方式, 數據是如何存儲的,又通過怎樣的方式被訪問?
機械硬碟主要由磁碟碟片、磁頭、主軸與傳動軸等組成;數據就存放在磁碟碟片中
現代硬碟尋道都是採用CHS( Cylinder Head Sector )的方式,硬碟讀取數據時,讀寫磁頭沿徑向移動,移到要讀取的扇區所在磁軌的上方,這段時間稱為 尋道時間(seek time) 。 因讀寫磁頭的起始位置與目標位置之間的距離不同,尋道時間也不同 。磁頭到達指定磁軌後,然後通過碟片的旋轉,使得要讀取的扇區轉到讀寫磁頭的下方,這段時間稱為 旋轉延遲時間(rotational latencytime) 。然後再讀寫數據,讀寫數據也需要時間,這段時間稱為 傳輸時間(transfer time) 。
固態硬碟主要由主控晶元、快閃記憶體顆粒與緩存組成;數據就存放在快閃記憶體晶元中
通過主控晶元進行定址, 因為是電信號方式, 沒有任何物理結構, 所以定址速度非常快且與數據存儲位置無關
如何查看系統IO狀態
查看磁碟空間
調用 open , fwrite 時到底發生了什麼?
在一個IO過程中,以下5個API/系統調用是必不可少的
Create 函數用來打開一個文件,如果該文件不存在,那麼需要在磁碟上創建該文件
Open 函數用於打開一個指定的文件。如果在 Open 函數中指定 O_CREATE 標記,那麼 Open 函數同樣可以實現 Create 函數的功能
Clos e函數用於釋放文件句柄
Write 和 Read 函數用於實現文件的讀寫過程
O_SYNC (先寫緩存, 但是需要實際落盤之後才返回, 如果接下來有讀請求, 可以從內存讀 ), write-through
O_DSYNC (D=data, 類似O_SYNC, 但是只同步數據, 不同步元數據)
O_DIRECT (直接寫盤, 不經過緩存)
O_ASYNC (非同步IO, 使用信號機制實現, 不推薦, 直接用aio_xxx)
O_NOATIME (讀取的時候不更新文件 atime(access time))
sync() 全局緩存寫回磁碟
fsync() 特定fd的sync()
fdatasync() 只刷數據, 不同步元數據
mount noatime(全局不記錄atime), re方式(只讀), sync(同步方式)
一個IO的傳奇一生 這里有一篇非常好的資料,講述了整個IO過程;
下面簡單記錄下自己的理解的一次常見的Linux IO過程, 想了解更詳細及相關源碼,非常推薦閱讀上面的原文
Linux IO體系結構
[站外圖片上傳中...(image-38a7b-1644137945193)]
Superblock 超級描述了整個文件系統的信息。為了保證可靠性,可以在每個塊組中對superblock進行備份。為了避免superblock冗餘過多,可以採用稀疏存儲的方式,即在若干個塊組中對superblock進行保存,而不需要在所有的塊組中都進行備份
GDT 組描述符表 組描述符表對整個組內的數據布局進行了描述。例如,數據塊點陣圖的起始地址是多少?inode點陣圖的起始地址是多少?inode表的起始地址是多少?塊組中還有多少空閑塊資源等。組描述符表在superblock的後面
數據塊點陣圖 數據塊點陣圖描述了塊組內數據塊的使用情況。如果該數據塊已經被某個文件使用,那麼點陣圖中的對應位會被置1,否則該位為0
Inode點陣圖 Inode點陣圖描述了塊組內inode資源使用情況。如果一個inode資源已經使用,那麼對應位會被置1
Inode表 (即inode資源)和數據塊。這兩塊占據了塊組內的絕大部分空間,特別是數據塊資源
一個文件是由inode進行描述的。一個文件佔用的數據塊block是通過inode管理起來的 。在inode結構中保存了直接塊指針、一級間接塊指針、二級間接塊指針和三級間接塊指針。對於一個小文件,直接可以採用直接塊指針實現對文件塊的訪問;對於一個大文件,需要採用間接塊指針實現對文件塊的訪問
最簡單的調度器。它本質上就是一個鏈表實現的 fifo 隊列,並對請求進行簡單的 合並 處理。
調度器本身並沒有提供任何可以配置的參數
讀寫請求被分成了兩個隊列, 一個用訪問地址作為索引,一個用進入時間作為索引,並且採用兩種方式將這些request管理起來;
在請求處理的過程中,deadline演算法會優先處理那些訪問地址臨近的請求,這樣可以最大程度的減少磁碟抖動的可能性。
只有在有些request即將被餓死的時候,或者沒有辦法進行磁碟順序化操作的時候,deadline才會放棄地址優先策略,轉而處理那些即將被餓死的request
deadline演算法可調整參數
read_expire : 讀請求的超時時間設置(ms)。當一個讀請求入隊deadline的時候,其過期時間將被設置為當前時間+read_expire,並放倒fifo_list中進行排序
write_expire :寫請求的超時時間設置(ms)
fifo_batch :在順序(sort_list)請求進行處理的時候,deadline將以batch為單位進行處理。每一個batch處理的請求個數為這個參數所限制的個數。在一個batch處理的過程中,不會產生是否超時的檢查,也就不會產生額外的磁碟尋道時間。這個參數可以用來平衡順序處理和飢餓時間的矛盾,當飢餓時間需要盡可能的符合預期的時候,我們可以調小這個值,以便盡可能多的檢查是否有飢餓產生並及時處理。增大這個值當然也會增大吞吐量,但是會導致處理飢餓請求的延時變長
writes_starved :這個值是在上述deadline出隊處理第一步時做檢查用的。用來判斷當讀隊列不為空時,寫隊列的飢餓程度是否足夠高,以時deadline放棄讀請求的處理而處理寫請求。當檢查存在有寫請求的時候,deadline並不會立即對寫請求進行處理,而是給相關數據結構中的starved進行累計,如果這是第一次檢查到有寫請求進行處理,那麼這個計數就為1。如果此時writes_starved值為2,則我們認為此時飢餓程度還不足夠高,所以繼續處理讀請求。只有當starved >= writes_starved的時候,deadline才回去處理寫請求。可以認為這個值是用來平衡deadline對讀寫請求處理優先順序狀態的,這個值越大,則寫請求越被滯後處理,越小,寫請求就越可以獲得趨近於讀請求的優先順序
front_merges :當一個新請求進入隊列的時候,如果其請求的扇區距離當前扇區很近,那麼它就是可以被合並處理的。而這個合並可能有兩種情況,一個是向當前位置後合並,另一種是向前合並。在某些場景下,向前合並是不必要的,那麼我們就可以通過這個參數關閉向前合並。默認deadline支持向前合並,設置為0關閉
在調度一個request時,首先需要選擇一個一個合適的cfq_group。Cfq調度器會為每個cfq_group分配一個時間片,當這個時間片耗盡之後,會選擇下一個cfq_group。每個cfq_group都會分配一個vdisktime,並且通過該值採用紅黑樹對cfq_group進行排序。在調度的過程中,每次都會選擇一個vdisktime最小的cfq_group進行處理。
一個cfq_group管理了7棵service tree,每棵service tree管理了需要調度處理的對象cfq_queue。因此,一旦cfq_group被選定之後,需要選擇一棵service tree進行處理。這7棵service tree被分成了三大類,分別為RT、BE和IDLE。這三大類service tree的調度是按照優先順序展開的
通過優先順序可以很容易的選定一類Service tree。當一類service tree被選定之後,採用service time的方式選定一個合適的cfq_queue。每個Service tree是一棵紅黑樹,這些紅黑樹是按照service time進行檢索的,每個cfq_queue都會維護自己的service time。分析到這里,我們知道,cfq演算法通過每個cfq_group的vdisktime值來選定一個cfq_group進行服務,在處理cfq_group的過程通過優先順序選擇一個最需要服務的service tree。通過該Service tree得到最需要服務的cfq_queue。該過程在 cfq_select_queue 函數中實現
一個cfq_queue被選定之後,後面的過程和deadline演算法有點類似。在選擇request的時候需要考慮每個request的延遲等待時間,選擇那種等待時間最長的request進行處理。但是,考慮到磁碟抖動的問題,cfq在處理的時候也會進行順序批量處理,即將那些在磁碟上連續的request批量處理掉
cfq調度演算法的參數
back_seek_max :磁頭可以向後定址的最大范圍,默認值為16M
back_seek_penalty :向後定址的懲罰系數。這個值是跟向前定址進行比較的
fifo_expire_async :設置非同步請求的超時時間。同步請求和非同步請求是區分不同隊列處理的,cfq在調度的時候一般情況都會優先處理同步請求,之後再處理非同步請求,除非非同步請求符合上述合並處理的條件限制范圍內。當本進程的隊列被調度時,cfq會優先檢查是否有非同步請求超時,就是超過fifo_expire_async參數的限制。如果有,則優先發送一個超時的請求,其餘請求仍然按照優先順序以及扇區編號大小來處理
fifo_expire_sync :這個參數跟上面的類似,區別是用來設置同步請求的超時時間
slice_idle :參數設置了一個等待時間。這讓cfq在切換cfq_queue或service tree的時候等待一段時間,目的是提高機械硬碟的吞吐量。一般情況下,來自同一個cfq_queue或者service tree的IO請求的定址局部性更好,所以這樣可以減少磁碟的定址次數。這個值在機械硬碟上默認為非零。當然在固態硬碟或者硬RAID設備上設置這個值為非零會降低存儲的效率,因為固態硬碟沒有磁頭定址這個概念,所以在這樣的設備上應該設置為0,關閉此功能
group_idle :這個參數也跟上一個參數類似,區別是當cfq要切換cfq_group的時候會等待一段時間。在cgroup的場景下,如果我們沿用slice_idle的方式,那麼空轉等待可能會在cgroup組內每個進程的cfq_queue切換時發生。這樣會如果這個進程一直有請求要處理的話,那麼直到這個cgroup的配額被耗盡,同組中的其它進程也可能無法被調度到。這樣會導致同組中的其它進程餓死而產生IO性能瓶頸。在這種情況下,我們可以將slice_idle = 0而group_idle = 8。這樣空轉等待就是以cgroup為單位進行的,而不是以cfq_queue的進程為單位進行,以防止上述問題產生
low_latency :這個是用來開啟或關閉cfq的低延時(low latency)模式的開關。當這個開關打開時,cfq將會根據target_latency的參數設置來對每一個進程的分片時間(slice time)進行重新計算。這將有利於對吞吐量的公平(默認是對時間片分配的公平)。關閉這個參數(設置為0)將忽略target_latency的值。這將使系統中的進程完全按照時間片方式進行IO資源分配。這個開關默認是打開的
target_latency :當low_latency的值為開啟狀態時,cfq將根據這個值重新計算每個進程分配的IO時間片長度
quantum :這個參數用來設置每次從cfq_queue中處理多少個IO請求。在一個隊列處理事件周期中,超過這個數字的IO請求將不會被處理。這個參數只對同步的請求有效
slice_sync :當一個cfq_queue隊列被調度處理時,它可以被分配的處理總時間是通過這個值來作為一個計算參數指定的。公式為: time_slice = slice_sync + (slice_sync/5 * (4 - prio)) 這個參數對同步請求有效
slice_async :這個值跟上一個類似,區別是對非同步請求有效
slice_async_rq :這個參數用來限制在一個slice的時間范圍內,一個隊列最多可以處理的非同步請求個數。請求被處理的最大個數還跟相關進程被設置的io優先順序有關
通常在Linux上使用的IO介面是同步方式的,進程調用 write / read 之後會阻塞陷入到內核態,直到本次IO過程完成之後,才能繼續執行,下面介紹的非同步IO則沒有這種限制,但是當前Linux非同步IO尚未成熟
目前Linux aio還處於較不成熟的階段,只能在 O_DIRECT 方式下才能使用(glibc_aio),也就是無法使用默認的Page Cache機制
正常情況下,使用aio族介面的簡要方式如下:
io_uring 是 2019 年 5 月發布的 Linux 5.1 加入的一個重大特性 —— Linux 下的全新的非同步 I/O 支持,希望能徹底解決長期以來 Linux AIO 的各種不足
io_uring 實現非同步 I/O 的方式其實是一個生產者-消費者模型:
邏輯卷管理
RAID0
RAID1
RAID5(糾錯)
條帶化
Linux系統性能調整:IO過程
Linux的IO調度
一個IO的傳奇一生
理解inode
Linux 文件系統是怎麼工作的?
Linux中Buffer cache性能問題一探究竟
Asynchronous I/O and event notification on linux
AIO 的新歸宿:io_uring
Linux 文件 I/O 進化史(四):io_uring —— 全新的非同步 I/O