前言
微內(nèi)核架構(gòu) (Microkernel Architecture),也被稱為 插件式架構(gòu) (plug-in architecture),作為一個在幾十年前就被創(chuàng)建出來的架構(gòu)模式,它如今仍然被廣泛應(yīng)用在各個領(lǐng)域中。比如在Web瀏覽器領(lǐng)域,谷歌的Chrome瀏覽器之所以被認為功能強大,一個很重要的原因是它有著豐富的插件類型;在開發(fā)工具領(lǐng)域,微軟的VS Code初始安裝后還只是個簡單的文本編輯器,但用戶可以安裝各種插件,從而讓它搖身一變成為功能強大的IDE。
Chrome和VS Code都是微內(nèi)核架構(gòu)的典型應(yīng)用例子,它們提供一個具備最基礎(chǔ)能力的核心系統(tǒng),并定義好插件的開發(fā)接口。至于需要開發(fā)或安裝哪種類型的插件,則完全由普通開發(fā)者和用戶決定,這樣的設(shè)計讓系統(tǒng) 具備了極強的可定制化和可擴展能力 。
架構(gòu)視圖
微內(nèi)核架構(gòu)由以下兩部分組成: 核心系統(tǒng) (core system)和 插件 (plug-in component), 將應(yīng)用系統(tǒng)的業(yè)務(wù)邏輯拆分成核心系統(tǒng)和插件,能夠提供很好的可擴展性和靈活性,極大地方便了后續(xù)需求的新增和修改 。
微內(nèi)核架構(gòu)架構(gòu)視圖
核心系統(tǒng)
核心系統(tǒng)通常只需提供能夠支撐整個系統(tǒng)正常運行的基本功能 ,比如前文所舉的VS Code例子,用戶初始安裝的是VS Code的核心系統(tǒng),它只是一個提供了打開文件、編輯文件內(nèi)容和保存文件等基本功能的文本編輯器,其他的擴展功能(如語法檢查)都是通過安裝插件集成的。 將復雜的業(yè)務(wù)邏輯從核心系統(tǒng)中剝離出來,并通過插件實現(xiàn),能夠提升系統(tǒng)的可擴展性和可維護性 。同時,因為復雜的功能都成了互不干擾的插件,系統(tǒng)的可測性也得到了提高。
考慮現(xiàn)在需要實現(xiàn)一個電子設(shè)備回收系統(tǒng),在回收之前,每種型號的手機設(shè)備的回收流程都不一樣,那么我們可以這樣去實現(xiàn):
public void assessDevice(String deviceID) {
if (deviceID.equals("iPhone6s")) {
assessiPhone6s();
} else if (deviceID.equals("iPad1"))
assessiPad1();
} else if (deviceID.equals("Galaxy5"))
assessGalaxy5();
} else ...
...
}
}
如果我們把assessDevice
看成是核心系統(tǒng),那么后面每次新增一個型號的手機,都需要新增一個if
分支,也即對核心系統(tǒng)進行了改動。這樣的設(shè)計會導致核心系統(tǒng)非常地脆弱,正所謂 改的越多,出問題的概率也越大 。
比起這種將所有的可定制業(yè)務(wù)邏輯放在核心系統(tǒng)上的設(shè)計,更好的應(yīng)該是將它們實現(xiàn)為插件的形式,這樣不僅每個設(shè)備回收邏輯都解耦了,還提供了強大的可擴展性:添加一個新的回收設(shè)備類型,只需新增一種插件即可,核心系統(tǒng)無需變動。
public void assessDevice(String deviceID) {
String plugin = pluginRegistry.get(deviceID);
DevicePlugin devicePlugin =
(DevicePlugin)constructor.newInstance();
DevicePlugin.assess();
}
微內(nèi)核架構(gòu)在實現(xiàn)時通常都結(jié)合了其他架構(gòu)模式 ,這主要體現(xiàn)在核心系統(tǒng)的設(shè)計上,比如根據(jù)具體的業(yè)務(wù)特點,我們可以將核心系統(tǒng)設(shè)計成technically partitioned的分層架構(gòu),或者是domain partitioned的模塊化架構(gòu)。
核心系統(tǒng)的架構(gòu)設(shè)計
插件
插件就是一些包含了定制化業(yè)務(wù)邏輯、擴展功能、附加功能的獨立組件,用于擴充核心系統(tǒng)的功能 。插件之間是獨立的,插件與核心系統(tǒng)之間則一般是“點對點”通信:核心系統(tǒng)通過調(diào)用插件提供的接口(比如插件類的方法)使用擴展功能。
插件可以劃分為編譯時插件和運行時插件兩種類型,前者每次變更都需要重新構(gòu)建和部署整個系統(tǒng),但實現(xiàn)較為簡單;后者則可以在系統(tǒng)運行時進行插件的新增和刪除操作,相對地,實現(xiàn)也較為復雜。
編譯時插件
在編譯時插件中,插件通常以package或namespace實現(xiàn),比如在package中可以以這樣的命名規(guī)則來區(qū)分插件:app.plug-in.
。
編譯時插件實現(xiàn)
運行時插件
運行時插件中插件的實現(xiàn)通常是動態(tài)庫的形式,比如.jar
、.so
、.dll
文件。在上述的設(shè)備回收系統(tǒng)的例子中,每種型號的手機設(shè)備回收邏輯包含在一個獨立的.jar
文件中:
運行時插件實現(xiàn)
遠端插件
當然,插件和核心系統(tǒng)并非只能通過本地接口調(diào)用進行通信,還可以采用REST/消息隊列/RPC等方式,這種場景下,插件就變成了一個獨立部署的服務(wù)。遠程插件具備運行時插件的特點,而且能夠提供更好的scalability: 插件和核心系統(tǒng)甚至都不必使用相同的技術(shù)棧實現(xiàn),只需遵守既定的REST接口即可 。
遠端插件
為了提升系統(tǒng)處理請求的responsiveness,我們還可以將核心系統(tǒng)調(diào)用插件的過程實現(xiàn)為異步通信 。以前文的電子設(shè)備回收系統(tǒng)為例,在異步通信的架構(gòu)下,系統(tǒng)通過一個線程觸發(fā)插件啟動對某個設(shè)備的回收流程。之后,該線程無需一直等待回收結(jié)束,它可以去繼續(xù)回收別的設(shè)備。當設(shè)備回收結(jié)束后,插件會通過異步隊列告知核心系統(tǒng)。這樣的異步設(shè)計可以減少無謂的等待流程,明顯改善系統(tǒng)的responsiveness。
如果涉及到讀寫數(shù)據(jù)庫,為了能夠維持插件的獨立性,每個插件最好能夠擁有獨立的數(shù)據(jù)庫 。如果插件間有著無可避免的數(shù)據(jù)交互,則可以為核心系統(tǒng)配置一個中心數(shù)據(jù)庫,并通過它來進行數(shù)據(jù)中轉(zhuǎn)。
插件的的獨立數(shù)據(jù)庫
插件中心
核心系統(tǒng)在加載插件前,必須得知道 當前有哪些可用的插件 ,以及 這些插件在哪里可以獲取 。這要求系統(tǒng)有一個地方去管理插件,這就是 插件中心 (plug-in registry)的功能。插件中心類似于服務(wù)化架構(gòu)中服務(wù)注冊中心的作用,它保存了所有插件的基本信息,包括名稱、數(shù)據(jù)契約、通信協(xié)議、加載地址等。
我們可以簡單地將插件中心實現(xiàn)為一個本地的map
表,其中key可以是插件名稱,value為獲取插件的地址:
Map<String, String> registry = new HashMap<String, String>();
static {
//point-to-point access example
registry.put("iPhone6s", "Iphone6sPlugin");
//messaging example
registry.put("iPhone6s", "iphone6s.queue");
//restful example
registry.put("iPhone6s", "https://atlas:443/assess/iphone6s");
}
為了實現(xiàn)一些較為復雜的功能,如插件上下線通知等,我們還可以借助Apache ZooKeeper、ETCD這類的分布式協(xié)同系統(tǒng)實現(xiàn) 遠程插件中心 。
通信契約
通信契約定義了插件與核心系統(tǒng)之間的通信方式、交互行為和數(shù)據(jù)格式。通信方式可以是本地接口調(diào)用、REST、RPC、消息隊列等;交互行為則可以理解為插件對核心系統(tǒng)提供的接口,比如本地的函數(shù)/方法、REST的URI等;對本地插件而言,數(shù)據(jù)格式通常是一個類/結(jié)構(gòu)體,對遠程插件而言,常用的數(shù)據(jù)格式有JSON、XML、ProtoBuf等。
考慮電子設(shè)備回收系統(tǒng)的例子,系統(tǒng)有著如下定義的通信契約:
public interface AssessmentPlugin {
// 回收設(shè)備流程
public AssessmentOutput assess();
// 將該插件注冊到插件中心
public String register();
// 從插件中心去注冊
public String deregister();
}
public class AssessmentOutput {
// 回收報告,僅僅用于展示結(jié)構(gòu)給用戶看,核心系統(tǒng)無需了解該格式
public String assessmentReport;
// 用于標識該設(shè)備是否可以在二手市場上重新售賣
public Boolean resell;
// 表示該設(shè)備的價值
public Double value;
// 表示推薦的售賣價格
public Double resellPrice;
}
從該契約定義中可以看出,通信方式為本地接口調(diào)用(AssessmentPlugin
接口);它有著3個交互行為,assess()
為回收設(shè)備流程、register()
表示將該插件注冊到插件中心、deregister
表示去注冊;數(shù)據(jù)格式則是AssessmentOutput
類,它定義了回收流程的結(jié)果。
架構(gòu)評分
微內(nèi)核架構(gòu)的架構(gòu)評分
和之前介紹的分層架構(gòu)、管道架構(gòu)一樣,微內(nèi)核架構(gòu)同樣屬于單體架構(gòu),因此Simplicity和Overall cost是該架構(gòu)模式主要優(yōu)勢;而Elasticity、Fault tolerance和Scalability是主要劣勢。
另外,微內(nèi)核架構(gòu)的Testability、Deployability、Reliability、Modularity之所以能夠取得3顆星,得益于不同的功能能夠被拆分至獨立的插件上,特別地,運行時插件的增刪無需重新部署系統(tǒng)。 這使得系統(tǒng)能夠快速響應(yīng)需求變更,具備很高的擴展性 。比如對于前面的電子設(shè)備回收系統(tǒng),如果需要新增一種新的電子設(shè)備回收流程,只需新增一個插件即可;如果某種設(shè)備不再需要回收,則去除對應(yīng)插件即可。
微內(nèi)核架構(gòu)比較特別的一點是,它既可以是technically partitioned,也可以是domain partitioned,這取決于核心系統(tǒng)的實現(xiàn)方式,前文也有介紹。
總結(jié)
Robert C.Martin曾經(jīng)說過, 軟件開發(fā)技術(shù)發(fā)展的歷史就是一個如何想方設(shè)法方便地增加插件,從而構(gòu)建一個可擴展、可維護的系統(tǒng)架構(gòu)的故事 。在敏捷開發(fā)的潮流之下,需求的變更如同家常便飯,系統(tǒng)不應(yīng)該因為某一部分發(fā)生變更從而導致其他不相關(guān)的部分出現(xiàn)問題。將系統(tǒng)設(shè)計為微內(nèi)核架構(gòu),就等于構(gòu)建起了一面變更無法逾越的防火墻,插件發(fā)生的變更就不會影響系統(tǒng)的核心業(yè)務(wù)邏輯。
微內(nèi)核架構(gòu)的設(shè)計思想,能夠極大提升系統(tǒng)的可擴展性和健壯性 ,在其他的一些軟件方法論里,我們也隱約能看到它的影子。比如在領(lǐng)域驅(qū)動設(shè)計中,領(lǐng)域?qū)?/strong>就相當于核心系統(tǒng),它定義了系統(tǒng)的核心業(yè)務(wù)邏輯;基礎(chǔ)設(shè)施層則相當于插件,切換不同的基礎(chǔ)設(shè)施并不會影響系統(tǒng)的業(yè)務(wù)邏輯,這得益于基礎(chǔ)設(shè)施層依賴倒置的設(shè)計原則。
當然,作為微內(nèi)核架構(gòu)也有著一些缺點,它天然具備了單體架構(gòu)的一些劣勢,比如核心系統(tǒng)作為架構(gòu)的中心節(jié)點并不具備Fault tolerance能力。因此,該架構(gòu)模式往往被廣泛應(yīng)用于一些著重提供很強的用戶定制化功能的小型產(chǎn)品,如VS Code等,它們對系統(tǒng)的Elasticity、Fault tolerance和Scalability并沒有很高的要求。
每種架構(gòu)模式都有其合適的應(yīng)用場景,只有熟悉常用的幾種架構(gòu)模式,才能設(shè)計出更好的軟件系統(tǒng)。
-
Web
+關(guān)注
關(guān)注
2文章
1287瀏覽量
71400 -
IDE
+關(guān)注
關(guān)注
0文章
352瀏覽量
47742 -
微內(nèi)核架構(gòu)
+關(guān)注
關(guān)注
0文章
5瀏覽量
6604 -
瀏覽器
+關(guān)注
關(guān)注
1文章
1040瀏覽量
36287
發(fā)布評論請先 登錄
晶體管架構(gòu)的演變過程

微服務(wù)器架構(gòu)幾種典型的基礎(chǔ)框架,你了解嗎?
揭秘云計算架構(gòu)的分層奧秘
微服務(wù)容器化部署好處多嗎?
容器化能替代微服務(wù)嗎?兩者有何區(qū)別
寶藏級微服務(wù)架構(gòu)工具合集
k8s微服務(wù)架構(gòu)就是云原生嗎?兩者是什么關(guān)系
SSR與微服務(wù)架構(gòu)的結(jié)合應(yīng)用
GPU服務(wù)器AI網(wǎng)絡(luò)架構(gòu)設(shè)計

架構(gòu)與設(shè)計 常見微服務(wù)分層架構(gòu)的區(qū)別和落地實踐

微服務(wù)架構(gòu)與容器云的關(guān)系與區(qū)別
入門級攻略:如何容器化部署微服務(wù)?
就服務(wù)器而言,ARM架構(gòu)與X86架構(gòu)有什么區(qū)別?各自的優(yōu)勢在哪里?
Proxyless的多活流量和微服務(wù)治理

評論