日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Kafka实践:到底该不该把不同类型的消息放在同一个主题中

發布時間:2024/1/17 编程问答 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Kafka实践:到底该不该把不同类型的消息放在同一个主题中 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

如果你使用了像Kafka這樣的流式處理平臺,就要搞清楚一件事情:你需要用到哪些主題?特別是如果你要將一堆不同的事件作為消息發布到Kafka,是將它們放在同一個主題中,還是將它們拆分到不同的主題中?

Kafka主題最重要的一個功能是可以讓消費者指定它們想要消費的消息子集。在極端情況下,將所有數據放在同一個主題中可能不是一個好主意,因為這樣消費者就無法選擇它們感興趣的事件——它們需要消費所有的消息。另一種極端情況,擁有數百萬個不同的主題也不是一個好主意,因為Kafka的每個主題都是有成本的,擁有大量主題會損害性能。

實際上,從性能的角度來看,分區數量才是關鍵因素。在Kafka中,每個主題至少對應一個分區,如果你有n個主題,至少會有n個分區。不久之前,Jun Rao寫了一篇博文,解釋了擁有多個分區的成本(端到端延遲、文件描述符、內存開銷、發生故障后的恢復時間)。根據經驗,如果你關心延遲,那么每個節點分配幾百個分區就可以了。如果每個節點的分區數量超過成千上萬個,就會造成較大的延遲。

相關廠商內容

實時監控業務質量現狀

機器學習在大規模服務器治理復雜場景的實踐

如何構建微服務下的性能監控

基于NEO區塊鏈的專家網絡應用實踐

2018年,你應該關注這些運維技術熱點

相關贊助商

CNUTCon全球運維技術大會,11月16日-17日,上海,|https://cnutcon2018.geekbang.org/?utm_source=infoq&utm_medium=vcrbox]]

關于性能的討論為設計主題結構提供了一些指導:如果你發現自己有數千個主題,那么將一些細粒度、低吞吐量的主題合并到粗粒度主題中可能是個明智之舉,這樣可以避免分區數量蔓延。

然而,性能并不是我們唯一關心的問題。在我看來,更重要的是主題結構的數據完整性和數據模型。我們將在本文的其余部分討論這些內容。

主題等于相同類型事件的集合?

人們普遍認為應該將相同類型的事件放在同一主題中,不同的事件類型應該使用不同的主題。這種思路讓我們聯想到關系型數據庫,其中表是相同類型記錄的集合,于是我們就有了數據庫表和Kafka主題之間的類比。

Confluent Avro Schema Registry進一步強化了這種概念,因為它鼓勵你對主題的所有消息使用相同的Avro模式(schema)。模式可以在保持兼容性的同時進行演化(例如通過添加可選字段),但所有消息都必須符合某種記錄類型。稍后我會再回過頭來討論這個問題。

對于某些類型的流式數據,例如活動事件,要求同一主題中所有消息都符合相同的模式,這是合理的。但是,有些人把Kafka當成了數據庫來用,例如事件溯源,或者在微服務之間交換數據。對于這種情況,我認為是否將主題定義為具有相同模式的消息集合就不那么重要了。這個時候,更重要的是主題分區中的消息必須是有序的。

想象一下這樣的場景:你有一個實體(比如客戶),這個實體可能會發生許多不同的事情,比如創建客戶、客戶更改地址、客戶向帳戶中添加新的信用卡、客戶發起客服請求,客戶支付賬單、客戶關閉帳戶。

這些事件之間的順序很重要。例如,我們希望其他事件必須在創建客戶之后才能發生,并且在客戶關閉帳戶之后不能再發生其他事件。在使用Kafka時,你可以將它們全部放在同一個主題分區中來保持它們的順序。在這個示例中,你可以使用客戶ID作為分區的鍵,然后將所有事件放在同一個主題中。它們必須位于同一主題中,因為不同的主題對應不同的分區,而Kafka是不保證分區之間的順序的。

順序問題

如果你為customerCreated、customerAddressChanged和customerInvoicePaid事件使用了不同的主題,那么這些主題的消費者可能就看不到這些事件之間的順序。例如,消費者可能會看到一個不存在的客戶做出的地址變更(這個客戶尚未創建,因為相應的customerCreated事件可能發生了延遲)。

如果消費者暫停一段時間(比如進行維護或部署新版本),那么事件出現亂序的可能性就更高了。在消費者停止期間,事件繼續發布,并且這些事件被存儲在特定定的主題分區中。當消費者再次啟動時,它會消費所有積壓在分區中的事件。如果消費者只消費一個分區,那就沒問題:積壓的事件會按照它們存儲的順序依次被處理。但是,如果消費者同時消費幾個主題,就會按任意順序讀取主題中數據。它可以先讀取積壓在一個主題上的所有數據,然后再讀取另一個主題上積壓的數據,或者交錯地讀取多個主題的數據。

因此,如果你將customerCreated、customerAddressChanged和customerInvoicePaid事件放在三個單獨的主題中,那么消費者可能會在看到customerCreated事件之前先看到customerAddressChanged事件。因此,消費者很可能會看到一個客戶的customerAddressChanged事件,但這個客戶卻未被創建。

你可能會想到為每條消息附加時間戳,并用它來對事件進行排序。如果你將事件導入數據倉庫,再對事件進行排序,或許是沒有問題的。但在流數據中只使用時間戳是不夠的:在你收到一個具有特定時間戳的事件時,你不知道是否需要等待具有較早時間戳的事件,或者所有之前的事件是否已經在當前事情之前到達。依靠時鐘進行同步通常會導致噩夢,有關時鐘問題的更多詳細信息,請參閱“Designing Data-Intensive Applications”的第8章。

何時拆分主題,何時合并主題?

基于這個背景,我將給出一些經驗之談,幫你確定哪些數據應該放在同一主題中,以及哪些數據應該放在不同的主題中。

  • 首先,需要保持固定順序的事件必須放在同一主題中(并且需要使用相同的分區鍵)。如果事件屬于同一實體,那么事件的順序就很重要。因此,我們可以說,同一實體的所有事件都應該保存在同一主題中。

    如果你使用事件溯源進行數據建模,事件的排序尤為重要。聚合對象的狀態是通過以特定的順序重放事件日志而得出的。因此,即使可能存在不同的事件類型,聚合所需要的所有事件也必須在同一主題中。

  • 對于不同實體的事件,它們應該保存在相同的主題中還是不同的主題中?我想說,如果一個實體依賴于另一個實體(例如一個地址屬于一個客戶),或者經常需要同時用到它們,那么它們也應該保存在同一主題中。另一方面,如果它們不相關,并且屬于不同的團隊,那么最好將它們放在不同的主題中。

    另外,這也取決于事件的吞吐量:如果一個實體類型的事件吞吐量比其他實體要高很多,那么最好將它分成幾個主題,以免讓只想消費低吞吐量實體的消費者不堪重負(參見第4點)。不過,可以將多個具有低吞吐量的實體合并起來。

  • 如果一個事件涉及多個實體該怎么辦?例如,訂單涉及到產品和客戶,轉賬至少涉及到兩個賬戶。

    我建議在一開始將這些事件記錄為單個原子消息,而不是將其分成幾個屬于不同主題的消息。在記錄事件時,最好可以保持原封不動,即盡可能保持數據的原始形式。你可以隨后使用流式處理器來拆分復合事件,但如果過早進行拆分,想要重建原始事件會難得多。如果能夠為初始事件分配一個唯一ID(例如UUID)就更好了,之后如果你要拆分原始事件,可以帶上這個ID,從而可以追溯到每個事件的起源。

  • 看看消費者需要訂閱的主題數量。如果幾個消費者都訂閱了一組特定的主題,這表明可能需要將這些主題合并在一起。

    如果將細粒度的主題合并成粗粒度的主題,一些消費者可能會收到他們不需要的事件,需要將其忽略。這不是什么大問題:消費消息的成本非常低,即使最終忽略了一大半的事件,總的成本可能也不會很大。只有當消費者需要忽略絕大多數消息(例如99.9%是不需要的)時,我才建議將大容量事件流拆分成小容量事件流。

  • 用作Kafka Streams狀態存儲(KTable)的變更日志主題應該與其他主題分開。在這種情況下,這些主題由Kafka Streams流程來管理,所以不應該包含其他類型的事件。

    最后,如果基于上述的規則依然無法做出正確的判斷,該怎么辦?那么就按照類型對事件進行分組,把相同類型的事件放在同一個主題中。不過,我認為這條規則是最不重要的。

  • 模式管理

    如果你的數據是普通文本(如JSON),而且沒有使用靜態的模式,那么就可以輕松地將不同類型的事件放在同一個主題中。但是,如果你使用了模式編碼(如Avro),那么在單個主題中保存多種類型的事件則需要考慮更多的事情。

    如上所述,基于Avro的Kafka Confluent Schema Registry假設了一個前提,即每個主題都有一個模式(更確切地說,一個模式用于消息的鍵,一個模式用于消息的值)。你可以注冊新版本的模式,注冊表會檢查模式是否向前和向后兼容。這樣設計的一個好處是,你可以讓不同的生產者和消費者同時使用不同版本的模式,并且仍然保持彼此的兼容性。

    Confluent的Avro序列化器通過subject名稱在注冊表中注冊模式。默認情況下,消息鍵的subject為<topic>-key,消息值的subject為<topic>-value。模式注冊表會檢查在特定subject下注冊的所有模式的相互兼容性。

    最近,我為Avro序列化器提供了一個補丁(https://github.com/confluentinc/schema-registry/pull/680),讓兼容性檢查變得更加靈活。這個補丁添加了兩個新的配置選項:key.subject.name.strategy(用于定義如何構造消息鍵的subject名稱)和value.subject.name.strategy(用于定義如何構造消息值的subject名稱)。它們的值可以是如下幾個:

    • io.confluent.kafka.serializers.subject.TopicNameStrategy(默認):消息鍵的subject名稱為<topic>-key,消息值為<topic>-value。這意味著主題中所有消息的模式必須相互兼容。
    • io.confluent.kafka.serializers.subject.RecordNameStrategy:subject名稱是Avro記錄類型的完全限定名。因此,模式注冊表會檢查特定記錄類型的兼容性,而不管是哪個主題。這個設置允許同一主題包含不同類型的事件。
    • io.confluent.kafka.serializers.subject.TopicRecordNameStrategy:subject名稱是<topic>-<type>,其中<topic>是Kafka主題名,<type>是Avro記錄類型的完全限定名。這個設置允許同一主題包含不同類型的事件,并進一步對當前主題進行兼容性檢查。

    有了這個新特性,你就可以輕松地將屬于特定實體的所有不同類型的事件放在同一個主題中。現在,你可以自由選擇主題的粒度,而不僅限于一個類型對應一個主題。

    英文原文:http://martin.kleppmann.com/2018/01/18/event-types-in-kafka-topic.html

    總結

    以上是生活随笔為你收集整理的Kafka实践:到底该不该把不同类型的消息放在同一个主题中的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。