Kafka相關內容總結(存儲和性能)


Kafka消息的存儲

  • Kafka的設計基於一種非常簡單的指導思想:不是要在內存中保存盡可能多的數據,在需要時將這些數據刷新(flush)到文件系統,而是要做完全相反的事情。所有數據都要立即寫入文件系統中持久化的日志中,但不進行刷新數據的任何調用。實際中這樣做意味着,數據被傳輸到OS內核的頁面緩存中了,OS隨后會將這些數據刷新到磁盤。

  • 大家普遍為“磁盤很慢”,因而人們都對持久化(persistent structure)結構能夠提供說得過去的性能抱有懷疑態度。實際上,同人們的期望值相比,磁盤可以說是既很慢又很快,這取決決於磁盤的使用方式。設計的很好的磁盤結構可以和網絡一樣快。在一個由6個7200rpm的SATA硬盤組成的RAID-5磁盤陣列上,線性寫入(linear write)的速度大約是600MB/秒,但隨機寫入卻只有100k/秒,其中的差距接近6000倍。

  • Kafka並沒有在內存中創建緩沖區,然后再向磁盤write的方法,而是直接使用了PageCache。

  • OS在文件系統的讀寫上已經做了太多的優化,PageCache就是其中最重要的一種方法.

  • 直接使用PageCache有如下幾個好處:

    • 減少內存開銷: Java對象的內存開銷(overhead)非常大,往往是對象中存儲的數據所占內存的兩倍以上。
    • 避免GC問題:Java中的內存垃圾回收會隨着堆內數據不斷增長而變得越來越不明確,回收所花費的代價也會越來越大。
    • 簡單可靠:OS會調用所有的空閑內存作為PageCache,並在其上做了大量的優化:預讀,后寫,flush管理等,這些都不用應用層操心,而是由OS自動完成。
  • 由於這些因素,使用文件系統並依賴於PageCache頁面緩存要優於自己在內存中維護一個緩存或者什么其他別的結構。

讀寫空中接力

  • 當寫操作發生時,它只是將數據寫入Page Cache中,並將該頁置上dirty標志。

  • 當讀操作發生時,它會首先在Page Cache中查找內容,如果有就直接返回了,沒有的話就會從磁盤讀取文件再寫回Page Cache。

  • 可見,只要生產者與消費者的速度相差不大,消費者會直接讀取之前生產者寫入Page Cache的數據,大家在內存里完成接力,根本沒有磁盤訪問。而比起在內存中維護一份消息數據的傳統做法,這既不會重復浪費一倍的內存,Page Cache又不需要GC(可以放心使用大把內存了),而且即使Kafka重啟了,Page Cache還依然在

相關內核參數

  • 不能及時flush的話,OS crash(不是應用crash) 可能引起數據丟失;

  • 內核線程pdflush負責將有dirty標記的頁面,發送給IO調度層。內核會為每個磁盤起一條pdflush線程,每5秒(/proc/sys/vm/dirty_writeback_centisecs)喚醒一次,根據下面三個參數來決定行為:

    •  /proc/sys/vm/dirty_expire_centiseconds:如果page dirty的時間超過了30秒(單位是10ms),就會被刷到磁盤,所以crash時最多丟30秒左右的數據。

    • /proc/sys/vm/dirty_background_ratio:如果dirty page的總大小已經超過了10%的可用內存(cat /proc/meminfo里 MemFree+ Cached - Mapped),則會在后台啟動pdflush 線程寫盤,但不影響當前的write(2)操作。增減這個值是最主要的flush策略里調優手段。

    • /proc/sys/vm/dirty_ratio:如果wrte(2)的速度太快,比pdflush還快,dirty page 迅速漲到 10%的總內存(cat /proc/meminfo里的MemTotal),則此時所有應用的寫操作都會被block,各自在自己的時間片里去執行flush,因為操作系統認為現在已經來不及寫盤了,如果crash會丟太多數據,要讓大家都冷靜點。這個代價有點大,要盡量避免。在Redis2.8以前,Rewrite AOF就經常導致這個大面積阻塞,現在已經改為Redis每32Mb先主動flush()一下了。

原理分析結論

  • Kafka使用文件系統來交換消息,性能是否比使用內存來交換消息的系統要低很多?

    • 在Apache Kafka里,消息的讀寫都發生在內存中(Pagecache),真正寫盤的就是那條pdflush內核線程,根本不在Kafka的主流程中,讀操作大多數會命中Pagecache,同時由於預讀機制存在,所以性能非常好,從原理上有保證的。
  • 每個分區一個文件,那么多個分區會有多個文件同時讀寫,是否會極大的降低性能?

    • 首先,由於Kafka讀寫流程是發生在PageCache中,后台的flush不在主流程中觸發,所以正常情況下理論上是沒有影響的,除非PageCache占用內存過大,或是釋放導致讀寫消耗Kafka進程的CPU時間
    • 再次,文件都是順序讀寫,OS層面有預讀和后寫機制,即使一台服務器上有多個Partition文件,經過合並和排序后都能獲得很好的性能,不會出現文件多了變成隨機讀寫的情況,但是當達到相當多的數量之后,也會存在一定的影響。
    • 當PageCache過大,大量觸發磁盤I/O的時候,超過了/proc/sys/vm/dirty_ratio,Flush會占用各個應用自己的CPU時間,會對主流程產生影響,讓主流程變慢。
  • 使用SSD盤並不能顯著地改善 Kafka 的性能,主要有兩個原因:

    • Kafka寫磁盤是異步的,不是同步的。就是說,除了啟動、停止之外,Kafka的任何操作都不會去等待磁盤同步(sync)完成;而磁盤同步(syncs)總是在后台完成的。這就是為什么Kafka消息至少復制到三個副本是至關重要的,因為一旦單個副本崩潰,這個副本就會丟失數據無法同步寫到磁盤。
    • 每一個Kafka Partition被存儲為一個串行的WAL(Write Ahead Log)日志文件。因此,除了極少數的數據查詢,Kafka中的磁盤讀寫都是串行的。現代的操作系統已經對串行讀寫做了大量的優化工作。
  • 如何對Kafka Broker上持久化的數據進行加密

    • 目前,Kafka不提供任何機制對Broker上持久化的數據進行加密。用戶可以自己對寫入到Kafka的數據進行加密,即是,生產者(Producers)在寫Kafka之前加密數據,消費者(Consumers)能解密收到的消息。這就要求生產者(Producers)把加密協議(protocols)和密鑰(keys)分享給消費者(Consumers)。
    • 另外一種選擇,就是使用軟件提供的文件系統級別的加密,例如Cloudera Navigator Encrypt。Cloudera Navigator Encrypt是Cloudera企業版(Cloudera Enterprise)的一部分,在應用程序和文件系統之間提供了一個透明的加密層。
  • Kafka是否支持跨數據中心的可用性

    • Kafka跨數據中心可用性的推薦解決方案是使用MirrorMaker。在你的每一個數據中心都搭建一個Kafka集群,在Kafka集群之間使用MirrorMaker來完成近實時的數據復制。
    • 使用MirrorMaker的架構模式是為每一個”邏輯”的topic在每一個數據中心創建一個topic:例如,在邏輯上你有一個”clicks”的topic,那么你實際上有”DC1.clicks”和“DC2.clicks”兩個topic(DC1和DC2指得是你的數據中心)。DC1向DC1.clicks中寫數據,DC2向DC2.clicks中寫數據。MirrorMaker將復制所有的DC1 topics到DC2,並且復制所有的DC2 topics到DC1。現在每個DC上的應用程序都能夠訪問寫入到兩個DC的事件。這個應用程序能夠合並信息和處理相應的沖突。
    • 另一種更復雜的模式是在每一個DC都搭建本地和聚合Kafka集群。這個模式已經被Linkedin使用,Linkedin Kafka運維團隊已經在 這篇Blog 中有詳細的描述(參見“Tiers and Aggregation”)。

參考


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM