標籤:角度 空間 會同 lis logical 組織 seconds 情況 使用者權限
檔案系統是作業系統中管理持久性資料的子系統,提供資料存放區和訪問功能。對於伺服器開發人員,比較關注的是unix(linux)環境下的檔案系統,比如分區與磁碟關係,磁碟的剩餘空間,檔案的類型與許可權控制,檔案連結等相關知識。
磁碟結構簡介:回到頂部
檔案系統是建立在物理磁碟之上的,因此在介紹檔案系統之前先簡單介紹磁碟的結構,這樣便於理解後面的相關概念。本文對磁碟的介紹可能比較粗略,感興趣的讀者可以參考《硬碟的讀寫原理》這一篇文章,寫的非常詳盡。先來一張結構:
相關術語解釋如下:
- 磁碟面(platter):相互平行的儲存介質
- 磁頭(Heads):每個磁頭對應一個磁碟面,負責該磁碟面上的資料的讀寫。
- 磁軌(Track):每個盤面會圍繞圓心劃分出多個同心圓圈,每個圓圈叫做一個磁軌。
- 柱面(Cylinders):所有碟片上的同一位置的磁軌組成的立體叫做一個柱面。
- 扇區(Sector):以磁軌為單位管理磁碟仍然太大,所以電腦前輩們又把每個磁軌劃分出了多個扇區
- 磁頭臂(arm):驅動磁頭的移動
邏輯上,磁碟被分成一個個扇區,扇區是磁碟訪問的最基本單位,如果所示,一塊地區由cylinder, head,sector三塊地區組成(CHS)。早期的作業系統需要知道磁碟的所有參數才能讀寫資料,而現在的磁碟越來越複雜,扇區可能還有不同的大小。因此,現在的磁碟需要提供更高階的介面,將磁碟的容量宦維城一組邏輯的塊(blocks),作業系統直接對這些邏輯塊進行操作。
一次磁碟的讀寫可能需要經曆以下三個步驟,因此讀寫效能也取決於這三部分的速度:
- 尋道(seek):磁頭移動定位到指定磁軌,速度非常慢
- 旋轉延遲(rotation):等待指定扇區從磁頭下旋轉經過,速度比較慢
- 資料轉送(transfer):資料在磁碟與記憶體之間的實際傳輸,速度比較快
因此,要提升效能主要是最小化seek(miliseconds)和rotation的代價。而seek是最耗時的,那麼在同時又多個讀寫請求的時候最小化seek的次數,就能提高整體效能。現在的磁碟都是自己做調度,因為相比OS,磁碟更清楚自己的各項參數。 在linux環境下,可以通過fdisk來查看磁碟的相關資訊。包括磁碟總的容量、扇區的大小與數理,磁碟與分區的對應關係等等。for example(是虛擬街結果): 什麼是檔案系統:
首先得知道什麼檔案,檔案是具有符號名,由位元組序列組成的資料項目集合,是檔案系統的基本資料單位。平常提到檔案的時候,基本上只關注檔案的內容,但是檔案本身也有很多資訊,比如檔案名稱、類型、位置、大小、許可權控制、建立時間、修改時間等,這些資訊成為檔案的中繼資料(meta data),在unix系統中個,中繼資料記錄在inode中。
檔案系統是作業系統中管理檔案的子系統,提供檔案資料存放區和訪問功能,具體來說,檔案系統應具備以下功能:
- 分配檔案磁碟空間:需要管理已經分配的檔案塊,包括位置與順序;管理所有的空閑空間;用一定的分配演算法為新的檔案分配空間
- 管理檔案集合:以某種組織方式結構化檔案的資訊,以便能夠通過名字找到檔案,並讀取檔案的內容
- 資料可靠與安全:首先是提供不同的手段,多層次保護資料安全,比如存取權限控制。通過持久儲存檔案,避免系統崩潰錯誤、冗餘來保證檔案的可靠。
作業系統中一般都是用分層的檔案系統,即檔案以目錄的形式組織,目錄裡面也可以包含子目錄,這樣,整個檔案系統就形成了一棵樹形結構。基於這種分層結構,檔案的名字解析(用邏輯名字到實體資源)就比較簡單了,根據檔案的完整路徑,遍曆檔案目錄直到找到目標檔案。
由於曆史和使用環境的差異,存在著各種不同的磁碟檔案系統,比如FAT、NTFS、EXT2、EXT3;還有網路Distributed File System,比如NFS、SMB,不同的檔案系統,作用不同,安全要求不同,最佳化的目標也不同。面對有多種不同的檔案系統,又需要向上層提供一致的介面,因此引入了虛擬檔案系統(virtual file system)。分區(即一個虛擬檔案系統)與磁碟並不是一一對應的關係,一個磁碟可以對應多個分區,如LVM;多個磁碟也可以對應一個分區,如RAID
作業系統會為每個進程維護一個開啟的檔案表,為每一個開啟的檔案分配套一個唯一的標誌,即檔案描述符(file descriptor)。開啟檔案表用檔案描述符做索引,對應的項維護開啟檔案的狀態和相關資訊,比如:
- 檔案指標:最近一次讀寫位置,寫過C語言的同學應該不陌生。雖然一個檔案可以被多個進程同事開啟,但每個進程分別維護自己的檔案指標
- 檔案開啟計數:當前開啟檔案的次數,當最後一個進程關閉檔案時,將其從開啟檔案表中移除??
- 檔案的磁碟資訊:作業系統會把一部分訪問的檔案內容緩衝在記憶體當中,以便加速訪問。緩衝的資料資訊也會記錄
- 存取權限:每個進程的檔案訪問模式資訊,開啟檔案時的選項,唯讀、唯寫、還是可讀可寫
在使用者的角度,檔案是持久化的資料結構。而在作業系統的角度,檔案是資料區塊(block)的集合,作業系統以快為單位對檔案資料進行讀寫,即使只需讀寫一個欄位,也需要讀取一個塊(大小為1k、2k或者4k),這裡的塊是邏輯儲存單元,而扇區是實體儲存體單元,塊大小不等同於扇區大小,一般來說,若干個扇區構成一個資料區塊。
檔案分配:
檔案分配是指將哪些塊分配給檔案來儲存資料,包括資料庫的位置與順序。在這裡,塊的大小非常重要,第一:大多數檔案都比較小,因此塊空間不能太大,需要對小檔案提供很好的支援;第二,一些檔案非常大,必須支援大檔案,訪問需要高效(如果塊太小,那麼大檔案需要很多的塊)。衡量分配策略的指標主要有兩個:儲存效率,即外部片段;讀寫效能,即訪問速度。分配方式有以下三種:
- 連續分配:優點在於訪問效率高,支援高效的順序和隨機訪問。但缺點在於會引入外部片段,而且對於檔案增長問題不是很好處理。
- 鏈式分配:優點在於建立、增大、縮小都容易,而且沒有外部片段。缺點在於訪問效率低,無法實現真正的隨機訪問。
- 索引分配:優點在於建立、增大、縮小都容易,沒有外部片段,而且支援直接存取。缺點在於當檔案很小時,儲存索引的開銷,對大檔案的處理也是需要考慮的問題
在unix中,使用多級索引分配。
從可以看到:檔案頭總共包含13個指標(PS: 上面來自清華大學的課程,按照Inode_pointer_structure,現在的作業系統有15個block pointer),其中
- 前10個指標直接指向資料庫
- 第11個指標指向索引塊i
- 第12個指標指向二級索引快
- 第13個指標指向三級索引快
多級索引分配提高了檔案大小限制閾值,而且可以動態分配資料區塊,檔案的擴充很容易。檔案比較小的時候,直接索引;檔案比較大的時候,也能處理,只是效率會差一點。
檔案分享權限設定和存取控制
在多使用者作業系統中(比如unix),檔案的共用是分成有必要的,首先一部分檔案對於每個使用者都是相同的(或者預設是情況下是相同的),沒有必要每個使用者都儲存一份;其次,使用者之間可能需要協同處理同一份檔案。有共用就需要互斥,這個跟進程線程間的同步互斥是一樣的道理,比如對於同一個檔案,一個進程在讀,另一個進程在寫,怎麼協調,作業系統並不解決多個進程共用檔案時候的一致性問題,需要英語程式來規範解決。
存取控制分為兩個層面,第一個是哪些使用者可以訪問(廣義的訪問,不限於讀寫執行)到檔案,第二是怎麼訪問這個檔案。更一般的抽象的就是某個使用者用什麼樣的許可權來訪問某個檔案,檔案(objects)是what,使用者(subjects)是who,方式(actions)是how。從使用者的角度來看,需要維護檔案與許可權的列表,即Access Control list(ACL);從檔案的角度看,需要維護使用者與使用者對該檔案的許可權的列表,即Capabilities:
對於每一個使用者(subject),都有一個ACL,那麼當使用者用來越時且一個檔案在很多個使用者之間共用的時候,ACL列表就會變得非常龐大,因此在unix中,提出了group的概念,同一個group裡面的使用者對同一個檔案分享權限設定相同的許可權。
檔案系統效能:
由於物理裝置的制約,磁碟檔案的讀寫與記憶體比起來相差十萬八千裡。為了提升檔案的讀寫效率,磁碟會根據自身的參數做最佳化,比如盡量把一個檔案(包括中繼資料資訊)放在臨界的扇區。同時,檔案系統也會做一些最佳化,比如:
檔案快取,File buffer cache,將部分檔案內容緩衝在記憶體中,由於記憶體的讀寫比較快,這樣就能極大提高效能。作業系統統一管理緩衝,所有進程共用快取資訊,在需要置換的時候也是使用LRU之類的演算法。
滯後寫,wtire behind,需要寫操作的時候,並不立即刷到磁碟,而是維護未提交塊的隊列,周期性把隊列內容刷到磁碟上。但問題是不可靠,可能造成資料不一致。
預先讀,read ahead,如果檔案系統預測進程會讀取下一個塊,就預先將下一個塊讀到cache中來,這個在連續的檔案讀取環境下,十分有效。
RAID:資料可靠性
RAID是Redundant Array of Independent Disks,即獨立磁碟冗餘序列。其基本思想就是把多個相對便宜的硬碟組合起來,成為一個硬碟陣列組,使效能達到甚至超過一個價格昂貴、容量巨大的硬碟。根據選擇的版本不同,RAID比單顆硬碟有以下一個或多個方面的好處:增強Data Integration度,增強容錯功能,增加處理量或容量。另外,磁碟陣列對於電腦來說,看起來就像一個單獨的硬碟或邏輯儲存單元。是wiki上各種磁碟陣列的比較表:
linux下的檔案
linux環境下的檔案系統分為三個層級,其基本資料結構如下:
(1)檔案磁碟控制區塊:superblock
每一個檔案系統一個,在檔案系統掛接的時候載入,記錄檔案系統的詳細資料,比如塊、塊大小、空閑塊、各種計數和指標。
(2)目錄項:dentry(dictionary entry)
每一個目錄項一個,在遍曆檔案的時候載入到記憶體,包含指向檔案控制區,父目錄、子目錄等資訊
(3)檔案控制區:inode
每個檔案一個,在檔案訪問的時候載入到記憶體,記錄的就是檔案的中繼資料(meta data)。
在linux環境下,可以使用df(disk free)查看本系統上的檔案系統的剩餘空間與相應的掛載情況,然後使用dumpe2fs xxx(檔案系統名)即查看檔案系統資訊,包括superblock資訊,總共/可用的block inode資訊,每個block inode的大小等。
檔案的meta data
使用list -l可以查看一部分檔案的中繼資料,不過使用stat命令會更加詳細一些, for example:
比較重要的資訊包括:
File type: 檔案類型,已經指出為“regular file”, Access的第一位也是用來表明檔案類型。
Inode:中繼資料位置索引,每個檔案唯一
Links:有多少個檔案名稱指向這個檔案,後面介紹檔案連結的時候還會提到
Access:存取權限
atime:access time, 檔案的最後訪問時間
mtime: modification time, 檔案內容修改時間
ctime: change time, 檔案屬性(meta data)修改時間
從上面的可以看到,檔案的三個時間屬性可能是不同的值,三者之間可能相互影響,關係如下:
- atime的變化不會影響mtime和ctime
- ctime的變化也不會影響mtime 和atime
- mtime的變化會同時影響到atime和mtime,因為修改檔案必定會訪問檔案,另外檔案內容的大小是檔案的中繼資料
對於檔案系統來說,檔案的類型也是非常重要的資訊,而且作業系統的其他部分也需要知道檔案的類型資訊。在windows下,通過尾碼名來區分檔案類型,在unix下,會將檔案的類型通過magic number記錄。linux下檔案類型通過ls -l 命令第一行即可看到,可能得類型如下:
- 普通檔案,第一個欄位為-
- 目錄,第一個欄位為d
- 管道(PIPE), 第一個欄位為p, 用來做處理序間通訊(IPC)
- 通訊端(socket),第一個欄位是s,之前已經介紹過,unix domain socket,也是用作處理序間通訊
- 符號連結檔案(symbol link), 第一個欄位是l,後面會詳細介紹
- 塊裝置(block), 第一個欄位是b,即磁碟裝置
- 字元裝置(character), 第一個欄位是c,指的是滑鼠、鍵盤燈串列裝置
其中。普通檔案又分為純文字檔案、二進位檔案等,可通過file命令查看
存取權限控制
我們都知道對於一個檔案,使用者有三種許可權:r(可讀)、w(可寫)、x(可執行),對於普通檔案來說很好理解,但是對於目錄來說是是你們意思呢,特別是目錄的寫操作和執行?
r: 具有讀取目錄結構列表的許可權,比如使用ls(list)
w:具有更改目錄結構列表的許可權,不如建立檔案、目錄;刪除檔案、目錄;重新命名等
x:使用者能否進入該目錄成為工作目錄, 比如使用cd
以前就出現過cd失敗的原因,原來是因此這個許可權問題。
另外也能在使用者權限位看到s、t等情況,這個具體意義可以參考《Linux特殊許可權:SUID、SGID、SBIT》。下面製作簡單總結
- 檔案具有SUID的許可權時,代表使用者執行此二進位程式的時候,執行過程中使用者檔案所有者的許可權
- 目錄具有SGID的許可權時,代表使用者在這個目錄下建立的檔案使用者組都會與該目錄的使用者組相同
- 目錄具有SBIT的許可權時,代表使用者在這個目錄下建立的檔案只有自己和root能夠刪除
atime & noatime
上面提到 atime是檔案的最後訪問時間,我自己測試了一下,用cat訪問檔案,但是訪問前後的時間戳記並沒有發生變化,就是說,訪問檔案並沒有改變atime。於是網上查了一下,原因如下:
相信對效能、最佳化這些關鍵字有興趣的朋友都知道在 Linux 下面掛載檔案系統的時候設定 noatime 可以顯著提高檔案系統的效能。預設情況下,Linux ext2/ext3 檔案系統在檔案被訪問、建立、修改等的時候記錄下了檔案的一些時間戳記,比如:檔案建立時間、最近一次修改時間和最近一次訪問時間。因為系統啟動並執行時候要訪 問大量檔案,如果能減少一些動作(比如減少時間戳記的記錄次數等)將會顯著提高磁碟 IO 的效率、提升檔案系統的效能。Linux 提供了 noatime 這個參數來禁止記錄最近一次訪問時間戳記。
在wiki stat上面也有對著問題的描述,稱之為“Criticism_of_atime”,提到關於atime的更新有以下幾種選項:
- strictatime (formerly atime, and formerly the default; strictatime as of 2.6.30) – always update atime, which conforms to the behavior defined by POSIX
- relatime ("relative atime", introduced in 2.6.20 and the default as of 2.6.30) – only update atime under certain circumstances: if the previous atime is older than the mtime or ctime, or the previous atime is over 24 hours in the past
- nodiratime – never update atime of directories, but do update atime of other files
- noatime – never update atime of any file or directory; implies nodiratime; highest performance, but least compatible
- lazytime – update atime according to specific circumstances laid out below
其中noatime表示永遠不更新任何檔案和目錄的atime屬性。配置在/etc/fstab。for example:
永久連結與符號連結:
永久連結:多個檔案項指同一個檔案(同一個inode)
符號連結:連結檔案與被連結檔案的描述資訊(中繼資料,meta data)各自獨立,只是說連結檔案裡面儲存另一個檔案的完整路徑,以此實現檔案別名,類似windows中的“捷徑”。
linux下面使用指令ln src target 即可建立永久連結,target指向的是和src同樣的檔案,擁有同樣的inode(即meta data)資訊。也可以理解為,只是多了一個邏輯名指向某個檔案。執行指令:ln Server.log Server_hardlink.log
結合上面介紹meta data時候的,可以看到,建立永久連結之後唯一變化的就是Links的數值變成了2,因為現在Server_hardlink.log也指向了這個檔案。永久連結的好處在於更改的安全性,當我們用rm刪除一個檔案的時候,其實只是將檔案的links數目減少1,只有當links數目減少到0之後才會真正的刪除檔案。
linux下面使用指令ln -s src target 即可建立符號連結,如所示,src和target指向的是不同的inode
關於永久連結和符號連結,《Linux軟連結和永久連結》這篇文章比較詳盡清楚。
總結:
本文記錄了關於檔案系統的一些基礎知識,以及linux中檔案系統相關的命令,文章中主要是筆者之前不太清晰的一些知識點,並不全面,感興趣的讀者可以看看《鳥哥私房菜》。
檔案系統與linux相關知識點