Linux 文件系統剖析

【轉自】https://www.ibm.com/developerworks/cn/linux/l-linux-filesystem/

按照分層結構討論 Linux 文件系統

在文件系統方面,Linux® 能夠算得上操做系統中的 「瑞士軍刀」。Linux 支持許多種文件系統,從日誌型文件系統到集羣文件系統和加密文件系統。對於使用標準的和比較奇特的文件系統以及開發文件系統來講,Linux 是極好的平臺。本文討論 Linux 內核中的虛擬文件系統(VFS,有時候稱爲虛擬文件系統交換器),而後介紹將文件系統鏈接在一塊兒的主要結構。php

基本的文件系統體系結構

Linux 文件系統體系結構是一個對複雜系統進行抽象化的有趣例子。經過使用一組通用的 API 函數,Linux 能夠在許多種存儲設備上支持許多種文件系統。例如,read 函數調用能夠從指定的文件描述符讀取必定數量的字節。read 函數不瞭解文件系統的類型,好比 ext3 或 NFS。它也不瞭解文件系統所在的存儲媒體,好比 AT Attachment Packet Interface(ATAPI)磁盤、Serial-Attached SCSI(SAS)磁盤或 Serial Advanced Technology Attachment(SATA)磁盤。可是,當經過調用 read 函數讀取一個文件時,數據會正常返回。本文講解這個機制的實現方法並介紹 Linux 文件系統層的主要結構。node

 

什麼是文件系統?

首先回答最多見的問題,「什麼是文件系統」。文件系統是對一個存儲設備上的數據和元數據進行組織的機制。因爲定義如此寬泛,支持它的代碼會頗有意思。正如前面提到的,有許多種文件系統和媒體。因爲存在這麼多類型,能夠預料到 Linux 文件系統接口實現爲分層的體系結構,從而將用戶接口層、文件系統實現和操做存儲設備的驅動程序分隔開。linux

掛裝

在 Linux 中將一個文件系統與一個存儲設備關聯起來的過程稱爲掛裝(mount)。使用 mount 命令將一個文件系統附着到當前文件系統層次結構中(根)。在執行掛裝時,要提供文件系統類型、文件系統和一個掛裝點。程序員

爲了說明 Linux 文件系統層的功能(以及掛裝的方法),咱們在當前文件系統的一個文件中建立一個文件系統。實現的方法是,首先用 dd 命令建立一個指定大小的文件(使用 /dev/zero 做爲源進行文件複製)—— 換句話說,一個用零進行初始化的文件,見清單 1。數據庫

清單 1. 建立一個通過初始化的文件
$ dd if=/dev/zero of=file.img bs=1k count=10000
10000+0 records in
10000+0 records out
$

如今有了一個 10MB 的 file.img 文件。使用 losetup 命令將一個循環設備與這個文件關聯起來,讓它看起來像一個塊設備,而不是文件系統中的常規文件:windows

$ losetup /dev/loop0 file.img
$

這個文件如今做爲一個塊設備出現(由 /dev/loop0 表示)。而後用 mke2fs 在這個設備上建立一個文件系統。這個命令建立一個指定大小的新的 ext2 文件系統,見清單 2。緩存

清單 2. 用循環設備建立 ext2 文件系統
$ mke2fs -c /dev/loop0 10000
mke2fs 1.35 (28-Feb-2004)
max_blocks 1024000, rsv_groups = 1250, rsv_gdb = 39
Filesystem label=
OS type: Linux
Block size=1024 (log=0)
Fragment size=1024 (log=0)
2512 inodes, 10000 blocks
500 blocks (5.00%) reserved for the super user
...
$

使用 mount 命令將循環設備(/dev/loop0)所表示的 file.img 文件掛裝到掛裝點 /mnt/point1。注意,文件系統類型指定爲 ext2。掛裝以後,就能夠將這個掛裝點看成一個新的文件系統,好比使用 ls 命令,見清單 3。服務器

清單 3. 建立掛裝點並經過循環設備掛裝文件系統
$ mkdir /mnt/point1
$ mount -t ext2 /dev/loop0 /mnt/point1
$ ls /mnt/point1
lost+found
$

如清單 4 所示,還能夠繼續這個過程:在剛纔掛裝的文件系統中建立一個新文件,將它與一個循環設備關聯起來,再在上面建立另外一個文件系統。網絡

清單 4. 在循環文件系統中建立一個新的循環文件系統
$ dd if=/dev/zero of=/mnt/point1/file.img bs=1k count=1000
1000+0 records in
1000+0 records out
$ losetup /dev/loop1 /mnt/point1/file.img
$ mke2fs -c /dev/loop1 1000
mke2fs 1.35 (28-Feb-2004)
max_blocks 1024000, rsv_groups = 125, rsv_gdb = 3
Filesystem label=
...
$ mkdir /mnt/point2
$ mount -t ext2 /dev/loop1 /mnt/point2
$ ls /mnt/point2
lost+found
$ ls /mnt/point1
file.img lost+found
$

經過這個簡單的演示很容易體會到 Linux 文件系統(和循環設備)是多麼強大。能夠按照相同的方法在文件上用循環設備建立加密的文件系統。能夠在須要時使用循環設備臨時掛裝文件,這有助於保護數據。less

 

文件系統體系結構

既然已經看到了文件系統的構造方法,如今就看看 Linux 文件系統層的體系結構。本文從兩個角度考察 Linux 文件系統。首先採用高層體系結構的角度。而後進行深層次討論,介紹實現文件系統層的主要結構。

 

高層體系結構

儘管大多數文件系統代碼在內核中(後面討論的用戶空間文件系統除外),可是圖 1 所示的體系結構顯示了用戶空間和內核中與文件系統相關的主要組件之間的關係。

圖 1. Linux 文件系統組件的體系結構
圖 1. Linux 文件系統組件的體系結構

用戶空間包含一些應用程序(例如,文件系統的使用者)和 GNU C 庫(glibc),它們爲文件系統調用(打開、讀取、寫和關閉)提供用戶接口。系統調用接口的做用就像是交換器,它將系統調用從用戶空間發送到內核空間中的適當端點。

VFS 是底層文件系統的主要接口。這個組件導出一組接口,而後將它們抽象到各個文件系統,各個文件系統的行爲可能差別很大。有兩個針對文件系統對象的緩存(inode 和 dentry)。它們緩存最近使用過的文件系統對象。

每一個文件系統實現(好比 ext二、JFS 等等)導出一組通用接口,供 VFS 使用。緩衝區緩存會緩存文件系統和相關塊設備之間的請求。例如,對底層設備驅動程序的讀寫請求會經過緩衝區緩存來傳遞。這就容許在其中緩存請求,減小訪問物理設備的次數,加快訪問速度。以最近使用(LRU)列表的形式管理緩衝區緩存。注意,能夠使用 sync 命令將緩衝區緩存中的請求發送到存儲媒體(迫使全部未寫的數據發送到設備驅動程序,進而發送到存儲設備)

這就是 VFS 和文件系統組件的高層狀況。如今,討論實現這個子系統的主要結構。

主要結構

Linux 以一組通用對象的角度看待全部文件系統。這些對象是超級塊(superblock)、inode、dentry 和文件。超級塊在每一個文件系統的根上,超級塊描述和維護文件系統的狀態。文件系統中管理的每一個對象(文件或目錄)在 Linux 中表示爲一個 inode。inode 包含管理文件系統中的對象所需的全部元數據(包括能夠在對象上執行的操做)。另外一組結構稱爲 dentry,它們用來實現名稱和 inode 之間的映射,有一個目錄緩存用來保存最近使用的 dentry。dentry 還維護目錄和文件之間的關係,從而支持在文件系統中移動。最後,VFS 文件表示一個打開的文件(保存打開的文件的狀態,好比寫偏移量等等)。

虛擬文件系統層

VFS 做爲文件系統接口的根層。VFS 記錄當前支持的文件系統以及當前掛裝的文件系統。

可使用一組註冊函數在 Linux 中動態地添加或刪除文件系統。內核保存當前支持的文件系統的列表,能夠經過 /proc 文件系統在用戶空間中查看這個列表。這個虛擬文件還顯示當前與這些文件系統相關聯的設備。在 Linux 中添加新文件系統的方法是調用 register_filesystem。這個函數的參數定義一個文件系統結構(file_system_type)的引用,這個結構定義文件系統的名稱、一組屬性和兩個超級塊函數。也能夠註銷文件系統。

在註冊新的文件系統時,會把這個文件系統和它的相關信息添加到 file_systems 列表中(見圖 2 和 linux/include/linux/mount.h)。這個列表定義能夠支持的文件系統。在命令行上輸入 cat /proc/filesystems,就能夠查看這個列表。

圖 2. 向內核註冊的文件系統
圖 2. 向內核註冊的文件系統

VFS 中維護的另外一個結構是掛裝的文件系統(見圖 3)。這個結構提供當前掛裝的文件系統(見 linux/include/linux/fs.h)。它連接下面討論的超級塊結構。

圖 3. 掛裝的文件系統列表
圖 3. 掛裝的文件系統列表

超級塊

超級塊結構表示一個文件系統。它包含管理文件系統所需的信息,包括文件系統名稱(好比 ext2)、文件系統的大小和狀態、塊設備的引用和元數據信息(好比空閒列表等等)。超級塊一般存儲在存儲媒體上,可是若是超級塊不存在,也能夠實時建立它。能夠在 ./linux/include/linux/fs.h 中找到超級塊結構(見圖 4)。

圖 4. 超級塊結構和 inode 操做
圖 4. 超級塊結構和 inode 操做

超級塊中的一個重要元素是超級塊操做的定義。這個結構定義一組用來管理這個文件系統中的 inode 的函數。例如,能夠用 alloc_inode 分配 inode,用 destroy_inode 刪除 inode。能夠用 read_inode 和 write_inode 讀寫 inode,用 sync_fs 執行文件系統同步。能夠在 ./linux/include/linux/fs.h 中找到 super_operations 結構。每一個文件系統提供本身的 inode 方法,這些方法實現操做並向 VFS 層提供通用的抽象。

inode 和 dentry

inode 表示文件系統中的一個對象,它具備唯一標識符。各個文件系統提供將文件名映射爲唯一 inode 標識符和 inode 引用的方法。圖 5 顯示 inode 結構的一部分以及兩個相關結構。請特別注意 inode_operations 和 file_operations。這些結構表示能夠在這個 inode 上執行的操做。inode_operations 定義直接在 inode 上執行的操做,而 file_operations 定義與文件和目錄相關的方法(標準系統調用)。

圖 5. inode 結構和相關聯的操做
圖 5. inode 結構和相關聯的操做

inode 和目錄緩存分別保存最近使用的 inode 和 dentry。注意,對於 inode 緩存中的每一個 inode,在目錄緩存中都有一個對應的 dentry。能夠在 ./linux/include/linux/fs.h 中找到 inode 和 dentry 結構。

緩衝區緩存

除了各個文件系統實現(能夠在 ./linux/fs 中找到)以外,文件系統層的底部是緩衝區緩存。這個組件跟蹤來自文件系統實現和物理設備(經過設備驅動程序)的讀寫請求。爲了提升效率,Linux 對請求進行緩存,避免將全部請求發送到物理設備。緩存中緩存最近使用的緩衝區(頁面),這些緩衝區能夠快速提供給各個文件系統。

 

本文沒有討論 Linux 中可用的具體文件系統,可是值得在這裏稍微提一下。Linux 支持許多種文件系統,包括 MINIX、MS-DOS 和 ext2 等老式文件系統。Linux 還支持 ext三、JFS 和 ReiserFS 等新的日誌型文件系統。另外,Linux 支持加密文件系統(好比 CFS)和虛擬文件系統(好比 /proc)。

最後一種值得注意的文件系統是 Filesystem in Userspace(FUSE)。這種文件系統能夠將文件系統請求經過 VFS 發送回用戶空間。因此,若是您有興趣建立本身的文件系統,那麼經過使用 FUSE 進行開發是一種不錯的方法。

 

結束語

儘管文件系統的實現並不複雜,但它是可伸縮和可擴展的體系結構的好例子。文件系統體系結構已經發展了許多年,併成功地支持了許多不一樣類型的文件系統和許多目標存儲設備類型。因爲使用了基於插件的體系結構和多層的函數間接性,Linux 文件系統在近期的發展很值得關注。

 

=====================================================

Q:如何查看分區和目錄及使用狀況

–      fdisk查看硬盤分區表

–      df:查看分區使用狀況

–      du: 查看文件佔用空間狀況

Q: 爲何要分區,如何分區?

–      能夠把不一樣資料,分別放入不一樣分區中管理,下降風險。

–      大硬盤搜索範圍大,效率低

–      磁盤配合只能對分區作設定

–      /home /var /usr/local常常是單獨分區,由於常常會操做,容易產生碎片

2.Mount掛載和NFS簡介

掛載的概念 :當要使用某個設備時,例如要讀取硬盤中的一個格式化好的分區、光盤或軟件等設備時,必須先把這些設備對應到某個目錄上,而這個目錄就稱爲「掛載點(mount point)」,這樣才能夠讀取這些設備,而這些對應的動做就是「掛載」。 將物理分區細節屏蔽掉。用戶只有統一的邏輯概念。全部的東西都是文件。Mount命令能夠實現掛載:

mount [-fnrsvw] [-t vfstype] [-o options] device dir

Q:全部的磁盤分區都必須被掛載上才能使用,那麼咱們機器上的硬盤分區是如何被掛載的?

A:這主要是它利用了/etc/fstab文件。每次內核加載它知道從這裏開始mount文件系統。每次系統啓動會根據該文件定義自動掛載。若沒有被自動掛載,分區將不能使用。 以下是個人/etc/fstab的定義,主要是根據裝機的分區來的:

# <file system> <mount point>   <type>  <options>       <dump>  <pass>

proc            /proc           proc    defaults        0       0

#/dev/sda1被自動掛載到  /

UUID=cb1934d0-4b72-4bbf-9fad-885d2a8eeeb1 /               ext3    relatime,errors=remount-ro 0       1

# /dev/sda5 被自動掛載到分區/home

UUID=c40f813b-bb0e-463e-aa85-5092a17c9b94 /home           ext3    relatime        0       2

#/dev/sda7 被自動掛載到/work

UUID=0f918e7e-721a-41c6-af82-f92352a568af /work           ext3    relatime        0       2

#分區 /dev/sda6被自動掛載到swap

UUID=2f8bdd05-6f8e-4a6b-b166-12bb52591a1f none            swap    sw              0       0

 

Q:移動硬盤如何掛載?如何掛載一個新的分區?

移動硬盤有驅動模塊會自動掛載,若是有個新硬盤,要先進行分區,並經過mount命令掛載到某個文件夾。若是要自動掛載則能夠修改/etc/fstab文件.

NFS簡介:NFS相信在不少地方都有普遍使用,是一個很是好的文件共享方式。咱們公司所使用的上傳服務就是把文件上傳到某臺網絡服務器上,中間就是經過NFS實現。

使用NFS客戶端能夠透明的地訪問服務器端的文件。NFS也是經過mount來實現,底層是經過NFS通訊協議實現。基本原理:

 

 

圖2:NFS基本原理

 

3.文件類型

Linux下面的文件類型主要有:

a)         普通文件:C語言元代碼、SHELL腳本、二進制的可執行文件等。分爲純文本和二進制。

b)         目錄文件:目錄,存儲文件的惟一地方。

c)         連接文件:指向同一個文件或目錄的的文件。

d)         特殊文件:與系統外設相關的,一般在/dev下面。分爲塊設備和字符設備。

能夠經過ls –l, file, stat幾個命令來查看文件的類型等相關信息。

4.文件存儲結構

 

Linux正統的文件系統(如ext二、ext3)一個文件由目錄項、inode和數據塊組成。

目錄項:包括文件名和inode節點號。

Inode:又稱文件索引節點,是文件基本信息的存放地和數據塊指針存放地。

數據塊:文件的具體內容存放地。

 

 

 

Linux正統的文件系統(如ext二、3等)將硬盤分區時會劃分出目錄塊、inode Table區塊和data block數據區域。一個文件由一個目錄項、inode和數據區域塊組成。Inode包含文件的屬性(如讀寫屬性、owner等,以及指向數據塊的指針),數據區域塊則是文件內容。當查看某個文件時,會先從inode table中查出文件屬性及數據存放點,再從數據塊中讀取數據。

 

站在2w英尺視圖,文件存儲結構大概以下:

 

 

圖3:文件存儲結構2w英尺視圖

 

 

其中目錄項的結構以下(每一個文件的目錄項存儲在改文件所屬目錄的文件內容裏):

 

 圖4:目錄項結構 

 

其中文件的inode結構以下(inode裏所包含的文件信息能夠經過stat filename查看獲得):

 

 

圖5:inode結構

 

以上只反映大致的結構,linux文件系統自己在不斷髮展。可是以上概念基本是不變的。且如ext二、ext三、ext4文件系統也存在很大差異,若是要了解能夠查看專門的文件系統介紹。

5.軟鏈接、硬連接

軟連接和硬連接是咱們常見的兩種概念:

硬鏈接:是給文件一個副本,同時創建二者之間的鏈接關係。修改其中一個,與其鏈接的文件同時被修改。若是刪除其中[color=red]任意一個[/color]其他的文件將不受影響。

軟鏈接:也叫符號鏈接,他只是對源文件在新的位置創建一個「快捷(借用一下wondows經常使用詞)」,因此,當源文件刪除時,符號鏈接的文件將成爲無源之水->僅僅剩下個文件名了,固然刪除這個鏈接,也不會影響到源文件,但對鏈接文件的使用、引用都是直接調用源文件的。

具體關係能夠看下圖:

 

 

 

圖5:軟連接和硬連接

 

 

從圖上能夠看出硬連接和軟連接的區別:

1:硬連接原文件和新文件的inode編號一致。而軟連接不同。

2:對原文件刪除,會致使軟連接不可用,而硬連接不受影響。

3:對原文件的修改,軟、硬連接文件內容也同樣的修改,由於都是指向同一個文件內容的。

 

6.文件目錄管理命令

磁盤和文件空間

fdisk df du

文件目錄與管理

cd pwd mkdir rmdir ls cp rm mv

查看文件內容

cat:
cat [file]
查看文件的內容。全程式concatenate的意思,將文件內容連續輸出到屏幕上。第一行到最後一行顯示。
tac:
tac [file]
和cat恰好相反 是從最後一行到第一行的方式查看。

cat有個比較很差的地方時當文件比較大時候沒辦法看清楚,這個時候能夠用more或者Less命令。

more:
more [file]
若是使用grep或者find等命令時,能夠配合使用more一頁一頁的查看。若是看到一半想退出,則敲入’q’便可退出。
less:
less [file]
less比more更有彈性,能夠上下翻頁。

若是隻想讀取文件的頭幾行或者文件的末尾幾行,能夠用head或tail.
head –n [file]:讀取文件的前n行。
tail –n [file]:讀取文件末尾n行。

以上命令都是用於查看字符文件,二進制文件出來的都是亂碼,要看二進制文件的內容,能夠用od命令,如查看一個MP3文件裏面的內容:
od shijiemori.mp3

 

文件目錄與權限

chmod chown chgrp umask

文件查找

which:
which [filename]
該命令用於查詢經過PATH路徑到該路徑內查找可執行文件。
如:Which passwd:查找可執行文件passwd
whereis:
whereis [-bmsu] [keyword]
該命令用於把相關字的文件和目錄都列出來。(Linux 會將文件都記錄在一個文件數據庫裏面,該命令式從數據庫去查詢,因此速度比較快,Linux天天會更新該數據庫)

locate:
locate [filename]
該命令用於把相關字的文件和目錄都列出來。查找數據特別快,也是經過數據庫方式來查詢。可是數據庫一週更新一次,因此可能有些存在數據查不到。能夠去修改配置文件。

find:
find [path] [參數] [keyword]
該命令用於在指定路徑下查找文件。不是經過數據來查詢,因此速度會比較慢。  

7.常見目錄解釋

Linux各類發行版的目錄結構基本一致,各個目錄簡單介紹以下:

 

目錄

描述

/

根目錄

/bin

作爲基礎系統所須要的最基礎的命令就是放在這裏。好比 ls、cp、mkdir等命令;功能和/usr/bin相似,這個目錄中的文件都是可執行的,普通用戶均可以使用的命令。

/boot

Linux的內核及引導系統程序所須要的文件,好比 vmlinuz initrd.img 文件都位於這個目錄中。在通常狀況下,GRUB或LILO系統引導管理器也位於這個目錄;啓動裝載文件存放位置,如kernels,initrd,grub。通常是一個獨立的分區。

/dev

一些必要的設備,聲卡、磁盤等。還有如 /dev/null. /dev/console /dev/zero /dev/full 等。

/etc

系統的配置文件存放地. 一些服務器的配置文件也在這裏;好比用戶賬號及密碼配置文件;

/etc/opt:/opt對應的配置文件

/etc/X11:Xwindows系統配置文件

/etc/xml:XML配置文件

……

/home

用戶工做目錄,和我的配置文件,如我的環境變量等,全部的帳號分配一個工做目錄。通常是一個獨立的分區。

/lib

庫文件存放地。bin和sbin須要的庫文件。相似windows的DLL。

/media

可拆卸的媒介掛載點,如CD-ROMs、移動硬盤、U盤,系統默認會掛載到這裏來。

/mnt

臨時掛載文件系統。這個目錄通常是用於存放掛載儲存設備的掛載目錄的,好比有cdrom 等目錄。能夠參看/etc/fstab的定義。

/opt

可選的應用程序包。

/proc

操做系統運行時,進程(正在運行中的程序)信息及內核信息(好比cpu、硬盤分區、內存信息等)存放在這裏。/proc目錄假裝的文件系統proc的掛載目錄,proc並非真正的文件系統,它的定義能夠參見 /etc/fstab 。

/root

Root用戶的工做目錄

/sbin

和bin相似,是一些可執行文件,不過不是全部用戶都須要的,通常是系統管理所須要使用獲得的。

/tmp

系統的臨時文件,通常系統重啓不會被保存。

/usr

包含了系統用戶工具和程序。

/usr/bin:非必須的普通用戶可執行命令

/usr/include:標準頭文件

 /usr/lib:/usr/bin/ 和 /usr/sbin/的庫文件

 /usr/sbin:非必須的可執行文件

/usr/src:內核源碼

/usr/X11R6:X Window System, Version 11, Release 6.

/srv

該目錄存放一些服務啓動以後須要提取的數據

 

============================================================

關於文件系統,相信你們都不陌生。身爲攻城獅的咱們幾乎每天都會與之打交道,可是細深剖一下,其中又有多少是咱們理解深度不夠的呢。那麼讓咱們一塊兒來看一下下面這一組Linux文件系統相關的問題吧:

一、機械磁盤隨機讀寫時速度很是慢,操做系統是採用什麼技巧來提升隨機讀寫的性能的?

二、touch一個新的空文件佔用磁盤空間嗎? 佔用的話佔用多少?

三、新建一個空目錄佔用磁盤空間嗎?佔用多少?和新建一個文件相比,哪一個佔用的更大?

四、你知道文件名是記錄在磁盤的什麼地方嗎?

五、文件名最長多長?受什麼制約?

六、文件名太長了會影響系統性能嗎?爲何會產生影響?

七、一個目錄下最多能創建多少個文件?

八、新建一個內容大小1k的文件,實際會佔用多大的磁盤空間?

九、向操做系統發起讀取文件2Byte的命令,操做系統實際會讀取多少呢?

十、咱們使用文件時要怎麼樣來能提升磁盤IO速度?

  若是你能想也不用想的就回答上來百分八十的問題,那麼請關掉本篇文章吧。若是不能,並且你也像做者同樣對有窺探操做系統隱私的嗜好,那麼就請隨我一塊兒來探索文件系統的這些有趣的地方,相信理解了這些以後對咱們手中的工做會有很大的幫助。
 
1、磁盤構成及分區

一、磁盤物理結構

  仍是先從最基本的磁盤物理結構提及吧,注意本文只討論機械磁盤,SSD不在本文討論範圍以內。咱們人類管理任何事物老是習慣先劃分出必定的結構,再此規則的基礎上進行管理。軍隊分軍、師、旅、團和營。公司分事業羣、部門、中心和小組。,而後。對於管理 磁盤,分磁盤面、磁頭、磁道、柱面和扇區

    磁盤面:磁盤是由一疊磁盤面組成,見下左圖。

    磁頭(Heads):每一個磁頭對應一個磁盤面,負責該磁盤面上的數據的讀寫。
    磁道(Track):每一個盤面會圍繞圓心劃分出多個同心圓圈,每一個圓圈叫作一個磁道。

    柱面(Cylinders):全部盤片上的同一位置的磁道組成的立體叫作一個柱面。

    扇區(Sector):以磁道爲單位管理磁盤仍然太大,因此計算機前輩們又把每一個磁道劃分出了多個扇區,見下右圖
 
 
  本人愛上Linux的一個緣由就是隻要你願意下功夫,你就能把Linux的外衣一脫到底,知足你的一切慾望(請想歪的騷年去面壁)。Linux上能夠經過 fdisk命令,來查看當前系統使用的磁盤的這些物理信息。
 
 
  以上是我本人的一臺虛擬機的磁盤物理信息。能夠看出個人磁盤有255個heads,也就是說共有255個盤面。3263個cylinders,也就是說每一個盤面上都有3263個磁道, 63sectors/track說的是每一個磁道上共有63個扇區。命令結果也給出了Sector size的值是512bytes。那咱們動筆算一下該磁盤的大小吧。

  255盤面  * 3263柱面 * 63扇區 * 每一個扇區512bytes = 26839088640byte。
結果是26.8G,和磁盤的總大小相符(至於fdisk給出的詳細結果相差了約4M的大小,筆者也沒有弄完全明白,有興趣的讀者能夠繼續研究)。

  另外查看了其它兩臺機器的磁盤狀況,發現個有意思的事情。以下圖,不管磁盤的容量大或者是小,其磁頭數和每磁道扇區數都是不變的,只是磁道變多了而已。
 
 
二、分區
  分區是操做系統對磁盤進行管理的第一步,這也是咱們任何一個計算機使用者都很是熟悉的概念。例如Windows下的C、D、E、F盤。那麼請思考一下,

    思考:前面的磁盤的詳細物理結構已經有了,若是讓你把整塊磁盤分紅C、D等分區,你會怎麼分呢? 
    
  方案一: 255個盤面,C盤是0-100盤面, D盤是101-200個盤面,……

  方案二:3263個柱面,C盤0-1000個柱面,D盤1001-20001個柱面,……

  對於以上的兩個方案,你會選擇哪種呢??先說下磁盤IO時的過程。第一步,首先是磁頭徑向移動來尋找數據所在的磁道。這部分時間叫尋道時間。第二步,找到目標磁道後經過盤面旋轉,將目標扇區移動到磁頭的正下方。第三步,向目標扇區讀取或者寫入數據。到此爲止,一次磁盤IO完成,故:

  單次磁盤IO時間 = 尋道時間 + 旋轉延遲 + 存取時間。

  對於旋轉延時,如今主流服務器上常用的是1W轉/分鐘的磁盤,每旋轉一週所需的時間爲60*1000/10000=6ms,故其旋轉延遲爲(0-6ms)。對於存取時間,通常耗時較短,爲零點幾ms。對於尋道時間,現代磁盤大概在3-15ms,其中尋道時間大小主要受磁頭當前所在位置和目標磁道所在位置相對距離的影響。

  其實採用哪種,最主要看的是那種方式性能更快。由於同一分區下的數據常常會一塊兒讀取,假如採用第一種,那麼這樣磁頭就須要在3000多個track間不停地跳來跳去,這樣磁盤的尋道時間就會翻倍,磁盤性能就會降低。而對於方案二,假如對於磁盤C,只須要在磁頭在1-1000個磁道間移動就能夠了,大大下降了尋道時間。(實際上分區並非從0開始的,磁盤的第一個磁道對應的柱面會被用來安裝引導加載程序以及磁盤分區表)。因此,方案二的分區方式能夠下降磁盤IO時間中的尋道時間部分,因此全部的操做系統採用的都是方案二,沒有用方案一的。

    在Linux下使用過fdisk進行分區的話能夠注意到如下信息。
 
 
 
  這充分證實了操做系統是採用方案二的。

  回到開篇問題1,操做系統是採用什麼技巧來下降隨機讀寫的性能問題的呢?操做系統經過按磁道對應的柱面劃分分區,來下降磁盤IO所花費的的尋道時間 ,進而提升磁盤的讀寫性能。

2、 目錄與文件

一、引子   

  好了,磁盤基礎都說完了,那咱們正式進入主題,開始咱們Linux文件系統相關的討論吧。文件系統不就是目錄和文件嗎?這二位但是咱們熟悉的不能再熟悉的傢伙了。可你確認它不是你的那位熟悉的陌生人麼?我先來來建立個 空目錄和空文件吧,查看結果以下圖:
 
 

  咱們都知道第五列顯示的是佔用的空間大小,那麼我來提個幾個小小的問題吧。
(1)爲何目錄佔用的空間是4096?


(2)爲何空文件佔用的空間倒是0?


(3)若是空文件真佔用0byte空間,那麼該文件的文件名、建立者以及權限-rw-rw-r—等文件夾相關的信息都存到哪兒去了?


二、我就不信空文件不佔用空間


  爲了解開這個謎底,須要藉助df命令。輸入df –i,

  Linux結果中紅框位置處顯示的是inodes的相關信息,若是你對inode的概念不熟悉,你能夠暫時把它當成一個操做系統祕密管理的一個傢伙,會佔用空間就好了。接下來我touch一個空的文件後再次df -i。

  雖然前面操做系統告訴咱們,一個新建的空文件佔用的空間是0。可是這個實驗卻證實操做系統「欺騙」了咱們,它消耗掉了一個inode。那麼inode的節點大小是多少呢,使用dumpe2fs命令能夠幫助咱們查看到這個東東的實際大小。

  在輸出的結果中咱們能夠找到下面這行:

  它告訴咱們每一個inode的大小是256Byte。固然這個大小每臺機器都會不同,它其實是在系統格式化磁盤的時候決定的。


  好了,開篇第二個問題也有答案了。原來新建一個空的文件是會佔用磁盤空間的,實際佔用的是256Byte。哦,不,準確的說法應該是一個inode size,具體的值是在格式化時決定的。

  再說說新建空目錄吧,前面說了新建空目錄會佔用4KB的磁盤空間。那麼僅僅如此嗎? 咱們一樣在新建目錄先後都使用df –i來監視系統inode的佔用。

  原來目錄也是會佔用一個inode節點的,第三個問題也有了答案了,新建一個空目錄會佔用磁盤空間4KB + inode size。 哦,這個在你的系統上也不必定是4K,它實際上一個block size。一樣在dumpe2fs下能夠看到。


  只不過個人磁盤在格式化時採用的是4KB的大小,呵呵!

三、神祕的空目錄的4KB

  前面的謎團解開了,能夠做爲攻城獅的我對另一個東西產生了好奇心。就是空目錄佔用的那4KB,這些空間是用來存什麼的呢?好神祕呀。

  cd到咱們新建的目錄下查看。

  咱們再新建兩個空的文件,再查看下目錄的空間佔用狀況。

  貌似,沒有什麼新發現。由於空文件不佔用block,因此這裏顯示的仍然是目錄佔用的block,和以前大小沒有變化。那麼我繼續使用php腳本建立100個文件名長度爲32Byte的空文件。

  這時咱們發現目錄佔用的磁盤空間變大了,成了3個Block了。哈哈,這就解答了咱們開篇的第四個問題,文件名是存在目錄佔用的block中的。接下來我又還證實了每一個目錄block中能保存的文件名個數是和文件名的長度有關的(好像有點廢話的意思,不過親手證實本身的猜測仍是有點小爽的)。我又另外新建了個空目錄,建立了100個文件名長度爲32*3個空文件,該臨時目錄佔用的磁盤空間以下:

  你可能會問我爲何文件名變成了3倍後,佔用的block數目爲何沒有變成3倍。其實Linux文件系統關於文件的結構體中除了文件名之外,還有其它的一些字段的,文件名變長3倍不會致使結構體變大3倍的,這點能夠參考Linux系統內核相關書籍。


  好了,到如今開篇問題6也有了答案了。文件名長了固然會對系統性能產生影響,由於這可能會致使更多的磁盤IO。不少程序員都喜歡將文件命名爲有意義的長串,令人一看文件名就知道用途。固然我沒說這樣很差,可是若是你的文件數量至關大的時候,你就要考慮你的文件名是否致使你的目錄block佔用太多了。佔用的空間卻是小事,磁盤很便宜,可是你得考慮下在目錄下查找文件時操做系統的感覺,操做系統可須要用你你提供的文件名進行字符串比較,並且運氣很差的話須要將其名下全部block都搞一遍才行啊。(固然了,你的文件名長度不變態,並且數量沒有達到十萬數量級的話實際上這個開銷也不會太大,可是這個開銷你仍是知道的爲好)

  至於開篇問題5,文件名最長多長。實際上Linux操做系統就是爲了不程序員不節制地使用長文件名,強加了個限制,不得超過255byte


  另外,你們有沒有經驗,在目錄下文件不少的時候,咱們使用ls命令時會很慢。如今你們知道緣由了吧,這時實際上操做系統在讀取當前目錄的全部block,若是block比較多的話,可能得須要屢次IO操做才能完成這個簡單的ls命令。

  我在本身的電腦某個目錄下建立了一100W個空文件,ls命令1分鐘還沒出結果,被我ctrl+c掉了。在本身的項目中可不要這麼幹,雖然操做系統能夠cache住你的目錄數據,使你下次調用時會塊不少,但我仍是建議你單個目錄下文件數目不要過萬。不然你的程序在重啓後首次運行時可能會出現性能不佳的狀況。

  好了,回到開篇問題7,你有答案了嗎?一個目錄下最多能建多少個文件,這個最多實際上是受限於你目錄所在分區的inode數量,你有100W個inode,你最多就能夠新建100W個文件。可是,上面說了,單個目錄下文件數量最好不要過萬,不然會帶來系統性能的問題。


四、文件的block


  再作個關於文件的實驗。我新建了個空目錄,並在其下新建了個文件,裏面只寫了一個空格數據,保存後du命令顯示以下:

  這8K裏有4K是目錄的,也就能夠算出操做系統爲只包含一個空格的文件分配了4KB。其實文件的block比較簡單的了,不像目錄的block裏會存不少文件系統的結構體,文件的block裏只會保存文件的數據。上面這個實驗代表,操做系統分配空間時是以block爲最小單位。也就是說只要你的文件數據不爲空,操做系統就至少會給你分配一個block來存儲,直到你超過了4KB,操做系統再給你分配下一個block,就是這樣。因此對於開篇問題8,新建一個內容大小爲1k的文件,實際會佔用1個block(通常爲4k)和一個inode(通常爲256byte)。


  其實文件系統在向磁盤發起IO請求的時候,也是以block size爲單位的。哪怕你只向操做系統發起讀取文件的2Byte,可是操做系統會一次性給你讀取4KB回來。所以磁盤IO真的是很慢,並且咱們只要訪問了這2Byte,確實頗有可能接下來繼續訪問這2byte後面的內容,這也就是程序局部性原理,因此操做系統索性一次性就多讀取些回來了。呵呵,這就是開篇問題9的答案。
這就像咱們去逛超市,逛一次真的是很浪費時間,這可要比坑爹的磁盤IO也慢許多了。咱們總不會逛了一圈超市就買了一個蘋果就回來了吧,咱們確定會多買些東西爲家裏之後的需求準備着,反正買一堆東西比買一個蘋果也沒多花多少時間,何樂爲不爲呢,就是這個道理。


  再說說開篇問題10,咱們攻城獅怎麼樣設計你的文件能提升一些IO速度呢?那就是若是你知道你的要新建的文件大概會佔用多大的空間的話,好比1M。那麼你新建文件時就順便和操做系統說一下,讓它幫你將文件的size預留下來。這樣實際上操做系統時會盡量爲你分配連續的block,這樣你再讀取這個文件時,磁頭就省去不少尋道時間了,IO速度就顯得快多了。   
 
3、寫在後面的話


  前面咱們說的都是基於我本身的文件系統,情形是一個block size是4KB,一個inode size是256byte,包括我虛擬機上的inode數量才只有140多萬個。這些值實際上不是固定的,你徹底能夠在格式化你的硬盤的時候設置成其它的值。設置的原則就是看你的硬盤的容量,以及你的用途。


  若是你的文件都是大於4KB,甚至是幾M,幾G的文件,那麼建議你的block仍是儘量的大一點吧,這樣inode裏就能少記幾個地址。


  若是你的文件大部分都是1K如下的,那麼確實使用4K的block會形成一點點浪費,若是你的老闆對成本要求異常苛刻的話,你能夠適當考慮把你的block設置得小一點。


  另外,要關注你的文件系統的inode。操做系統在查看目錄和文件佔用的磁盤空間信息時把inode節點的佔用給隱藏起來了,其用意在於爲用戶提供一個白盒的環境,把數據佔用的空間交給咱們來認知,而把inode信息隱藏起來爲了下降咱們理解操做系統的難度。而實際上,咱們做爲非普通用戶的開發人員應該具有這個知情權。這個東東直接關係到你文件系統能建立文件數量。不然哪天等你發現線上機器磁盤還剩大把大把的空間,但就是inode使用光了,那時候就只有從新格式化或者遷移服務器了。這兩個操做想一想都以爲苦逼啊,仍是能避免就儘可能避免吧。       思考題:咱們你們有個經驗就是目錄下小文件太多的狀況下,往其它地方拷貝的話,速度會很是的慢,咱們這時每每會把目錄壓縮一下再拷貝。如今你能說出這樣作爲何會快嗎?

相關文章
相關標籤/搜索