重慶分公司,新征程啟航
為企業提供網站建設、域名注冊、服務器等服務
為企業提供網站建設、域名注冊、服務器等服務
想要一看linux的超級塊全貌,首先你必須得知道超級塊(superblock)寄宿在哪個設備上。
10余年的烏拉特后網站建設經驗,針對設計、前端、開發、售后、文案、推廣等六對一服務,響應快,48小時及時工作處理。網絡營銷推廣的優勢是能夠根據用戶設備顯示端的尺寸不同,自動調整烏拉特后建站的顯示方式,使網站能夠適用不同顯示終端,在瀏覽器中調整網站的寬度,無論在任何一種瀏覽器上瀏覽網站,都能展現優雅布局與設計,從而大程度地提升瀏覽體驗。創新互聯從事“烏拉特后網站設計”,“烏拉特后網站推廣”以來,每個客戶項目都認真落實執行。
先查看一下我們的設備:
root@xiahuixia-Inspiron-3437:/home/xiahuixia/tmp# df
Filesystem 1K-blocks Used Available Use% Mounted on
/dev/sda1 476559384 13315584 439012940 3% /
none 4 0 4 0% /sys/fs/cgroup
udev 1964312 4 1964308 1% /dev
tmpfs 395000 1360 393640 1% /run
none 5120 0 5120 0% /run/lock
none 1974984 17240 1957744 1% /run/shm
none 102400 36 102364 1% /run/user
root@xiahuixia-Inspiron-3437:/home/xiahuixia/tmp#
ok, 有一個設備叫做/dev/sda1,是的,它就是我的硬盤了,我沒有把我的硬盤分區,所以只有一個/dev/sda1 ,沒有/dev/sda2 、/dev/sda3….
然后查看一下這個命令“dumpe2fs”(dump ext2 file system , ext2文件系統是linux的正規文件系統)
DUMPE2FS(8) System Manager's Manual DUMPE2FS(8)
NAME
dumpe2fs - dump ext2/ext3/ext4 filesystem information
SYNOPSIS
dumpe2fs [ -bfhixV ] [ -o superblock=superblock ] [ -o blocksize=block‐ size ] device
DESCRIPTION
dumpe2fs prints the super block and blocks group information for the filesystem present on device.
Note: When used with a mounted filesystem, the printed information may be old or inconsistent.
OPTIONS
-b print the blocks which are reserved as bad in the filesystem.
-o superblock=superblock
use the block superblock when examining the filesystem.This option is not usually needed except by a filesystem wizard who is examining the remains of a very badly corrupted filesystem.
至于man手冊開頭的DUMPE2FS(8), 8是什么意思呢?
再執行man man 看一下:
The table below shows the section numbers of the manual followed by the types of pages they contain.
1 Executable programs or shell commands
2 System calls (functions provided by the kernel)
3 Library calls (functions within program libraries)
4 Special files (usually found in /dev)
5 File formats and conventions eg /etc/passwd
6 Games
7 Miscellaneous (including macro packages and conventions), e.g. man(7), groff(7)
8 System administration commands (usually only for root)
9 Kernel routines [Non standard]
A manual page consists of several sections.
看到了嗎? 8 System administration commands (usually only for root)
好了,回到命令dumpe2fs來,dumpe2fs dev, 那么,這個dev該用什么來代替呢?就是我們的設備/dev/sda1了。
好了,看一下我們超級塊的樣子:
dumpe2fs /dev/sda1, oop!內容太多了,將內容重定向到文件里吧:
dumpe2fs /dev/sda1 input
vi input
let us have a look at the content of input:
Filesystem volume name: none
Last mounted on: /
Filesystem UUID: 83a4e993-4703-42ac-88ce-81f7b8c5ae35
Filesystem magic number: 0xEF53
Filesystem revision #: 1 (dynamic)
Filesystem features: has_journal ext_attr resize_inode dir_index filetype needs_recovery extent flex_bg sparse_super large_file huge_file uninit_bg dir_nlink extra_isize
Filesystem flags: signed_directory_hash
Default mount options: user_xattr acl
Filesystem state: clean
Errors behavior: Continue
Filesystem OS type: Linux
Inode count: 30269440
Block count: 121072384
Reserved block count: 6053619
Free blocks: 115812611
Free inodes: 30026282
First block: 0
Block size: 4096
Fragment size: 4096
Reserved GDT blocks: 995
Blocks per group: 32768
LINUX中進程的最大理論數計算:
每個進程的局部段描述表LDT都作為一個獨立的段而存在,在全局段描述表GDT中要有一個表項指向這個段的起始地址,并說明該段的長度以及其他一些 參數。除上之外,每個進程還有一個TSS結構(任務狀態段)也是一樣。所以,每個進程都要在全局段描述表GDT中占據兩個表項。那么,GDT的容量有多大 呢?段寄存器中用作GDT表下標的位段寬度是13位,所以GDT中可以有8192個描述項。除一些系統的開銷(例如GDT中的第2項和第3項分別用于內核 的代碼段和數據段,第4項和第5項永遠用于當前進程的代碼段和數據段,第1項永遠是0,等等)以外,尚有8180個表項可供使用,所以理論上系統中最大的 進程數量是4090。
磁盤結構與數據存儲方式, 數據是如何存儲的,又通過怎樣的方式被訪問?
機械硬盤主要由磁盤盤片、磁頭、主軸與傳動軸等組成;數據就存放在磁盤盤片中
現代硬盤尋道都是采用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