ThinkChat🤖让你学习和工作更高效,注册即送10W Token,即刻开启你的AI之旅 广告
# 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 生命周期: ``` put reserve delete -----> [READY] ---------> [RESERVED] --------> *poof* ``` 当然,它也可能经历更复杂的演化,如下图: ``` put with delay release with delay ----------------> [DELAYED] <------------. | | kick | (time passes) | | | put v reserve | delete -----------------> [READY] ---------> [RESERVED] --------> *poof* ^ ^ | | | \ release | | | `-------------' | | | | kick | | | | bury | [BURIED] <---------------' | | delete `--------> *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 ,命令格式如下: ``` put <pri> <delay> <ttr> <bytes>\r\n <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 <id>\r\n* | 插入成功,id 是一个 interger ,标识新插入的 job | | *BURIED <id>\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 中。 ``` use <tube>\r\n ``` | 选项 | 描述 | |---|---| | *tube* | 一个最大不超过 200 bytes 的名称,它指定一个 tube ,如果这个 tube 不存在,则会自动创建 | | 响应 | 描述 | |---|---| | *USING <tube>\r\n* | <tube>是接下来开始使用的 tube | ## 消费者命令 从 queue 中消费 job 会使用以下命令: - reserve - delete - release - bury ### reserve ``` reserve\r\n ``` 另外,你还能指定接收的超时时间,如下: ``` 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 ,又或者客户端连接已经关闭,此时会返回此值 | **成功响应:** ``` RESERVED <id> <bytes>\r\n <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 。 ``` 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 失败的情况下。 ``` 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 命令。 ``` 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影响** ``` 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 。 ``` watch <tube>\r\n ``` |选项|描述| |---|---| | tube | 200 bytes 以内的字符串,代表着 tube 的名字,如果该 tube 不存在,则会自动创建 | 返回响应: ``` WATCHING <count>\r\n ``` conut 是一个数值,指当前 watch list 中有多少 tube 。 ### ignore 此命令用于从 watch list 中移除一个 tube ,移除之后,该消费者不再接收被移除的 tube 内的 job 。 ``` ignore <tube>\r\n ``` |选项|描述| |---|---| | tube | 200 bytes 以内的字符串,代表着 tube 的名字,如果该 tube 不存在,则会自动创建 | |失败响应|描述| |---|---| | *NOT_IGNORED\r\n* | 如果当前 watch list 中只存在最后一个 tube,则会返回这个响应 | 成功响应: ``` WATCHING <count>\r\n ``` conut 是一个数值,指当前 watch list 中有多少 tube 。 ## 其他命令 ### peek 用于客户端检查 job ,此命令有四种形态,除了第一个操作以外,其它操作都只针对于当前的 tube 。 ``` peek <id>\r\n 根据 id 返回一个 job peek-ready\r\n 返回下一个 ready job peek-delayed\r\n 返回下一个剩余延迟时间最短的 delayed job peek-buried\r\n 返回下一个 buried job ``` | 失败响应|描述| |---|---| | *NOT_FOUND\r\n* | 找不到 job 或没有该状态的 job | 成功响应: ``` FOUND <id> <bytes>\r\n <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 。 ``` kick <bound>\r\n ``` |选项|描述| |---|---| | bound | 指定要 kick 多少 job| 响应: ``` KICKED <count>\r\n ``` count 表示该操作成功修改了几个 job 。 ### kick-job 这是一个 kick 扩展命令,用于将单独的一个 job 修改为 ready 。它需要传入一个 job id 。 如果传入的 job id 所代表的 job 在当前 tube 中存在,并且该 job 的状态处于 buried 或 delayed ,则会将这个 job 设置为 ready ,并仍然在当前 tube 中。 ``` kick-job <id>\r\n ``` |选项|描述| |---|---| | id | job id| |响应|描述| |---|---| | *NOT_FOUND\r\n* | job 不存在或不处于可 kick 的状态,另外,这也可能发生在内部错误上 | | *KICKED\r\n* | 操作成功 | ### stats-job 此命令用于查看一个 job 的统计信息 ``` stats-job <id>\r\n ``` |选项|描述| |---|---| | id | job id | |错误响应|描述 | |---|---| | *NOT_FOUND\r\n* | job 不存在 | 成功响应: ``` OK <bytes>\r\n <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 存在的话。 ``` stats-tube <tube>\r\n ``` | 选项 | 描述 | |---|---| | tube | 传入 tube 的名称 | | 失败响应 | 描述 | |---|---| | *NOT_FOUND\r\n* | 不存在这个 tube | 成功响应: ``` OK <bytes>\r\n <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 此命令返回整个服务器系统的统计信息。 ``` stats\r\n ``` 成功响应: ``` OK <bytes>\r\n <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 。 ``` list-tubes\r\n ``` 成功响应: ``` OK <bytes>\r\n <data>\r\n ``` bytes 是指 data 的大小,不包含「\r\n」。 data 返回一个 YAML 字符串,里面包含了 tube 的列表。 ### list-tube-used 此命令返回当前所 use 的 tube 。 ``` list-tube-used\r\n ``` 成功响应: ``` USING <tube>\r\n ``` tube 是指当前 use 的 tube 名字。 ### list-tubes-watched 此命令用于查看当前客户端 watch-list 中的 tube 。 ``` list-tubes-watched\r\n ``` 成功响应: ``` OK <bytes>\r\n <data>\r\n ``` bytes 是指 data 的大小,不包含「\r\n」。 data 是一个包含了 tube list 的 YAML 字符串。 ### quit 此命令用于关闭当前连接。 ``` quit\r\n ``` ### pause-tube 此命令为某个 tube 指定一个时间,在这个时间内,此 tube 内的 job 将不会被 reserve 。 ``` pause-tube <tbe-name> <delay>\r\n ``` |选项|描述| |---|---| | tube | tube 的名字 | | delay | 指定一个秒数 | |响应|描述| |---|---| | *PAUSED\r\n* | 操作成功 | | *NOT_FOUND\r\n* | 没有这个 tube |