使用beanstalk搭建队列服务
一. 应用场景
- 在web后端服务的交互中很多场景上游和下游处理的时间不匹配,比如上游处理的快,下游处理的慢。这时候就需要队列服务来缓冲服务以达到更高的吞吐率(扛过高峰)
- 延迟处理请求,比如:延迟添加用户奖励,延迟写入mysql等等。逻辑可以只关注主流程即返回。
二. 我们现在的解决方案-beanstalk队列服务
-
协议介绍
https://raw.githubusercontent.com/kr/beanstalkd/master/doc/protocol.txt -
Beanstalkd设计里面的核心概念:
-
job:
一个需要异步处理的任务,是Beanstalkd中的基本单元,需要放在一个tube中。 -
tube:
一个有名的任务队列,用来存储统一类型的job,是producer和consumer操作的对象。 -
producer:
Job的生产者,通过put命令来将一个job放到一个tube中。 -
consumer:
Job的消费者,通过reserve/release/bury/delete命令来获取job或改变job的状态。 -
job生命周期:
job状态转移图 -
一个典型的使用流程:** 延迟发放用户奖励 **
1)上游put job 并带有delay设置(delay n秒后在进入ready队列)
2)job进入ready状态,下游使用reserve接口取得job内容,并使job进入reserved状态。
3)如果job在RRT时间内处理完成,则下游直接调用delete,删除该job,表示处理正常完成。如果job在RRT时间没有处理完成,该job会自动变为ready状态,以供其他的下游worker使用。
4)注意:3)中会有可能1个job被多个work处理多次的问题,如果要严格限制job被执行一次或者失败,则可以在2)步骤后由下游直接调用bury接口将job置为buried状态,这样其只会被一个下游获取并执行。 -
集群化方案
开源的beanstalk是单机版本的队列,集群化需要自己维护。
上游写入客户端需要做负载均衡和分组的工作(一致性hash)。
下游读取客户端需要线性扫描读取每个队列并读取。这里面有个问题就是:原来beanstalk设置的读取超时时间,会在现有的策略中放大N倍。
监控和辅助工具
- 重点关注如下数据项
总体的
bmq.cmd-release
the cumulative number of release commands
bmq.current-connections
the number of currently open connections
bmq.job-timeouts
the cumulative count of times a job has timed out
bmq.total-jobs
the cumulative count of jobs created in this tube in the current beanstalkd process
tube的
bmq.current-jobs-delayed
the number of delayed jobs in this tube
bmq.current-jobs-ready
the number of jobs in the ready queue in this tube
bmq.current-jobs-reserved
the number of jobs reserved by all clients in this tube
bmq.current-jobs-urgent
the number of ready jobs with priority < 1024 in this tube
- 辅助工具
phpBeanstalkdAdmin
系统性能数据
系统稳定性
- 当开启-b启动持久化后,其会将binlog每隔N秒(N可配置为0)刷入到硬盘,类似redis的aof持久化方式
系统容量
- 依赖内存大小(持久化只是把binlog刷到硬盘)
系统性能
- 可以保守认为job 的body size小于1k时,qps可以到put 10k,reserve+delete 9k
- 单 server 最大 put 速度
client 开 50 进程,每进程写入 10k 条 “00”,用时 36s,平均 13800/s - 单 server 最大 reserve + delete 速度
client 开 50 进程,每进程 10k 条,用时 52s,平均 9600/s