NFS文件系統中的RPC協議詳解
前文我們介紹了NFS的整體架構,其核心是將主機端的函數調用通過網絡傳輸到服務端,并轉化為服務端的函數調用。其主要實現是主機端與服務端的一一對應的存根。那么這種轉化是如何進行的呢?這就涉及到RPC協議了。
在Linux NFS中,將網絡文件系統分為兩層,其中RPC協議承載了NFS協議。由于RPC協議的存在,是的NFS協議變得非常簡單。
圖片
RPC協議的全稱為Remote Procedure Call,翻譯成中文是遠程過程調用。也就是通過該協議,可以實現一個遠程的函數調用,這樣在客戶端調用一個函數,可以在服務端完成業務處理。而對于客戶端來說并不關心該函數是在客戶端還是服務端。
這里的函數是經過特殊方式實現的,在NFS中稱為存根(stub)。以Linux內核中的實現為例,文件系統的所有操作都對應著一個存根函數,具體如下所示。
圖片
而客戶端的這些存根函數在服務端也是有一一對應的存根函數的。Linux NFS中服務端的存根函數如下所示。
圖片
所以,當客戶端文件系統希望完成某一個文件操作時,比如創建子目錄。那么在文件系統層面可以直接調用客戶端的存根函數,比如nfs3_proc_mkdir。而該函數會將請求封裝后通過RPC發送到服務端,服務端的程序會根據解析后的消息調用服務端對應的存根函數完成客戶端期望的操作,然后給客戶端反饋。
那么這個流程是如何實現的呢?這就涉及到RPC協議的內容了。RPC的原理其實非常簡單,如下是RPC數據包的格式,可以看出該格式中包含很多字段。這些字段就是用來描述存根函數的。
圖片
Sun的RPC協議在設計的時候期望實現對多種服務的支持,比如NFS協議、掛載協議和NLM等。因此在設計RPC協議的時候,RPC有3個相關的字段來進行標識,其中Program字段標識程序,區分NFS、MOUNT和NLM等其它程序類型;Program Version字段標識程序版本,考慮升級的兼容性;Procedure字段則標識程序中的過程(函數),也就是存根函數。
通過上述Program和Procedure等關鍵信息,當服務端收到該消息時就可以知道應該由哪個版本的哪個程序來處理該消息,而且進一步知道應該調用哪個存根函數(函數指針)來進行處理。
上面的介紹更多的是理論層面的,我們通過WireShark抓個包看看Sun RPC是如何傳輸數據的,以及數據的格式。如圖5?8所示是我們抓取的掛載命令的數據包,我們可以對比一下該數據包的內容與協議的關系。
圖片
可以看到,這里Program是100005;Program版本是3,也就是NFS v3的數據;Procedure的值為1。由于WireShark是支持RPC和NFS協議的,因此在圖5?8中上半部分可以看到具體的描述信息。在該圖的下半部分則是原始的數據包數據。
正是由于在RPC數據包中包含的這些關鍵信息,當主機端發送的消息被服務端接收后,服務端根據這些信息就能知道應該調用哪個存根函數。