最初發布在https://streamsql.io。
為什麼StreamSQL從Apache Kafka遷移到Apache Pulsar
今天,Apache Kafka和事件流實際上是同義詞。 事件流是平臺的核心部分,我們最近將Kafka換成了Pulsar。 我們已經與客戶和會議現場進行了討論。 最近,Apache Pulsar社區中的一位朋友建議我寫一篇文章,以分享我們的經驗和切換的原因。
我們在Kafka上構建了平臺,並發現自己編寫了大量代碼,以使系統按需運行。 我們認為卡夫卡不是完成這項工作的正確工具。 顯然,這對於許多許多用例來說都不是正確的,即使是這樣,無論如何也要使用它代替Pulsar還是有意義的。 在本文的其餘部分中,我將描述我們使用Kafka構建的解決方案,以及為什麼決定遷移到Pulsar。
我們的問題陳述
什麼是StreamSQL?
StreamSQL是圍繞事件源構建的數據存儲系統。 StreamSQL由三個部分組成:事件存儲,轉換和實體化狀態。 事件存儲是發送到我們系統的每個域事件的不變分類帳。 我們使用與Cassandra,Redis和CockroachDB類似的API為物化狀態提供服務。 轉換是將事件映射到狀態的純函數。 根據轉換,將處理我們收到的每個事件並將其應用於物化狀態。
StreamSQL可對所有數據追溯地運行新的轉換。 結束狀態是整個事件流的真實體現。 此外,您可以通過回滾和重放事件來生成"虛擬"狀態。 虛擬狀態可用於訓練和驗證機器學習模型,以及用於調試目的(例如用於前端開發的Redux)。
要求
系統需要能夠執行以下操作:
· 將每個域事件永久存儲在系統中。
· 通過保證每個傳入事件的一次處理來保持物化狀態的一致性。
· 能夠對所有歷史事件以與我們收到事件相同的順序進行轉換。
· 回滾並重播事件分類帳,並在此時實現視圖。
原始的基於Kafka的解決方案
最初的基於Kafka的解決方案由一組縫合在一起的大數據工具組成。 系統將過去的事件存儲在S3中,並使用Spark處理它們。 對於流數據,它使用了Kafka和Flink。 要使事件和實例化視圖保持一致,就需要在每個系統之間進行復雜的協調。
無限期存儲每個域事件
每個域事件都將通過Kafka進入系統,然後將其保存到S3中。 這使我們能夠以高耐用性和低成本存儲很少使用的數據。
我們嘗試使用Kafka對流的無限保留,但發現它昂貴且無法維護。 我們開始看到較大主題的性能下降和延遲不定。 由於我們幾乎完全搬到了Pulsar,因此我們沒有做進一步的調查。
從批處理數據引導實例化視圖
我們通過按順序處理每個事件來實現視圖。 我們使用Spark處理S3中存儲的大部分歷史數據。 如果我們可以在發生這種情況時暫停事件,那麼它將簡化事情。 在這種情況下,我們可以讀取所有S3數據,然後切換到處理主題開頭的Kafka。 實際上,從Kafka持續到S3的事件之間存在一個延遲,在將大型批處理集群交換為較小的流處理集群之間存在另一個延遲。 我們不能錯過任何事件的處理,因此我們使用Spark在S3中處理儘可能多的事件,然後讓其返回上一個事件的ID。 由於我們已將Kafka配置為保留最近幾周的數據,因此我們可以回填Kafka以外的其他事件。
從Kafka回填
Spark能夠處理大多數過去的事件,但是並不能使我們進入最新狀態。 為了處理過去的最後一組事件,我們將Kafka集群配置為保留已確認事件的最後兩週。 我們運行Flink作業以繼續Spark啟動的SQL轉換。 我們將Flink指向Kafka中的第一個事件,並使其通讀,直到到達Spark停止的messageID為止,什麼都不做。 從那時起,它將繼續更新實例化視圖,直到到達流的開頭。 最後,它通知Transformation API實例化視圖是最新的並且可以使用。
更新即將發生的事件
一旦啟動,StreamSQL必須使實例化視圖保持最新。 在這一點上,這個問題是微不足道的。 Kafka將每個傳入事件直接傳遞給Flink,然後Flink執行必要的更新。 此時,轉換API和Spark處於空閒狀態。 但是,如果用戶更新或創建轉換,我們仍將每個傳入事件保留到S3中。
多租戶,回滾和重播,錯誤處理等
我們協調Flink和Kafka一起工作,以維護實例化視圖的快照。 通過適當的協調,我們可以允許無縫回滾和重放功能。 描述此過程將需要一個博客帖子(我們希望在不久的將來寫)。
在此博客文章中,我們還將不介紹如何擴展Flink和Kafka集群,如何處理服務故障或如何在所有這些不同服務之間實現安全的多租戶(提示:每種解決方案都有不同的解決方案) 回答)。 如果您迫切需要了解以上任何內容,請隨時與我們聯繫。 我們很樂意分享。
為什麼選擇Pulsar?
Pulsar旨在永久存儲事件,而不是在系統之間流式傳輸事件。 此外,Pulsar是在Yahoo!上建造的。 適用於在全球範圍內構建各種產品的團隊。 它本身支持地理分佈和多租戶。 執行復雜的部署(例如為某些租戶保留專用服務器)變得容易。 我們會盡力利用這些功能。 這使我們可以將自定義邏輯的很大一部分交給Pulsar。
分層存儲到S3
StreamSQL用戶可以隨時創建一個新的實例化視圖。 這些視圖必須是所有事件的投影,因此每個轉換都按順序處理每個歷史事件。 在基於Kafka的解決方案中,我們將所有已確認的事件流式傳輸到S3或GCS中。 然後,Spark中的批處理管道處理了這些事件。 整個系統需要我們協調事件流,批處理存儲,批處理計算,流計算和狀態存儲。 在現實世界中,協調這些系統容易出錯,昂貴且難以自動化。
如果我們可以將事件存儲配置為永久保留事件,那麼它將使我們可以將批處理和流傳輸管道合併在一起。 脈衝星和卡夫卡都允許這樣做; 但是,Kafka沒有分層存儲。 這意味著所有事件都必須保留在Kafka節點的磁盤上。 事件分類帳單調增加,因此我們必須不斷添加存儲。 大多數歷史事件很少讀取,因此我們大多數昂貴的磁盤存儲都處於休眠狀態。
另一方面,Apache Pulsar具有內置的分層存儲。 Pulsar將每個事件日誌細分為多個段,並將不活動的段卸載到S3。 這意味著我們只需對Kafka進行簡單的配置更改即可獲得無限便宜的存儲空間。 我們不必不斷增加集群的規模,我們可以合併批處理和流管道。
我們可以將Pulsar配置為在主題達到特定大小時卸載事件,也可以手動運行它。 這使我們能夠靈活地設置正確的卸載策略,以平衡成本和速度。 我們正在構建機器學習模型,以使我們的卸載策略適合每個主題的特定需求。
分別計算和存儲擴展
我們的活動數量和使用方式在一天之中和整個用戶之間變化很大。 每個用戶的使用方式不同,將導致更大的存儲量或計算使用量。 幸運的是,Pulsar將其經紀人與存儲層分開。
Pulsar可以執行三種不同的操作:尾部寫入,尾部讀取和歷史讀取。 像卡夫卡(Kafka)一樣,脈衝星的寫作總是走到最後。 對於Pulsar來說,寫作包含三個步驟。 首先,代理接收請求,然後將其寫入簿記員,最後,將其緩存以供後續尾部讀取。 這意味著尾部讀取非常快,完全不會觸及存儲層。 相比之下,歷史讀取在存儲層上非常繁重。
對於Kafka和Pulsar而言,添加存儲節點都相對容易,但是這是非常昂貴的操作。 必須重新整理數據並進行復制,以正確平衡存儲節點。 在Kafka的情況下,代理和存儲位於同一節點上,因此任何擴展操作都非常昂貴。 相反,在Pulsar,經紀人是無國籍的,並且規模容易,便宜。 這意味著尾部讀數不會造成明顯的規模問題。 我們可以使我們的集群適應歷史讀取和尾部讀取的當前使用模式。
內置多租戶
Pulsar內置了多租戶。在Yahoo !,許多地理分佈在不同產品上的團隊共享同一個Pulsar集群。 該系統必須處理跟蹤不同的預算和各種SLA。 它具有一項功能集,使我們可以在同一個Pulsar群集上運行所有用戶,同時保持性能,可靠性和安全性。
每個Pulsar主題都屬於一個名稱空間,而每個名稱空間均屬於一個租戶。 每個StreamSQL帳戶都映射到一個租戶。 租戶彼此安全隔離。 一個用戶無法觸摸其他用戶的信息流。
從性能的角度來看,名稱空間還提供了其他有關隔離的有趣動態。 我們可以將用戶的名稱空間隔離到一組特定的代理和存儲節點。 這限制了單個用戶對整個系統的影響。 同時,我們可以在代理上設置自動減載,以便大型系統可以吸收單個客戶端的高峰。
積極主動的社區
脈衝星社區的閒散頻道真是太神奇了。 我幾乎很快就能收到大多數問題的答案,而且我總是通過關注新事物來學習新事物。 舉行了幾次聚會和一次Pulsar峰會,以進行面對面的學習和建立網絡。 我們知道,在最壞的情況下,我們可以與相關人員聯繫,甚至可以解決最棘手的問題。 社區給了我們與Pulsar一起前進的信心。
基於Pulsar的解決方案
無限期存儲每個域事件
Pulsar允許我們將整個不可變分類帳存儲在Pulsar主題中。 我們將其視為一切都在Pulsar中,但是在後臺,Pulsar將事件卸載到S3中。 我們獲得了使用事件分類帳的簡單性優勢,以及將事件放入S3的成本和維護優勢。 所有這些都比我們的Kafka系統表現更好,而無需我們保持任何複雜性。
從批處理數據引導實例化視圖
Pulsar架構融合了我們的流和批處理功能。 這使我們可以刪除Spark以及Spark和Flink之間的所有協調代碼。 Pulsar-> Flink連接器在批處理和流處理模式之間無縫切換。 該架構的簡單性消除了基於Kafka的版本中存在的大量邊緣情況,錯誤處理和維護成本。
更新即將發生的事件
我們編寫一個作業來處理批處理和流數據。 在沒有我們任何協調的情況下,Flink維護一次精確的處理,並在其批處理和流模式之間進行交換。
Pulsar的缺點
整合方式
Pulsar的存在時間與Kafka差不多,並且在Yahoo中得到了證明。 我們認為Pulsar的核心穩定可靠。 集成是一個不同的問題。 有無窮無盡的集成清單可以寫。 在大多數情況下,Pulsar社區會建立並維護其集成。 例如,我們想將S3設置為接收器,並瞭解到不存在開源連接器。 我們構建了自己的開放源代碼解決方案,以推動社區向前發展,但我們希望將來能發現缺少的集成。
鑑於到目前為止,Pulsar還不如Kafka受歡迎,因此大多數Pulsar集成都是在Pulsar回購中構建和維護的。 例如,我們使用的Flink連接器位於Pulsar存儲庫中,但是也有一個開放的Apache Flink票證可以在其一側構建一個票證。 在Pulsar成為主流之前,將繼續缺少集成。
缺乏公共案例研究
幾乎所有的Pulsar內容都是由託管的Pulsar提供商發佈的,例如Streamlio(由Splunk購買),Stream Native和Kafkaesque。 很少有公司看到Pulsar案例研究,該案例將其大規模用於生產而與Pulsar沒有商業聯繫。 有很多大公司在生產中使用它,但是很少將其經驗公開。 公共案例研究使我們無需重新發明輪子就能掌握技巧和陷阱。 幸運的是,Stream Native在他們的博客中保留了它們的列表。
相比之下,有很多關於Kafka的案例研究。 Kafka是最著名的事件流媒體平臺,並且繼續得到普及,因此,大多數撰寫其數據平臺的公司都會深入瞭解如何使用Kafka。
基礎設施責任
我們的Pulsar部署需要一個用於元數據的Zookeeper群集,一個用於存儲的Bookkeeper群集,一個代理群集和一個代理群集。 即使使用AWS和Google Cloud服務,這也是很多維護責任。 僅Pulsar就有大量的配置可能性,但是當您查看底層時,它可能需要多個專業工程師進行維護和優化。
下一步是什麼?
Pulsar函數
當前,我們使用Flink處理流事件並更新我們的實例化視圖。 Flink不允許將新節點附加到群集中。 相反,我們必須保存一個檢查點並以更大的大小重新啟動集群。 相反,Pulsar函數在單獨的計算集群中運行,我們可以動態調整其大小。
Flink的處理引擎更具表現力和功能,但擴展規模要複雜得多。 Pulsar的規模易於擴展,但侷限性更大。 我們很快將能夠對轉換進行分類並決定在哪裡運行它們,並傾向於使用Pulsar功能。
流式DAG
StreamSQL當前不允許轉換將實例化視圖用作狀態。 我們正在像Airflow一樣將系統建模為DAG(有向無環圖)。 與Airflow不同,依賴關係無法逐步執行,每個事件都必須經過整個DAG。 每次事件通過DAG時,Pulsar將使維護此保證變得更加容易。
StreamSQL在Beta中
StreamSQL使您的數據科學團隊能夠專注於構建模型,而不是數據管道。 為要素構建數據管道是機器學習團隊最耗時的活動。 StreamSQL將每個功能的迭代時間從數週縮短至數小時。 它允許團隊編寫單個功能定義並將其用於培訓和服務。 StreamSQL從過去的事件回填,並結合批處理和流數據以生成和維護服務數據和培訓集。 StreamSQL還允許團隊共享,發現和重用組織其他部分中生成的功能,通過結合ML努力節省時間和金錢。 StreamSQL當前正在為數千萬的最終用戶提供面向用戶的機器學習功能。
(本文翻譯自Simba Khadder的文章《Why StreamSQL moved from Apache Kafka to Apache Pulsar》,參考:https://medium.com/@simba_k/why-streamsql-moved-from-apache-kafka-to-apache-pulsar-8fcf06e37e7f)