最近工做上須要寫一個小工具,用於解析 beanstalkd 的 binlog。一如既往,我先在網上搜索相關的資料。令我驚訝的是,beanstalkd 官方文檔中連關於 binlog 格式的隻言片語都沒有。網絡上跟 beanstalkd binlog 格式相關的資料也幾乎是個空白。因此在閱讀了 beanstalkd 相關源碼,並編寫了對應工具以後,我試着在本文記下 beanstalkd 的 binlog 的一些相關信息。git
beanstalkd 的 binlog 位於 -b
選項指定的文件夾中,名字就叫 binlog.$order
。binlog 的序號 $order 從 1 開始,逐一遞增。
binlog 文件大小是固定的,能夠經過 -s
選項指定,默認爲 10M。beanstalkd 在建立 binlog 文件時,會先用 0 填充文件的所有內容。github
beanstalkd 的 binlog 內容很是淺顯直白。每一個 binlog 文件最開始是一個 int 類型的版本號,表示 binlog 版本號。
從 2013 年至今,最新的版本號是 7。能夠這麼認爲,現行見到的 binlog 版本號都是 7。以後是每一個操做的 binlog 記錄。
值得一提的是,這裏的 int 的大小是由編譯時編譯器決定的,雖然在主流平臺上它的值是 32 位的。在解析時,最好用 int32 或等價操做去
處理它,而不是照搬 int 的定義。好比像 golang 裏面的 int 就是默認 64 位的。golang
每一個操做的 binlog 記錄由四部份組成:網絡
job record 的格式以下:工具
// 注意我把 padding 標記成 _,原來的結構體定義裏面是沒有這個符號的 struct Jobrec { uint64 id; // id >= 1 uint32 pri; uint32 _; // 注意這裏有一個內存對齊致使的 padding int64 delay; // 精確到納秒 int64 ttr; // 精確到納秒 int32 body_size; int32 _; // 這裏是另一個內存對齊致使的 padding int64 created_at; // 建立時間, epoch 紀年,精確到納秒 int64 deadline_at; // 下一個會因超時而產生狀態變遷的時間 uint32 reserve_ct; // reserve 狀態切換計數,_ct 結尾的都是狀態計數 uint32 timeout_ct; uint32 release_ct; uint32 bury_ct; uint32 kick_ct; byte state; byte[3] _; // 又一個 padding };
建立的操做,會進行 write job full。也即會寫入 len(tubeName),tubeName,record,body 這四項記錄。
其餘操做,會進行 write job short。只寫入 0,record 這兩項記錄。這是由於 record 裏面已經存有 id 了,
能夠經過 id 獲取對應 job 的 tubeName 和 body,因此就不須要在 binlog 裏重複記錄。ui
record 中的 state 取值以下:spa
enum // Jobrec.state { Invalid, Ready, Reserved, Buried, Delayed, Copy };
Ready, Reserved, Buried, Delayed 這四種狀態對應的是 beanstalkd protocol
裏面 job 的四種狀態。
Invalid 對應的是刪除特定的 job 的操做。
Copy 是 stats*
或 peek*
系列命令處理過程當中產生的臨時 job 纔有的狀態,不會記錄到 binlog 中。日誌
當咱們解析到 id 爲 0 的 job 時,意味着該 binlog 已經所有解析完畢,能夠開始解析下一個 binlog 文件了。code
總之解析每一個 binlog 文件的流程是這樣的:
內存
beanstalkd 會不停地產生 binlog 記錄,若是缺乏清理機制,很快就會把磁盤給塞滿。
beanstalkd 在內部維護每個 binlog 文件的 ref 計數。當一個文件裏進行 write job full 操做時,會增長 ref;當一個 job
被刪除時,會減小對應文件的 ref。當一個文件的 ref 減至 0,就能夠放心地把它刪掉了。這一操做,相似於 GC 中的引用計數,
在 beanstalkd 內部實現中也是把它稱做 GC。
上述機制有一個問題。若是有個 job 一直不可以被刪除掉,則對應的 binlog 文件也會一直沒法刪除掉。受影響的不止單個文件。因爲
beanstalkd 須要保證 binlog 文件的有序性,該文件以後的其餘 binlog 也沒法被刪除掉。
所以 beanstalkd 引入了 compat 機制來解決這個問題。若是實際使用量不及日誌量的一半,beanstalkd 會開始進行 compat。compat 不會修改現有 job,但會減小 job 對應文件的 ref,並新寫入一條記錄。其效果等價於,把一箇舊的 job 操做記錄移動到新的文件中來。這麼一來,就能夠避免舊文件的回收被阻塞的狀況了。