文件系統小冊(FusePosixK8s csi)【1 Fuse】

文件系統小冊(Fuse&Posix&K8s csi)【1 Fuse:用戶空間的文件系統】

Fuse(filesystem in userspace),是一個用戶空間的文件系統。通過fuse內核模塊的支持,開發者只需要根據fuse提供的接口實現具體的文件操作就可以實現一個文件系統。由于其主要實現代碼位于用戶空間中,而不需要重新編譯內核,這給開發者帶來了眾多便利。

  • 雖然Fuse簡化了文件系統的實現,給開發者帶來了便利。但是其額外的內核態/用戶態切換帶來的性能開銷不能被忽視,所以fuse性能問題,一直是業界繞不開的話題。下面說到的splice、多線程、writeback cache都是為了改善其性能問題。

1 架構設計(執行流程)

  1. 用戶程序掛載到fuse文件系統,比如此時執行ls命令
  2. VFS(虛擬文件系統)檢測到掛載到fuse文件系統上的用戶程序發送的請求,會將其轉發給fuse driver
  3. fuse driver接受到request請求,會將其保存到queue中,同時暫停用戶程序(ls會卡主,等待返回結果),同時喚醒fuse daemon處理請求
  4. fuse daemon(守護進程)通過/dev/fuse讀取queue中的request,經過處理后將其轉發給內核底層文件系統(EXT4等)。
  5. 內核文件系統處理完成后將結果返回給fuse daemon,fuse daemon將結果寫回/dev/fuse
  6. fuse driver將該request標記為completed,并喚醒用戶進程,返回對應執行結果。(ls執行結束,終端展示文件列表)
    在這里插入圖片描述

2 相關組件

①VFS:轉發請求給fuse driver

VFS(虛擬文件系統)檢測到掛載到fuse文件系統上的用戶程序發送的請求,會將其轉發給fuse driver

② FUSE drvier(queue):接受請求保存到queue

fuse driver接受到request請求,會將其保存到queue中,同時暫停用戶程序(ls會卡主,等待返回結果)

③/dev/fuse(橋梁):fuse daemon通過/dev/fuse讀取queue中的請求

FUSE 驅動程序(fuse driver)處理請求并將其加入隊列,然后通過 /dev/fuse 文件(FUSE 守護程序無法讀取該文件)中的特定連接實例將請求提交給負責處理該 FUSE 文件系統的 FUSE 守護程序。

  • fuse daemon通過/dev/fuse來讀取request queue中的請求

④fuse daemon(中間人):從queue中讀取請求轉發給底層文件系統

fuse daemon(守護進程)通過/dev/fuse讀取queue中的request,經過處理后將其轉發給內核底層文件系統(EXT4等)。

⑤fuse lib:提供接口和內核fuse模塊通信

fuse的lib庫,封裝好了對應接口。fuse的lib庫,提供接口和內核fus模塊通信

⑥內核文件系統(如:EXT4)

內核層面的文件系統,真正操作文件的系統。

3 實現細節

① fuse用戶空間流程

1. fuse mount:通過mount函數將path掛載到/dev/fuse設備

Fuse的掛載通過mount函數,將指定的fuse_path掛載到/dev/fuse設備上。之后對于fuse_path下的文件操作,都會通過fuse文件系統,并通過/dev/fuse被fuse daemon讀取處理。

在這里插入圖片描述

2. fuse thread:fuse daemon創建的服務線程

Fuse daemon還會創建一個服務線程,基于libfuse庫來處理文件操作請求。這里主要關注fuse_session_new和fuse_session_loop_mt。通過fuse_session_new在libfuse中注冊了fuse daemon實現的fuse_lowlevel_ops,之后通過fuse的所有的文件操作,都會通過libfuse回調到fuse daemon進行處理。fuse_session_loop_mt在libfuse中實現了一個多線程模式來讀取請求,相比單線程,在請求處理上效率更高。

  • fuse daemon創建的服務線程
  • 基于libfuse庫處理請求
  • 可多線程模式
  • 通過fuse_session_new(new一個session,與內核fuse模塊通信)+fuse_session_loop_mt(多線程處理請求)

在這里插入圖片描述

3. libfuse:fuse的lib庫,提供接口和內核fus模塊通信

fuse_session_loop_mt:fuse thread基于多線程方式處理請求

  • splice實現內存零拷貝。在默認情況下,fuse daemon必須通過read()從/dev/fuse讀取請求,通過write()將請求回復寫入/dev/fuse。每次讀寫系統調用都需要進行一次內核-用戶空間的內存拷貝。這樣對讀寫的性能損耗十分嚴重,因為一次內存拷貝需要處理大量數據。為了緩解這個問題,fuse支持了Linux內核提供的 splice 功能。splice 允許用戶空間在兩個內核內存緩沖區之間傳輸數據,而無需將數據復制給用戶空間。如果fuse daemon實現了write_buf()方法,則 FUSE 從/dev/fuse讀取數據,并以包含文件描述符的緩沖區的形式將數據直接傳遞給此方法處理,從而省去了一次內存申請與拷貝。[提供緩沖區傳數據,避免用戶空間與內核空間來回切換耗時]
  • 多線程模式。在多線程模式下,fuse daemon以一個線程開始,如果內核隊列中有兩個以上的request,則會自動生成其他線程。默認最大支持10個線程同時處理請求。 [多線程:隊列request>2,自動生成新線程,最大支持10并發]在這里插入圖片描述

②fuse內核隊列(維護了5個隊列)

fuse在內核中維護了五個隊列,分別為:Backgroud、Pending、Processing、Interrupts、Forgets。一個請求在任何時候只會存在于一個隊列中。

  • Backgroud:存異步請求
  • Pending:存同步請求
  • Processing:存處理中的請求
  • Interrupts:存中斷請求(如:用戶ctrl+C,取消請求),優先級最高
  • Forgets:存forget請求(清理cache中的inode)

在這里插入圖片描述

1. Backgroud:暫存異步請求

Backgroud:background 隊列用于暫存異步請求。在默認情況下,只有讀請求進入 background 隊列;當writeback cache啟用時,寫請求也會進入 background 隊列。當開啟writeback cache時,來自用戶進程的寫請求會先在頁緩存中累積,然后當bdflush 線程被喚醒時會下刷臟頁。在下刷臟頁時,FUSE會構造異步請求,并將它們放入 background 隊列中。

2. Pending:存儲同步請求

同步請求(例如,元數據)放在 pending 隊列中,并且pending隊列會周期性接收來自background 的請求。但是pending隊列中異步請求的個數最大為max_background(最大為12),當pending隊列的異步請求未達到12時,background隊列的請求將被移動到pending隊列中。這樣做的目的是為了控制pending隊列中異步請求的個數,防止在突發大量異步請求的情況下,阻塞了同步請求。

3. Processing:存儲正在處理的請求

Processing:當pending隊列中的請求被轉發到fuse daemon的同時,也被移動到processing隊列。所以processing隊列中的請求,表示正在被處理fuse daemon處理的請求。當fuse daemon真正處理完請求,通過/dev/fuse下發reply時,該請求將從processing隊列中刪除。

4. Interrupts:存放中斷請求(用戶取消請求:如:ctrl+C)

Interrupts:用于存放中斷請求,比如當發送的請求被用戶取消時,內核會發送一個Interrupts請求,來取消已被發送的請求。中斷請求的優先級最高,Interrupts中的請求會最先得到處理。

5. Forgets:記錄清理cache中inode的請求

Forgets:存儲forgets請求,forget請求用于刪除cache中緩存的inode。

③/dev/fuse 讀寫調用流程

Fuse driver加載過程中注冊了對/dev/fuse的操作接口fuse_dev_operations。fuse_dev_do_read/fuse_dev_do_write分別對應fuse daemon從內核讀取請求,以及處理完請求后寫回reply的函數調用。

  1. pending 、interrups、forgets隊列為空時,讀進程休眠。
  2. 一旦有request到達,對應等待隊列上的進程被喚醒(Interrups 和 forgets優先級高于pending隊列請求)
  3. 當請求數據內容被拷貝到用戶空間后(fuse daemon在進行處理了)
  4. 該請求被移動到processing隊列,標識該請求已被處理。
  5. req->flags會保存當前請求的狀態
  6. fuse daemon處理完請求后(fuse daemon與內核底層FS打交道)
  7. fuse daemon將結果寫回到/dev/fuse。
  • 其中寫數據保存在struct fuse_copy_state中,并且會根據unique id在fc(fuse_conn)中找到對應的req,并將寫回的參數從fuse_copy_state拷貝至req->out。

源碼邏輯:

當pending 、interrups、forgets隊列都沒有請求時,讀進程進入休眠。一旦有請求到達,這個等待隊列上的進程將被喚醒。Interrups 和 forgets的請求優先級高于pending隊列。當請求的數據內容被拷貝至用戶空間后,該請求會被移至processing隊列,并且req->flags會保存當前請求的狀態。

在這里插入圖片描述

當fuse daemon處理完請求后,會將結果寫回到/dev/fuse。寫數據保存在struct fuse_copy_state中,并且會根據unique id在fc(fuse_conn)中找到對應的req,并將寫回的參數從fuse_copy_state拷貝至req->out。

在這里插入圖片描述

4案例:以unlink為例

  1. fuse daemon會阻塞在讀/dev/fuse,當app進程在fuse掛載點下面有新的文件操作(unlink)
  2. 這時系統調用會調用fuse內核接口,并生成request,同時喚醒阻塞的fuse daemon
  3. fuse daemon讀到request后,在libfuse中進行解析,根據request的opcode來執行對應的ops
  4. 完成后會把處理結果返回給/dev/fuse。此時vfs調用阻塞的行為將被喚醒,最后返回vfs調用。

在這里插入圖片描述

5 實戰(go-fuse)

相關倉庫地址:

  • https://github.com/hanwen/go-fuse
  • https://github.com/bazil/fuse
  • https://github.com/libfuse/libfuse/

Golang操作fuse的庫主要有go-fuse、libfuse。這里主要講解go-fuse

①概述

Go-Fuse 是一個開源的庫,由 Han-Wen Nienhuys 創建并維護。該庫提供了對 Linux FUSE(Filesystem in Userspace)接口的支持,使得開發人員可以使用 Go 語言構建自己的文件系統。
功能:

  • 構建自定義文件系統:使用 Go-Fuse,您可以根據需要構建自己的文件系統。這可能包括加密、壓縮、優化性能等功能。
  • 支持各種平臺:由于 Go-Fuse 基于 FUSE,因此它可以跨多個操作系統(如 Linux、macOS 和 Windows)運行。
  • 高度自定義:通過實現特定的接口方法,您可以控制文件系統的每個細節。這為實現復雜的文件系統行為提供了極大的靈活性。

②環境準備

我準備在我本地macos上構建,因此需要fuse命令。

  • macos:https://github.com/osxfuse/osxfuse/releases(下載dmg安裝配置)
  • ubuntu: sudo apt-get -y update && sudo apt-get install -y fuse
  • centos:sudo yum -y update && sudo yum install -y fuse

安裝好之后,需要確保當前用戶需要有執行fuse命令的權限

# 如果當前用戶沒有權限,可以進行提權或者切換用戶,或者修改fuse配置
vim /etc/fuse.conf打開user_allow_other

③全部代碼&解析

//安裝依賴
go get "github.com/hanwen/go-fuse/v2/fs"
go get "github.com/hanwen/go-fuse/v2/fuse"
package mainimport ("context""flag""log""syscall""github.com/hanwen/go-fuse/v2/fs""github.com/hanwen/go-fuse/v2/fuse"
)type HelloRoot struct {fs.Inode
}func (r *HelloRoot) OnAdd(ctx context.Context) {ch := r.NewPersistentInode(ctx, &fs.MemRegularFile{Data: []byte("file.txt data"),Attr: fuse.Attr{Mode: 0644,},}, fs.StableAttr{Ino: 2})r.AddChild("file.txt", ch, false)
}func (r *HelloRoot) Getattr(ctx context.Context, fh fs.FileHandle, out *fuse.AttrOut) syscall.Errno {out.Mode = 0755return 0
}var _ = (fs.NodeGetattrer)((*HelloRoot)(nil))
var _ = (fs.NodeOnAdder)((*HelloRoot)(nil))//./yi-fuse test
func main() {debug := flag.Bool("debug", false, "print debug data")flag.Parse()if len(flag.Args()) < 1 {log.Fatal("Usage:\n  ./yi-fuse MOUNTPOINT")}opts := &fs.Options{}opts.Debug = *debugserver, err := fs.Mount(flag.Arg(0), &HelloRoot{}, opts)if err != nil {log.Fatalf("Mount fail: %v\n", err)}server.Wait()
}
  • 我們通過go-fuse庫創建了一個用戶空間文件系統,該文件系統只包含一個名為file.txt的文件。
  • context:用于處理上下文,可以在異步操作中取消請求。
  • flag:處理命令行參數。
  • log:日志記錄。
  • syscall:系統調用接口。
  • fs 和 fuse:來自github.com/hanwen/go-fuse/v2的庫,用于實現用戶空間文件系統。
  • HelloRoot 結構體:
    • 表示文件系統的根節點,實現了NodeGetattrer和NodeOnAdder接口。
    • OnAdd 方法:當文件系統被加載時調用,創建一個包含file.txt的持久化節點。
    • Getattr 方法:獲取文件屬性,將file.txt的權限設置為0755。
    • main 函數:
      處理命令行參數,設置調試標志。
      檢查至少有一個掛載點參數。
      創建fs.Options,啟用調試模式。
      調用fs.Mount掛載文件系統。
      如果掛載失敗,打印錯誤信息并退出。
  • server.Wait()阻塞直到文件系統卸載。

④測試

//編譯可執行文件到linux
GOOS=linux GOARCH=amd64 go build -o yi-fuse main.go 
//創建掛載目錄
mkdir -p /root/test
//執行掛載(如果不加nohup,默認前臺運行)
nohup ./yi-fuse /root/test &//預期返回我們代碼里寫的file.txt文件
ls -l /root/test//讀取file.txt文件內容
cat /root/test/file.txt//卸載掛載
umount /root/test

在這里插入圖片描述

參考文章:
https://www.cnblogs.com/Linux-tech/p/14110335.html
https://blog.csdn.net/gitblog_00007/article/details/136569849

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/20164.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/20164.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/20164.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【測評|白嫖】雨云寧波新區,2C4G200M,公測期間全免費!

雨云香港三區云服務器&#xff0c;高性能的 Xeon Platinum 處理器 企業級 NVME SSD 高性能云服務器。 一鍵白嫖鏈接&#xff1a;https://www.rainyun.com 本篇純測評&#xff0c;無任何廣告&#xff0c;請放心食用&#xff01;&#xff01; 本次測評服務器配置如下&#xff1…

用萬界星空科技低代碼平臺能快速搭建一個云MES系統

一、低代碼平臺與MES:智能制造的新篇章 隨著工業4.0和智能制造的興起&#xff0c;企業對于生產過程的數字化、智能化需求日益迫切。傳統的MES系統實施周期長、成本高&#xff0c;成為許多企業數字化轉型的瓶頸。而低代碼開發平臺的出現為這一問題提供了新的解決思路。 二、萬界…

linux可觀測性ebpf(一) ----------- 環境搭建

參考書籍 開發環境 Ubuntu 18.04.6 LTS (GNU/Linux 5.4.0-150-generic x86_64) 1.1 下載內核源碼 cd /usr/src/ sudo git clone -b v5.4 https://github.com/torvalds/linux.git1.2 下載書中代碼 git clone https://github.com/bpftools/linux-observability-with-bpf1.3 編…

海外媒體通稿:9個極具創意的旅游業媒體推廣案例分享-華媒舍

如今&#xff0c;旅游業正迅速發展&#xff0c;媒體推廣成為吸引游客的關鍵。為了更好地展示旅游目的地&#xff0c;許多創意而富有創新的媒體推廣策略應運而生。本文將介紹九個極富創意的旅游業媒體推廣案例&#xff0c;為廣大從業者帶來靈感和借鑒。 1. 視頻系列&#xff1a;…

【Python面試題收錄】Python的GIL機制

Python中的全局解釋器鎖&#xff08;Global Interpreter Lock&#xff0c;簡稱GIL&#xff09;&#xff0c;同一進程中假如有多個線程運行&#xff0c;一個線程在運行python程序的時候會霸占python解釋器&#xff08;加了一把鎖即GIL&#xff09;&#xff0c;使該進程內的其他線…

4. MySQL 約束

文章目錄 【 1. 主鍵約束 PRIMARY KEY 】1.1 在創建表時設置主鍵約束設置單字段主鍵在創建表時設置聯合主鍵 1.2 在修改表時添加主鍵約束1.3 刪除主鍵約束1.4 主鍵自增長 AUTO_INCREMENT指定自增字段初始值自增字段不連續 【 2. 外鍵約束 FOREIGN KEY 】2.1 在創建表時設置外鍵…

Mybatis數據加密解密

文章目錄 Mybatis數據加密解密一、自定義注解二、自定義參數處理攔截器結果集攔截器加密解密 Mybatis數據加密解密 方案一&#xff1a;Mybatis攔截器之數據加密解密【Interceptor】 攔截器介紹 Mybatis Interceptor 在 Mybatis 中被當作 Plugin(插件)&#xff0c;不知道為什么…

ARM32開發——LED點燈

&#x1f3ac; 秋野醬&#xff1a;《個人主頁》 &#x1f525; 個人專欄:《Java專欄》《Python專欄》 ??心若有所向往,何懼道阻且長 文章目錄 點燈的兩種方式灌入電流法輸出電流法擴展板點燈點燈方式點亮LED1-4完整實現 點燈的兩種方式 不同顏色LED&#xff0c;達到相同亮度…

[數據集][目標檢測]貓狗檢測數據集VOC+YOLO格式8291張2類別

數據集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路徑的txt文件&#xff0c;僅僅包含jpg圖片以及對應的VOC格式xml文件和yolo格式txt文件) 圖片數量(jpg文件個數)&#xff1a;8291 標注數量(xml文件個數)&#xff1a;8291 標注數量(txt文件個數)&#xff1a;8291 標注…

ETLCloud中如何使用Kettle組件

ETLCloud中如何使用Kettle組件在當今數據驅動的時代&#xff0c;數據處理和分析已成為企業決策的關鍵。為了更高效地處理海量數據&#xff0c;ETL&#xff08;Extract, Transform, Load&#xff09;工具變得至關重要。而在眾多ETL工具中&#xff0c;Kettle作為一款開源、靈活且…

c#面向對象:接口詳解

接口&#xff08;interface&#xff09; 抽象類中的抽象方法只規定了不能是 private 的&#xff0c;而接口中的“抽象方法”只能是 public 的。這樣的成員訪問級別就決定了接口的本質&#xff1a;接口是服務消費者和服務提供者之間的契約。既然是契約&#xff0c;那就必須是透…

攻防實戰 | 郵件高級威脅檢測與自動化響應

歷經三個月的時間&#xff0c;年度重磅直播節目Fortinet 2024年度“Demo季”近日終于迎來了備受矚目的壓軸大戲——Demo Day第三期&#xff0c;主題為《新郵件安全下的高級威脅檢測與自動化響應》。繼成功舉辦了前兩期《企業網絡中的多源威脅情報自動化整合與集成》和《應急響應…

【持久層】在Spring Boot中使用Hibernate和Gradle構建項目

Hibernate是一個廣泛使用的Java持久化框架&#xff0c;它使得Java對象與關系數據庫之間的映射變得簡單高效。在Spring Boot應用中&#xff0c;結合Gradle構建工具&#xff0c;能夠方便地集成和使用Hibernate。本文將簡述如何在Spring Boot中使用Hibernate&#xff0c;并通過Gra…

Pycharm使用時的紅色波浪線報錯——形如‘break‘ outside loop

背景&#xff1a; 我在一個方法中&#xff0c;寫了一個if判斷&#xff0c;寫了一個break&#xff0c;期望終止這個函數&#xff0c;編輯器出現報錯 形如下圖 視頻版問題教程&#xff1a; Pycharm下出現波浪線報錯&#xff0c;形如break outside loop 過程&#xff1a; 很奇…

IDEA一鍵啟動多個微服務

我們在做微服務項目開發的時候&#xff0c;每次剛打開IDEA&#xff0c;就需要把各個服務一個個依次啟動&#xff0c;特別是服務比較多時&#xff0c;逐個點擊不僅麻煩還費時。下面來說一下如何一鍵啟動多個微服務。 操作步驟 點擊Edit Configurations 2.點擊“”&#xff0c;…

【設計模式】JAVA Design Patterns——Facade(外觀模式)

&#x1f50d;目的 為一個子系統中的一系列接口提供一個統一的接口。外觀定義了一個更高級別的接口以便子系統更容易使用。 &#x1f50d;解釋 真實世界例子 一個金礦是怎么工作的&#xff1f;“嗯&#xff0c;礦工下去然后挖金子&#xff01;”你說。這是你所相信的因為你在使…

性價比為王,物流商怎么選擇高效的國際物流管理平臺

在全球化貿易日益繁榮的今天&#xff0c;國際物流行業作為鏈接國內商家和海外市場的重要橋梁&#xff0c;發揮著極其重要的作用。 然而&#xff0c;隨著國際物流市場競爭的加劇&#xff0c;對物流商來說&#xff0c;也面臨著成本管控和效率提升的雙重挑戰。今天我們會重點探討…

解決 DataGrip 2024.1.3 連接 Tdengine 時timestamp字段顯示時區不正確問題

設置中找到該設置&#xff0c;將原來的設置 yyyy-MM-dd HH:mm:ss 修改為: yyyy-MM-dd HH:mm:ss.SSS z 即可。 注意&#xff1a;只能修改第一個,修改后提示錯誤&#xff0c;但是查詢數據時能成功格式化時間&#xff0c;修改第二個不生效&#xff0c;可能是 bug 具體格式見: Date…

DOS編程入門:探索基礎、深入技巧與實戰應用

DOS編程入門&#xff1a;探索基礎、深入技巧與實戰應用 DOS編程&#xff0c;作為計算機編程的基石之一&#xff0c;對于初學者來說&#xff0c;既是一種挑戰&#xff0c;也是一次深入了解計算機底層運作的絕佳機會。本文將從四個方面、五個方面、六個方面和七個方面&#xff0…

Opera 瀏覽器與Google聯手,推出由Gemini驅動的全新AI功能

每周跟蹤AI熱點新聞動向和震撼發展 想要探索生成式人工智能的前沿進展嗎&#xff1f;訂閱我們的簡報&#xff0c;深入解析最新的技術突破、實際應用案例和未來的趨勢。與全球數同行一同&#xff0c;從行業內部的深度分析和實用指南中受益。不要錯過這個機會&#xff0c;成為AI領…