消息隊列學習筆記(二)

1.消息複製的問題

    RocketMQ 提供新、老兩種複製方式:傳統的主從模式和新的基於 Dledger 的複製方式。傳統的主從模式性能更好,但靈活性和可用性稍差,而基於 Dledger 的複製方式,在 Broker 故障的時候可以自動選舉出新節點,可用性更好,性能稍差,並且資源利用率更低一些。Kafka 提供了基於ISR的更加靈活可配置的複製方式,用戶可以自行配置,在可用性、性能和一致性這幾方面根據系統的情況來做取捨。但是,這種靈活的配置方式學習成本較高。並沒有一種完美的複製方案,可以同時能夠兼顧高性能、高可用和一致性。你需要根據你實際的業務需求,先做出取捨,然後再去配置消息隊列的複製方式。

2.RocketMQ的NameServer

    在RocketMQ中,NameServer是一個獨立的進程,爲Broker、生產者和消費者提供服務。NameServer最主要的功能就是,爲客戶端提供尋址服務,協助客戶端找到主題對應的 Broker 地址。此外,NameServer 還負責監控每個 Broker 的存活狀態。

    RouteInfoManager中5個Map對象,保存了集羣所有的Broker和主題的路由信息。

  • topicQueueTable 保存的是主題和隊列信息,其中每個隊列信息對應的類 QueueData 中,還保存了 brokerName。需要注意的是,這個 brokerName 並不真正是某個 Broker 的物理地址,它對應的一組 Broker 節點,包括一個主節點和若干個從節點。
  • brokerAddrTable 中保存了集羣中每個 brokerName 對應 Broker 信息,每個 Broker 信息用一個 BrokerData 對象表示。
  • brokerLiveTable 中,保存了每個Broker當前的動態信息,包括心跳更新時間,路由數據版本等等。
  • clusterAddrTable 中,保存的是集羣名稱與 BrokerName 的對應關係。
  • filterServerTable 中,保存了每個Broker對應的消息過濾服務的地址,用於服務端消息過濾。

    根據Broker請求過來的路由信息,依次對比並更新clusterAddrTable、brokerAddrTable、topicQueueTable、brokerLiveTable和filterServerTable這5個保存集羣信息和路由信息的 Map 對象中的數據。

    客戶端在啓動後,會啓動一個定時器,定期從NameServer上拉取相關主題的路由信息,然後緩存在本地內存中,在需要的時候使用。

3.Kafka 中 ZooKeeper的使用

    Kafka 在 ZooKeeper 中保存的元數據,主要就是 Broker 的列表和主題分區信息兩棵樹。這份元數據同時也被緩存到每一個 Broker 中。
    Kafka 在每個 Broker 中都維護了一份和 ZooKeeper 中一樣的元數據緩存,並不是每次客戶端請求元數據就去讀一次 ZooKeeper。由於 ZooKeeper 提供了 Watcher 這種監控機制,Kafka 可以感知到 ZooKeeper 中的元數據變化,從而及時更新 Broker 中的元數據緩存。
    客戶端並不直接和 ZooKeeper 來通信,而是在需要的時候,通過 RPC 請求去 Broker 上拉取它關心的主題的元數據,然後保存到客戶端的元數據緩存中,以便支撐客戶端生產和消費。

缺點:目前 Kafka 的這種設計,集羣的可用性是嚴重依賴 ZooKeeper 的,也就是說,如果 ZooKeeper 集羣不能提供服務,那整個 Kafka 集羣也就不能提供服務了,這其實是一個不太好的設計。

可行的解決辦法:如果你需要要部署大規模的 Kafka 集羣,建議的方式是,拆分成多個互相獨立的小集羣部署,每個小集羣都使用一組獨立的 ZooKeeper 提供服務。這樣,每個 ZooKeeper 中存儲的數據相對比較少,並且如果某個 ZooKeeper 集羣故障,只會影響到一個小的 Kafka 集羣,故障的影響面相對小一些。

4.事務

    RocketMQ 是把這些消息暫存在一個特殊的隊列中,待事務提交後再移動到業務隊列中;而 Kafka 直接把消息放到對應的業務分區中,配合客戶端過濾來暫時屏蔽進行中的事務消息。

    RocketMQ 和 Kafka 的事務,它們的適用場景是不一樣的,RocketMQ 的事務適用於解決本地事務和發消息的數據一致性問題,而 Kafka 的事務則是用於實現它的 Exactly Once 機制,應用於實時計算的場景中。

5.消息隊列使用場景

    消息隊列最常被使用的三種場景:異步處理、流量控制(削峯填谷)和服務解耦。

6.消息可靠性

關於消息可靠性的服務水平,有下面三種級別:
    At most once: 至多一次,消息在傳遞時,最多會被送達一次。換一個說法就是,沒什麼消息可靠性保證,允許丟消息。一般都是一些對消息可靠性要求不太高的監控場景使用,比如每分鐘上報一次機房溫度數據,可以接受數據少量丟失。
    At least once: 至少一次,消息在傳遞時,至少會被送達一次。也就是說,不允許丟消息,但是允許有少量重複消息出現。
    Exactly once:恰好一次,消息在傳遞時,只會被送達一次,不允許丟失也不允許重複,這個是最高的等級。
Kafka、RocketMQ 和 RabbitMQ 以及我們常見的大部分消息隊列,能提供的服務水平都是一樣的:At least once,也就是至少一次,消息有可能會重複,但可以保證不丟消息。
    Kafka 宣稱是支持 Exactly Once 特性的,但是,Kafka 支持的這個“Exactly once”特性,並不是保證我們這個題目中所說的“從消息生產直到消費完成”這一過程中消息不重不丟。它解決的是,在流計算中,用 Kafka 作爲數據源,並且將計算結果保存到 Kafka 這種場景下,數據從 Kafka 的某個主題中消費,在計算集羣中計算,再把計算結果保存在 Kafka 的其他主題中。這樣一個過程中,Kafka 的 Exactly Once 機制,保證每條消息都被恰好計算一次,確保計算結果正確。

7.順序性

    大部分消息隊列都只能保證在分區(隊列)上的嚴格順序,單調性是指如果已經有一些內容通過哈希分派到了相應的分區中,又有新的分區加入到主題中,哈希的結果應能夠保證,原有已分配的內容可以被映射到原有的或者新的分區中去,而不會被映射到舊的分區集合中的其他分區。只要是滿足單調性的分片算法,我們就可以按照“先擴容分區 -> 將舊分區中的遺留消息消費完 -> 同時消費所有分區”這樣一個方式,確保擴容過程中消息的嚴格順序。

8.Kafka 發送消息的可靠性

    Kafka 發送消息的可靠性依靠的是“請求 - 確認”機制,即使是批量發送,這個機制依然可以保證不丟消息,所以沒必要把批量大小設置爲 1。

9.RocketMQ 的主從模式集羣

    由於 RocketMQ 的主從模式集羣是不支持自動選舉的,一旦主節點宕機,雖然,消費者可以自動切換到從節點繼續消費,但生產者就不能再往這個節點上的隊列發消息了。所以,爲了保證生產的可用性,必須把主題中的隊列分佈到多個 Broker 上。

10.理解RPC框架

    在 RPC 框架中,最關鍵的就是理解“樁”的實現原理,樁是 RPC 框架在客戶端的服務代理,它和遠程服務具有相同的方法簽名,或者說是實現了相同的接口。客戶端在調用 RPC 框架提供的服務時,實際調用的就是“樁”提供的方法,在樁的實現方法中,它會發請求的服務名和參數到服務端,服務端的 RPC 框架收到請求後,解析出服務名和參數後,調用在 RPC 框架中註冊的“真正的服務提供者”,然後將結果返回給客戶端。

    通過定義一個接口來解耦調用方和實現。在設計上這種方法稱爲“依賴倒置原則(Dependence Inversion Principle)”,它的核心思想是,調用方不應依賴於具體實現,而是爲實現定義一個接口,讓調用方和實現都依賴於這個接口。這種方法也稱爲“面向接口編程”。

    像 gRPC 這類多語言的 RPC 框架,都是在編譯 IDL 的過程中生成樁的源代碼,再和業務代碼,使用目標語言的編譯器一起編譯的。而像 Dubbo 這類沒有編譯過程的 RPC 框架,都是在運行時,利用一些語言動態特性,動態創建的樁。RPC 框架的這種“樁”的設計,其實是一種動態代理設計模式。這種設計模式可以在不修改源碼,甚至不需要源碼的情況下,在調用鏈中注入一些業務邏輯。這是一種非常有用的高級技巧,可以用在權限驗證、風險控制、調用鏈跟蹤等等很多場景中。

    RPC 框架的服務端主要需要實現下面這兩個功能:服務端的業務代碼把服務的實現類註冊到 RPC 框架中 ;接收客戶端樁發出的請求,調用服務的實現類並返回結果。

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