Ubuntu14.04+Beanstalkd1.9最佳实践
目录
1、基本概念
1.1、什么是Beanstalkd?
Beanstalkd 是一个轻量级消息中间件,它最大特点是将自己定位为基于管道 (tube) 和任务 (job) 的工作队列。
Beanstalkd 支持任务优先级 (priority), 延时 (delay), 超时重发 (time-to-run) 和预留 (buried), 能够很好的支持分布式的后台任务和定时任务处理。它的内部采用libevent,服务器-客户端之间采用类似Memcached的轻量级通讯协议,因此性能很高(enque: 9000 jobs/second, worker: 5200 jobs/second)
尽管是内存队列, Beanstalkd 提供了 binlog 机制, 当重启 beanstalkd 时,当前任务状态能够从纪录的本地 binlog 中恢复。Beanstalkd支持过有9.5 million用户的Facebook Causes应用。后来开源,现在有PostRank大规模部署和使用,每天处理百万级任务。Beanstalkd是典型的类Memcached设计,协议和使用方式都是同样的风格,所以使用过Memcached的用户会觉得Beanstalkd似曾相识。
Beanstalkd支持的语言有很多,可以参考这里:https://github.com/kr/beanstalkd/wiki/client-libraries
1.2、Beanstalkd设计的核心概念?
- job
一个需要异步处理的任务,是Beanstalkd中的基本单元,需要放在一个tube中。
- tube
一个有名的任务队列,用来存储统一类型的job,是producer和consumer操作的对象。
- producer
Job的生产者,通过put命令来将一个job放到一个tube中。
- consumer
Job的消费者,通过reserve/release/bury/delete命令来获取job或改变job的状态。
1.3、Beanstalkd中Job的生命周期介绍
Beanstalkd的流程如下图:

- 当producer直接put一个job时,job就处于READY状态,等待consumer来处理,如果选择延迟put,job就先到DELAYED状态,等待时间过后才迁移到READY状态。
- consumer获取了当前READY的job后,该job的状态就迁移到RESERVED,这样其他的consumer就不能再操作该job。
- 当consumer完成该job后,可以选择delete, release或者bury操作;
- delete之后,job从系统消亡,之后不能再获取
- release操作可以重新把该job状态迁移回READY(也可以延迟该状态迁移操作),使其他的consumer可以继续获取和执行该job
- bury操作,可以把该job休眠,等到需要的时候,再将休眠的job kick回READY状态,也可以delete buride状态的job
正是有这些有趣的操作和状态,才可以基于此做出很多意思的应用,比如要实现一个循环队列,就可以将RESERVED状态的job休眠掉,等没有READY状态的job时再将BURIED状态的job一次性kick回READY状态。
1.4、Beanstalkd有什么不足?
Beanstalkd 没有提供主备同步 + 故障切换机制, 在应用中有成为单点的风险。实际应用中,可以用数据库为任务 (job) 提供持久化存储。 和 Memcached 类似, Beanstalkd 依赖 libevent 的单线程事件分发机制, 不能有效利用多核 cpu 的性能。这一点可以通过单机部署多个实例克服。

一个Beanstalkd尚无提供删除一个tube的操作,只能将tube的job依次删除,并让Beanstalkd来自动删除空tube。还有就是Beanstalkd不支持客户端认证机制(开发者将应用场景定位在局域网)。
Beanstalk速度非常快,协议简单,占用内存空间少,而且支持持久化。唯一的不足是挂了之后恢复慢,3G日志数据恢复了十多分钟。
2、Beanstalkd的官网在哪里?
http://kr.github.io/beanstalkd/
3、Beanstalkd在哪里下载?
http://kr.github.io/beanstalkd/download.html
4、如何安装Beanstalkd?
使用下面的命令进行安装,同时查看版本:
lion@node1:~$ sudo apt-get install beanstalkd
lion@node1:~$ beanstalkd -v
beanstalkd 1.9
Beanstalkd可以使用以下命令停止和启动:
lion@node1:~$ sudo service beanstalkd stop #停止
lion@node1:~$ sudo service beanstalkd start #启动
通过apt-get安装后的配置文件目录在/etc/default/beanstalkd,里面描述了Beanstalkd监听的地址和端口
lion@node1:~$ cat /etc/default/beanstalkd
## Defaults for the beanstalkd init script, /etc/init.d/beanstalkd on
## Debian systems.
BEANSTALKD_LISTEN_ADDR=127.0.0.1
BEANSTALKD_LISTEN_PORT=11300
# You can use BEANSTALKD_EXTRA to pass additional options. See beanstalkd(1)
# for a list of the available options. Uncomment the following line for
# persistent job storage.
#BEANSTALKD_EXTRA="-b /var/lib/beanstalkd"
4.1、安装beanstool管理工具
beanstool是一个Beanstalkd管理工具,不需要任何依赖就可以使用,是用Golang编写的。
lion@node1:~/_app$ wget https://github.com/src-d/beanstool/releases/download/v0.2.0/beanstool_v0.2.0_linux_amd64.tar.gz
lion@node1:~/_app$ tar -xvzf beanstool_v0.2.0_linux_amd64.tar.gz
lion@node1:~/_app$ sudo cp beanstool_v0.2.0_linux_amd64/beanstool /usr/local/bin/
5、Beanstalkd调用案例
我们是使用Golang语言来调用Beanstalkd的,在官网上可以看到有现成的Golang包Beanstalk,使用下面的命令先安装Beanstalk
lion@node1:~$ go get github.com/kr/beanstalk
5.1、使用默认的Tube发送、接收消息
producer_default.go(Produce jobs):
package main
import (
"fmt"
"github.com/kr/beanstalk"
"time"
"log"
)
const (
//uri
uri = "127.0.0.1:11300"
//network
network = "tcp"
//
content = "hello idoall.org"
)
//如果存在错误,则输出
func failOnError(err error, msg string) {
if err != nil {
log.Fatalf("%s: %s", msg, err)
panic(fmt.Sprintf("%s: %s", msg, err))
}
}
func main(){
conn, err := beanstalk.Dial(network, uri)
failOnError(err, "Failed to connect to beanstalkd")
defer conn.Close()
//把job放入tube中并设置优先级
//
id, err := conn.Put(
[]byte(content), //内容
1, //优先级 0~2^32 个优先级, 0 代表最高优先级,默认优先级为1024。
0, //要延迟发送的时间,0表示不延迟
time.Minute)
failOnError(err, "Failed puts a job into tube")
fmt.Println("job", id)
}
consumer_default.go:
package main
import (
"fmt"
"github.com/kr/beanstalk"
"time"
"log"
)
const (
//uri
uri = "127.0.0.1:11300"
//network
network = "tcp"
)
//如果存在错误,则输出
func failOnError(err error, msg string) {
if err != nil {
log.Fatalf("%s: %s", msg, err)
panic(fmt.Sprintf("%s: %s", msg, err))
}
}
func main(){
conn, err := beanstalk.Dial(network, uri)
failOnError(err, "Failed to connect to beanstalkd")
defer conn.Close()
//
id, body, err := conn.Reserve(1 * time.Second)
failOnError(err, "returns a job from one of the tubes failed")
fmt.Println("job", id)
fmt.Println(string(body))
err = conn.Delete(id)
failOnError(err, "delete jobs failed")
}
**查看结果 **
Console1(Procuder):
lion@node1:~/_code/_beanstalk/_golang$ go run producer.go
job 1
使用beanstool工具查看队列状态:
lion@node1:~/_app$ beanstool stats
+---------+----------+----------+----------+----------+----------+----------+----------+
| Name | Buried | Delayed | Ready | Reserved | Urgent | Waiting | Total |
+---------+----------+----------+----------+----------+----------+----------+----------+
| default | 0 | 0 | 1 | 0 | 1 | 0 | 1 |
+---------+----------+----------+----------+----------+----------+----------+----------+
Console2(Consumer):
lion@node1:~/_code/_beanstalk/_golang$ go run consumer_default.go
job 1
hello idoall.org
5.2、使用指定的Tube发送、接收消息
producer_tube_idoall.go(Produce jobs):
package main
import (
"fmt"
"github.com/kr/beanstalk"
"time"
"log"
)
const (
//uri
uri = "127.0.0.1:11300"
//network
network = "tcp"
//
tubeName = "test-idoall-tube"
//
content = "hello idoall.org from idoall tube"
)
//如果存在错误,则输出
func failOnError(err error, msg string) {
if err != nil {
log.Fatalf("%s: %s", msg, err)
panic(fmt.Sprintf("%s: %s", msg, err))
}
}
func main(){
conn, err := beanstalk.Dial(network, uri)
failOnError(err, "Failed to connect to beanstalkd")
defer conn.Close()
tube := &beanstalk.Tube{conn, tubeName}
//把job放入tube中并设置优先级
//
id, err := tube.Put(
[]byte(content), //内容
1, //优先级 0~2^32 个优先级, 0 代表最高优先级,默认优先级为1024。
0, //要延迟发送的时间,0表示不延迟
time.Minute)
failOnError(err, "Failed puts a job into tube")
fmt.Println("job", id)
conn.Close()
}
consumer_tube_idoall.go:
package main
import (
"fmt"
"github.com/kr/beanstalk"
"time"
"log"
)
const (
//uri
uri = "127.0.0.1:11300"
//network
network = "tcp"
//
tubeName = "test-idoall-tube"
)
//如果存在错误,则输出
func failOnError(err error, msg string) {
if err != nil {
log.Fatalf("%s: %s", msg, err)
panic(fmt.Sprintf("%s: %s", msg, err))
}
}
func main(){
conn, err := beanstalk.Dial(network, uri)
failOnError(err, "Failed to connect to beanstalkd")
defer conn.Close()
tubeSet := beanstalk.NewTubeSet(conn, tubeName)
//
id, body, err := tubeSet.Reserve(10 * time.Hour)
failOnError(err, "returns a job from one of the tubes failed")
fmt.Println("job", id)
fmt.Println(string(body))
err = conn.Delete(id)
failOnError(err, "delete jobs failed")
}
查看结果
Console1(Procuder):
lion@node1:~/_code/_beanstalk/_golang$ go run producer_tube_idoall.go
job 5
使用beanstool工具查看队列状态:
lion@node1:~/_app$ beanstool stats
+------------------+----------+----------+----------+----------+----------+----------+----------+
| Name | Buried | Delayed | Ready | Reserved | Urgent | Waiting | Total |
+------------------+----------+----------+----------+----------+----------+----------+----------+
| default | 0 | 0 | 0 | 0 | 0 | 0 | 4 |
| test-idoall-tube | 0 | 0 | 1 | 0 | 1 | 0 | 1 |
+------------------+----------+----------+----------+----------+----------+----------+----------+
Console2(Consumer):
lion@node1:~/_code/_beanstalk/_golang$ go run consumer_tube_idoall.go
job 5
hello idoall.org from idoall tube
5.3、Beanstalkd的消息持久化
持久化消息非常简单,在启动的时候使用-b参数,指定目录:
lion@node1:~$ /usr/bin/beanstalkd -l 127.0.0.1 -p 11300 -b /home/lion/tmp
可以参考文章使用Supervisor3.2.1基于Mac10.10.3对系统进程进行管理将Beanstalkd的命令做为系统进程,在开机的时候随系统启动。
6、参考资料
博文作者:迦壹
博客地址:[Ubuntu14.04+Beanstalkd1.9最佳实践](http://idoall.org/blog/post/lion/16)
转载声明:可以转载, 但必须以超链接形式标明文章原始出处和作者信息及版权声明,谢谢合作!
Ubuntu14.04+Beanstalkd1.9最佳实践的更多相关文章
- Ubuntu14.04+RabbitMQ3.6.3+Golang的最佳实践
目录 [TOC] 1.RabbitMQ介绍 1.1.什么是RabbitMQ? RabbitMQ 是由 LShift 提供的一个 Advanced Message Queuing Protocol ...
- 基于ABP落地领域驱动设计-04.领域服务和应用服务的最佳实践和原则
目录 系列文章 领域服务 应用服务 学习帮助 系列文章 基于ABP落地领域驱动设计-00.目录和前言 基于ABP落地领域驱动设计-01.全景图 基于ABP落地领域驱动设计-02.聚合和聚合根的最佳实践 ...
- memcache的最佳实践方案
1.memcached的基本设置 1)启动Memcache的服务器端 # /usr/local/bin/memcached -d -m 10 -u root -l 192.168.0.200 -p 1 ...
- PHP最佳实践(译)
原文: PHP Best Practices-A short, practical guide for common and confusing PHP tasks 译者:youngsterxyf 最 ...
- 基于开源软件在Azure平台建立大规模系统的最佳实践
作者 王枫 发布于2014年5月28日 前言 Microsoft Azure 是微软公有云的唯一解决方案.借助这一平台,用户可以以多种方式部署和发布自己的应用. 这是一个开放的平台,除了对于Windo ...
- 10个精妙的Java编码最佳实践
这是一个比Josh Bloch的Effective Java规则更精妙的10条Java编码实践的列表.和Josh Bloch的列表容易学习并且关注日常情况相比,这个列表将包含涉及API/SPI设计中不 ...
- Rolling cURL: PHP并发最佳实践
Rolling cURL: PHP并发最佳实践 在实际项目或者自己编写小工具(比如新闻聚合,商品价格监控,比价)的过程中, 通常需要从第3方网站或者API接口获取数据, 在需要处理1个URL队列时, ...
- ubuntu14.04 安装 tensorflow
如果内容侵权的话,联系我,我会立马删了的-因为参考的太多了,如果一一联系再等回复,战线太长了--蟹蟹给我贡献技术源泉的作者们- 最近准备从理论和实验两个方面学习深度学习,所以,前面装好了Theano环 ...
- Ubuntu14.04双网卡主备配置
近日有个需求,交换机有两台,做了堆叠,服务器双网卡,每个分别连到一台交换机上.这样就需要将服务器的网卡做成主备模式,以增加安全性,使得当其中一个交换机不通的时候网卡能够自动切换. 整体配置不难,网上也 ...
随机推荐
- yate: windows下源码下载,配置,编译
源码下载:使用svn下载checkout:http://voip.null.ro/svn/yate/trunk 配置:(本人使用的是vs2008,故下载的qt工具都是对应2008) 1. 下载并安装q ...
- mysql 分组查询问题 group_concat
这几天在做购物车的时候.购物车内的商品为一个商品占一行,结果再从数据库读出的时候,没有分组,而是循环所有的内容出来,然后进行判断.如果一样的话就把他保存到一个变量中.但是自己逻辑没搞清楚.一直出bug ...
- sqoop笔记
adoop学习笔记—18.Sqoop框架学习 一.Sqoop基础:连接关系型数据库与Hadoop的桥梁 1.1 Sqoop的基本概念 Hadoop正成为企业用于大数据分析的最热门选择,但想将你的数 ...
- mozilla firefox 安装flash player
下载 flash player http://get.adobe.com/cn/flashplayer/ for linux .tar.gz文件 install_flash_player_11_li ...
- 一、Android屏幕的计量单位
px :是屏幕的像素点in :英寸mm:毫米pt :磅,1/72英寸dp :一个基于density的抽象单位,如果一个160dpi的屏幕,1dp=1pxdip :等同于dpsp :同dp ...
- HTML5的form表单属性
form:HTML4中,表单内的从属元素必须书写在<form></form>之内,但是在HTML5中,表单的从属元素可以处于页面的任何位置,然后为其添加form属性,属性值为f ...
- HDU5840 (分块+树链剖分)
Problem This world need more Zhu 题目大意 给一颗n个点的有点权的树,有m个询问,对于每个询问u,v,k,首先将点u到点v的最短路径上的所有点按顺序编号,u的编号为1, ...
- Ansible-Tower快速入门-6.查看tower的仪表板【翻译】
查看tower的仪表板 到这一步,我们已经可以在屏幕上看到tower的仪表板了,我们可以看到你目前"主机""资产清单"和"项目"的汇总信息, ...
- 学习RaphaelJS矢量图形包--Learning Raphael JS Vector Graphics中文翻译(一)
(原文地址:http://www.cnblogs.com/idealer3d/p/LearningRaphaelJSVectorGraphics.html) 前面3篇博文里面,我们讲解了一本叫做< ...
- IOS照片颠倒分析及PHP服务端的处理
前言: 因朋友的PHP小项目, 而去帮忙解决了一个小问题, 现在来总结概括一下. 也不知道大家在使用和开发的过程中有没有遇到类似的场景, IPhone手机上传照片后, 发现图片方向颠倒了, 甚至各种姿 ...