騰訊自研萬億級消息中間件TubeMQ捐贈給Apache!

導語 | 近日,雲+社區技術沙龍“騰訊開源技術”圓滿落幕。本次沙龍邀請了多位騰訊技術專家圍繞騰訊開源與各位開發者進行探討,深度揭祕了騰訊開源項目TencentOS tiny、TubeMQ、Kona JDK、TARS以及MedicalNet。本文是對張國成老師演講的整理。

本文要點:

  • Message Queue 的原理和特點;
  • TubeMQ相關實現原理及使用介紹;
  • TubeMQ後續的發展和探討。

一、Message Queue 簡介

對於Message Queue(以下簡稱MQ),Wiki百科上的定義指:不同進程之間或者相同進程不同線程之間的一種通訊方式,它是一種通訊方式。

那我們爲什麼要採用MQ呢?這是由MQ的特點來決定的。第一是因爲它可以整合多個不同系統共同協作;第二是它可以解耦,進行數據傳遞和處理;第三是它可以做峯值的緩衝處理,我們平常接觸到的像Kafka、RocketMQ、Pulsar等基本上也都有這樣的特點。

那作爲大數據場景下的MQ又有什麼特點呢?從我個人的理解來說,就是高吞吐低延時,系統儘可能地穩定,成本儘可能地低,協議也不需要特別地複雜,特別是水平擴展能力要儘可能的高。

因爲像海量數據基本上都是到百億、千億、萬億,比方說我們自己的生產環境可能一個月、一年的時間就會翻一番,如果沒有橫向的擴展能力,系統就很容易出現各種問題。

二、TubeMQ實現原理及使用介紹

1.TubeMQ的特點

那麼,騰訊自研的TubeMQ又有什麼樣的特點呢?TubeMQ屬於萬億級分佈式消息中間件,專注於海量數據下的數據傳輸和存儲,在性能、可靠性,和成本方面具有獨特的優勢。

針對大數據場景的應用,我們給出了一個測試方案(詳細方案在騰訊TubeMQ開源docs目錄裏可以查詢得到)。首先我們要做一個實際應用場景定義,在這個定義之下,再進行系統數據的收集整理。結果是:我們的吞吐量達到了14萬的TPS,消息時延可以做到5ms以內。

可能有些人會感到好奇,因爲有很多研究報告都分析過,同樣的分佈式發佈訂閱消息系統,例如Kafka這種,都能達到上百萬的TPS。相比來說,我們的數據會不會顯得太差?

其實這裏是有一個前提的,那就是:我們是在1000個Topic中,併爲每個Topic配置10個Partition的場景下達到的性能指標。對於Kafka,它或許可以達到百萬級的TPS,或許時延可以降到很低,但在我們的大數據的場景下,就遠遠到不了這個量級。

我們的系統在線上已經穩定運行了7年的時間,系統的架構採用的是瘦客戶端、偏服務器管控模型。這樣的技術特點就決定了它相應的應用場景。比如實時的廣告推薦、海量的數據上報、指標&監控、流處理、以及IOT場景下的數據上報等。

部分數據有損是可以允許的,因爲大不了重複再報一下也可以解決,但是考慮到數據的量級實在太大,所以只能犧牲部分的可靠性來換取高性能的數據接入。

2.TubeMQ的系統架構 

TubeMQ系統架構是怎樣的?如下圖所示,它通過一個SDK與外部交互,當然直接通過我們定義的TCP協議實現對接也是可以的。

值得注意的是:TubeMQ是純Java編寫的,它擁有Master HA的協調節點,採用弱zk來管理Offset。在消息存儲模式上也同樣進行了改進,調整了數據可靠性的方案,採用的是磁盤RAID10多副本+快速消費,而非多Broker節點多副本的方案,而且啓用了元數據自管理模式等。

3.TubeMQ的研發歷程

如下圖所示,自有數據記錄以來,我們一共經歷了四個階段,從引入到改進再到開始自研,再到現在的自我創新。從2013年6月最開始的200億,到2019年11月的35萬億,預計2020年能達到40萬億。

總的來說,這也是我們當初要選擇自研的重要的原因。因爲當數據量還不大的時候,比如在10億或者是10億量級以下,用什麼樣MQ其實都是可以的。但是一旦達到百億、百億到千億、千億到萬億甚至是萬億以上數據量的時候,越來越多的制約因素就會相繼出現,包括系統的穩定性、性能以及機器成本和運維成本等問題。

我們現網TubeMQ擁有1500臺的機器,而1500臺機器就只需要用到一個左右的人力來運維就可以了(非全職的兩個人)。對於我們的Broker存儲服務器,能夠做到上線持續運行4個月不重啓,這些都是我們在原基礎之上所做的改進和創新帶來的。

4.TubeMQ與其他MQ的橫向比較

下圖的這個表格是TubeMQ與其他MQ橫向比較的數據情況,我們項目是開源的,大家如果感興趣的話可以直接去驗證一下。總的來說,TubeMQ比較適合需要高性能、低成本又容許極端情況下有數據損失的場景,是經得起實踐考驗的。

三、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來定義存儲單元的,一個數據文件 + 一個索引文件。大家可以去分析一下,它們是各有特點,不同的場景下的表現特徵是不一樣的,包括你的硬件場景,其實還是有很大差異的。

發佈了339 篇原創文章 · 獲贊 238 · 訪問量 23萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章