與行程一樣,分散式檔案系統的通訊沒有太特別之處:多數系統以遠端程序呼叫(Remote Procedure Call, RPC)為基礎,再針對特殊情境做些有趣的強化。選擇 RPC 機制的主因,是讓系統獨立於底層作業系統、網路與傳輸協定。
NFS 中的 RPC#
NFS 的所有主從通訊都走 **Open Network Computing RPC(ONC RPC)**協定,並附有封裝資料表示法的標準;ONC RPC 與一般 RPC 系統類似。
每個 NFS 操作都能實作成對檔案伺服器的一次 RPC。在 NFSv4 之前,用戶端被要求把請求保持簡單、減輕伺服器負擔。例如第一次讀取檔案資料時,用戶端通常得先用 lookup 查出 file handle,再發出 read 請求——兩次連續的 RPC。
這種做法的缺點在廣域環境下最明顯:第二次 RPC 的額外延遲會造成效能劣化。
為了繞開此問題,NFSv4 支援複合程序(compound procedure),可將多個 RPC 打包成單一請求。前例中用戶端把 lookup 與 read 合併成一次 RPC(v4 中讀取前還需 open:查到 file handle 後交給 open,伺服器接著執行 read),整體效果是主從之間只需交換兩則訊息。

圖 11-7:(a) 在 NFS 第 3 版中讀取檔案資料。(b) 在第 4 版中以複合程序讀取資料。
複合程序的語意須注意:
- 沒有交易語意:打包在一起的操作只是依請求順序逐一處理;若有其他用戶端的並行操作,不會採取任何避免衝突的措施。
- 失敗即中止:任一操作失敗,其後的操作不再執行,直接把目前已得的結果回傳給用戶端——例如 lookup 失敗,接下來的 open 根本不會嘗試。
RPC2 子系統#
另一項有趣的 RPC 強化來自 Coda 檔案系統的 RPC2:一個在不可靠的 UDP 之上提供可靠 RPC 的套件。每次呼叫遠端程序,RPC2 用戶端程式碼會啟動新的執行緒送出請求並阻塞等待回應;由於請求處理時間可能任意長,伺服器會定期回傳訊息告知「仍在處理中」。若伺服器死了,該執行緒遲早會發現訊息中斷,向呼叫端回報失敗。
副作用(side effects)#
RPC2 的一個有趣特點是支援副作用:讓主從雙方能用應用特定的協定通訊。例如用戶端向視訊伺服器開檔時,需要建立等時(isochronous)傳輸模式的連續資料串流——資料傳輸保證落在最小與最大端到端延遲之間。RPC2 允許主從雙方作為一次 RPC 呼叫的副作用建立一條獨立連線來準時傳送視訊資料。RPC2 執行期系統為此提供一組由應用開發者實作的副作用常式介面(例如建立連線、傳輸資料的常式),這些常式由 RPC2 執行期在主從兩端自動呼叫,但其實作與 RPC2 完全獨立。

圖 11-8:Coda 的 RPC2 系統中的副作用。
MultiRPC 與平行失效通知#
RPC2 另一個與眾不同的特點是支援群播(multicasting)。Coda 的重要設計是伺服器追蹤哪些用戶端持有檔案的本地副本;檔案被修改時,伺服器透過 RPC 通知相關用戶端使其副本失效。
若伺服器一次只能通知一個用戶端,逐一循序失效可能拖很久:RPC 偶爾會失敗,伺服器聯絡不上(可能已當機的)用戶端時,要等相對長的逾時才會放棄,期間其他用戶端仍在讀取本地舊副本。
較好的解法是同時對所有用戶端送出失效訊息:所有未失效的用戶端在一次 RPC 的時間內全部收到通知,伺服器也能在一般逾時時間內察覺哪些用戶端沒有回應,將其判定為已當機。

圖 11-9:(a) 一次送出一則失效訊息。(b) 平行送出失效訊息。
平行 RPC 由 RPC2 套件中的 MultiRPC 系統實作,重點特性:
- 對被呼叫端完全透明:接收端無法分辨 MultiRPC 呼叫與一般 RPC。
- 呼叫端也大致透明:失效情況下的語意與一般 RPC 幾乎相同,副作用機制照常可用。
- 實作上等同平行執行多個 RPC:呼叫端對每個接收者明確送出請求,但延後阻塞直到所有請求送出——亦即發出多個單向 RPC 後,再阻塞等待所有未失效接收者的回應。另一種平行執行方式是建立群播群組,用 IP multicast 把 RPC 送給所有成員。
Plan 9 的檔案導向通訊#
最後值得一提的是一種截然不同的路線:Plan 9 與其說是分散式檔案系統,不如說是以檔案為本的分散式系統(file-based distributed system)。所有資源都以檔案式的語法與操作存取,連行程、網路介面這類資源也不例外。這個想法承襲自 UNIX,但 Plan 9 貫徹得更深更一致:網路介面不是(如 UNIX 那樣)用單一檔案表示,而是用一個檔案系統(一組特殊檔案)表示。
以單一 TCP 連線為例,它表示為一個子目錄,內含若干檔案:
ctl:送出控制命令。例如要開一條到 IP 192.31.231.42、port 23 的 telnet 會談,發送端對 ctl 寫入字串
connect 192.31.231.42!23;接收端則須事先寫入announce 23,表示可接受連入的會談請求。data:以一般 read/write 操作交換資料,遵循尋常的 UNIX 檔案操作語意。例如往連線寫資料就是:
res = write(fd, buf, nbytes);其中
fd是開啟 data 檔後取得的檔案描述子,buf指向待寫資料緩衝區,nbytes是位元組數,回傳實際寫入的位元組數。listen:等待連線建立請求。行程宣告願意接受新連線後,可對 listen 做阻塞式讀取;有請求進來時,呼叫回傳一個檔案描述子,指向新建連線目錄中對應的 ctl 檔。

圖 11-10:Plan 9 中與單一 TCP 連線相關聯的檔案。
由此可見,一套完全以檔案為導向的通訊方式是可以實現的。