從IPC到分布式軟總線的隨筆
在Linux 系統中, 客觀來說,缺乏相對開發者比較友好的進程間通信框架。談到Linux上進程間通信,一般都會想起管道(匿名、有名)、信號/信號燈、共享內存、消息隊列和socket。這些都是偏低層的技術,有沒有方便開發者使用的技術或者框架呢?軟件總線以及分布式軟總線或許是一種不錯的候選。
Linux 中的進程間通信一瞥
Linux環境下通信機制眾多,各種通信方式都有其適用的場合。
管道是Linux支持的最初Unix IPC機制之一,是實現方法最簡單的一種通信機制。但是,只能以半雙工的形式在進程間進行通信。
信號是多種通信機制中唯一一種異步方式進行通信的機制。信號方式通信傳輸的數據量較少,側重于控制進程根據不同的信號觸發不同的行為。
消息隊列是在內核中開辟的一組鏈表,以隊列的形式接收和發送信息,適用于傳輸數據量較少的場合。消息隊列與管道通信相比,其優勢是對每一個消息可以指定特定消息類型,接收的時候不需要按隊列次序,而是可以根據自定義條件接收特定類型的消息。但在消息信息的發送進程—操作系統內核和內核—接收進程間復制時需要額外占用CPU的時間。
共享內存通信機制在進程間可以傳送大量的數據,并且由于讀寫進程均將共享內存塊視為本進程所有,可直接讀寫,因此傳輸速度最快。但由于多個進程對共享內存塊的訪問必須以互斥形式進行,因此還需要信號量機制予以配合。
信號量機制通過信號量值的變化來控制多進程互斥的訪問共享資源,或者協調多個進程并發執行的節奏,并未在進程之間實際的傳輸數據。
基于 Socket 的進程間通信機制是現在所有網絡操作系統必不可少的基礎功能,大多數現代進程間通信框架都是基于Socket 完成的。
久遠一點的DCOP
大約從KDE2.0 開始,都包含了非常強大的部件,叫做“Desktop COmmunication Protocol”,簡稱為 DCOP,從開發者的角度來看,利用 DCOP 可以很方便地將強大的腳本功能添加到應用程序中。從用戶的角度來看,利用 DCOP 可以容易地控制 KDE 應用程序,并可以將它們以強大而有趣方式組合起來。

就其本質而言,DCOP 是一個操作于socket之上的輕量級進程間通信機制,由一個服務器(即 dcopserver,它在 KDE 啟動時會自動啟動)和任意多個客戶端(支持 DCOP 的應用程序)構成。DCOP客戶段之間可以通過服務器互相發送消息,要求執行函數,等等。
kdebindings 軟件包中含對 Java 的 Qt/KDE 綁定,可以在 Java 中使用 Qt/KDE 類,還包括對 C、Perl、Python 的綁定,也可以在這些語言中使用 DCOP,還包括了 XParts,將非 KDE 應用程序作為一個 KPart 嵌入使用。
DCOP 一般用于動態管理Linux運行時軟件配置框架,一般的Linux軟件在運行時讀取配置文件后,所有的參數不可再次調整,而Dcop能夠在啟動軟件后,再次根據需求去配置軟件各項參數。
普遍使用的D-Bus
現如今,在Linux 中使用廣泛的D-Bus 又是什么呢?

D-Bus是一個有面向對象接口的協議框架,以及應用程序用戶互相發現和監視的守護進程。也就是說,這是一個進程間的通訊系統,是由兩個守護進程,一個是系統范圍,一個是用戶會話范圍,提供了生命周期內的跟蹤、服務激活、安全檢查等高級功能。這樣的守護進程可以啟動服務以便給其它程序提供某些功能。D-Bus 可以看作DCOP的升級版,比DCOP要復雜一些,而且DCOP主要用作桌面應用之間的通信。
但是,D-bus 也不是一個普遍適用的通訊系統,這一點和Corba等明顯不同。在設計之初,D-Bus 設計被用來作為用戶交互接口與系統服務之間的解耦和通信,以及系統服務之間的通信。對于 D-Bus而言,由于不信任對端發來的數據,一定要做復雜的校驗,導致比直接使用socket讀寫數據慢2.5倍,甚至比DCOP乃至Corba等通訊機制都要慢一些。
Corba,又是一個久遠的存在,20多年前的Corba 實現Orbit都要比D-Bus快,Corba和D-Bus都使用了二機制的通訊協議,但Corba 更通用和開放。然而,D-Bus很多地方都是硬編碼,所以D-Bus要比Corba簡單得多。
DCOM 是Windows 下的IPC系統,類似于Corba,由于老碼農已經多年不涉及Windows 平臺的軟件開發了,也不知道現在發展到怎樣的程度了。
面向嵌入式的ubus
OpenWrt 提供的ubus,類似于Linux桌面系統的D-Bus,目標也是提供系統級的進程間通信功能。在設計理念上基本一致,但與D-Bus相比減少了內存空間的占用,可以更適合嵌入式Linux低內存和低CPU性能的特殊環境。

ubus是OpenWrt的RPC工具大約是在2011年加入OpenWrt中的。為了提供各種后臺進程和應用程序之間的通信機制,ubus模塊由3部分組成:
- ubusd精靈進程。
- ubus接口庫
- ubus命令行工具
ubus模塊的核心是ubusd精靈進程,在系統啟動時運行,負責進程間的消息路由和傳遞。其他進程注冊到 ubusd進程進行消息的發送和接收,這個接口是用L文件socket和TLV收發消息來實現的。每一個進程在指定命名空間下注冊自己的路徑。每一個路徑都可以提供帶有各種參數的多個函數處理過程,函數處理程序可以在完成處理后返回消息。
ubus提供的功能主要有以下4個方面:
- 提供注冊對象和方法供其他實體調用。
- 調用其他應用程序提供的注冊對象的控制接口。
- 在特定對象上注冊監聽事件。
- 向特定對象發送事件消息。
ubus主要用于兩個進程之間的通信,能夠以JSON格式和用戶進行數據交換,不用關心消息的實際傳輸格式。ubus代碼基于LGPL2.1發布,在OpenWrt 12.09版開始正式使用。
面向內核環境的KDBUS
kdbus是在內核里實現的D-Bus,可傳輸大數據塊乃至GB級的消息流,可做到消息傳遞的零拷貝,在最壞情況下,一條消息及其回復過程不超過2次拷貝,2次驗證和2次上下文切換。全部的憑據信息(用戶ID,進程ID,cgroup信息,權限等)隨每個消息傳遞,而且所有消息都有時間戳。
kdbus在內核中作為一個字符設備,先要open設備,再調用mmap()將一個消息傳遞區域映射到自己的地址空間。消息在這個區域組裝后交給內核傳輸,內核簡單地將消息從一個進程映射的區域拷貝到另一個進程的區域。一般地,kdbus通過memfd機制實現消息傳遞的零拷貝。memfd是一塊帶有文件描述符的內存區域,可以被“密封”,即擁有它的進程不能再改變其內容。要傳遞一條消息,進程先在memfd區域構造消息,密封,然后交給kdbus傳輸。內核可以把相應的內存頁面映射到接收進程的地址空間,從而避免拷貝數據,這取決于消息的大小。消息比較小時內存映射的開銷比較大,這時是直接拷貝數據。消息還可以攜帶對收到回復的時間限制(“方法調用窗口”)。

由于處于內核中,kdbus隨時可用,不需要類似D-Bus那樣的守護進程啟動,Linux安全模塊可以直接與其掛鉤,可避免競態條件,API也得到了簡化。另外,kdbus信號廣播機制采用布隆過濾器來選擇接受者,也提高了廣播的效率。
遺憾的是, kdbus 曾經試圖合入到主流發行版的內核中,但好像沒有成功,前景又讓人有點捉摸不透了。
面向分布式系統的FDBUS
FDBus提供了分布式的進程間通信機制,支持跨主機的C/S通信,使用服務名而非物理地址作為尋址方式,通過各種服務和心跳重連機制確保連接的動態性和可靠性,進而保證系統內的節點可以動態增刪與部署,可以任意重啟,無需管理啟動順序和依賴,通信各方都能保持連接,從而把各個分立的模塊組成一個牢固的整體。

從進程間通信視角來看,FDBus和的D-Bus類似,但功能更齊全,性能更高,使用更便利,除了支持主機內的IPC,還能在多個主機之間組網。FDBus構建于socket(Unix和TCP)之上,采用protocol buffer來支持各種復雜的數據類型,也支持raw data格式,便于大量數據傳輸。FDBus 采用IDL來定義接口并支持自動代碼生成,大大降低序列化和反序列化工作,而且支持安全策略,對訪問區劃分了安全等級,確保整個系統的安全性。
FDBus支持字符串形式的名字作為server地址,通過類似DNS作用的name server自動為server分配Unix domain地址和TCP端口號,實現client和server之間以服務名稱進行尋址。其高性能主要體現在點對點直接通信,不通過中央Hub或Broker進行轉發,目前已經在Windows,Linux和QNX上得到了驗證。作為C/S模式,支持如下通信模式:
- 帶超時的同步請求/應答
- 帶超時的異步請求/應答
- 無應答的命令請求
- 訂閱模式,實現多點廣播
FDBus不僅僅是IPC機制,也是一個中間件開發框架,包含開發中間件過程中經常用到的公共組件和基礎模型,提供了跨平臺且功能強大的支持。源碼開放之后,FDBus經過更多開發者的使用、測試和改進,逐漸成為眾多中間件開發框架的候選之一。
xBus 與軟件總線
除了早期的DCOP,上面的幾種進程間通信機制都命名為xBus,為啥呢?在計算機領域,Bus 一詞最早出現在硬件架構中, 代表總線,是一組能為多個部件分時共享的公共信息傳送線路。

從總線所處的位置來看,分為片內總線和片外總線。片內總線是CPU內部的寄存器、算術邏輯部件、控制部件以及總線接口部件之間的公共信息通道,片外總線則泛指CPU與外部器件之間的公共信息通道,我們談到的總線一般指的是片外總線。
從總線傳輸方式的設計視角來看,計算機總線有串行總線和并行總線,可以由一個或多個通道組成,每個通道是單線連接,數據的傳輸方式將根據通道的數量而有所不同。
從通信用途的視角來看,總線又可以分為3種:地址總線、數據總線、控制總線。地址總線用于指定CPU將要操作的內存地址;數據總線用于讀寫內存的數據,控制總線用于發送和接受信號,比如中斷、設備復位等信號,CPU收到信號后進行響應,這時則需要控制總線。
在CPU、內存與外設確定的情況下,計算機的總線速度是制約計算機整體性能的關鍵。
計算機的軟件總線是一種虛擬的存在,它是在計算機硬件總線的功能含義類比的基礎上得到的定義。軟件總線是軟件工程人員為了進一步保證軟件系統建設的規范性,以及提高計算機系統的應用價值而提出的一種設計理念。軟件總線可以將各種軟件進行相互連接,組成一個通用的操作平臺,通常表現為一個接口界面。作為一種軟件模塊,軟件總線為各個軟件組成部分進行準確的數據傳輸,同時為各種軟件提供虛擬共享的通道和接口。
軟件總線源于分布式異構環境的搭建所提出的,軟件復用、構件化以及面向對象技術的發展促進了它的形成。軟件總線只是對軟件的構件進行組裝而不是更改,這不僅有效的提高了軟件開發的工作效率,縮短了軟件開發的周期。前面提到的各種xBus,都可以看作軟件總線的一種實現。
HarmonyOS的分布式軟總線
鴻蒙的分布式軟總線是為了解決所有1+8+N設備之間的互聯互通問題,在華為提出的1+8+N中:1指的是手機,8指的是車機、音箱、耳機、手表/手環、平板、大屏、PC、AR/VR,N指的是其他IOT設備。一般情況下,用戶都是通過手動操作的方式進行設備之間的連接,隨著外圍設備越來越多,手動操作的方式不方便,甚至會影響用戶的體驗。HarmonyOS的分布式總線技術是為了能夠讓所有的設備之間能夠方便、高效的互聯。

HarmonyOS分布式軟總線最主要的功能包括:發現、連接、組網/拓撲管理、任務總線、數據總線。其中,”發現”指的是搜索周圍是否有相關設備;”連接”指的是與所發現的設備建立連接;”組網/拓撲管理”指的是對所有發現的設備進行網絡拓撲管理,比如組成星狀網絡拓撲,或者是組成Mesh網絡拓撲。”任務總線”指的是在所建立的網絡拓撲基礎上,用于傳輸小數據量信息的通路。”數據總線”指的是用于傳輸較大數據量信息的通路。發現與組網是分布式軟總線的核心術,目前沒有開到公開的細節信息。
把眾多外圍設備連接形成網絡后,需要保證各個設備在時間上的同步。尤其是IoT設備,由于成本方面的原因,晶振的質量可能比較差,會存在相對較大的頻率漂移。分布式軟總線關鍵技術之一是時鐘同步算法,將不同設備原本不同步的時鐘做到統一同步。在軟時鐘算法的同步下,就可以進行資源的調度。軟總線技術中提出了LaneHub的概念,可以理解為調度管理各通信通路的模塊。通過軟總線的LaneHub可以對這不同連接方式的設備進行統一調度,達到減少干擾、提升速率的目的。
在分布式軟總線的基礎上,華為提出了”超級終端”的概念,就是通過分布式軟總線技術將手機外圍的其他相關設備連接在一起,形成了所謂的”超級終端”,即個體終端變成了群體終端。
一句話小結
盡管“一切程序都會歸于系統調用”,但軟件工程的效率提升是業界不變的追求,從進程間通信到分布式軟總線也是如此,或許,基于FDBUS就可以相對容易地開發出類似HarmonyOS的分布式軟總線呢。
【參考資料】
- https://gitee.com/Janisa/Dcop/
- http://dbus.freedesktop.org/doc/dbus-faq.html
- https://github.com/skawu/fdbus
- https://git.openwrt.org/project/ubus.git
- https://developer.harmonyos.com/
- https://www.bilibili.com/video/BV16b4y1h75z?spm_id_from=333.999.0.0




























