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