|
在這篇文章中,我們將介紹 MQTT Broker 集群在可擴(kuò)展性方面的一些改進(jìn)。 我們將主要關(guān)注 EMQX 內(nèi)部使用的數(shù)據(jù)庫(kù)引擎,以及它在 EMQX 5.0 版本中是如何改進(jìn)的。
在開始本文之前,我們需要了解 EMQX 集群中是數(shù)據(jù)是如何復(fù)制的:EMQX broker 將主題和客戶端的運(yùn)行時(shí)信息存儲(chǔ)在 Mnesia 數(shù)據(jù)庫(kù)中,有助于跨集群復(fù)制數(shù)據(jù)。
Mnesia 簡(jiǎn)介Mnesia 是一個(gè)開源數(shù)據(jù)庫(kù)管理系統(tǒng),由愛立信公司開發(fā)作為開放電信平臺(tái)( Open Telecom Platform )的一部分,最初是用來處理 ISP 級(jí)電信交換機(jī)中的配置和運(yùn)行時(shí)數(shù)據(jù)。EMQX 4.3 之前的版本使用其來存儲(chǔ)各種運(yùn)行時(shí)數(shù)據(jù),例如主題、路由、ACL 規(guī)則、告警等等。
MySQL、Postgres、MongoDB 等數(shù)據(jù)庫(kù)以及 Redis 和 memcached 等內(nèi)存存儲(chǔ)大家應(yīng)該都非常熟悉,對(duì) Mnesia 則可能不甚了解。但它確實(shí)有其獨(dú)特的優(yōu)勢(shì),可將上述產(chǎn)品的許多功能集成到一個(gè)簡(jiǎn)潔的應(yīng)用程序中。
Mnesia 有一個(gè)相當(dāng)學(xué)術(shù)的定義:一個(gè)嵌入式、分布式、事務(wù)型的 noSQL(非關(guān)系型)數(shù)據(jù)庫(kù)。聽起來有些復(fù)雜,我們接下來將逐一為大家解釋。
嵌入式MySQL 和 Postgres 等最廣泛使用的數(shù)據(jù)庫(kù)普遍采用客戶端—服務(wù)器模式:數(shù)據(jù)庫(kù)在單獨(dú)的進(jìn)程中運(yùn)行(通常在專用服務(wù)器上),業(yè)務(wù)應(yīng)用程序通過網(wǎng)絡(luò)或 UNIX 域套接字發(fā)送請(qǐng)求并等待答復(fù),通過這種方式來與數(shù)據(jù)庫(kù)交互。這種模式在很多方面都很方便,因?yàn)樗试S將業(yè)務(wù)邏輯與存儲(chǔ)分開并單獨(dú)管理。 但同時(shí)也有一些缺點(diǎn):與遠(yuǎn)程進(jìn)程交互不可避免地會(huì)增加每個(gè)請(qǐng)求的延遲。
相反,嵌入式數(shù)據(jù)庫(kù)與業(yè)務(wù)應(yīng)用程序則在相同的進(jìn)程中運(yùn)行。sqlite 是一個(gè)典型的嵌入式數(shù)據(jù)庫(kù)的例子。Mnesia 也屬于這一類:它與其他 EMQX 應(yīng)用程序在同一進(jìn)程中運(yùn)行。 從 Mnesia 表中讀取數(shù)據(jù)可以像讀取局部變量一樣快,因此我們可以在熱點(diǎn)中讀取數(shù)據(jù)庫(kù)數(shù)據(jù)而不會(huì)影響性能。
分布式我們之前提到過 Mnesia 是一個(gè)分布式數(shù)據(jù)庫(kù),這意味著數(shù)據(jù)表被網(wǎng)絡(luò)復(fù)制到不同的物理位置。對(duì)于分布式數(shù)據(jù)庫(kù),如果節(jié)點(diǎn)之間不共享任何物理資源(如 RAM 或磁盤),而是在應(yīng)用程序級(jí)別進(jìn)行協(xié)調(diào),這種類型稱為無共享架構(gòu) (SN)。 這種類型通常是首選,因?yàn)樗恍枰魏螌iT的硬件,并且可以水平擴(kuò)展。
Mnesia 應(yīng)用程序與 EMQX 一起運(yùn)行,有助于通過 Erlang 分發(fā)協(xié)議跨集群中的所有節(jié)點(diǎn)復(fù)制表更新。 這意味著業(yè)務(wù)應(yīng)用程序可以在本地讀取更新的數(shù)據(jù)。它還有助于提升容錯(cuò)性能:只要集群中有一個(gè)節(jié)點(diǎn)處于活動(dòng)狀態(tài),數(shù)據(jù)就是安全的。EMQX 依靠此功能實(shí)現(xiàn)跨集群復(fù)制路由信息。
事務(wù)型Mnesia 支持 ACID 事務(wù),這是嵌入式數(shù)據(jù)庫(kù)的一個(gè)非常獨(dú)特的功能。這意味著可以將多個(gè)讀取和更新操作組合在一起。一個(gè) Mnesia 事務(wù)具有原子性(必須完整或無任何效力)、一致性(盡管保證比 Postgres 更寬松)、隔離性(不影響其他事務(wù))和持久性。所有這些保證都在整個(gè)集群中保留。
在數(shù)據(jù)一致性關(guān)鍵場(chǎng)景中,EMQX 采用 Mnesia 事務(wù)。
NoSQL傳統(tǒng)的關(guān)系型數(shù)據(jù)庫(kù)使用一種稱為 SQL 的特殊查詢語(yǔ)言與數(shù)據(jù)庫(kù)進(jìn)行交互,這種數(shù)據(jù)庫(kù)通常使用 ORM(對(duì)象關(guān)系映射) 來加快開發(fā)速度。 另一方面,Mnesia 沒有專門的查詢語(yǔ)言:它使用 Erlang(或 Elixir)作為查詢語(yǔ)言,因此不需要 ORM。 它直接使用 Erlang 術(shù)語(yǔ)進(jìn)行查詢操作,與業(yè)務(wù)邏輯的集成非常順暢。
架構(gòu)在 Mnesia 集群中,所有節(jié)點(diǎn)都是平等的。 每個(gè)節(jié)點(diǎn)都可以存儲(chǔ)任何表的副本、啟動(dòng)事務(wù)并訪問這些表。 Mnesia 集群使用全網(wǎng)狀拓?fù)洌好總(gè)節(jié)點(diǎn)都與集群中的所有其他節(jié)點(diǎn)對(duì)話。 每個(gè)事務(wù)都被復(fù)制到集群中的所有節(jié)點(diǎn),如下圖所示:
Mnesia 集群
針對(duì) CAP 原則(在一致性、可用性、分區(qū)容錯(cuò)性三個(gè)要素中選擇兩個(gè)),Mnesia 默認(rèn)為 AP(可用性、分區(qū)容錯(cuò)性)。
挑戰(zhàn)綜上所述,Mnesia 數(shù)據(jù)庫(kù)有一系列獨(dú)特的功能,并都在 EMQX 中得到了使用。現(xiàn)在,我們要談?wù)勊娜秉c(diǎn)以及我們改進(jìn)它的原因。
盡管 Mnesia 與硬件無關(guān),但它最初的開發(fā)考慮了特定的集群架構(gòu):一組服務(wù)器,通過快速、低延遲的局域網(wǎng)實(shí)現(xiàn)互連。
在理想條件下,網(wǎng)狀拓?fù)浣Y(jié)構(gòu)可以減少事務(wù)復(fù)制延遲:節(jié)點(diǎn)之間的所有通信都可以并行完成,無需任何中介。 然而,它限制了集群的水平可擴(kuò)展性,因?yàn)楣?jié)點(diǎn)之間的鏈接數(shù)量和節(jié)點(diǎn)數(shù)量之間是平方關(guān)系。隨著節(jié)點(diǎn)數(shù)量的增加,保持所有節(jié)點(diǎn)完全同步的成本越來越高,事務(wù)的性能也會(huì)下降。
節(jié)點(diǎn)的同等性質(zhì)和傳統(tǒng)的集群范式疊加后,使得更換單個(gè)節(jié)點(diǎn)變得容易,但是可以同時(shí)加入集群的節(jié)點(diǎn)數(shù)量受到限制。
于是我們就面臨這樣一個(gè)局面:集群部署在地理冗余的云環(huán)境中,一切都是動(dòng)態(tài)的和暫時(shí)的,節(jié)點(diǎn)在自動(dòng)擴(kuò)展組中運(yùn)行,我們希望它們一直在波動(dòng)狀態(tài)。
為了應(yīng)對(duì)這些挑戰(zhàn),我們對(duì) Mnesia 進(jìn)行了擴(kuò)展,稱之為 Mria。
對(duì)策:Mria 的引入Mria 是 Mnesia 的開源擴(kuò)展版本,它為 Mnesia 帶來了最終一致性。
Mria 從全網(wǎng)狀拓?fù)浼軜?gòu)轉(zhuǎn)變?yōu)榫W(wǎng)狀+星型拓?fù)浼軜?gòu)。 每個(gè)節(jié)點(diǎn)承擔(dān)兩個(gè)角色之一:核心(core)或復(fù)制者(replicant)。
核心(core)節(jié)點(diǎn)的行為很像常規(guī)的 Mnesia 節(jié)點(diǎn):它們以全網(wǎng)狀連接,每個(gè)節(jié)點(diǎn)都可以發(fā)起寫事務(wù)、持有鎖等。核心節(jié)點(diǎn)很大程度上都是靜態(tài)和持久的。
另一方面,復(fù)制(replicant)節(jié)點(diǎn)不參與事務(wù)。它們連接到某一個(gè)核心節(jié)點(diǎn),并被動(dòng)地從中復(fù)制事務(wù)。這意味著不允許復(fù)制節(jié)點(diǎn)自行執(zhí)行任何寫操作。相反,它們要求核心節(jié)點(diǎn)代表它們更新數(shù)據(jù)。同時(shí),它們擁有數(shù)據(jù)的完整本地副本,因此讀取訪問速度也同樣快。
Mria 集群
可以將 Mria 看作是客戶端-服務(wù)器和嵌入式數(shù)據(jù)庫(kù)的組合:通過服務(wù)器寫入,但在本地讀取。
這種集群拓?fù)浼軜?gòu)解決了兩個(gè)問題:
由于復(fù)制節(jié)點(diǎn)不參與寫入,因此當(dāng)向集群添加更多復(fù)制節(jié)點(diǎn)時(shí),事務(wù)延遲不會(huì)受到影響,從而允許創(chuàng)建更大的 EMQX 集群。
此外,復(fù)制節(jié)點(diǎn)被設(shè)計(jì)為暫時(shí)的。 添加或刪除它們不會(huì)改變數(shù)據(jù)冗余,因此可以將它們放在自動(dòng)擴(kuò)展組中,從而實(shí)現(xiàn)更好的 DevOps 實(shí)踐。
在下一篇文章中,我們將更詳細(xì)地討論如何配置 EMQX 來充分 Mria 的優(yōu)勢(shì)。
本系列中的其它文章原創(chuàng)文章,作者:EMQ,如若轉(zhuǎn)載,請(qǐng)注明出處:https://www.emqx.com/zh/blog/mqtt-broker-clustering-part-3-challenges-and-solutions-of-emqx-horizontal-scalability