日誌存儲系統
❶ 深入理解kafka(五)日誌存儲
5.1文件目錄布局
根目錄下有以下5個checkpoint文件: cleaner-offset-checkpoint, log-start-offset-checkpoint, meta.properties, recovery-point-offset-checkpoint, replication-offset-checkpoint
分區目錄下有以下目錄: 0000xxx.index(偏移量為64位長整形,長度固定為20位), 0000xxx.log, 0000xxx.timeindex.
還有可能包含.deleted .cleaned .swap等臨時文件, 以及可能的.snapshot .txnindex leader-epoch-checkpoint
5.2日誌格式演變
5.2.1 v0版本
kafka0.10.0之前
RECORD_OVERHEAD包括offset(8B)和message size(4B)
RECORD包括:
crc32(4B):crc32校驗值
magic(1B):消息版本號0
attributes(1B):消息屬性。低3位表示壓縮類型:0-NONE 1-GZIP 2-SNAPPY 3-LZ4(0.9.x引入)
key length(4B):表示消息的key的長度。-1代表null
key: 可選
value length(4B):實際消息體的長度。-1代表null
value: 消息體。可以為空,如墓碑消息
5.2.2 v1版本
kafka0.10.0-0.11.0
比v0多了timestamp(8B)欄位,表示消息的時間戳
attributes的第4位也被利用起來,0表示timestamp的類型為CreateTime,1表示timestamp的類型為LogAppendTime
timestamp類型由broker端參數log.message.timestamp.type來配置,默認為CreateTime,即採用生產者創建的時間戳
5.2.3 消息壓縮
保證端到端的壓縮,服務端配置compression.type,默認為"procer",表示保留生產者使用的壓縮方式,還可以配置為"gzip","snappy","lz4"
多條消息壓縮至value欄位,以提高壓縮率
5.2.4 變長欄位
變長整形(Varints):每一個位元組都有一個位於最高位的msb位(most significant bit),除了最後一個位元組為1,其餘都為0,位元組倒序排列
為了使編碼更加高效,Varints使用ZigZag編碼:sint32對應 (n<<1)^(n>>31) sint64對應 (n<<1)^(n>>63)
5.2.5 v2版本
Record Batch
first offset:
length:
partition leader epoch:
magic:固定為2
attributes:兩個位元組。低3位表示壓縮格式,第4位表示時間戳類型,第5位表示事務(0-非事務1-事務),第6位控制消息(0-非控制1控制)
first timestamp:
max timestamp:
procer id:
procer epoch:
first sequence:
records count:
v2版本的消息去掉了crc欄位,另外增加了length(消息總長度)、timestamp delta(時間戳增量)、offset delta(位移增量)和headers信息,並且棄用了attributes
Record
length:
attributes:棄用,但仍占據1B
timestamp delta:
offset delta:
headers:
5.3日誌索引
稀疏索引(sparse index):每當寫入一定量(broker端參數log.index.interval.bytes指定,默認為4096B),偏移量索引文件和時間索引文件分別對應一個索引項
日誌段切分策略:
1.大小超過broker端參數log.segment.bytes配置的值,默認為1073741824(1GB)
2.當前日誌段消息的最大時間戳與當前系統的時間戳差值大於log.roll.ms或者log.roll.hours,ms優先順序高,默認log.roll.hours=168(7天)
3.索引文件或者時間戳索引文件的大小大於log.index.size.max.bytes配置的值,默認為10485760(10MB)
4.偏移量差值(offset-baseOffset)>Integer.MAX_VALUE
5.3.1 偏移量索引
每個索引項佔用8個位元組,分為兩個部分:1.relativeOffset相對偏移量(4B) 2.position物理地址(4B)
使用kafka-mp-log.sh腳本來解析.index文件(包括.timeindex、.snapshot、.txnindex等文件),如下:
bin/kafka-mp-log.sh --files /tmp/kafka-logs/topicId-0/00……00.index
如果broker端參數log.index.size.max.bytes不是8的倍數,內部會自動轉換為8的倍數
5.3.2 時間戳索引
每個索引項佔用12個位元組,分為兩個部分:1.timestamp當前日誌分段的最大時間戳(12B) 2.relativeOffset時間戳對應的相對偏移量(4B)
如果broker端參數log.index.size.max.bytes不是12的倍數,內部會自動轉換為12的倍數
5.4日誌清理
日誌清理策略可以控制到主題級別
5.4.1 日誌刪除
broker端參數log.cleanup.policy設置為delete(默認為delete)
檢測周期broker端參數log.retention.check.interval.ms=300000(默認5分鍾)
1.基於時間
broker端參數log.retention.hours,log.retention.minutes,log.retention.ms,優先順序ms>minutes>hours
刪除時先增加.delete後綴,延遲刪除根據file.delete.delay.ms(默認60000)配置
2.基於日誌大小
日誌總大小為broker端參數log.retention.bytes(默認為-1,表示無窮大)
日誌段大小為broker端參數log.segment.bytes(默認為1073741824,1GB)
3.基於日誌起始偏移量
DeleteRecordRequest請求
1.KafkaAdminClient的deleteRecord()
2.kafka-delete-record.sh腳本
5.4.2 日誌壓縮
broker端參數log.cleanup.policy設置為compact,且log.cleaner.enable設置為true(默認為true)
5.5磁碟存儲
相關測試:一個由6塊7200r/min的RAID-5陣列組成的磁碟簇的線性寫入600MB/s,隨機寫入100KB/s,隨機內存寫入400MB/s,線性內存3.6GB/s
5.5.1 頁緩存
linux操作系統的vm.dirty_background_ratio參數用來指定臟頁數量達到系統的百分比之後就觸發pdflush/flush/kdmflush,一般小於10,不建議為0
vm.dirty_ratio表示臟頁百分比之後刷盤,但是阻塞新IO請求
kafka同樣提供同步刷盤及間斷性強制刷盤(fsync)功能,可以通過log.flush.interval.messages、log.flush.interval.ms等參數來控制
kafka不建議使用swap分區,vm.swappiness參數上限為100,下限為0,建議設置為1
5.5.2 磁碟I/O流程
一般磁碟IO的場景有以下4種:
1.用戶調用標准C庫進行IO操作,數據流為:應用程序Buffer->C庫標准IOBuffer->文件系統也緩存->通過具體文件系統到磁碟
2.用戶調用文件IO,數據流為:應用程序Buffer->文件系統也緩存->通過具體文件系統到磁碟
3.用戶打開文件時使用O_DIRECT,繞過頁緩存直接讀寫磁碟
4.用戶使用類似dd工具,並使用direct參數,繞過系統cache與文件系統直接讀寫磁碟
Linux系統中IO調度策略有4種:
1.NOOP:no operation
2.CFQ
3.DEADLINE
4.ANTICIPATORY
5.5.3 零拷貝
指數據直接從磁碟文件復制到網卡設備中,不需要經應用程序
對linux而言依賴於底層的sendfile()
對java而言,FileChannal.transferTo()的底層實現就是sendfile()
❷ Linux日誌式文件系統面面觀
文件系統是用來管理和組織保存在磁碟驅動器上的數據的系統軟體,其實現了數據完整性的保 證,也就是保證寫入磁碟的數據和隨後讀出的內容的一致性。除了保存以文件方式存儲的數據以外,一個文件系統同樣存儲和管理關於文件和文件系統自身的一些重要信息(例如:日期時間、屬主、訪問許可權、文件大小和存儲位置等等)。這些信息通常被稱為元數據(metadata)。
由於為了避免磁碟訪問瓶頸效應,一般文件系統大都以非同步方式工作,因此如果磁碟操作被突然中斷可能導致數據被丟失。例如如果出現這種情況:如果當你處理一個在linux的ext2文件系統上的文檔,突然機器崩潰會出現什麼情況?
有這幾種可能:
*當你保存文件以後,系統崩潰。這是最好的情況,你不會丟失任何信息。只需要重新啟動計算機然後繼續工作。
*在你保存文件之前系統崩潰。你會丟失你所有的工作內容,但是老版本的文檔還會存在。
*當正在將保存的文檔寫入磁碟時系統崩潰。這是最糟的情況:新版文件覆蓋了舊版本的文件。這樣磁碟上只剩下一個部分新部分舊的文件。如果文件是二進制文件那麼就會出現不能打開文件的情況,因為其文件格式和應用所期待的不同。
在最後這種情況下,如果系統崩潰是發生在驅動器正在寫入元數據時,那麼情況可能更糟。這時候就是文件系統發生了損壞,你可能會丟失整個目錄或者整個磁碟分區的數據。
linux標准文件系統(ext2fs)在重新啟動時會通過調用文件掃描工具fsck試圖恢復損壞的元數據信息。由於ext2文件系統保存有冗餘的關鍵元數據信息的備份,因此一般來說不大可能出現數據完全丟失。系統會計算出被損壞的數據的位置,然後或者是通過恢復冗餘的元數據信息,或者是直接刪除被損壞或是元數據信息損毀的文件。
很明顯,要檢測的文件系統越大,檢測過程費時就越長。對於有幾十個G大小的分區,可能會花費很長時間來進行檢測。由於Linux開始用於大型伺服器中越來越重要的應用,因此就越來越不能容忍長時間的當機時間。這就需要更復雜和精巧的文件系統來替代ext2。
因此就出現了日誌式文件系統(journalling filesystems)來滿足這樣的需求。
什麼是日誌式文件系統
這里僅僅對日誌式文件系統進行簡單的說明。如果需要更深入的信息請參考文章日誌式文件系統,或者是日誌式文件系統介紹。
大多數現代文件系統都使用了來自於資料庫系統中為了提高崩潰恢復能力而開發的日誌技術。磁碟事務在被真正寫入到磁碟的最終位置以前首先按照順序方式寫入磁碟中日誌區(或是log區)的特定位置。
根據日誌文件系統實現技術的不同,寫入日誌區的信息是不完全一樣的。某些實現技術僅僅寫文件系統元數據,而其他則會記錄所有的寫操作到日誌中。
現在,如果崩潰發生在日誌內容被寫入之前發生,那麼原始數據仍然在磁碟上,丟失的僅僅是最新的更新內容。如果當崩潰發生在真正的寫操作時(也就是日誌內容已經更新),日誌文件系統的日誌內容則會顯示進行了哪些操作。因此當系統重啟時,它能輕易根據日誌內容,很快地恢復被破壞的更新。
在任何一種情況下,都會得到完整的數據,不會出現損壞的分區的情況。由於恢復過程根據日誌進行,因此整個過程會非常快只需要幾秒鍾時間。
應該注意的是使用日誌文件系統並不意味著完全不需要使用文件掃描工具fsck了。隨機發生的文件系統的硬體和軟體錯誤是根據日誌是無法恢復的,必須藉助於fsck工具。
目前Linux環境下的日誌文件系統
在下面的內容里將討論三種日誌文件系統:第一種是ext3,由Linux內核Stephen Tweedie開發。ext3是通過向ext2文件系統上添加日誌功能來實現的,目前是redhat7.2的默認文件系統;Namesys開發的ReiserFs日誌式文件系統,可以下載,目前Mandrake8.1採用該日誌式文件系統。SGI在2001年三月發布了XFS日誌式文件系統。可以在 oss.sgi.com/projects/xfs/下載。下面將對這三種日誌文件系統採用不同的工具進行檢測和性能測試。
安裝ext3
關於ext3文件系統技術方面的問題請參考Dr. Stephen Tweedie的論文和訪談。ext3日誌式文件系統直接來自於其祖先ext2文件系統。其具有完全向後兼容的關鍵特性,實際上其僅僅是在ext2日誌式文件系統上添加了日誌功能。其最大的缺點是沒有現代文件系統所具有的能提高文件數據處理速度和解壓的高性能。
ext3從 2.2.19開始是作為一個補丁方式存在的。如果希望對內核添加對ext3文件系統的支持,就需要使用補丁,可以得到補丁程序,一共需要如下文件:
* ext3-0.0.7a.tar.bz2:內核補丁
* e2fsprogs-1.21-WIP-0601.tar.bz2 支持ext3的e2fsprogs程序套件
拷貝linux-2.2.19.tar.bz2和ext3-0.0.7a.tar.bz2到/usr/src目錄下,進行解壓:
mv linux linux-old
tar -Ixvf linux-2.2.19.tar.bz2
tar -Ixvf ext3-0.0.7a.tar.bz2
cd linux
cat ../ext3-0.0.7a/linux-2.2.19.kdb.diff | patch -sp1
cat ../ext3-0.0.7a/linux-2.2.19.ext3.diff | patch -sp1
首先對內核添加SGI的kdb內核調試器補丁,第二個是ext3文件系統補丁。下來就需要配置內核,對文件系統部分的"Enable Second extended fs development code"回答Yes。然後編譯。
內核編譯安裝以後,需要安裝e2fsprogs軟體套件:
tar -Ixvf e2fsprogs-1.21-WIP-0601.tar.bz2
cd e2fsprogs-1.21
./configure
make
make check
make install
下來要做的工作就是在分區上創建一個ext3文件系統,使用新內核重新啟動,這時候你有兩種選擇創建新的日誌文件系統或者對一個已有的ext2文件系統升級到ext3日誌文件系統。
對於需要創建新ext3文件系統的情況下,只需要使用安裝的e2fsprogs軟體包中的mke2fs命令加-f參數就可以創建新的ext3文件系統:
mke2fs -j /dev/xxx
這里/dev/xxx是希望創建ext3文件系統的新分區。-j參數表示創建ext3而不是ext2文件系統。可以使用參數"-Jsize="來指定希望的日誌區大小(n單位為M)。
升級一個已有的ext2,使用tune2fs就可以了:
tune2fs -j /dev/xxx
你可以對正在載入的文件系統和沒有載入的文件系統進行升級操作。如果當前文件系統正在被載入,則文件.journal會在文件系統載入點的所在目錄被創建。如果是升級一個當時沒有載入的文件系統,則使用隱含的系統inode來記錄日誌,這時候文件系統的所有內容都會被保留不被破壞。
你可以使用下面的命令載入ext3文件系統:
mount -t ext3 /dev/xxx /mount_dir
由於ext3實際上是帶有日誌功能的ext2文件系統 ,因此一個ext3文件系統可以以ext2的方式被載入。
安裝XFS文件系統
如果需要從技術方面了解XFS文件系統,請參考SGI的XFS文件系統和SGI信息頁面。也可以參考FAQ。
XFS是一個SGI開發的linux環境下的日誌文件系統,它是一個成熟的技術,最初是使用在IRIX系統上的文件系統。XFS遵循GPL版權申明。目前xfs文件系統最新版本是1.02。下載得到對內核xfs文件系統支持補丁或者直接下載RPM包方式的內核,下面我們就以補丁方式說明如何對2.4.14內核使用xfs。首先下載如下內容
patch-2.4.14-xfs-1.0.2.bz2
patch-2.4.14-xfs-1.0.2-kdb.bz2
拷貝Linux內核linux-2.4.2.tar.bz2到 /usr/src目錄下,修改老的內核目錄名,然後解壓新內核:
mv linux linux-old
tar -Ixf inux-2.4.2.tar.bz2
拷貝每個每個補丁到內核源碼目錄下(例如:/usr/src/linux),並打補丁:
zcat patch-2.4.14-xfs-1.0.2.bz2 | patch -p1
zcat patch-2.4.14-xfs-1.0.2-kdb.bz2 | patch -p1
然後配置內核,打開文件系統部分的內核選項:"XFS filesystem support" (CONFIG_XFS_FS)和"Page Buffer support" (CONFIG_PAGE_BUF)。同時需要升級下面這些系統工具到下面或更高的版本:
motils-2.4.0
autoconf-2.13
e2fsprogs-devel-1.18
安裝新內核並重啟伺服器。
然後下載xfs工具。這個軟體包包括下面的命令來處理文件系統,使用下面的命令來安裝該軟體包::
tar -zxf xfsprogs-1.2.0.src.tar.gz
cd xfsprogs-1.2.0
make configure
make
make install
安裝這些命令以後,就可以創建新的XFS文件系統:
mkfs -t xfs /dev/xxx
如果xxx是一個已經存在的文件系統,那麼就需要使用"-f"參數來創建新分區,但是記得這將會破壞該分區的所有數據。
mkfs -t xfs -f /dev/xxx
創建以後就可以使用基於下面的命令載入新文件系統:
mount -t xfs /dev/xxx /mount_dir
安裝ReiserFS文件系統
如果希望更多地從技術方面了解reiserFS文件系統,請參考NAMESYS和FAQ。
ReiserFS文件系統從2.4.1-pre4開始就是Linux內核的正式支持的文件系統了。為了使用reiserFS文件系統那你首先需要在系統上安裝文件系統支持工具(如:創建ReiserFS文件系統的mkreiserfs工具)。最新的ReiserFS文件系統版本可以以補丁的方式添加到2.2.x或者2.4.x內核中。這里我們以2.2.19為例:
第一步,首先下在內核源碼,並下在ReiserFS文件系統的2.2.19補丁 ,目前補丁最新版本是linux-2.2.19-reiserfs-3.5.34-patch.bz2。同時應該下載工具軟體包:reiserfsprogs-3.x.0j.tar.gz。
然後解壓內核源碼和補丁包到/usr/src中:
tar -Ixf linux-2.2.19.tar.bz2
bzcat linux-2.2.19-reiserfs-3.5.34-patch.bz2 | patch -p0
編譯內核支持reiserfs,安裝內核。然後安裝文件系統工具軟體:
cd /usr/src/linux/fs/reiserfs/utils
make
make install
安裝新內核並重新啟動。現在就可以創建新的'reiserfs文件系統,並載入:
mkreiserfs /dev/xxxx
mount -t reiserfs /dev/xxx /mount_dir
文件系統性能測試
測試環境使用的計算機環境如下:Pentium III - 16 Mb RAM - 2 Gb HD,操作系統為RedHat6.2。所有的文件系統都能正常工作,所以就進行benchmark分析來對它們進行性能比較。首先我直接拔掉系統電源以模擬系統掉電情況,以測試日誌文件系統恢復過程。所有的文件系統都成功地經過了文件掃描檢測階段,在數秒以後系統都經過了掃描然後正常啟動了系統。
下一步就採用了bonnie++性能測試程序進行測試,這個程序對一個文件進行資料庫類型的訪問,進行了創建、讀和刪除小文件,這些操作對於Squid、INN或者Maildir格式的郵件伺服器程序(qmail)是最常見的操作。性能測試命令為:
bonnie++ -d/work1 -s10 -r4 -u0
其對載入在/work1目錄下的文件系統進行了10Mb(-s10)的測試。因此在執行測試之前必須創建適當類型的文件系統並載入到目錄/work1下。其他的參數指定內存大小(-r4)的M數,和以root身份運行測試程序,測試結果如下:
每種測試都有兩組數據:文件系統速度(K/sec)和CPU佔用率(%CPU)。速度越高,文件系統越好。而對於CPU率來說,數字越小性能越好。可以看到Reiserfs文件系統在文件操作方面(Sequential Create和Random Create部分的) 的性能最好,超出其他文件系統10倍之多。在其他方面(Sequential Output和Sequential Input)則和其他文件系統性能不相上下。對於其他文件系統則沒有特別明顯的區別。XFS性能接近ext2文件系統,ext3文件系統則比ext2要稍微慢上一些(因為記錄日誌需要一些額外的時間)。 最後使用從得到的性能測試程序mongo,並對其進行了修改以對三種日誌文件系統進行測試。這里在mongo.pl程序中添加了添加了載入xfs和ext3文件系統的命令,並對其進行格式化處理,然後就開始性能測試分析。 該腳本格式劃分區/dev/xxxx,載入其並在每個階段運行指定數目的進程:創建、拷貝、符號連接處理、讀、顯示文件狀態信息、重命名和刪除文件。同時,該程序在創建和拷貝階段以後會計算分段數(fragmentation)。
Fragm = number_of_fragments / number_of_files
可以在結果文件中得到同樣的測試比較結果:
log - 原始結果
log.tbl - 比較程序的輸出結果
log_table - 表格式的結果
下面的命令進行測試:
mongo.pl ext3 /dev/hda3 /work1 logext3 1
如果要測試其他文件系統,就需要把上面命令的參數中的ext3修改為reiserfs或xfs。其他參數分別為要載入的分區,載入路徑,保存測試結果的文件名及啟動的進程數。
下面的表格是測試結果。數據單位為秒。值越低性能越好。第一個表格測試使用的數據塊大小為100位元組,第二個表格為1000位元組,最後一個為10000位元組
從上面的表格可以看到ext3在狀態刪除和重命名方面要性能更好一些,而ReiserFS文件系統在文件創建和拷貝性能表現更出色。同時也可以看到reiserFS正如其技術文檔提到的其在小文件處理方面性能相當出色。
結論
目前Linux至少有兩個健壯可靠的日誌文件系統可供選擇(XFS和reiserFS),其都得到了廣泛的應用。例如Mandrake8.1就默認支持reiserFS文件系統。
從性能測試的結果可以看到,reiserFS是最好的選擇。
