從百萬(wàn)到億級(jí):EMQX 5.0 新架構(gòu)的利與弊
1.Mnesia:Erlang語(yǔ)言中的分布式數(shù)據(jù)庫(kù)
在EMQX 5.x版本之前,集群數(shù)據(jù)存儲(chǔ)采用的是Erlang/OTP自帶的實(shí)時(shí)分布式數(shù)據(jù)庫(kù)管理系統(tǒng)——Mnesia。Mnesia是用Erlang語(yǔ)言實(shí)現(xiàn)的,并且與Erlang緊密耦合,這也造就了它的獨(dú)特之處,它幾乎將Erlang變成了一種數(shù)據(jù)庫(kù)編程語(yǔ)言。Mnesia可以說(shuō)是專為用Erlang編寫(xiě)的工業(yè)級(jí)電信應(yīng)用程序而設(shè)計(jì)的,并提供了支持高容錯(cuò)電信級(jí)系統(tǒng)所必需的常用功能。它試圖解決典型電信系統(tǒng)所需的所有數(shù)據(jù)管理問(wèn)題,并具有許多傳統(tǒng)DBMS通常不具備的功能。其提供的特性主要包括:
- 快速實(shí)時(shí)的鍵值查找;
- 復(fù)雜的非實(shí)時(shí)性查詢;
- 分布式數(shù)據(jù)支持;
- 高容錯(cuò)性;
- 復(fù)雜的數(shù)據(jù)對(duì)象。
Mnesia通常支持兩種數(shù)據(jù)訪問(wèn)模式:本地模式和遠(yuǎn)程模式。本地模式采用的是全連接、點(diǎn)對(duì)點(diǎn)的復(fù)制模式,即節(jié)點(diǎn)中的數(shù)據(jù)表會(huì)復(fù)制到集群所有節(jié)點(diǎn)中;而在遠(yuǎn)程模式中,當(dāng)要訪問(wèn)的表沒(méi)有本地副本時(shí),會(huì)通過(guò)RPC調(diào)用讀取遠(yuǎn)程具有數(shù)據(jù)表副本的節(jié)點(diǎn)。本地模式訪問(wèn)的缺點(diǎn)是集群擴(kuò)展性差,且存在腦裂的風(fēng)險(xiǎn),但優(yōu)點(diǎn)也顯而易見(jiàn),因?yàn)榧褐忻總€(gè)節(jié)點(diǎn)都擁有集群全量的數(shù)據(jù),故而可以通過(guò)本地查詢來(lái)提高檢索效率。
相對(duì)于遠(yuǎn)程模式的網(wǎng)絡(luò)操作而言,本地讀取數(shù)據(jù)的延遲要比遠(yuǎn)程模式的網(wǎng)絡(luò)延遲小幾個(gè)數(shù)量級(jí)。另外,這種實(shí)現(xiàn)方式也能提高集群的分布式容錯(cuò)能力,只要保證集群中仍有存活的節(jié)點(diǎn),集群數(shù)據(jù)就是全量的、安全的。所以在早期的EMQX實(shí)現(xiàn)中,默認(rèn)使用的就是本地模式。尤其是在消息分發(fā)時(shí),通過(guò)本地查詢Mnesia數(shù)據(jù)庫(kù)中的路由表數(shù)據(jù)快速定位到消息要投遞的節(jié)點(diǎn),可以實(shí)現(xiàn)個(gè)位數(shù)毫秒的高效、低延時(shí)的消息分發(fā)操作。
2.Mnesia的弊端:復(fù)制帶來(lái)的開(kāi)銷
如前文所述,由于Mnesia集群使用全網(wǎng)狀的連接架構(gòu),集群中每個(gè)節(jié)點(diǎn)都會(huì)與其它所有的節(jié)點(diǎn)建立連接,每個(gè)節(jié)點(diǎn)產(chǎn)生的事務(wù)也都被會(huì)復(fù)制到集群中的所有節(jié)點(diǎn)上。這就導(dǎo)致集群的整體可擴(kuò)展性差:首先,集群中每增加一個(gè)節(jié)點(diǎn),集群數(shù)據(jù)同步的開(kāi)銷也會(huì)隨之增大,且由于網(wǎng)絡(luò)問(wèn)題導(dǎo)致的集群腦裂的風(fēng)險(xiǎn)也會(huì)增加。其次,集群中每個(gè)節(jié)點(diǎn)都要能夠承載全量的集群數(shù)據(jù),相對(duì)于Mnesia這種經(jīng)常將數(shù)據(jù)存放在內(nèi)存中的應(yīng)用場(chǎng)景來(lái)說(shuō),服務(wù)器資源的投入也會(huì)跟著集群規(guī)模的擴(kuò)展而增加,對(duì)機(jī)器配置和性能的要求也會(huì)越來(lái)越高。集群節(jié)點(diǎn)間的數(shù)據(jù)復(fù)制成本和服務(wù)器資源投入這兩個(gè)問(wèn)題一直是限制集群擴(kuò)展性的核心問(wèn)題。
Mnesia 網(wǎng)狀拓?fù)浼軜?gòu)
3.Mria:從全網(wǎng)狀到單復(fù)制
為了解決Mnesia全網(wǎng)狀復(fù)制帶來(lái)的問(wèn)題,EMQX 5.x版本中引入了新的數(shù)據(jù)層解決方案實(shí)現(xiàn)——Mria。Mria對(duì)Mnesia進(jìn)行了封裝,其核心訴求是在實(shí)現(xiàn)數(shù)據(jù)的本地讀寫(xiě)的基礎(chǔ)上,盡可能地減少集群節(jié)點(diǎn)復(fù)制的開(kāi)銷。
Mria將原有的全網(wǎng)狀復(fù)制的Mnesia節(jié)點(diǎn)擴(kuò)展成兩種不同的角色節(jié)點(diǎn)——核心節(jié)點(diǎn)(Core)和復(fù)制節(jié)點(diǎn)(Replicant)。核心節(jié)點(diǎn)與傳統(tǒng)的Mnesia節(jié)點(diǎn)行為類似,仍舊采用全網(wǎng)狀的復(fù)制模式,所有核心節(jié)點(diǎn)之間的事務(wù)仍會(huì)復(fù)制到其它核心節(jié)點(diǎn)上。復(fù)制節(jié)點(diǎn)則不直接參與Mnesia事務(wù)處理,而是連接到集群中某個(gè)核心節(jié)點(diǎn)上,被動(dòng)地復(fù)制來(lái)自核心節(jié)點(diǎn)的數(shù)據(jù)更新。為此,核心節(jié)點(diǎn)還同時(shí)擁有另外一項(xiàng)重要的工作,即處理連接到自身的所有復(fù)制節(jié)點(diǎn)的數(shù)據(jù)處理。
由于復(fù)制節(jié)點(diǎn)不再參與集群中事務(wù)的同步工作,只有少數(shù)的核心節(jié)點(diǎn)會(huì)實(shí)時(shí)地同步事務(wù),而復(fù)制節(jié)點(diǎn)只是復(fù)制對(duì)應(yīng)核心節(jié)點(diǎn)的數(shù)據(jù),所以這種實(shí)現(xiàn)模式在復(fù)制節(jié)點(diǎn)可以擁有集群全量數(shù)據(jù)以實(shí)現(xiàn)高效的本地?cái)?shù)據(jù)檢索的前提下,同時(shí)能夠減少整個(gè)集群的事務(wù)同步開(kāi)銷。借助于復(fù)制節(jié)點(diǎn)的特性,當(dāng)更多的設(shè)備需要接入到集群中時(shí),只需要相應(yīng)地?cái)U(kuò)展復(fù)制節(jié)點(diǎn)的數(shù)量,讓這些節(jié)點(diǎn)承載設(shè)備連接,而又不會(huì)直接增加核心節(jié)點(diǎn)寫(xiě)操作的延時(shí),從而達(dá)到擴(kuò)展集群規(guī)模的效果。
Mria 單復(fù)制拓?fù)浼軜?gòu)
但是Mria這種架構(gòu)實(shí)現(xiàn)也不是銀彈,雖然它可以解決全網(wǎng)狀復(fù)制帶來(lái)的數(shù)據(jù)同步問(wèn)題,但是依然無(wú)法很好地處理所有節(jié)點(diǎn)都要承載集群全量數(shù)據(jù)的問(wèn)題。
另外需要特別注意的是,為了提高M(jìn)ria架構(gòu)的復(fù)制效率,EMQX官方在Erlang/OTP實(shí)現(xiàn)的基礎(chǔ)上引入了一個(gè)叫做post-commit鉤子的實(shí)現(xiàn)。如果要應(yīng)用新的Mria架構(gòu),需要使用有此補(bǔ)丁的Erlang/OTP庫(kù),否則集群會(huì)自動(dòng)降級(jí)到Mnesia的實(shí)現(xiàn)模式。遺憾的是,到目前為止,該新特性并未合并到Erlang/OTP官方倉(cāng)庫(kù)中,需要研發(fā)人員自己構(gòu)建帶有此補(bǔ)丁的依賴庫(kù)。
PR: mnesia: Add post-commit hook #5926
4.AMQ 2.0:基于角色的路由分發(fā)
AMQ是中國(guó)移動(dòng)智慧家庭運(yùn)營(yíng)中心自研的基于開(kāi)源EMQX實(shí)現(xiàn)的物聯(lián)網(wǎng)連接中間件。為了增加集群的擴(kuò)展能力,我們?cè)?.0版本中引入了Mria開(kāi)源實(shí)現(xiàn)的新特性,用于解決集群節(jié)點(diǎn)復(fù)制的開(kāi)銷問(wèn)題。同時(shí),為了解決所有節(jié)點(diǎn)需要承載集群全量數(shù)據(jù)的問(wèn)題,我們?cè)O(shè)計(jì)了新的集群數(shù)據(jù)復(fù)制實(shí)現(xiàn)——連接分發(fā)引擎:一種基于節(jié)點(diǎn)角色進(jìn)行訂閱/復(fù)制的路由分發(fā)機(jī)制。
路由數(shù)據(jù)是物聯(lián)網(wǎng)連接集群中的核心數(shù)據(jù),它存儲(chǔ)設(shè)備訂閱主題與集群節(jié)點(diǎn)的映射關(guān)系,在消息發(fā)布時(shí)根據(jù)消息主題信息查找所有匹配的節(jié)點(diǎn),用于集群內(nèi)節(jié)點(diǎn)間的消息派發(fā)。在EMQX的實(shí)現(xiàn)中,路由數(shù)據(jù)存在于集群中的所有節(jié)點(diǎn)上??蛻舳说闹黝}訂閱數(shù)據(jù),則只保存在連接所在的節(jié)點(diǎn)上,用于節(jié)點(diǎn)內(nèi)部派發(fā)消息到客戶端。當(dāng)客戶端連接到集群某個(gè)節(jié)點(diǎn)訂閱某個(gè)新的主題時(shí),就會(huì)生成一條路由數(shù)據(jù),該數(shù)據(jù)最終會(huì)同步到集群所有節(jié)點(diǎn)上,每個(gè)節(jié)點(diǎn)都可以通過(guò)本地查詢找到任意主題對(duì)應(yīng)的訂閱節(jié)點(diǎn)列表。當(dāng)客戶端發(fā)布消息時(shí),連接所在節(jié)點(diǎn)會(huì)根據(jù)消息主題檢索路由數(shù)據(jù)得到所有訂閱節(jié)點(diǎn)的信息,然后將消息派發(fā)到這些節(jié)點(diǎn)上。
Mria實(shí)現(xiàn)的一個(gè)問(wèn)題就在于,集群中很多節(jié)點(diǎn)復(fù)制了本身就不需要的路由數(shù)據(jù)。設(shè)想這樣一種場(chǎng)景:一個(gè)智能門(mén)鎖和一個(gè)智能臺(tái)燈分別連接到集群中的NodeA和NodeB節(jié)點(diǎn)上,并且分別訂閱了主題TopicA和TopicB。由于EMQX實(shí)現(xiàn)的特性,這兩個(gè)節(jié)點(diǎn)都會(huì)存儲(chǔ)一條包含TopicA和TopicB的路由數(shù)據(jù)。但由于門(mén)鎖和臺(tái)燈之間不會(huì)直接互相發(fā)布消息,對(duì)這兩個(gè)節(jié)點(diǎn)來(lái)說(shuō),他們都存儲(chǔ)了一條永遠(yuǎn)也不會(huì)用到的路由數(shù)據(jù)。同理,當(dāng)集群中接入的設(shè)備越來(lái)越多時(shí),每個(gè)節(jié)點(diǎn)上都會(huì)存在大量無(wú)用的路由數(shù)據(jù)記錄。這不僅會(huì)增加服務(wù)器資源的投入,還會(huì)導(dǎo)致查詢性能的降低,另外在新節(jié)點(diǎn)加入集群時(shí),還會(huì)導(dǎo)致數(shù)據(jù)復(fù)制時(shí)間的增加,降低節(jié)點(diǎn)的接入效率。
在AMQ 2.0實(shí)現(xiàn)的路由分發(fā)機(jī)制中,每個(gè)節(jié)點(diǎn)都有一個(gè)數(shù)據(jù)復(fù)制角色:DB(Database),SVC(Service)或者CONN(Connection)。其中只有少數(shù)的DB角色節(jié)點(diǎn)才擁有全量的集群數(shù)據(jù),在集群中承擔(dān)“數(shù)據(jù)中心”的角色。DB節(jié)點(diǎn)負(fù)責(zé)根據(jù)可配置的訂閱策略將路由數(shù)據(jù)分發(fā)給對(duì)應(yīng)的SVC或CONN節(jié)點(diǎn)。另外,SVC和CONN節(jié)點(diǎn)并不會(huì)簡(jiǎn)單地復(fù)制DB節(jié)點(diǎn)的所有路由數(shù)據(jù),而是根據(jù)可配置的角色策略選擇性地復(fù)制自己所需要的數(shù)據(jù)。這樣,這些節(jié)點(diǎn)存儲(chǔ)的數(shù)據(jù)就是有限的,并不會(huì)隨著集群數(shù)據(jù)量的增加而增加,并且仍舊采取本地查詢的方式檢索數(shù)據(jù),不會(huì)影響消息派發(fā)時(shí)數(shù)據(jù)檢索的效率。此外,由于不需要同步集群全量數(shù)據(jù),每個(gè)SVC和CONN節(jié)點(diǎn)都可以做到快速接入、快速完成存量數(shù)據(jù)的復(fù)制。
AMQ基于角色的路由分發(fā)拓?fù)浼軜?gòu)
5.總結(jié)
無(wú)論是EMQX 4.x的Mnesia實(shí)現(xiàn),還是EMQX 5.x的Mria實(shí)現(xiàn),亦或是AMQ 2.0的路由分發(fā)實(shí)現(xiàn),目的都是一樣的:在確保數(shù)據(jù)讀寫(xiě)效率的前提下,盡可能地?cái)U(kuò)展集群的規(guī)模。