beanstalkd

协议

描述

beanstalkd 协议 运行在 TCP 层上,并采用了 ASCII 编码。
大致工作流程为:开启客户端连接、发送命令和数据、等待响应、关闭连接。
对于每一个连接而言,服务器会按照接收到指令的顺序一一执行这些指令,并且按照同样的顺序,发送响应。
在本协议中,所有涉及到的整数,都是指十进制,且为非负,除非另有说明。

命名约定

只支持 ASCII 字符进行命名
其支持的字符有:

  • 字母( A-Z、a-z )
  • 数字( 0-9 )
  • 小短横( - )
  • 加号( + )
  • 正斜杠( / )
  • 英文封号( ; )
  • 英文点号( . )
  • 美元符( $ )
  • 英文下划线( _ )
  • 英文左右小括号( “(“ 和 “)” )

    注意:命名不可以 - 作为开头,当遇到空格或换行时,会视作命名结束。每个命名的长度,至少为 1+ 个字符。

Errors

错误类型 描述
OUT_OF_MEMORY\r\n 服务器内存不够分配了,可能需要过一会再尝试
INTERNAL_ERROR\r\n 这说明服务器,也就是 beanstalkd 内部出现了 bug ,理论上不应该出现这个错误,如果出现了,请将这个 bug 提交到 google group
BAD_FORMAT\r\n 发送的命令格式错误。比如,命令行不是以 \r\n 结尾,又或者在该传入数值的地方传入了非数值,也可能参数数量错误等一切命令格式有误的可能性。
UNKMOWM_COMMAND\r\n 使用了未定义的命令(找不到这个命令),此时可能要检查是否拼写有错

Job 生命周期

一个 Job 由 put 命令创建,在它的生命周期以内,它必将处于以下四种状态中的一种:「ready」、「reserved」、「delayed」、「buried」
当使用完 put 命令,Job 一般从 「ready」 开始,它会在「ready」队列中等待,直到有「reserved」命令过来,当接收成功之后,则将该 Job 放入到 「reserved」 队列。接着,当进程处理完这个 Job 之后,则会发送一个「delete」命令,将这个 Job 从 beanstalkd 中删除。

状态 描述
ready 被放入 Tube 之后等待被接收和处理
reserved 当 Job 被 reserve 命令接收,Job 会进入这个状态,它代表被接收,但还没有得到其他反馈
delayed 延迟状态,等时间到了会变成 ready 状态
buried 预留状态,一般当消费者处理失败时,会将它设置为预留

图示 Job 生命周期:

  1. put reserve delete
  2. -----> [READY] ---------> [RESERVED] --------> *poof*

当然,它也可能经历更复杂的演化,如下图:

  1. put with delay release with delay
  2. ----------------> [DELAYED] <------------.
  3. | |
  4. kick | (time passes) |
  5. | |
  6. put v reserve | delete
  7. -----------------> [READY] ---------> [RESERVED] --------> *poof*
  8. ^ ^ | |
  9. | \ release | |
  10. | `-------------' |
  11. | |
  12. | kick |
  13. | |
  14. | bury |
  15. [BURIED] <---------------'
  16. |
  17. | delete
  18. `--------> *poof*

Tubes

一个 beanstalkd 服务允许拥有多个 Tube ,每一个 Tube 包含两个队列: ready queue 和 delay queue 。
每个 Job 都必然会存在于某个 Tube 之下。
可以通过 watch 指令关注某个 Tube ,也可以通过 ignore 命令取消关注。
当你使用 watch list 命令时,它会返回你所关注的 tubes 。
当消费者开始接收 Job 的时候,Job 一般来自 watch 了的 Tube。
当一个客户端连接进来,watch list 最初只有一个名为 default 的 tube 。如果当存入 Job 时没有使用 use 命令指定 tube ,这个 Job 就会被放入到 default tube 中。
Tubes 会在你使用到它的时候创建,如果 Tube 变空了(没有 ready Job ,没有 delayed Job , 没有 buried Job),且没有客户端连接指向它,它就会被删掉。

命令

生产者命令

put

此命令用于向队列中插入 job ,命令格式如下:

  1. put <pri> <delay> <ttr> <bytes>\r\n
  2. <data>\r\n

它默认会将 job 插入到当前所 use 的 tube , 这点可以参考下面的 use命令

选项 描述
pri 这是一个整型数值,代表着这个 job 的优先级,数值越小,排队排在越前面,优先级最高为 0 ,最后面为 4294967295
delay 这也是一个整型数值,是一个秒数,指多少秒之后将这个 job 放入到 ready queue 中,在那之前,这个 job 都将处于 delayed 状态
ttr 这也是一个整型数值,是一个描述,指一个 job 被允许处理的最大时间,这个时间从 job 被 reserve 起开始计算,超过时间还未被 delete 、 release 、 bury ,则服务器会自动释放这个 job,并重新插入到 ready queue 中。此数值最小支持 1 ,如果传的是 0 ,则服务器会默认将它变成 1
bytes 这是一个数值,用于指明这个 job body 的大小,不包含「\r\n」这两个字符。这个值必须小于 beanstalkd 配置的 max-job-size , 单位是 bytes
data 这是 job body ,上一行的 bytes 就是由此行除却「\r\n」计算得出的。

当成功发送 put 命令后,客户端要等待响应,响应结果可能是如下几个:

响应 描述
INSERTED \r\n 插入成功,id 是一个 interger ,标识新插入的 job
BURIED \r\n 如果服务器因为增加优先级队列而内存不足时会返回这个结果,id 是一个 interger ,标识新插入的 job
EXPECTED_CRLF\r\n job body 必须以「\r\n」结尾,这两个字节不用计入上一行的 bytes 计算中
JOB_TOO_BIG\r\n job body 超出了 max-job-size 的限制
DRAINING\r\n 目标服务器不再接收新的请求,需要尝试其他服务器,或断开连接之后晚点再重新尝试

use

此命令为 Producer 提供,当发送此命令之后,后续的 put 命令,就会把 job 全部放入到此 use 命令指定的 tube 中。如果没有通过 use 指定 tube , 则会默认将 job 放入到 default tube 中。

  1. use <tube>\r\n
选项 描述
tube 一个最大不超过 200 bytes 的名称,它指定一个 tube ,如果这个 tube 不存在,则会自动创建
响应 描述
USING \r\n 是接下来开始使用的 tube

消费者命令

从 queue 中消费 job 会使用以下命令:

  • reserve
  • delete
  • release
  • bury

    reserve

    1. reserve\r\n
    另外,你还能指定接收的超时时间,如下:
    1. reserve-with-timeout <seconds>\r\n
    这个命令将会返回一个新的、reserved 状态的 job
    如果没有可用的 job 能被接收,则 beanstalkd 一直等到出现一个可接收的 job 之后再返回。
    一旦一个 job 被客户端接收,客户端要在 ttr 指定的时间限定内处理 job ,否则,超时的话,服务器会将 job 重新放回 ready queue 中。
    可以在 stats-job 命令的 response 中找到 ttr 的值和已经使用掉的时间。
    如果处于 ready 状态的 job 不止一个,beanstalkd 将会选择一个 priority 最小的 job,如果 priority 相等,则会选择一个最先 put 的 job 。

    题外话:这里我怀疑 beanstalkd 的协议有一处写错了,原文为 Within each priority, it will choose the one that was reserved first. 我认为应该将 reserved 改为 put 。

如果指定的 timeout seconds 是 0 ,这将导致服务器立即返回 TIME_OUT 的响应(也有可能立即返回一个 job ,这取决于服务器的响应速度以及是否存在可接收的 job )
为 timeout 设置一个合理的 seconds ,可以限制客户端阻塞等待接收 job 的时间。

失败响应 描述
DEADLINE_SOON\r\n ttr 的最后一秒,被服务器设定为安全界限,在此期间,该客户端不会接收到另外一个 job 。比如:客户端在安全界限时间里发送了一条 reserve 命令,或者,当一条 reserve 命令在等待反馈时,安全界限时间正好到期,这时候,都将得到一个 DEADLINE_SOON\r\n 的响应
TIMED_OUT\r\n 当使用 reserve-with-timeout 命令,超过时间还未接收到 job ,又或者客户端连接已经关闭,此时会返回此值

成功响应:

  1. RESERVED <id> <bytes>\r\n
  2. <data>\r\n
参数 描述
id job 的 id ,一个整型值,在这个 beanstalkd 服务器中具备全局唯一性
bytes 表示 job data 的大小,不包含结束符 \r\n
data job data , 之前 put 时放入的 job data ,原模原样返回

delete

delete 命令用于从服务器完全删除一个 job , 这一般用于客户端成功处理 job 之后。
客户端可以删除 reserved 的 job , 使 job 进入准备状态 , 延迟 job ,预留 job 。

  1. delete <id>\r\n
选项 描述
id job 的 id
响应 描述
DELETED\r\n 删除成功
NOT_FOUND\r\n 找不到这个 job ,或者这个 job 并非这台 client 接收的、或是 job 处于 ready 、 buried 状态。这很可能发生在 ttr 时间到了之后才发送 delete 命令的情况下。

release

此命令可以把 reserved job 放回 ready 队列中,同时 job 的状态也会回到 ready ,release 之后,这个 job 可以被任何其他的客户端接收。
一般这个命令用在消费者处理 job 失败的情况下。

  1. release <id> <pri> <delay>\r\n
选项 描述
id job id
pri interger ,指定一个新的优先级,数值越小,越早被接收
delay interger ,指定一个新的延迟,如果设置了预留值,则 job 的状态会是 delayed ,直到延迟时间到期
响应 描述
RELEASED\r\n 处理成功
BURIED\r\n 因为新增优先级队列数据结构而导致内存溢出
NOT_FOUND\r\n 没有找到这个 job 或 此 job 不是当前客户端接收的

bury

这个命令可以将一个 job 操作为 buried 状态。
buried job 被存放在一个 FIFO (first input first out ,先进先出)的链表中,它不会被服务器再次操作,除非有客户端对它发起了 kick 命令。

  1. bury <id> <pri>\r\n
选项 描述
id job id
pri 优先级,一个整型数字,越小的越先被接收
响应 描述
BURIED\r\n 操作成功
NOT_FOUND\r\n 找不到 job 或该 job 不是被当前客户端所接收

touch

此命令能让当前消费者得到更多的执行 job 的时间。
比如,ttr 是用于避免消费者崩溃而导致 job 丢失,但同样也会误伤一批执行时间过长的消费者,实际上消费者没有崩溃,但执行时间已经超出了 ttr ,此时,通过 touch 命令,可以让客户端得到更多的处理时间,不先触发 ttr 机制。
当然,使用了 touch 命令,只是延长了 ttr 的时间,ttr 的机制仍然存在。
通过这个命令,消费者可以定期告诉服务器,当前处理程序仍处于活跃状态。
此命令不受 DEADLINE_SOON影响

  1. touch <id>\r\n
选项 描述
id job id
响应 描述
TOUCHED\r\n 操作成功
NOT_FOUND\r\n 没有找到这个 job 或者 该 job 不是这个客户端接收的

watch

watch 命令会往 watch list 中添加一个 tube ,消费者通过 reserve ,可以接收到 watch list 中任何一个 tube 传来的 job 。一个新的连接,watch list 中默认存在一个 default tube 。

  1. watch <tube>\r\n
选项 描述
tube 200 bytes 以内的字符串,代表着 tube 的名字,如果该 tube 不存在,则会自动创建

返回响应:

  1. WATCHING <count>\r\n

conut 是一个数值,指当前 watch list 中有多少 tube 。

ignore

此命令用于从 watch list 中移除一个 tube ,移除之后,该消费者不再接收被移除的 tube 内的 job 。

  1. ignore <tube>\r\n
选项 描述
tube 200 bytes 以内的字符串,代表着 tube 的名字,如果该 tube 不存在,则会自动创建
失败响应 描述
NOT_IGNORED\r\n 如果当前 watch list 中只存在最后一个 tube,则会返回这个响应

成功响应:

  1. WATCHING <count>\r\n

conut 是一个数值,指当前 watch list 中有多少 tube 。

其他命令

peek

用于客户端检查 job ,此命令有四种形态,除了第一个操作以外,其它操作都只针对于当前的 tube 。

  1. peek <id>\r\n 根据 id 返回一个 job
  2. peek-ready\r\n 返回下一个 ready job
  3. peek-delayed\r\n 返回下一个剩余延迟时间最短的 delayed job
  4. peek-buried\r\n 返回下一个 buried job
失败响应 描述
NOT_FOUND\r\n 找不到 job 或没有该状态的 job

成功响应:

  1. FOUND <id> <bytes>\r\n
  2. <data>\r\n

其中,id 为 job 的 id ,bytes 指 data 的大小(不包含 \r\n ),data 是 job 的具体内容

kick

此命令只适用于当前指定的 tube 。
此命令能将 job 状态改成 ready , 它需要传入一个数字,用于指定需要修改多少个 job 。
比如,你传入 10 ,则会将队列中十个 buried 或 delayed 状态的 job ,修改为 ready 。
如果,指定的队列中存在 buried job ,则只会修改 buried job,否则,就修改 delayed job 。

  1. kick <bound>\r\n
选项 描述
bound 指定要 kick 多少 job

响应:

  1. KICKED <count>\r\n

count 表示该操作成功修改了几个 job 。

kick-job

这是一个 kick 扩展命令,用于将单独的一个 job 修改为 ready 。它需要传入一个 job id 。
如果传入的 job id 所代表的 job 在当前 tube 中存在,并且该 job 的状态处于 buried 或 delayed ,则会将这个 job 设置为 ready ,并仍然在当前 tube 中。

  1. kick-job <id>\r\n
选项 描述
id job id
响应 描述
NOT_FOUND\r\n job 不存在或不处于可 kick 的状态,另外,这也可能发生在内部错误上
KICKED\r\n 操作成功

stats-job

此命令用于查看一个 job 的统计信息

  1. stats-job <id>\r\n
选项 描述
id job id
错误响应 描述
NOT_FOUND\r\n job 不存在

成功响应:

  1. OK <bytes>\r\n
  2. <data>\r\n

bytes 指后面 data 的大小,data 则是该 job 的统计信息,是一个 YAML 格式的文本。
data 包含以下 key :

key 描述
id job id
tube 此 job 所在的 tube
state job 的状态
pri job 的优先级
age job 在队列中存在的时间,是一个秒数
time-left 此 job 距离被放入 ready queue 的剩余秒数,这个时间到达之后,此 job j就会被放入到 ready 队列。此参数只在 job 状态为 reserved 和 delayed 时有意义,当状态为 reserved 时,此参数代表 job 的超时剩余秒数,即 ttr
file 此 job 的 binlog 序号,如果未开启 binlog ,则此值为 0
reserved 此 job 被 reserve 的次数
timeouts 此 job 的超时次数
releases 此 job 被 released 的次数
buries 此 job 被 bury 的次数
kicks 被 kicked的次数

stats-tube

此命令返回 tube 的统计信息,如果这个 tube 存在的话。

  1. stats-tube <tube>\r\n
选项 描述
tube 传入 tube 的名称
失败响应 描述
NOT_FOUND\r\n 不存在这个 tube

成功响应:

  1. OK <bytes>\r\n
  2. <data>\r\n

bytes 是指 data 的大小,不包含 「\r\n」。
data 是一个 YAML 格式的文本,它包含了你想要的 tube 的统计信息
下面是 data 的 key :

key 描述
name tube 的 name
current-jobs-urgent 这个 tube 中,优先级小于 1024 的 ready job 数量
current-jobs-ready 这个 tube 中的 ready job 数量
current-jobs-reserved 这个 tube 中被 reserve 的 job 数量,不论它是被哪个消费者接收的
current-jobs-delayed 这个 tube 中处于 delayed 状态的 job 数量
current-jobs-buried 这个 tube 中处于 buried 状态的 job 数量
total-jobs 此 tube 一共创建过几个 job
current-using 指向此 tube 的连接数量
current-waiting 指向此 tube 并且处于接收等待状态、但还未接收到 job 的连接数量
current-watching watch 了此 tube 的连接数量
pause 此 tube 停止服务的秒数
cmd-delete 此 tube 累计执行了几次 delete
cmd-pause-tube 此 tube 累计执行了几次 pause-tube
cmd-time-left 此 tube 几秒之后提供服务

stats

此命令返回整个服务器系统的统计信息。

  1. stats\r\n

成功响应:

  1. OK <bytes>\r\n
  2. <data>\r\n

bytes 是指 data 的大小,但不包括 「\r\n」。
data 是一个 YAML 文本,包含了如下 key :

key 描述
current-jobs-urgent 优先级小于 1024 的 ready job 数量
current-jobs-ready ready job 的数量
current-jobs-reserved 被接受的 job 数量,不区分客户端(消费者)
current-jobs-delayed delayed job 的数量
current-jobs-buried buried job 的数量
cmd-put 累积执行 put 的次数
cmd-peek 累积执行 peek 的次数
cmd-peek-ready 累积执行 peek-ready 的次数
cmd-peek-delayed 累积执行 peek-delayed 的次数
cmd-peek-buried 累积执行 peek-buried 的次数
cmd-reserve 累积执行 cmd-reserve 的次数
cmd-use 累积执行 use 的次数
cmd-watch 累积执行 watch 的次数
cmd-ignore 累积执行 ignore 的次数
cmd-delete 累积执行 delete 的次数
cmd-release 累积执行 release 的次数
cmd-bury 累积执行 bury 的次数
cmd-kick 累积执行 kick 的次数
cmd-stats 累积执行 stats 的次数
cmd-stats-job 累积执行 stats-job 的次数
cmd-stats-tube 累积执行 stats-tube 的次数
cmd-list-tubes 累积执行 list-tubes 的次数
cmd-list-tube-used 累积执行 list-tube-used 的次数
cmd-list-tubes-watched 累积执行 list-tubes-watched 的次数
cmd-pause-tube 累积执行 pause-tube 的次数
job-timeouts 累积 timeout 的 job 总数
total-jobs 累积创建了几个 job
max-job-size 最大允许的 job 字节数
current-tubes 当前有几个 tube
current-connections 当前有几个连接
current-producers 当前有几个至少发出过一条 put 指令的连接
current-workers 当前有几个至少发出过一条 reserve 指令的连接
current-waiting 当前有几个至少发出过一条 reserve 指令但还未接收到 response 的连接
total-connections 累积有过几个连接
pid 服务器的进程 id
version 当前服务器的版本
rusage-utime 进程占用用户 cpu 的时间,分别有「秒」和「微秒」的单位
rusage-stime 进程占用系统 cpu 的时间,分别有「秒」和「微秒」的单位
uptime 此进程已运行的秒数
binlog-oldest-index 最早存储的 job binlog 索引号
binlog-current-index 当前的 job binlog 索引号,新的 binlog 会从这里开始写入,如果未开启 binlog ,此值为 0
binlog-max-size 每个 binlog 文件允许分配的最大容量,单位 bytes
binlog-record-written 写入 binlog 的累积次数
binlog-records-migrated 以压缩形式写入 binlog 的累积次数
id 一个随机字符串,用于标记这个进程,在 beanstalkd 开启时生成
hostname 主机名,由 uname 决定

上面这些 key 的信息,自从 beanstalkd 启动以来就开始累积,如果重启,就会重新累积。另外,这些数据不存放在 binlog 中

list-tubes

此命令返回所有存在的 tube 。

  1. list-tubes\r\n

成功响应:

  1. OK <bytes>\r\n
  2. <data>\r\n

bytes 是指 data 的大小,不包含「\r\n」。
data 返回一个 YAML 字符串,里面包含了 tube 的列表。

list-tube-used

此命令返回当前所 use 的 tube 。

  1. list-tube-used\r\n

成功响应:

  1. USING <tube>\r\n

tube 是指当前 use 的 tube 名字。

list-tubes-watched

此命令用于查看当前客户端 watch-list 中的 tube 。

  1. list-tubes-watched\r\n

成功响应:

  1. OK <bytes>\r\n
  2. <data>\r\n

bytes 是指 data 的大小,不包含「\r\n」。
data 是一个包含了 tube list 的 YAML 字符串。

quit

此命令用于关闭当前连接。

  1. quit\r\n

pause-tube

此命令为某个 tube 指定一个时间,在这个时间内,此 tube 内的 job 将不会被 reserve 。

  1. pause-tube <tbe-name> <delay>\r\n
选项 描述
tube tube 的名字
delay 指定一个秒数
响应 描述
PAUSED\r\n 操作成功
NOT_FOUND\r\n 没有这个 tube