三、TubeMQ的存儲模式與管控措施
MQ裡最核心的是它的存儲模式,如下圖所示,右邊的存儲方案清單是一位叫陳大白的知乎使用者給我們提供的,左邊是TubeMQ的存儲方案。

TubeMQ采用的是按Topic組織記憶體+檔案的存儲執行個體方案來實作的,資料先寫到主記憶體,主記憶體寫滿之後切為備份記憶體,資料異步從備份記憶體刷到檔案完成資料寫入。它通過消費的偏移度來決定它是由主記憶體還是備記憶體還是檔案消費資料,這樣的話可以減輕系統的負擔,提高它的存儲量。
大家從右邊的存儲圖上面可以看到:Kafka、RocketMQ和京東2019年釋出JMQ,其實相差并不大。但是需要注意的是,每一種存儲模式在不同的資源要求下,它的性能名額和相應的量級是不一樣的。
因為我們做的是有損服務,有損的服務是怎麼回事呢?就是我們在機器斷電、沒有存儲或者沒有刷盤的情況下,資料就會丢失,在磁盤RAID10都無法恢複的磁盤故障情況下資料也會丢失。除了這兩種情況,其他的情況都不會丢。
因為上述兩類故障随時可能發生,因而TubeMQ其實不适合用做持久的反複消費、而又需要前後資料完全一緻的場景。那麼,我們為什麼要這麼做呢?我們是不是做不到多副本呢?其實也不是的。
問題就在于成本方面的考量。我們這樣做,如果橫向作比較,大家知道我們能夠省多少台機器嗎?換算成金錢的話能省多少嗎?
在這裡給大家提供一個資料:2019年11月8日,開源Kafka項目的LinkIn公司發表了一篇文章,他們7萬多條資料用了4000台機器,這個資訊大家網上可以查到。另一個是我們國内做大資料與應用相關場景公司的例子,采用原生Kafka做大資料接入,在2018年底也達到了7、8萬億的資料量,花了1500台萬兆機。
說回來,我們這種模式下需要多少台機器呢?我們現在達到35萬億的資料量用的也是1500台機器,在相同的前提下,我們對比外部MQ,使用的機器數量隻有它們的1/4、1/5。換算成人民币的話是多少?一台商用機大概是10萬左右,僅僅機器成本我們就可以節約到幾個億,這就是為什麼要采用這個方案的原因。
跟Kafka異步節點複制方案相比,我們隻需要1/4左右的機器量。當然,即便是用單複本,我們的性能也會比Kafka強很多,可以節約不少機器,相關資料可以看我們的測試報告。
TubeMQ所有的管控邏輯包括所有的API接口都是圍繞着它的存儲來做的,包括它的Topic的配置和流控的處理和資料的查詢、API的庫存等等。下圖所示的是TubeMQ最核心的API接口定義,主要分為4個章節。如果隻是使用的話,直接通過管控台操控就可以了,但如果你要精細化地去調控系統,就需要去了解API的定義了。
TubeMQ的管控子產品Master,是基于BDB嵌入式資料庫進行叢集的Broker節點管理。各個Broker配置的Topic資訊的資料存儲,隻要在标紅的操作欄裡操作,就會有一個狀态告知操作者目前處于什麼樣的過程,是基于執行操作還是隻讀隻寫或者是可讀寫的情況。還可以通過這個頁面查詢。本系統在Windows上面就可以運作起來,歡迎大家去試用。
TubeMQ的認證授權設計和傳統的也不太一樣,因為我們把TubeMQ的認證機做了重新的定義,具體可見下圖。
四、為什麼選擇開源?
第一,基于公司的開源政策要求:對内開源協同,對外形成技術影響力,是以我們選擇了開源。第二,從我們掌握的資訊來看,我們認為在這一領域開源TubeMQ,是可以對有需要的同學們産生實際價值的。第三,我們覺得開源是在打破壁壘。
在世界不同的角落,很多人都在研究這一問題,就像平行宇宙一樣,大家都在各自的宇宙裡面去研究和分析,互相之間沒有太多的交流,我們相信肯定有人比我們做得更好,有值得我們學習的地方,是以我們把它開源出來,形成一個大家都了解、可以互相學習的狀态,這樣對自己也是一種促進。基于以上這三點,我們最終選擇了開源。
在已經開源情況下為什麼還要去貢獻過給Apache呢?其實我也了解有很多做開發的同學不敢去用一些開源項目,因為有很多公司開源了一個項目,用着用着結果發現沒有人維護了。
為了解決這個問題,我們希望把它捐獻給一個中立的基金會,通過它已經成文的标準化流程,使項目成為一個大家可以接受的成熟項目,包括它的文檔化和多種接入的情況。即便原創團隊最後不接手這個項目了,後面也有人去接手它,使這個項目能夠持續向前改進。
是以我們把它捐獻給了基金會。為什麼選擇Apache呢?因為我們是專注于大資料場景的MQ,而Apache是基于大資料這個生态最為出名的社群,而我們也同樣也受惠于這個生态,是以理所當然就想回饋社群,将項目捐獻給Apache。前段時間TubeMQ已經成為了Apache的孵化項目。
五、TubeMQ的後續發展探讨
2020年上半年我們在開源的協同推廣下,内部接入的業務資料将會越來越多,日均接入量相信很快就會過40萬億。
我們的機器也将會由以前的TS60更新成BX2,它将會帶來什麼樣的變化呢?以往的機器是CPU 99%,磁盤IO是30~40%,根據最新的測試資料,在BX2上面變為CPU 30~40%,磁盤IO 99%。由此可見,我們需要把它磁盤的IO盡可能地降下來,或者選擇其他更合适的機器,這是需要去研究的。
另外,因為我們已經開源了,後續如何培養社群也是一個比較關鍵的點。目前來看,我們會基于協作的機制将它開源,無論是公司内還是公司外的同學,一起貢獻來把這個項目做大,我們會在自己擅長的領域把這個東西繼續夯實,大家可以根據自己的需要去使用我們的項目。
同時大家在使用的過程中如果能發現有些不完善的地方,也希望能通過社群貢獻出來,大家一起努力把這個項目做好。
其實我們不僅僅隻有MQ,我們同樣在做的還有彙聚層和采集層,在此之上還有管理層。我們的希望是把MQ這一塊做穩定以後,再将整體開源出來。我們會允許這一套系統接納不同的MQ,根據MQ不同的特點提供給外部業務使用,但對外部業務又是無感覺的。
六、Q&A
Q:張老師,你剛才做了TubeMQ和Kafka的對比,還介紹了TubeMQ内部的存儲結構,但是我發現它的内部存儲結構和Kafka的存儲沒有差别,你們隻多了一個備份緩存,我不知道為什麼你們隻是一個備份問題就可以把Kafka甩這麼遠?
A:Kafka是基于Partition的結構,一個Partition就會有一個檔案塊,而TubeMQ是基于Topic的,Partition已經是一個邏輯的概念。第二個不同是我們的記憶體是主備模式,你剛才已經提到了,為什麼多了一個記憶體塊就會快一些?寫記憶體更快基本上是共識,然後把一塊盤寫滿,寫滿了的切為備塊異步去刷到檔案,然後換塊記憶體繼續寫,這樣主備切換的話讀寫沖突就少了很多,整體就會更快一些。
我們為什麼改為這樣的存儲結構呢?像Kafka,1000×10的時候就已經變成了随機讀寫,跑起來資料名額不是很好,而且也不穩定。RocketMQ是所有資料存儲在一個檔案,每一個Partition又構造了一個檔案,這樣子就帶來一個問題:資料檔案會有寫入瓶頸,遇到流量增長時整個系統名額就上不來了。
JMQ是按Topic定義資料檔案,但每個Partition定義新的檔案,它比RocketMQ更寬泛一點,它資料不會集中到一個檔案,它是按照Topic來的,解決了RokcetMQ的一些問題。
TubeMQ是怎樣呢?TubeMQ是一個Topic一個資料檔案,不同的Topic有不同的檔案,我們沒有Partition。我們都是按Topic來定義存儲單元的,一個資料檔案 + 一個索引檔案。大家可以去分析一下,它們是各有特點,不同的場景下的表現特征是不一樣的,包括你的硬體場景,其實還是有很大差異的。