日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網為廣大站長提供免費收錄網站服務,提交前請做好本站友鏈:【 網站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

為了解決在數據備份場景中的可靠性、容量、成本問題,越來越多的用戶傾向于使用對象存儲來進行備份。開源的項目例如s3fs和goofys在大文件的讀寫場景下各有優劣,相比之下,UCloud優刻得對象存儲US3團隊自主研發的 US3FS 無論是讀還是寫都有更好的性能,而且和UCloud優刻得US3的適配性更強,更易于拓展。在移動需求場景下,特別是大文件居多的場景,通過US3FS能提升超過100倍的性能。

比如在數據庫備份場景下,如果直接使用對象存儲備份,可能需要先把數據庫通過mysqldump做邏輯備份,或者采用xtrabackup做物理備份到本地,然后使用基于對象存儲的SDK的工具把備份文件上傳到對象存儲,備份過程繁瑣。再例如服務的日志歸檔備份,為降低成本可以將日志存儲到UCloud優刻得對象存儲US3中,通過SDK或者工具來操作,不僅需要編寫備份代碼,而且管理復雜。如果能提供一種以POSIX接口遠程訪問對象存儲的方式,就可以很好地解決上述問題。

開源方案實踐

已經有一些開源的項目將對象存儲中的bucket映射為文件系統,如s3fs和goofys等,在使用這些開源方案的時候,我們發現了一些問題。

s3fs

s3fs通過FUSE將s3和支持s3協議的對象存儲的bucket掛載到本地(FUSE的介紹詳見下文)。通過對s3fs進行測試后,我們發現其在大文件的寫入方面性能特別差,研究其實現過程后,我們發現s3fs在寫入時會優先寫入本地臨時文件,然后以分片上傳的方式將并發的將數據寫入到對象存儲。如果空間不足,則會以同步的方式將分片上傳,代碼如下:

ssize_t FdEntity::Write(const char* bytes, off_t start, size_t size){ // no enough disk space if(0 != (result = NoCachePreMultipartPost())){ S3FS_PRN_ERR("failed to switch multipart uploading with no cache(errno=%d)", result); return static_cast(result); } // start multipart uploading if(0 != (result = NoCacheLoadAndPost(0, start))){ S3FS_PRN_ERR("failed to load uninitialized area and multipart uploading it(errno=%d)", result); return static_cast(result); }}

由于我們的主要使用場景為大文件的備份,基于云主機硬盤成本等方面的考慮,我們決定放棄這一方案。

goofys

goofys是用go實現的將s3以及部分非s3協議的對象存儲掛載到linux的文件系統,測試后,我們發現goofys主要有三個問題:

>寫入沒有進行并發控制。在大文件的寫入場景下,goofys同樣將文件進行分片,然后每個分片開一個協程寫入到后端存儲。對象存儲一般通過HTTP協議進行通信,由于請求是同步的方式,在不限制并發數的情況下會有大量的連接,消耗大量的內存等資源。

>讀取采用同步方式,性能很差。FUSE有兩種讀取模式async和sync,通過掛載時的設置去選擇,goofys強制使用了sync模式,并且預讀的實現為亂序讀取超過三次后停止預讀,代碼如下:

if !fs.flags.Cheap && fh.seqReadAmount >= uint64(READAHEAD_CHUNK) && fh.numOOORead < 3 { ... err = fh.readAhead(uint64(offset), len(buf)) ...}

fh.numOOORead為亂序讀取的次數,FUSE模塊會對超過128k的IO進行拆分,以128k對齊。簡單介紹一下FUSE的同步讀取和異步讀取模式的區別。內核的讀取一般入口是在底層文件系統的read_iter函數,然后調用VFS層的generic_file_read_iter,該函數內部實現會通過調用readpages進行預讀。如果預讀后沒有對應的page則會調用readpage讀取單頁。由于goofys不支持該設置,我們通過對s3fs設置不同的配置來測試,然后抓取讀取時的調用棧對比其中的區別。設置了異步讀取模式的讀堆棧如下所示:

fuse_readpages+0x5/0x110 [fuse]read_pages+0x6b/0x190__do_page_cache_readahead+0x1c1/0x1e0ondemand_readahead+0x1f9/0x2c0? pagecache_get_page+0x30/0x2d0generic_file_buffered_read+0x5a50xb10? mem_cgroup_try_charge+0x8b/0x1a0? mem_cgroup_throttle_swaprate+0x17/0x10efuse_file_read_iter+0x10d/0x130 [fuse]? __handle_mm_fault+0x662/0x6a0new_sync_read+0x121/0x170vfs_read+0x91/0x140

其中vfs_read是系統調用到vfs層的入口函數。之后會調用到readpages進行多頁的讀取。fuse_readpages將讀請求發給用戶態文件系統,進而完整整個讀取流程。同步讀取模式的堆棧如下所示:

fuse_readpage+0x5/0x60 [fuse] generic_file_buffered_read+0x61a/0xb10 ? mem_cgroup_try_charge+0x8b/0x1a0 ? mem_cgroup_throttle_swaprate+0x17/0x10e fuse_file_read_iter+0x10d/0x130 [fuse] ? __handle_mm_fault+0x662/0x6a0 new_sync_read+0x121/0x170vfs_read+0x91/0x140

和異步流程相同,依然是在generic_file_read_iter中進行讀取,當讀取之后沒有對應的頁,會嘗試讀取單頁。相關代碼如下,內核版本基于4.14:

no_cached_page: /* * Ok, it wasn't cached, so we need to create a new * page.. */ page = page_cache_alloc_cold(mapping); if (!page) { error = -ENOMEM; goto out; } error = add_to_page_cache_lru(page, mapping, index, mapping_gfp_constraint(mapping, GFP_KERNEL)); if (error) { put_page(page); if (error == -EEXIST) { error = 0; goto find_page; } goto out; } goto readpage;

如果設置了同步方式進行讀取,FUSE模塊會無效內核的預讀,轉而進入到no_cached_page讀取單頁。所以同步模式下落到用戶態文件系統的讀IO有大塊的readpagesIO和readpage的4K單頁IO,由于offset存在相同,goofys會判斷為亂序的讀取,超過3次后停止預讀,由于每次和US3的交互都是4K的GET請求,性能會比較差,難以滿足用戶的需求。

>分片上傳的大小不固定,無法適配US3 。US3目前的分片大小固定為4M,而goofys的分片大小需要動態的去計算,并手動修改進行適配,代碼如下:

func (fh *FileHandle) partSize() uint64 { var size uint64

if fh.lastPartId < 1000 { size = 5 * 1024 * 1024 } else if fh.lastPartId < 2000 { size = 25 * 1024 * 1024 } else { size = 125 * 1024 * 1024 }

...

}

同時,s3協議本身沒有rename的的接口,s3fs和goofys的rename都是通過將源文件內容復制到目標文件,然后刪除源文件實現的。

而US3內部支持直接修改文件名,US3FS通過使用相關的接口實現rename操作,相比s3fs和goofys性能更好。同時s3fs和goofys掛載US3的bucket都需要走代理進行協議的轉換,使用US3FS則減少了這一IO路徑,性能上更有優勢。

通過對s3fs和goofys的實踐,我們發現兩者在US3的備份場景上的性能有一些問題,同時適配的工作量也比較大,基于此,我們決定開發一款能夠滿足用戶在數據備份場景需求的,依托對象存儲作為后端的文件系統。

UCloud優刻得US3FS設計概述

US3FS通過FUSE實現部分POSIX API。在介紹US3FS實現之前,先簡單介紹一下Linux的VFS機制和FUSE實現(有這部分基礎的朋友可直接跳過)。

VFS

VFS,全稱Virtual File System,是linux內核中一個承上啟下的虛擬層,隸屬于IO子系統。對上,為用戶態應用提供了文件系統接口;對下,將具體的實現抽象為同一個函數指針供底層文件系統實現。

linux文件系統中的元數據分為dentry(directory entry)和inode,我們知道,文件名并不屬于文件的元數據,為了優化查詢,vfs在內存中建立dentry以緩存文件名和inode的映射以及目錄樹的實現。單機文件系統的實現,dentry只存在于內存中,不會落盤,當查找某個文件時內存沒有對應的dentry,vfs會調用具體的文件系統實現來查找對應的文件,并建立起對應的數據結構。inode緩存了一個文件的元數據,如大小,修改時間等,會持久化到硬盤中,數據的讀寫通過地址空間找到對應的page和block device進行讀寫。

FUSE

FUSE,全稱Filesystem in Userspace,用戶態文件系統,我們知道,一般直接在內核態實現某個特性是比較痛苦的事情,通常內核的debug比較困難,而且稍不注意就會陷入到內核的各種細節而無法自拔。FUSE就是為了簡化程序員的工作,將內核的細節隱藏起來,提供一套用戶態的接口用于實現自己的文件系統,用戶只需要實現對應的接口即可。內核態的FUSE模塊和用戶態的FUSE庫的交互通過/dev/fuse進行通信,然后調用用戶自己的實現。當然,缺點就是增加了IO路徑以及內核態/用戶態的切換,對性能有一定影響。

UCloud元數據設計

US3FS通過實現FUSE的接口,將US3中bucket的對象映射為文件,和分布式文件系統不同,沒有mds(metadata server)維護文件元數據,需要通過HTTP向us3獲取。當文件較多時,大量的請求會瞬間發出,性能很差。為了解決這一點,US3FS在內存中維護了bucket的目錄樹,并設置文件元數據的有效時間,避免頻繁和US3交互。

這也帶來了一致性的問題,當多個client修改同一bucket中的文件,其中的緩存一致性無法保證,需要用戶自己取舍。為了提升檢索的性能,文件并沒有像對象存儲以平鋪的方式放在整個目錄中,而是采用了傳統文件系統類似的方式,為每一個目錄構建相關數據結構來保存其中的文件,同時inode的設計也盡量簡潔,只保存必要字段,減少內存的占用。

目前Inode中保存的字段有uid,gid,size,mtime等,通過US3的元數據功能在對象中持久化。例如下圖所示,在US3的bucket中有一個名為"a/b/c/f1"的對象,在文件系統中,會將每一個“/"劃分的前綴映射為目錄,從而實現左邊的目錄樹。

UCloud IO流程設計

對于數據的寫入,US3支持大文件的分片上傳。利用這一特性,US3FS通過將數據寫入cache,在后臺將數據以分片上傳的方式,將數據以4MB的chunk寫入到后端存儲中。分片上傳的流程如下圖所示,通過令牌桶限制整個系統的寫入并發數。每個分片寫入的線程都會獲取令牌后寫入,通過當文件close時寫入最后一個分片,完成整個上傳流程。

文件的讀取通過在US3FS的cache實現預讀來提升性能。kernel-fuse自身對數據的讀寫進行了分片,在不修改內核的情況下,IO最大為128K。而大文件的讀取場景一般為連續的大IO,這種場景下IO會被切成128K的片,不做預讀的話,無法很好的利用網絡帶寬。US3FS的預讀算法如下所示:

如圖所示,第一次同步讀取完成后,會往后進行當前長度的預讀,并將預讀的中點設置為下次觸發預讀的trigger。之后的讀取如果不連續,則清空之前的狀態,進行新的預讀,如果連續,則判斷當前讀取的結束位置是否不小于觸發預讀的偏移,如果觸發預讀,則將預讀窗口的大小擴大為2倍,直到達到設定的閾值。之后以新的窗口進行預讀。如果未觸發,則不進行預讀。預讀對順序讀的性能有很大提升。鑒于US3FS使用場景多為大文件的場景,US3FS本身不對數據進行任何緩存。在US3FS之上有內核的pagecache,當用戶重復讀取同一文件時pagecache能夠很好的起作用。

UCloud數據一致性

由于對象存儲的實現機制原因,當前大文件的寫入,在完成所有的分片上傳之前,數據是不可見的,所以對于US3FS的寫入,在close之前,寫入的數據都是不可讀的,當close后,US3FS會發送結束分片的請求,結束整個寫入流程,此時數據對用戶可見。

對比測試

在并發度為64,IO大小為4M測試模型下,40G文件的順序寫和順序讀進行多次測試,平均結果如下:

測試過程中,goofys的內存占用比較高,峰值約3.3G,而US3FS比較平穩,峰值約305M,節省了90%內存空間。s3fs表現相對較好,因為使用本地臨時文件做緩存,所以內存占用比較少,但是寫入文件比較大,硬盤空間不足時,性能會下降到表格中的數據。

在順序讀的測試中,測試結果可以驗證我們的分析,goofys由于本身設計的原因,在這種場景下性能無法滿足我們的要求。另外在測試移動1G文件的場景中,對比結果如下:

可見在移動需求場景下,特別是大文件居多的場景,通過US3FS能提升上百倍的性能。

總結

總而言之,s3fs和goofys在大文件的讀寫場景下各有優劣,相比之下,UCloud優刻得US3自研的 US3FS 無論是讀還是寫都有更好的性能,而且和UCloud優刻得US3的適配性更強,更易于拓展。

分享到:
標簽:讀寫 文件系統 對象 性能 提升 用戶 設計 UCloud
用戶無頭像

網友整理

注冊時間:

網站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網站吧!
最新入駐小程序

數獨大挑戰2018-06-03

數獨一種數學游戲,玩家需要根據9

答題星2018-06-03

您可以通過答題星輕松地創建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數有氧達人2018-06-03

記錄運動步數,積累氧氣值。還可偷

每日養生app2018-06-03

每日養生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定