爲何我不推薦Kafka Streams和KSQL?

本文,我將首先簡要陳述本身的觀點,隨後深刻探討我得出這一觀點的緣由。數據庫

個人觀點是:不建議用戶使用 Kafka Streams,由於其缺乏檢查點機制,也不具有隨機排序等功能,而 KSQL 以 Kafka Streams 爲基礎,所以其一樣繼承了後者所固有的很多問題。架構

Kafka 並非數據庫,而是一套很是出色的消息傳遞系統。確實,直到如今也有不少人認定 Kafka 就是一套數據庫,因爲篇幅所限,我在本文中無法具體討論這些問題。我也認可,除非真正學習並瞭解過 Kafka,不然大多數開發者都很難理解這二者之間的差別。app

我發現,這樣的對話與爭論並沒能真正把觀點與論據區分開來。在這裏我但願作好區分,跟你們好好聊聊這個話題。框架

1KSQL 和 Kafka Streams 存在的問題 檢查點機制分佈式

我認爲這個問題是客觀存在的,無可辯駁,Kafka Sterams 確實存在檢查點機制問題。檢查點能夠說是操做分佈式系統的基礎。那麼,到底什麼是檢查點呢?ide

Kafka 是一套分佈式日誌記錄系統。在消息處理方面,Kafka 同時支持有狀態與無狀態兩類。在無狀態處理方面,用戶只會接收一條消息,而後進行實際處理,很是簡單。但一旦涉及有狀態處理,狀況就馬上變得不一樣。如今,開發者面對的第一個難題就是存儲狀態,只有這樣才能在遇到錯誤時配合對應狀態完成系統恢復。性能

對於 Kafka Streams,恢復工做看似很是簡單,由於擁有重構狀態所須要的所有消息。理論上,甚至可以經過一些方法將保存在 Kafka 中的消息控制在每鍵約一條的水平。學習

但這就沒問題了嗎?固然不是。由於每鍵一條消息,狀態量仍然至關誇張。若是你們擁有上千億個鍵,那就須要在狀態主題中保存超過 1 千億條消息,畢竟全部狀態變動都被放置在了對應的狀態變動主題內。隨着鍵數量的進一步增長,狀態的體積也會隨之膨脹。大數據

這種運營思路總結起來就是,一旦某個節點沒法正常運行,則必須從主題中重播全部消息並將其插入數據庫內。只有執行完成整個流程,處理才能恢復至原有狀態並繼續進行。優化

在極端狀況或者發生人爲錯誤的前提下,一切運行 Kafka Streams 做業的設備都有可能崩潰或者宕機,這意味着全部節點都必須重播全部狀態變動消息,然後才能繼續正常處理新的消息。

這種大規模重播可能會帶來長達數小時的停機時間。很多 Kafka Streams 的潛在用戶表示,他們估算出的停機時間至少達到 4 個小時。好的,就算 4 個小時,完成恢復流程以後,接下來還有這一時段內新增的大量消息。追上這部分進度,系統纔算是真正回到運行正軌之上。

有鑑於此,數據庫與處理框架每每採用檢查點機制(在 Flink 中,這一機制被稱爲快照)。所謂檢查點,是將當前總體態定入至持久存儲(S3/HDFS)中。所以,一旦發生大規模故障,恢復程序將直接讀取前一個檢查點,重播該檢查點以後的全部消息(一般在 1000 秒之內),以便快速恢復後續處理能力。整體而言,檢查點支持下的恢復流程通常僅耗時幾秒鐘到幾分鐘不等。

能夠看到,在檢查點的幫助下,系統的停機時間將由 Kafka Streams 的數小時顯著縮短至幾秒和幾分鐘水平。對於實時系統,停機時間必須儘量短,咱們也必須盡最大努力確保分佈式系統可以儘快從故障中恢復過來。

 隨機排序

隨機排序是分佈式處理流程的重要組成部分,其本質是將數據與同一個鍵整合起來的實現方法。若是須要對數據進行分析,則極可能會接觸到隨機排序。

事實上,Kafka Streams 的隨機排序與 Flink 或者 Spark Streaming 中的隨機排序存在巨大差別。下面來看看 JavaDoc 中關於其工做原理的描述:

若是某個鍵變動運算符在實際使用以前發生了變化(例如 selectKey(KeyValueMapper)、map(KeyValueMapper), flatMap(KeyValueMapper) 或者 transform(TransformerSupplier, String…)),且此後沒有發生數據從新分發(例如經過 through(String)),那麼在 Kafka 當中建立一個內部從新分區主題。該主題將被命名爲「${applicationId}-XXX-repartition」的形式,其中,「applicationId」由用戶在 StreamsConfig 中經過 APPLICATION_ID_CONFIG 參數進行指定,「XXX」爲內部生成的名稱,而「-repartition」則爲固定後綴。開發者能夠經過 KafkaStreams.toString() 檢索全部已生成的內部主題名稱。

這意味着只要變動鍵(通常用於分析),Kafka Streams 就會新建一個主題來實現隨機排序。這種隨機排序實現方法,證明了我在與開發者溝通時作出的幾個基本假設:

我曾與多位前 Kafka Streams 開發者進行過交流,他們並不清楚這種新的主題機制。他們直接在集羣上執行實時分析,但這會快速增長代理上的負載與數據總量,並最終致使系統崩潰。但從使用者的角度來看,他們只是在正常執行數據處理。

若是開發者對性能並不關注,那麼這種方法彷佛也能接受。可是,其餘一些處理框架(例如 Apache Flink)顯然更加理想,它們提供更完善的內置隨機排序功能,並且也能與 Kafka 配合使用。這些系統,無疑可以帶來更順暢的使用體驗。

 結論

因爲缺乏兩大關鍵功能,Kafka Streams 實用性會大打折扣。咱們不可能接受在實時生產系統上經歷長達數小時的停機,沒法接受隨機排序功能致使集羣崩潰。並且除非在每一項 KSQL 查詢以前都進行解釋,不然咱們也弄不明白可能出現哪些隨機排序操做。

2怎麼作? 不要過度糾結沒有實際價值的架構問題

在本次召開的 Kafka 峯會上,其中很多演講糾結於那些根本沒有實際使用的架構問題。例如,他們談到數據庫是負責執行數據處理的環境,確實某些小型數據架構以及很多數據倉庫方案都在使用數據庫進行數據處理。但我從沒見過有哪些大數據架構會採用這樣的處理方式,畢竟數據庫的可擴展性一直是個大問題。長久以來,咱們一直使用具備可擴展能力的處理引擎解決這方面需求,這也成爲大數據領域的一種客觀標準。

他們還將 KSQL 硬性拔高,表示其可以完成一部分目前由大數據生態系統項目處理的任務。在他們看來,目前生態系統項目過多已經成爲新的問題。大數據生態系統中包含太多技術方案,每一項技術負責解決或處理一種特定用例。組織固然能夠剔除掉部分技術方案,但這會大大減慢處理速度,甚至影響處理用例的能力。話雖沒錯,但就算是配合此次公佈的幾項新功能,KSQL 也仍不足以真正知足組織的處理需求。

這不由讓我好奇,爲何要積極鼓吹這麼多新的使用場景?在我看來,這次峯會中的很多發佈內容並不科學。很明顯,Kafka 確實不適合處理一些數據庫的任務。長期存儲的最佳選項,仍然是 S3 或者 HDFS。文件系統與 Kafka 不管在性能仍是存儲成本上,都有着巨大差異。

我鼓勵各位架構師認真研究這種差異,目前只有兩種方法可以經過時間戳或者提交 ID 的方式訪問 Kafka 中的歷史數據。通常來說,用例須要使用 where 子句進行隨機訪問,這一點咱們看到 KSQL 開始進行嘗試處理。然而,針對隨機訪問讀取的數據庫優化絕非易事,很多大型科技企業都須要圍繞這個問題創建專門的大規模工程技術團隊。

 Kafka 不是數據庫

現實狀況是,數據庫要麼位於代理進程中,要麼處於具有穩定持久存儲層的應用程序內。在我看來,使用 KSQL 經過 where 子句獲取當前狀態的架構並無任何實際意義。其它成熟的架構已經可以輕鬆獲取數據的當前狀態,例如數據庫或者帶有檢查點的其餘處理程序。

在主題演講最後,Confluent(一家圍繞 Kafka 創建的創業公司)提到新功能的出現並非要替代全部數據庫。我真心但願他們能再斟酌斟酌本身的發言。畢竟在列舉的衆多數據庫用例中,Confluent 都已經開始利用 KSQL 替換數據庫。這裏我要再次強調:建立數據庫絕非易事,而建立分佈式數據庫更是難上加難。

這篇文章的目的並非打擊 Kafka。若是充分理解 Kafka 的特性與用法,它絕對是一套很是強大的發佈和訂閱系統。所以,最重要的是瞭解如何正確使用 Kafka,而不能單純被市場宣傳牽着鼻子走。請記住,供應商的利益訴求與你的並不必定始終一致。他們的關注重點在於提高收入以及產品使用率,但爲此推出的全新產品使用方式,未必符合開發者的最大利益。

所以,在決定採用實時處理機制時,請首先確保擁有清晰明確的業務案例,並認真比較批量處理與實時處理之間的優劣差別。這個業務案例能夠來自當前場景,也能夠着眼將來需求。只有肯定其具有牢固的價值主張,咱們纔有必要嘗試新的技術實現方法;若是沒有,盲目行動只會帶來更多問題。

最後,我建議你們認真瞭解 Kafka 架構的固有侷限。其中一些可能不太引人注目,也有一些要求咱們對分佈式系統具備深入的理解才能體會。請確保您所在組織的架構師們真正清楚這一切對業務以及用例的實際影響。不然,您所作的一切其實都只是在爲供應商作嫁衣,甚至可能所以毀掉本身苦心積累起的業務體系。

相關文章
相關標籤/搜索