1 背景
在讀完kafka官方文檔,kafka設(shè)計(jì)里的持久化一章后,給我的第一印象是內(nèi)容很抽象,于是草擬和總結(jié)了給個(gè)副標(biāo)題,并把相關(guān)內(nèi)容進(jìn)行了歸類;有些生澀的句子,盡量用大白話和舉例進(jìn)行說(shuō)明,并加入了總結(jié)。
2 磁盤IO速度的快和慢,不取決我們的主觀認(rèn)知,而是由我們的使用方式?jīng)Q定的
kafka 里消息的緩存和存儲(chǔ),嚴(yán)重依賴文件系統(tǒng)。(根據(jù)上下文推測(cè),這里的緩存消息和存儲(chǔ)消息,指的是broker端 緩存和存儲(chǔ)消息)
在我們普遍的認(rèn)知里,都覺(jué)得“磁盤IO速度是非常慢的”,這種固有的觀點(diǎn),使得人們懷疑持久性結(jié)構(gòu)是否能夠提供競(jìng)爭(zhēng)性的性能。
(和其它MQ中間件相對(duì),你把數(shù)據(jù) 存入到磁盤上,還有性能上的優(yōu)勢(shì)嗎?)
但實(shí)際上,磁盤速度,取決于他們的使用方式,設(shè)計(jì)得當(dāng)?shù)拇疟P結(jié)構(gòu)往往可以和網(wǎng)絡(luò)一樣快。
從順序?qū)憯?shù)據(jù)到磁盤的角度分析 ------順序?qū)懘疟P,比隨機(jī)訪問(wèn)內(nèi)存的速度還快
事實(shí)上 關(guān)于磁盤性能,在過(guò)去十年中,硬盤驅(qū)動(dòng)器的吞吐量與磁盤尋道的延遲一直存在差異。
在具有六個(gè) 7200rpm SATA RAID-5 陣列的 JBOD 配置上,線性寫入性能約為 600MB/秒,但隨機(jī)寫入性能僅為約 100k/秒,相差超過(guò) 6000 倍。
這些線性讀取和寫入是所有使用模式中最可預(yù)測(cè)的,并且經(jīng)過(guò)操作系統(tǒng)的大力優(yōu)化。現(xiàn)代操作系統(tǒng)提供預(yù)讀和后寫技術(shù),以大塊倍數(shù)預(yù)取數(shù)據(jù),并將較小的邏輯寫入分組為較大的物理寫入。
有關(guān)此問(wèn)題的進(jìn)一步討論可以在這篇 ACM Queue 文章中找到;他們實(shí)際上發(fā)現(xiàn)順序磁盤訪問(wèn)在某些情況下比隨機(jī)內(nèi)存訪問(wèn)更快!如下圖所示:
從磁盤讀寫數(shù)據(jù)的角度 ------使用磁盤緩存,加速磁盤讀寫速度
為了彌補(bǔ)這種性能差異,現(xiàn)代操作系統(tǒng)在使用主內(nèi)存進(jìn)行磁盤緩存方面變得越來(lái)越積極。
現(xiàn)代操作系統(tǒng)將所有空閑內(nèi)存快樂(lè)地用于磁盤緩存,當(dāng)內(nèi)存被回收時(shí)幾乎沒(méi)有性能損失。
所有磁盤讀寫都將通過(guò)這個(gè)統(tǒng)一緩存進(jìn)行。
這個(gè)特性很難關(guān)閉,即使進(jìn)程在進(jìn)程內(nèi)保持?jǐn)?shù)據(jù)緩存,這些數(shù)據(jù)也可能會(huì)在OS頁(yè)面緩存中重復(fù)存儲(chǔ),實(shí)際上將所有東西存儲(chǔ)兩次。
(日常 數(shù)據(jù)在寫入磁盤時(shí),并沒(méi)有刷新到磁盤上,只是寫到了磁盤緩存里,而磁盤緩存其實(shí)是操作系統(tǒng)的主內(nèi)存;即把數(shù)據(jù)寫入文件的時(shí)候,其實(shí)還是寫到內(nèi)存中)
圖 kafka broker端 數(shù)據(jù)寫入過(guò)程
kafka在寫入數(shù)據(jù)到文件系統(tǒng)時(shí),同步寫入到pagecache,異步刷新并持久化到磁盤里。
3 把數(shù)據(jù)緩存到JVM有哪些劣勢(shì)了?
kafka構(gòu)建在JVM之上,任何花費(fèi)過(guò)時(shí)間了解過(guò) Java內(nèi)存使用的人都知道兩件事:
對(duì)象的內(nèi)存開銷很高,通常會(huì)使存儲(chǔ)的數(shù)據(jù)大小翻倍(或更糟)。(即原數(shù)據(jù)可能只有1K大小,但是轉(zhuǎn)換為java對(duì)象,可能要3K)
隨著堆內(nèi)數(shù)據(jù)的增加,Java垃圾回收變得越來(lái)越繁瑣和慢。(jvm里緩存的數(shù)據(jù),會(huì)放到堆內(nèi)存中;隨這數(shù)據(jù)越來(lái)越多,達(dá)到GC的臨界點(diǎn)會(huì)越來(lái)越快,導(dǎo)致GC越來(lái)越頻繁 ;這樣就會(huì)導(dǎo)致系統(tǒng)會(huì)把資源用于GC,而不是業(yè)務(wù)處理了)
4 把數(shù)據(jù)緩存到文件系統(tǒng)有哪些優(yōu)勢(shì)了?
使用文件系統(tǒng)并依賴頁(yè)面緩存方式,比維護(hù)內(nèi)存中緩存或其他結(jié)構(gòu)要更優(yōu) 。主要原因:
相對(duì)于把數(shù)據(jù)緩存到j(luò)vm中,直接使用操作系統(tǒng)頁(yè)面緩存,可讓程序能使用的緩存加倍。(因?yàn)閖vm 對(duì)象的內(nèi)存開銷很高,他會(huì)膨脹。1K的數(shù)據(jù)放入到頁(yè)面緩存還是1K;但是轉(zhuǎn)換為JVM對(duì)象,可能就占用了3K空間)
把消息數(shù)據(jù)使用字節(jié)結(jié)構(gòu)并且壓縮的方式進(jìn)行存儲(chǔ),比單個(gè)對(duì)象的存儲(chǔ)更節(jié)約空間,并且還可能進(jìn)一步帶來(lái)緩存內(nèi)存的加倍使用。
這樣做即使在 32GB 機(jī)器上也可產(chǎn)生高達(dá) 28-30GB 的緩存,而不會(huì)造成 GC 損失。(---即使緩存中的數(shù)據(jù)變大,也不會(huì)帶來(lái)頻繁的GC)
即使kafka 服務(wù)重新啟動(dòng),此緩存也將保持熱狀態(tài)。(頁(yè)面緩存中數(shù)據(jù)還在,因?yàn)閗afka進(jìn)程重新,而操作系統(tǒng)可能不會(huì)重啟) 而如果把數(shù)據(jù)放入到進(jìn)程內(nèi)緩存,kafka服務(wù)重啟時(shí)將需要在內(nèi)存中重建(對(duì)于 10GB 緩存可能需要 10 分鐘),否則它將需要以完全冷的緩存啟動(dòng) (這可能意味著糟糕的初始性能)。
極大地簡(jiǎn)化了代碼,因?yàn)橛糜诰S護(hù)緩存和文件系統(tǒng)之間一致性的所有邏輯現(xiàn)在都在操作系統(tǒng)中,這往往比一次性進(jìn)程內(nèi)嘗試更有效、更正確。
如果您的磁盤使用有利于順序讀取的方式,那么操作系統(tǒng)的預(yù)讀實(shí)際上是在每次磁盤讀取時(shí)使用有用的數(shù)據(jù)預(yù)先填充此緩存。
(這里涉及到操作系統(tǒng)讀取磁盤上的數(shù)據(jù)時(shí)的一種優(yōu)化---預(yù)讀。即往磁盤里讀一行數(shù)據(jù),操作系統(tǒng)實(shí)際上是把這一行數(shù)據(jù),和他后面的5K數(shù)據(jù),都會(huì)一次性讀出來(lái),放入到緩存里。這對(duì)于kafka這種順序消費(fèi)消息的模式,非常適用,因?yàn)槎嘧x出來(lái)的數(shù)據(jù),其實(shí)在后續(xù)消費(fèi)的時(shí)候,是需要的,這避免了重復(fù)從硬盤多次讀取數(shù)據(jù),非常類似于一次性加載大塊的數(shù)據(jù)到內(nèi)存中;然后還沒(méi)有浪費(fèi)內(nèi)存空間,因?yàn)檫@些數(shù)據(jù)后續(xù)馬上也是需要被消費(fèi)者消費(fèi)的)
5 kafka 以文件系統(tǒng)進(jìn)行存儲(chǔ)和緩存的設(shè)計(jì)建議
我們不是在內(nèi)存中保留盡可能多的內(nèi)容,而是在空間不足時(shí)將其全部刷新到文件系統(tǒng),而是將其反轉(zhuǎn)。所有數(shù)據(jù)都會(huì)立即寫入文件系統(tǒng)上的持久日志,而不必刷新到磁盤。實(shí)際上,這僅僅意味著它被轉(zhuǎn)移到內(nèi)核的頁(yè)面緩存中
(我們不會(huì)把數(shù)據(jù) 緩存到j(luò)vm進(jìn)程內(nèi)存里,當(dāng)空間不足時(shí),再刷新到緩存里;而是采用了相反的方式:即所有數(shù)據(jù)會(huì)立即寫入到文件系統(tǒng)里,即磁盤緩存里(即頁(yè)緩存里),但不會(huì)寫入后馬上刷新數(shù)據(jù)到磁盤里)
============以下為個(gè)人總結(jié)和觀點(diǎn)==============
6 kafka 這種同步寫文件緩存,異步順序刷新數(shù)據(jù)到磁盤的方式就不怕,操作系統(tǒng)掛了,數(shù)據(jù)會(huì)丟失嗎?
如果page cache在持久化到磁盤前,broker進(jìn)程宕機(jī)了,這個(gè)時(shí)候不會(huì)丟失消息,重啟broker即可;如果此時(shí)操作系統(tǒng)宕機(jī)或者物理機(jī)宕機(jī)了,page cache里的數(shù)據(jù)還沒(méi)有持久化到磁盤里,此種情況數(shù)據(jù)就丟了。
kafka應(yīng)對(duì)此種情況,建議是通過(guò)多副本機(jī)制來(lái)解決的,核心思想也挺簡(jiǎn)單的:如果數(shù)據(jù)保存在一臺(tái)機(jī)器上你覺(jué)得可靠性不夠,那么我就把相同的數(shù)據(jù)保存到多臺(tái)機(jī)器上,某臺(tái)機(jī)器宕機(jī)了可以由其它機(jī)器提供相同的服務(wù)和數(shù)據(jù)。 更加詳細(xì)的配置 請(qǐng)看《kafka 消息“零丟失”的配方》 broker端丟失消息的情況和解決方法一節(jié)
7 那能不能自己控制這個(gè)數(shù)據(jù)刷盤行為了?
可以的,在kafka的官方配置文檔里有兩個(gè)參數(shù):
log.flush.interval.messages 和 log.flush.interval.ms
一個(gè)控制消息量達(dá)到了多少,一個(gè)控制間隔時(shí)間多少;會(huì)把頁(yè)緩存里消息刷新到磁盤里;但這個(gè)控制刷盤行為也是異步的
8 總結(jié)
1、kafka broker端會(huì)把文件系統(tǒng),做為消息緩存和存儲(chǔ);因?yàn)椴僮飨到y(tǒng)在寫數(shù)據(jù)到磁盤時(shí),已進(jìn)行了優(yōu)化
2、kafka broker 在寫入數(shù)據(jù)到文件系統(tǒng)時(shí),同步寫入到磁盤緩存里(即內(nèi)存里),異步把緩存中的數(shù)據(jù)寫入到磁盤里。這是kafka 寫數(shù)據(jù)到文件系統(tǒng)高效的主要原因,也是核心業(yè)務(wù) 寫數(shù)據(jù)主流程 高效的主原因;異步順序刷新數(shù)據(jù)到磁盤里,我覺(jué)得是性能高的次要原因,畢竟不阻塞到主流程
3、kafka 作為消息系統(tǒng),天生就是順序?qū)懭霐?shù)據(jù)到文件系統(tǒng),并順序讀取文件系統(tǒng)的,這種天然的順序性,恰好可以利用操作系統(tǒng)的預(yù)讀功能:即一次磁盤IO 讀取數(shù)據(jù)時(shí),會(huì)把數(shù)據(jù)附近其他磁盤數(shù)據(jù)也讀寫到內(nèi)存中;下一次讀取下一條消息時(shí),不需要磁盤IO了,直接從內(nèi)存中獲取數(shù)據(jù),減少磁盤IO 這種非常慢的讀取次數(shù),加速取數(shù)過(guò)程。
審核編輯:湯梓紅
-
存儲(chǔ)
+關(guān)注
關(guān)注
13文章
4296瀏覽量
85798 -
內(nèi)存
+關(guān)注
關(guān)注
8文章
3019瀏覽量
74003 -
磁盤
+關(guān)注
關(guān)注
1文章
375瀏覽量
25201 -
文件
+關(guān)注
關(guān)注
1文章
565瀏覽量
24727 -
kafka
+關(guān)注
關(guān)注
0文章
51瀏覽量
5214
原文標(biāo)題:為什么kafka使用磁盤文件來(lái)緩存和存儲(chǔ)消息
文章出處:【微信號(hào):magedu-Linux,微信公眾號(hào):馬哥Linux運(yùn)維】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論