文件系統(tǒng)天生就是不平等的 - 實現(xiàn)崩潰一致性應用的復雜性

最近看到一篇 Paper,覺得很有意思,Paper 的主題是 “All File Systems Are Not Created Equal”,看來文件系統(tǒng)也跟人一樣,天生就是不平等的。這篇 Paper 主要是討論如何找出應用程序對文件操作的有問題的地方,保證在發(fā)生崩潰的時候,也能保證數(shù)據的一致性,從而正常的恢復,論文里面作者叫做 “crash consistent”,也就是『崩潰一致性』。

要讓應用在崩潰之后,能正?;謴?,說起來容易,實際還是比較困難的,因為一方面應用程序會依賴底層的文件系統(tǒng)的實現(xiàn),不同文件系統(tǒng)對一些保證是不一樣的,譬如是否能支持原子 rename 這些。同時,很多文件系統(tǒng),會提供豐富的配置供用戶調優(yōu),譬如 etx4 就有 write back,ordered 這些掛載屬性,這些就更加難判定文件系統(tǒng)在崩潰時的具體行為。

而另一方面,則是應用程序自己對數(shù)據一致性的處理,我們都知道,每次文件操作之后,都進行強制 sync,這樣就是非常安全的(當然,這里排除了硬件故障),但大家知道這個性能就是非常的差了,所以為了性能,我們勢必在文件操作上面做很多優(yōu)化,這些就在崩潰的時候引入了不確定性了。

為了解決這兩個問題,論文作者實現(xiàn)了兩個工具,一個就是 Block Order Breaker (BOB),而另一個就是 Application-Level Intelligent Crash Explorer(ALICE)。

BOB

BOB 主要是為了測試文件系統(tǒng)的 Persistence Properties。對于一個給定的文件系統(tǒng),當在發(fā)生崩潰之后,有哪些可能的狀態(tài),這個就是用 Persistence Properties 來確定的。

那這個 BOB 是怎么做的呢?首先 BOB 會一個簡單的場景去壓力測試 Persistence Properties(譬如,一批特定 size 的持續(xù)寫入來驗證 overwrite 的原子性)。BOB 會收集這個場景產生的 block I/O,然后重新排序這些收集的 blocks,選擇性的將一些寫入到磁盤去產生一個合法的磁盤 state。用這種方式,BOB 能產生一批在崩潰之后,多個對應不同 disk states 的唯一的磁盤 images 。然后 BOB 會在各自的 image 上面執(zhí)行文件系統(tǒng)的 recovery ,并檢查 Persistence Properites 是否繼續(xù)滿足(譬如 Write 是原子的)。

ALICE

ALICE 的原理其實比較簡單,就是通過 trace 應用程序的 system call 來直接構建文件的 state。

使用 ALICE 的時候,用戶首先需要提供一個初始化的文件 snapshot,譬如一個完整的文件目錄,一個 workload 腳本(譬如執(zhí)行一次事務),一個跟 workload 對應的 checker 腳本,用來檢查 workload 的不變性(譬如事務是否是原子的)。Alice 會在不同的 crash states 上面去執(zhí)行 checker。在執(zhí)行 workload 的時候,Alice 會生成 update protocol 的邏輯表示,記錄 protocol 里面的脆弱的地方以及對應的代碼,以及 persistence properties。

ALICE 會將 trace 的 system call 轉換成邏輯操作。邏輯操作會將當前的 system call,I/O 操作抽象成更精簡的文件系統(tǒng)操作。譬如,write,pwrite,writev,pwritev,mmap 這些操作會轉成 overwrite 或者 append。

對于不同的文件系統(tǒng)來說,crash state 是不一樣的,ALICE 使用一個 Abstract Persistence Model (APM) 來抽象出不同文件系統(tǒng)的 crash state,如果想測試特定文件系統(tǒng)里面的易脆性,可以寫一個特定的 APM。對于指定的文件系統(tǒng),APM 會指定邏輯操作里面原子性和順序性的所有約束,這樣就能定義 crash state。APM 通過兩個邏輯實體 - file inodes 包括 data 和 size,directories 包括 directory 的 entries。每個邏輯操作會操作一個或者多個這些實體。為了更好的抓住中間的 crash state,APM 會將邏輯操作拆分成多個微操作 - 也就是能用到邏輯實體的最小原子更新。主要包括:

  • write_block:也就是寫到文件的一個 size 的 block。包含兩個特定的參數(shù),zeroesrandomzero 意味著文件系統(tǒng)初始化了一個新分配的全為 0 的 block,而 random 則是表示一個未初始化的 block。如果文件不是追加寫,那么就不會更新文件的 size。
  • change_file_size:更新 file inode 的大小
  • create_dir_entry:在一個目錄里面創(chuàng)建一個目錄 entry,并且關聯(lián)一個文件 inode 或者目錄到它上面。
  • delete_dir_entry:刪掉一個目錄 entry。
  • stdout:在終端輸出添加消息。

APM 定義了邏輯操作如何轉換成微操作,譬如上面說的 overwrite 操作,就會轉換成一個或者多個 write_block 操作。APM 同樣也會定義不同微操作之間的順序,譬如所有在 sync 之后的操作都必須排在 sync 的后面。

有了微操作以及順序,ALICE 會先將應用程序的初始化 snapshot 表示成邏輯實體,然后會選擇滿足順序關系的不同集合的微操作對初始狀態(tài)進行應用,這樣就會構造出一個 crash state。對于每個 crash state,ALICE 會將邏輯實體重新轉換成對應的實際文件,然后使用 checker 進行檢查。

例子

這里說一下 ALICE 提供的一個 toy 例子,比較簡單,去掉了 assert 判斷:

int fd = open("tmp", O_CREAT | O_RDWR, 0666);
int ret = write(fd, "world", 5);
ret = close(fd);
ret = rename("tmp", "file1");
printf("Updated\n");
ret = link("file1", "link1");
ret = link("file1", "link2");

這個例子會做幾件事情:

  1. 打開 tmp 文件,會寫入 “world”,然后將 tmp 文件改名。當打印 “Updated” 之后,這個操作就完成,文件內容就必須是 “world”。
  2. 設置 link,link1 或者 link2 要不存在,要不不存在。

首先我們執(zhí)行 workload,也就是 toy_workload.sh 腳本,該腳本會編譯 toy 測試用例,創(chuàng)建兩個目錄,一個是 workload_dir,用來放置操作的文件,我們會創(chuàng)建一個 file1 文件,寫入 "hello"。另一個就是 traces_dir,用來保存 ALICE trace 的信息。然后執(zhí)行 alice-record --workload_dir . \ --traces_dir ../traces_dir \ ../a.out

然后我們就執(zhí)行 check,對應的 check 主要判斷邏輯如下:

if 'Updated' in stdout:
    # Check durability
    assert open('file1').read() == 'world'
else:
    # Check atomicity
    assert open('file1').read() in ['hello', 'world']

# Check whether link1 and link2 were created together as a single atomic unit
dirlist = os.listdir('.')
assert ('link1' in dirlist) == ('link2' in dirlist)

如果控制臺打印出來 “Updated”,那么文件一定有 “world”,否則就可能是原來的文件內容 “hello”,或者新的 “world”。Link1 和 Link2 要不都存在,要不都不在。

然后我們執(zhí)行 check,alice-check --traces_dir=traces_dir --checker=./toy_checker.py,首先會將應用對應的邏輯操作打印出來:

Parsing traces to determine logical operations ...
Logical operations:
0   creat("tmp", parent=200440197, mode='0666', inode=200446770)
1   append("tmp", offset=0, count=5, inode=200446770)
2   rename(dest="file1", source="tmp", source_hardlinks=1, source_parent=200440197, dest_size=5, dest_hardlinks=1, source_size=5, dest_parent=200440197, source_inode=200446770, dest_inode=200440198)
3   stdout("'Updated\n'")
4   link(dest="link1", source="file1", source_parent=200440197, dest_parent=200440197, source_inode=200446770)
5   link(dest="link2", source="file1", source_parent=200440197, dest_parent=200440197, source_inode=200446770)

然后根據 check 來檢查易脆性:

Finding vulnerabilities...
(Dynamic vulnerability) Across-syscall atomicity, sometimes concerning durability: Operations 4 until 5 need to be atomically persisted
(Static vulnerability) Across-syscall atomicity: Operation toy.c:19[main] until toy.c:21[main]
(Dynamic vulnerability) Ordering: Operation 1 needs to be persisted before 2
(Dynamic vulnerability) Ordering: Operation 2 needs to be persisted before 3
(Static vulnerability) Ordering: Operation toy.c:12[main] needed before toy.c:16[main]
(Static vulnerability) Ordering: Operation toy.c:16[main] needed before toy.c:19[main]
(Dynamic vulnerability) Atomicity: Operation 2(destination unlinked fully, source untouched, destination and source unlinked fully, destination unlinking partial  semi-truncated (3 count splits), destination unlinking partial , destination unlinking partial fully truncated)
(Static vulnerability) Atomicity: Operation toy.c:16[main] (destination unlinked fully, source untouched,destination unlinking partial fully truncated,destination and source unlinked fully,destination unlinking partial ,destination unlinking partial  semi-truncated (3 count splits))
Done finding vulnerabilities.

可以看到,在第二個操作 rename 之前,操作 1 必須持久化。

小結

上面只是對 ALICE 的一個簡單介紹,當然ALICE 還有很多限制,但對于一些常用的操作,還是能檢查出來了。后面還是需要再抽時間詳細研究一下。

下一步自然就是想到將 ALICE 應用到我們自己的系統(tǒng)中來,無論是 RocksDB,還是我們其他很多的文件操作,我們都可以使用 ALICE 來看系統(tǒng)的 crash consistent。如果你對這塊感興趣,歡迎聯(lián)系我,tl@pingcap.com

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容