RocketMQ學習筆記【一】RocketMQ簡介

一、爲什麼選用RocketMQ

       目前主流的MQ有RocketMQ、Kafka、RabbitMQ、ActiveMQ等,那麼開發者應該如何選用合適的MQ中間件呢?(面試官可能也會問爲什麼你們公司使用某個MQ)。個人覺得以下幾個方面都是在MQ選擇需要考慮的:

1、目前來看,每種MQ都有自身的優缺點,要結合這些MQ的特性比對我們的實際業務場景,選出最適合業務的。有的業務可能追求高吞吐量,可靠性要求低一些,比如日誌系統;有的業務可能追求高可靠性,數據不能丟失,吞吐量可以小一些,比如交易系統。要明確不是根據技術選擇,而是根據實際業務場景選擇;

2、所選MQ的可維護性和可拓展性。小公司的話,如果是服務部署在雲服務器上,現在基本雲服務廠商都會提供配套的MQ中間件,比如阿里雲的ons、華爲雲DMS,成本可以承受的話,可以直接配套使用,界面友好,維護簡單。大廠的話,因爲上述MQ可能與實際的業務匹配度還是不夠以及自身技術儲備足夠,會選擇自己開發或者對開源產品進行二次開發,這就需要考慮可拓展性。如果二次開發對開源產品進行定製,需要考慮選取MQ的開發語言。比如,Kafka是用Scala開發的,RabbitMQ是用的Erlang語言,這就對使用者的相關開發語言能力提出了要求,你如果想改造Kafka更貼合實際業務,最基本的必須要熟練掌握Scala才行吧;

3、選擇開源MQ的話,也要考慮社區的活躍性。社區的力量是巨大的,社區越活躍,能提供的支持就越多,使用中發現了問題也能推動產品迭代版本解決。選擇一個小衆冷門的MQ,如果出了問題,可能得到的支持有限,難以排查問題。

講了這麼多,看一下RocketMQ官網上是如何說爲什麼選用RocketMQ的?

    “Based on our research, with increased queues and virtual topics in use, ActiveMQ IO module reaches a bottleneck. We tried our best to solve this problem through throttling, circuit breaker or degradation, but it did not work well. So we begin to focus on the popular messaging solution Kafka at that time. Unfortunately, Kafka can not meet our requirements especially in terms of low latency and high reliability, see here for details.” 

        RocketMQ官網鏈接:http://rocketmq.apache.org/docs/motivation/

大致就是說基於研究,隨着消息隊列queue的增加以及virtual topic的使用,ActiveMQ IO模塊遇到了瓶頸。雖然做了種種努力嘗試進行解決,但是效果並不理想。於是,開始關注流行的消息傳遞解決方案Kafka。不幸的是,Kafka不能滿足我們的要求,特別是在低延遲和高可靠性方面。在附的鏈接中,提到了

       “Kafka是一個分佈式流媒體平臺,它源自於日誌聚合案例。它不需要太高的併發性。在阿里巴巴的一些大型案例中,我們發現原來的模式已經不能滿足我們的實際需求。因此,我們開發了一個名爲rocketmq的消息傳遞中間件,它可以處理廣泛的用例,從傳統的發佈/訂閱場景到要求高容量、不允許消息丟失的實時事務系統。現在,在阿里巴巴,Rocketmq集羣每天處理超過5000億個事件,爲超過3000個核心應用程序提供服務。

並且給出了爲什麼Kafka不能支持更多分區(Partition)的原因:

1、Kafka每個分區Partition存儲整個消息數據。雖然每個分區都是有序地寫入磁盤的,但是隨着同時寫入分區的數量增加,從操作系統的角度來看,寫入變得隨機。

2、由於數據文件分散,很難使用LinuxIO組提交機制。

這裏要簡單介紹一下Kafka的一點知識,Kafka中每個Topic會對應多個分區Partition(至少有一個Partition),同一個Topic下的不同Partition包含的消息是不同的,並且同一Topic的不同分區會分配在不同的Broker(可以簡單認爲是一臺物理服務器)上。Partition在邏輯上對應一個Log,Log是一個邏輯概念,可以對應到磁盤上的一個文件夾。在 Kafka中,生產者發送消息,實際上是把消息寫入分區Partition對應的Log中。Log由多個Segment段組成,每個Segment對應一個日誌文件和索引文件。正如第一點所說的,雖然 Kafka採用順序I/O,每次只向最新的Segment追加消息數據,但這只是每個Partition內部的寫入,同時有多個Partition進行寫入操作,在操作系統來看就是隨機寫入了。因爲上面Topic、Log和Segment的設計,消息數據文件確實是分散的。

再來看看RocketMQ是如何支持多分區的:

screenshot

                                                                                  圖片來自官網

1、所有消息數據都存儲在提交日誌文件中。所有寫入都是完全連續的,而讀取是隨機的;

2、消息隊列(ConsumeQueue)存儲實際的用戶消費位置信息(Offset in CommitLog),這些信息也按順序刷新到磁盤。

每個消費隊列都是輕量級的,並且包含有限數量的元數據。

對磁盤的訪問是完全連續的,這樣可以避免磁盤鎖爭用,並且在創建大量隊列時不會導致很高磁盤IO等待。

RocketMQ中寫雖然是順序寫,但是讀卻變成了隨機讀。(消費者)消息消費時將首先讀取ConsumeQueue,然後再讀Commit Log。這樣在最壞的情況下,這個過程會帶來一定的成本。

因爲要保證Commit Log 與 Consume Queue完全的一致,這會給編程帶來額外的複雜性。

設計動機:

1、隨機讀取。儘可能多地讀取以增加頁面緩存命中率,並減少讀取IO操作。所以大內存還是比較可取的。如果累積了大量的消息,讀取性能會嚴重下降嗎?答案是否定的,原因如下:

       即使消息的大小隻有1KB,系統也會提前讀取更多的數據,參考pagecache prefetch。這意味着,對於後續數據讀取,將執行對主內存的訪問,而不是緩慢的磁盤IO讀取。

       從磁盤隨機訪問確認。如果在SSD的情況下將I/O調度程序設置爲NOOP,則讀取QPS將大大加快,因此比其他電梯調度程序算法快得多。

2、由於ConsumeQueue只存儲固定大小的元數據,主要用於記錄消費進度,因此支持隨機讀取。利用頁面緩存預取,訪問ConsumeQueue的速度與訪問主內存的速度一樣快,即使它是在大量消息累積的情況下。因此,Consumeue不會對讀取性能帶來明顯的懲罰。

3、CommitLog幾乎存儲所有信息,包括消息數據。與關係數據庫的重放日誌類似,只要存在提交日誌,就可以完全恢復使用隊列、消息鍵索引和所有其他必需的數據。

        RocketMQ官網上還附了一個Rocketmq與activemq與kafka對比的表格,感興趣的可以看一下。需要額外說的一點是,時間早一些的資料還在說Kafka不支持事務,但Kafka大概在0.11版本之後開始支持事務了:https://archive.apache.org/dist/kafka/0.11.0.0/RELEASE_NOTES.html,Kafka最近版本迭代得也很快,截至本文今日,已經到2.3.0版本了,增加了很多特性和功能。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章