最近工做上须要写一个小工具,用于解析 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 操做记录移动到新的文件中来。这么一来,就能够避免旧文件的回收被阻塞的状况了。