Linux 本地文件存儲(chǔ)原理
在LINUX系統(tǒng)中有一個(gè)重要的概念:一切都是文件错蝴。UNIX系統(tǒng)把每個(gè)硬件都看成是一個(gè)文件,通常稱為設(shè)備文件啃奴,這樣用戶就可以用讀寫文件的方式實(shí)現(xiàn)對(duì)硬件的訪問。
Linux文件系統(tǒng)分為多層:
1. 系統(tǒng)調(diào)用
應(yīng)用程序通過系統(tǒng)調(diào)用(System call:應(yīng)用程序使用OS提供的接口調(diào)用內(nèi)核功能)訪問文件。
常用的與存儲(chǔ)相關(guān)的系統(tǒng)調(diào)用函數(shù)包括:open, close, write, read, mmap(mmap函數(shù)可以將一個(gè)文件的內(nèi)容映射到內(nèi)存蚌斩,這樣就可以直接對(duì)該內(nèi)存進(jìn)行操作,從而省去IO操作范嘱。)等送膳。
2. 虛擬文件系統(tǒng)
VFS是不同的文件系統(tǒng)的一個(gè)抽象,提供統(tǒng)一的API訪問接口丑蛤,這樣叠聋,用戶空間就不用關(guān)心不同文件系統(tǒng)中不一樣的API了。并且通過系統(tǒng)調(diào)用層受裹,可以在不同的文件系統(tǒng)之間復(fù)制和移動(dòng)數(shù)據(jù)碌补。
虛擬文件系統(tǒng)提供了一個(gè)通用的文件系統(tǒng)模型,采用了面向?qū)ο蟮脑O(shè)計(jì)思路棉饶,主要有以下4個(gè)對(duì)象類型:
- 超級(jí)塊(Super Block)
級(jí)塊代表一個(gè)已安裝的文件系統(tǒng)厦章,用于存儲(chǔ)文件系統(tǒng)的有關(guān)信息,如文件系統(tǒng)的類型照藻、大小袜啃、狀態(tài)等。對(duì)基于磁盤的文件系統(tǒng)幸缕,它存放在磁盤的特定扇區(qū)上群发。對(duì)非基于磁盤的文件系統(tǒng)晰韵,會(huì)現(xiàn)場(chǎng)創(chuàng)建保存在內(nèi)存中。
- 索引節(jié)點(diǎn)(Inode)
代表存儲(chǔ)設(shè)備上一個(gè)實(shí)際的物理文件熟妓,用于存儲(chǔ)該文件的有關(guān)信息雪猪。Linux將文件的相關(guān)信息(又稱文件的元數(shù)據(jù)),包括:
1)文件的字節(jié)數(shù)
2)文件擁有者
3)文件的Group ID
4)文件的讀起愈、寫只恨、執(zhí)行權(quán)限
5)文件的時(shí)間戳,共有三個(gè):ctime指inode上一次變動(dòng)的時(shí)間抬虽,mtime指文件內(nèi)容上一次變動(dòng)的時(shí)間坤次,atime指文件上一次打開的時(shí)間。
6)鏈接數(shù)斥赋,即有多少文件名指向這個(gè)inode
7)文件數(shù)據(jù)block的位置
與文件本身分開缰猴。
- 目錄項(xiàng)(Dentry)
描述了文件系統(tǒng)的層次結(jié)構(gòu)。對(duì)于虛擬文件系統(tǒng)疤剑,目錄和文件都是普通的文件滑绒。所以目錄和文件都是目錄項(xiàng)對(duì)象。文件目錄項(xiàng)主要是存儲(chǔ)文件名至文件inode的映射關(guān)系
- 文件
文件對(duì)象代表已經(jīng)被進(jìn)程打開的文件隘膘,主要用于建立進(jìn)程和文件之間的對(duì)應(yīng)關(guān)系疑故。由open()創(chuàng)建,close()銷毀弯菊,當(dāng)且僅當(dāng)進(jìn)程訪問文件期間存在于內(nèi)存之中纵势。
3. Page Cache
Page Cache是以物理頁為單位對(duì)磁盤文件進(jìn)行緩存,以減少磁盤IO次數(shù)管钳,提高對(duì)文件的訪問速度钦铁。
- 扇區(qū)、塊才漆、物理頁
扇區(qū)是塊設(shè)備傳輸數(shù)據(jù)的基本單元牛曹,也就是說它是塊設(shè)備中最小的尋址單位。
塊是扇區(qū)之上的一個(gè)抽象醇滥。一個(gè)塊通常對(duì)應(yīng)一個(gè)或多個(gè)相鄰的扇區(qū)黎比。內(nèi)核將塊作為對(duì)磁盤操作的最小單位,因此VFS將其看作是單一的數(shù)據(jù)單元鸳玩。塊的大小是扇區(qū)的整數(shù)倍阅虫,一般是512Byte、1KB或4KB不跟。內(nèi)核只能基于塊來訪問物理文件系統(tǒng)颓帝,所以塊也被稱為文件系統(tǒng)的最小尋址單元。
一個(gè)磁盤塊被調(diào)入內(nèi)存時(shí),它需要存儲(chǔ)在一個(gè)緩沖區(qū)躲履,每個(gè)塊在內(nèi)存中都與一個(gè)緩沖區(qū)相對(duì)應(yīng)。一個(gè)物理頁框可能包含一個(gè)或多個(gè)塊緩沖區(qū)聊闯。
即:扇區(qū)是磁盤的最小存儲(chǔ)單位工猜;磁盤塊是文件系統(tǒng)讀寫數(shù)據(jù)的最小單位;頁是內(nèi)存的最小存儲(chǔ)單位菱蔬;
- 讀緩存
我們讀取數(shù)據(jù)的時(shí)候首先先檢查頁緩存中數(shù)據(jù)是否存在篷帅,如果存在直接讀取,如果不存在就從磁盤中讀取拴泌,然后將數(shù)據(jù)放到頁緩存中魏身。
- 寫緩存
一般而言,寫緩存有三種實(shí)現(xiàn)方式:
1) 不緩存:直接寫到磁盤蚪腐,并且標(biāo)記頁緩存中的數(shù)據(jù)過期
2) 寫透緩存:寫緩存同時(shí)寫磁盤箭昵,保持了良好的一致性
3) 回寫:只寫到緩存中,標(biāo)記頁面為臟表示磁盤中的數(shù)據(jù)過期回季,過段時(shí)間再刷新到磁盤家制。
- 緩存的回收
1)LRU:最近最少使用
2)雙鏈策略:有兩個(gè)鏈表,分別為熱鏈表泡一,冷鏈表颤殴。熱鏈表上的頁面不會(huì)被換出,冷鏈表上的頁面可以被換出鼻忠。頁面首先加入冷鏈表中涵但,如果再次被訪問就加入熱鏈表,當(dāng)熱鏈表過長帖蔓,需要將溢出的頁面重新加入冷鏈表矮瘟。
- Page Cache 和 Buffer Cache
早期Page Cache 和 Buffer Cache是兩個(gè)獨(dú)立的緩存。內(nèi)核2.4.10版本開始塑娇,Buffer Cache被包含在了Page Cache中芥永,通過Page Cache來實(shí)現(xiàn)。
- Direct I/O 與 Buffer IO
使用Page Cache的IO稱為Buffer IO钝吮。而對(duì)于一些特殊應(yīng)用程序埋涧,比如說自緩存應(yīng)用程序,具有自己的用戶空間的緩存機(jī)制奇瘦,不需要利用內(nèi)核中的緩存棘催,如數(shù)據(jù)庫,就可以在進(jìn)程打開文件的時(shí)候?qū)⑽募脑L問模式設(shè)置為O_DIRECT耳标,使用Direct I/O方式讀寫文件醇坝。
Direct I/O 優(yōu)點(diǎn)是通過減少內(nèi)核緩沖區(qū)和用戶空間的數(shù)據(jù)復(fù)制次數(shù),降低文件讀/寫時(shí)帶來的CPU負(fù)載能力及內(nèi)存帶寬的占用率。
4. 文件系統(tǒng)
文件系統(tǒng)提供了存儲(chǔ)相關(guān)API的具體具體實(shí)現(xiàn)呼猪。文件系統(tǒng)把文件讀/寫命令轉(zhuǎn)換成對(duì)邏輯區(qū)塊地址(LBA)的讀寫画畅,并最終翻譯成每個(gè)設(shè)備對(duì)應(yīng)的可識(shí)別的地址。
linux下主流的文件系統(tǒng)包括:EXT2/3/4, xfs, btfs等宋距。 目前大多Linux發(fā)行版本默認(rèn)使用的文件系統(tǒng)一般是ext4轴踱。
- 目錄
目錄在ext2/3是一張線性表。如果在一個(gè)目錄下按文件名查找一個(gè)文件谚赎,需要進(jìn)行線性遍歷淫僻。ext3中引入了目錄索引,即如果一個(gè)目錄下的文件容量超過2KB壶唤,索引節(jié)點(diǎn)中的i_data域就會(huì)指向一個(gè)特殊的block雳灵,按照B-Tree結(jié)構(gòu)對(duì)文件進(jìn)行存儲(chǔ)。而Btfs直接使用了B-Tree結(jié)構(gòu)進(jìn)行存儲(chǔ)闸盔。
通過Linux的設(shè)備驅(qū)動(dòng)對(duì)物理設(shè)備悯辙,如硬盤驅(qū)動(dòng)器或固態(tài)硬盤進(jìn)行相關(guān)的讀寫。
Linux文件系統(tǒng)的實(shí)現(xiàn)都是在內(nèi)核進(jìn)行的迎吵。但用戶態(tài)也有一些管理機(jī)制可以對(duì)塊設(shè)備文件進(jìn)行相應(yīng)的管理笑撞。如mkfs, LVM等。
基于extend的文件存儲(chǔ)
inode中保存了指向block位置的指針钓觉。在Ext2文件系統(tǒng)中茴肥,數(shù)據(jù)塊都是被單獨(dú)管理的,索引節(jié)點(diǎn)里指針數(shù)量至少是文件占用的數(shù)據(jù)塊的數(shù)量荡灾。該指針包括了一級(jí)(指針直接指向磁盤的block位置)和多級(jí)(先指向一個(gè)指針列表瓤狐,最后指向block位置,Ext2最多有3級(jí))批幌。
而ext4, Btfs所支持的extend础锐,是由一些連續(xù)的block組成,由起始的block加上長度定義的荧缘。inode里可以指向一個(gè)extend皆警,這樣能夠大大減少指針的數(shù)量和層級(jí),提高操作大文件的性能截粗。
- 寫時(shí)復(fù)制
寫時(shí)復(fù)制是指在對(duì)數(shù)據(jù)進(jìn)行修改的時(shí)候信姓,不會(huì)直接在原來的數(shù)據(jù)位置上進(jìn)行操作,而是找一個(gè)新的位置修改绸罗,一旦系統(tǒng)突然斷電意推,重啟之后將不需要fsck。
例如Btfs中珊蟀,每次數(shù)據(jù)寫入磁盤時(shí)菊值,先將更新的數(shù)據(jù)寫入一個(gè)新的Block,寫入成功后再更新指針。
5. 塊層 (Block layer)
塊層負(fù)責(zé)維持一個(gè)I/O請(qǐng)求在上層文件系統(tǒng)與底層物理磁盤之間的關(guān)系腻窒。
在通用塊層中昵宇,使用bio結(jié)構(gòu)體來描述一個(gè)I/O請(qǐng)求。而Linux驅(qū)動(dòng)儿子,則是使用request結(jié)構(gòu)體來描述向塊設(shè)備發(fā)出的I/0請(qǐng)求瓦哎。一個(gè)request中包含了一個(gè)或多個(gè)bio。request存在的目的就是為了進(jìn)行io的調(diào)度典徊。通過request這個(gè)輔助結(jié)構(gòu),我們來給bio進(jìn)行某種調(diào)度方法的排序恩够,從而最大化地提高磁盤訪問速度卒落。
而對(duì)于慢速的磁盤設(shè)備,請(qǐng)求的處理速度很慢蜂桶,這時(shí)內(nèi)核就提供一種request_queue儡毕,把request添加到隊(duì)列中
- bio 與 request
每個(gè)bio對(duì)應(yīng)磁盤里面一塊連續(xù)的位置。bio在塊層會(huì)被轉(zhuǎn)化為request扑媚,多個(gè)連續(xù)的bio可以合并到一個(gè)request中腰湾,生成的request會(huì)繼續(xù)合并,排序疆股,并最終調(diào)用塊設(shè)備驅(qū)動(dòng)的接口將request從塊層的request_queue中移到驅(qū)動(dòng)層進(jìn)行處理费坊,
- I/O合并
I/O合并會(huì)把符合條件的多個(gè)I/O合并成單個(gè)I/O請(qǐng)求進(jìn)行一并處理。能夠進(jìn)行合并的位置主要有Page Cache, Plug List 和 I/O調(diào)度器旬痹。
每個(gè)進(jìn)程有一個(gè)私有的Plug隊(duì)列附井,進(jìn)程在向通用塊層派發(fā)I/O請(qǐng)求之前如果開啟了蓄流功能,make request會(huì)嘗試把bio合并到一個(gè)進(jìn)程本地Plug隊(duì)列里的request,如果無法合并則創(chuàng)造一個(gè)新的request两残。
泄流的時(shí)候永毅,進(jìn)程本地Plug隊(duì)列的request會(huì)被加入調(diào)度算法隊(duì)列中。這個(gè)調(diào)度算法主要目的是進(jìn)一步合并request, 把request對(duì)硬盤的訪問順序化人弓,以及執(zhí)行一定的QoS (Quality of Service)
- I/O調(diào)度
Linux支持多個(gè)I/O調(diào)度器沼死,可以給每個(gè)磁盤定制不同的調(diào)度算法。常見的調(diào)度算法包括:
1)noop
不調(diào)度的算法(no operation, noop)崔赌,即逐個(gè)執(zhí)行隊(duì)列中的I/O請(qǐng)求意蛀。該算法適合那些不希望調(diào)度器重新組織I/O請(qǐng)求順序的應(yīng)用〗“牛可以分為兩種類型:
1> I/O調(diào)度器下方有更智能的I/O調(diào)度設(shè)備浸间,不需要額外的調(diào)度工作。如磁盤陣列吟榴、SAN魁蒜、NAS等 2>上層應(yīng)用程序已對(duì)I/O請(qǐng)求進(jìn)行優(yōu)化
2)deadline
基于經(jīng)典的電梯算法,即請(qǐng)求的處理按照塊設(shè)備的偏移(一般是扇區(qū)號(hào))朝一個(gè)方向移動(dòng),直到到達(dá)最遠(yuǎn)的對(duì)方兜看,然后再按照反方向移動(dòng)锥咸,就像電梯的運(yùn)行過程一樣。deadline算法在該算法基礎(chǔ)上增加了deadline的邏輯细移,即deadline時(shí)間到了(都請(qǐng)求為500ms, 寫請(qǐng)求為5s),就會(huì)先處理這些請(qǐng)求搏予。從而保證了每個(gè)I/O請(qǐng)求在一定時(shí)間內(nèi)一定會(huì)被服務(wù)到,避免了“饑餓”的請(qǐng)求弧轧。
3)CFQ (Completely Fair Queuing)
cfq算法雪侥,給每個(gè)進(jìn)程一個(gè)IO隊(duì)列,然后輪詢各個(gè)隊(duì)列精绎,達(dá)到公平的效果速缨。適用于傳統(tǒng)硬盤,也是長久以來的默認(rèn)算法代乃。為減少尋址旬牲,該算法嘗試給IO排序,極端情況可導(dǎo)致IO饑餓搁吓,即如果一個(gè)程序有大量順序讀寫原茅,那么它就會(huì)插隊(duì),導(dǎo)致其他程序IO饑餓堕仔。CentOS 6默認(rèn)使用cfq算法擂橘。
Linux 存儲(chǔ)結(jié)構(gòu)與磁盤劃分
1. Linux常見的目錄名稱及對(duì)應(yīng)的內(nèi)容
/boot 開機(jī)所需文件—內(nèi)核、開機(jī)菜單以及所需配置文件等
/dev 以文件形式存放任何設(shè)備與接口
/etc 配置文件
/home 用戶家目錄
/bin 存放單用戶模式下還可以操作的命令
/lib 開機(jī)時(shí)用到的函數(shù)庫摩骨,以及/bin 與/sbin 下面的命令要調(diào)用的函數(shù)
/sbin 開機(jī)過程中需要的命令
/media 用于掛載設(shè)備文件的目錄
/opt 放置第三方的軟件
/root 系統(tǒng)管理員的家目錄
/srv 一些網(wǎng)絡(luò)服務(wù)的數(shù)據(jù)文件目錄
/tmp 任何人均可使用的“共享”臨時(shí)目錄
/proc 虛擬文件系統(tǒng)贝室,例如系統(tǒng)內(nèi)核、進(jìn)程仿吞、外部設(shè)備及網(wǎng)絡(luò)狀態(tài)等
/usr/local 用戶自行安裝的軟件
/usr/sbin Linux 系統(tǒng)開機(jī)時(shí)不會(huì)使用到的軟件/命令/腳本
/usr/share 幫助與說明文件滑频,也可放置共享文件
/var 主要存放經(jīng)常變化的文件,如日志
/lost+found 當(dāng)文件系統(tǒng)發(fā)生錯(cuò)誤時(shí)唤冈,將一些丟失的文件片段存放在這里
2. 物理設(shè)備的命名規(guī)則
Linux中的硬盤設(shè)備一般以“/dev/sd”開頭峡迷。例如設(shè)備名稱“/dev/sda5”,其中“a”是硬盤的順序號(hào)(a,b,c......表示)你虹,表示系統(tǒng)中同類接口中第一個(gè)被識(shí)別到的設(shè)備绘搞。“5”是分區(qū)的順序號(hào)(以數(shù)字1,2,3.....表示)
- 分區(qū)
硬盤設(shè)備是由大量的扇區(qū)組成的傅物,每個(gè)扇區(qū)容量為512 byte夯辖。其中第一個(gè)扇區(qū)保存了主引導(dǎo)記錄(Master Boot Record, MBR)和分區(qū)表信息。其中分區(qū)表為64 byte董饰,每記錄一個(gè)分區(qū)就需要16字節(jié)蒿褂。因此圆米,只能創(chuàng)建4個(gè)主分區(qū)。為了解決分區(qū)數(shù)不夠的問題啄栓,可以將一個(gè)分區(qū)表的16字節(jié)空間指向另一個(gè)分區(qū)娄帖,從而產(chǎn)生一個(gè)擴(kuò)展分區(qū),在這個(gè)擴(kuò)展分區(qū)中創(chuàng)建數(shù)個(gè)邏輯分區(qū)昙楚。通常情況下近速,用戶會(huì)選擇3個(gè)主分區(qū)加一個(gè)擴(kuò)展分區(qū)的方法。
3. 硬盤的管理
通過虛擬機(jī)設(shè)置為linux虛擬機(jī)設(shè)備添加一塊硬盤后堪旧,在/dev目錄下將會(huì)按照命名規(guī)則生成一個(gè)硬盤設(shè)備文件削葱。可以使用fdisk命令來對(duì)磁盤進(jìn)行管理淳梦。命令參數(shù)包括:
m 查看全部可用的參數(shù)
n 添加新的分區(qū)
d 刪除某個(gè)分區(qū)信息
l 列出所有可用的分區(qū)
t 改變某個(gè)分區(qū)的類型
p 查看分區(qū)信息
w 保存并退出
q 不保存直接退出
使用fdisk 命令來管理/dev/sdb 硬盤設(shè)備析砸。
[root@192 dev]# fdisk /dev/sdb
歡迎使用 fdisk (util-linux 2.23.2)。
更改將停留在內(nèi)存中谭跨,直到您決定將更改寫入磁盤干厚。
使用寫入命令前請(qǐng)三思李滴。
Device does not contain a recognized partition table
使用磁盤標(biāo)識(shí)符 0x473b5500 創(chuàng)建新的 DOS 磁盤標(biāo)簽螃宙。
命令(輸入 m 獲取幫助):p
磁盤 /dev/sdb:10.7 GB, 10737418240 字節(jié),20971520 個(gè)扇區(qū)
Units = 扇區(qū) of 1 * 512 = 512 bytes
扇區(qū)大小(邏輯/物理):512 字節(jié) / 512 字節(jié)
I/O 大小(最小/最佳):512 字節(jié) / 512 字節(jié)
磁盤標(biāo)簽類型:dos
磁盤標(biāo)識(shí)符:0x473b5500
設(shè)備 Boot Start End Blocks Id System
命令(輸入 m 獲取幫助):n
Partition type:
p primary (0 primary, 0 extended, 4 free)
e extended
Select (default p): p
分區(qū)號(hào) (1-4所坯,默認(rèn) 1):1
起始 扇區(qū) (2048-20971519谆扎,默認(rèn)為 2048):
將使用默認(rèn)值 2048
Last 扇區(qū), +扇區(qū) or +size{K,M,G} (2048-20971519,默認(rèn)為 20971519):+2G
分區(qū) 1 已設(shè)置為 Linux 類型芹助,大小設(shè)為 2 GiB
命令(輸入 m 獲取幫助):w
The partition table has been altered!
Calling ioctl() to re-read partition table.
正在同步磁盤堂湖。
在上述步驟執(zhí)行完畢之后,Linux 系統(tǒng)會(huì)自動(dòng)把這個(gè)硬盤主分區(qū)抽象成/dev/sdb1 設(shè)備文件状土。我們可以使用 file 命令查看該文件的屬性无蜂。
[root@192 dev]# file /dev/sdb1
/dev/sdb1: block special
接著我們使用mkfs命令在分區(qū)上創(chuàng)建指定的文件系統(tǒng)。例如我們創(chuàng)建xfs文件系統(tǒng):
[root@192 dev]# mkfs.xfs /dev/sdb1
meta-data=/dev/sdb1 isize=512 agcount=4, agsize=131072 blks
= sectsz=512 attr=2, projid32bit=1
= crc=1 finobt=0, sparse=0
data = bsize=4096 blocks=524288, imaxpct=25
= sunit=0 swidth=0 blks
naming =version 2 bsize=4096 ascii-ci=0 ftype=1
log =internal log bsize=4096 blocks=2560, version=2
= sectsz=512 sunit=0 blks, lazy-count=1
realtime =none extsz=4096 blocks=0, rtextents=0
然后我們就可以掛載并使用存儲(chǔ)設(shè)備了蒙谓。mount命令可以把硬盤設(shè)備或分區(qū)與一個(gè)目錄文件進(jìn)行關(guān)聯(lián)斥季,然后就能在目錄中看到硬件設(shè)備中的數(shù)據(jù)了。
[root@192 ~]# mkdir /newFS
[root@192 ~]# mount /dev/sdb1 /newFS/
需注意的是累驮,使用mount 命令掛載的設(shè)備文件會(huì)在系統(tǒng)下一次重啟的時(shí)候失效酣倾。如果想讓這個(gè)設(shè)備文件的掛載永久有效,則需要把掛載的信息寫入到配置文件中:
[root@192 ~]# vim /etc/fstab
...
/dev/sdb1 /newFS xfs defaults 0 0
最后使用df -h 命令來查看掛載狀態(tài)和硬盤使用量信息
[root@192 ~]# df -h
文件系統(tǒng) 容量 已用 可用 已用% 掛載點(diǎn)
...
/dev/sdb1 2.0G 33M 2.0G 2% /newFS
- LVM
在硬盤分好區(qū)后谤专,再想修改硬盤分區(qū)大小就不容易了躁锡。而LVM 技術(shù)是在硬盤分區(qū)和文件系統(tǒng)之間添加了一個(gè)邏輯層,它提供了一個(gè)抽象的卷組置侍,可以把多塊硬盤進(jìn)行卷組合并映之。這樣一來拦焚,用戶不必關(guān)心物理硬盤設(shè)備的低層架構(gòu)和布局,就可以實(shí)現(xiàn)對(duì)硬盤分區(qū)的動(dòng)態(tài)調(diào)整惕医。
物理卷(Physical Volume)處于LVM中的最底層耕漱,可以將其理解為物理硬盤、硬盤分區(qū)或者RAID 磁盤陣列抬伺。卷組(Volume Group)建立在物理卷之上螟够,一個(gè)卷組可以包含多個(gè)物理卷,而且在卷組創(chuàng)建之后也可以繼續(xù)向其中添加新的物理卷峡钓。邏輯卷(Logical Volume)是用卷組中空閑的資源建立的妓笙,并且邏輯卷在建立后可以動(dòng)態(tài)地?cái)U(kuò)展或縮小空間。這就是LVM 的核心理念能岩。