最近业务需要使用Rabbitmq
工作队列实现任务的负载分发
RabbitMQ
是实现AMQP
(高级消息队列协议)的消息中间件的一种,服务器端用Erlang
语言编写,支持多种客户端,如:Python、Ruby、.NET、Java、JMS、C、PHP、ActionScript、XMPP、STOMP
等,支持AJAX
。用于在分布式系统中存储转发消息。
AMQP
?AMQP
,即Advanced Message Queuing Protocol
,高级消息队列协议,是应用层协议的一个开放标准,为面向消息的中间件设计。它从生产者接收消息并递送给消费者,在这个过程中,根据规则进行路由,缓存与持久化。
而在AMQP中主要有两个组件:Exchange
和 Queue
(在 AMQP 1.0 里还会有变动),如下图所示,绿色的 X
就是 Exchange
,红色的是 Queue
,这两者都在 Server
端,又称作 Broker
,这部分是 RabbitMQ
实现的,而蓝色的则是客户端,通常有 Producer
和 Consumer
两种类型:
Broker:简单来说就是消息队列服务器实体
Exchange:消息交换机,它指定消息按什么规则,路由到哪个队列
Queue:消息队列载体,每个消息都会被投入到一个或多个队列
Binding:绑定,它的作用就是把exchange和queue按照路由规则绑定起来
Routing Key:路由关键字,exchange根据这个关键字进行消息投递
vhost:虚拟主机,一个broker里可以开设多个vhost,用作不同用户的权限分离
producer:消息生产者,就是投递消息的程序
consumer:消息消费者,就是接受消息的程序
channel:消息通道,在客户端的每个连接里,可建立多个channel,每个channel代表一个会话任务
安装配置过程,这里不赘述。
RabbitMQ
有六种应用场景,这里做简单介绍一个P向queue
发送一个message
,一个C从该queue
接收message
并打印。
send.py
producer,连接至RabbitMQ Server,声明队列,发送message,关闭连接,退出。
将耗时的消息处理通过队列分配给多个consumer来处理,我们称此处的consumer为worker,我们将此处的queue称为Task Queue,其目的是为了避免资源密集型的task的同步处理,以及立即处理task并等待完成。相反,调度task使其稍后被处理。以及把task封装进message并发送到task queue,worker进程在后台运行,从task queue取出task并执行job,若运行了多个worker,则task可在多个worker间分配。
new_task.py
建立连接,声明队列,发送可以模拟耗时任务的message,断开连接、退出。
worker.py(同一代码,可多个控制台端,多个服务器端,同时执行)
建立连接,声明队列,不断的接收message,处理任务,进行确认。
在应用场景2中一个message(task)
仅被传递给了一个comsumer(worker)
。现在我们设法将一个message
传递给多个consumer
。这种模式被称为publish/subscribe
。此处以一个简单的日志系统为例进行说明。该系统包含一个log
发送程序和一个log
接收并打印的程序。由log发送者发送到queue的消息可以被所有运行的log接收者接收。因此,我们可以运行一个log接收者直接在屏幕上显示log,同时运行另一个log接收者将log写入磁盘文件。
receive_logs.py
日志消息接收者:建立连接,声明exchange,将exchange与queue进行绑定,开始不停的接收log并打印。
emit_log.py
日志消息发送者:建立连接,声明fanout类型的exchange,通过exchage向queue发送日志消息,消息被广播给所有接收者,关闭连接,退出。
应用场景3中构建了简单的log系统,可以将log message
广播至多个receiver
。现在我们将考虑只把指定的message
类型发送给其subscriber
,比如,只把error message
写到log file
而将所有log message
显示在控制台。
应用场景4中改进的log
系统中用direct
类型的exchange
替换应用场景3中的fanout
类型exchange
实现将不同的log message
发送给不同的subscriber
(也即分别通过不同的routing_key
将queue
绑定到exchange
,这样exchange
便可将不同的message
根据message
内容路由至不同的queue
)。但仍然存在限制,不能根据多个规则路由消息,比如接收者要么只能收error
类型的log message
要么只能收info
类型的message
。如果我们不仅想根据log的重要级别如info、warning、error
等来进行log message
路由还想同时根据log message
的来源如auth、cron、kern
来进行路由。为了达到此目的,需要topic
类型的exchange
。topic
类型的exchange
中routing_key
中可以包含两个特殊字符:“*”
用于替代一个词,“#”
用于0个或多个词。
receive_logs_topic.py
log message接收者:建立连接,声明topic类型的exchange,声明queue,根据程序参数构造routing_key
,根据routing_key
将queue
绑定到exchange
,循环接收并处理message
。
emit_log_topic.py
log message发送者:建立连接、声明topic类型的exchange、根据程序参数构建routing_key和要发送的message,以构建的routing_key将message发送给topic类型的exchange,关闭连接,退出。
在应用场景2中描述了如何使用work queue
将耗时的task
分配到不同的worker
中。但是,如果我们task
是想在远程的计算机上运行一个函数并等待返回结果呢。这根场景2中的描述是一个完全不同的故事。这一模式被称为远程过程调用。现在,我们将构建一个RPC
系统,包含一个client
和可扩展的RPC server
,通过返回斐波那契数来模拟RPC service
。
rpc_server.py
RPC server
:建立连接,声明queue
,定义了一个返回指定数字的斐波那契数的函数,定义了一个回调函数在接收到包含参数的调用请求后调用自己的返回斐波那契数的函数并将结果发送到与接收到message
的queue
相关联的queue
,并进行确认。开始接收调用请求并用回调函数进行请求处理。
rpc_client.py
RPC client
:远程过程调用发起者:定义了一个类,类中初始化到RabbitMQ Server
的连接、声明回调queue
、开始在回调queue
上等待接收响应、定义了在回调queue
上接收到响应后的处理函数on_response
根据响应关联的correlation_id
属性作出响应、定义了调用函数并在其中向调用queue
发送包含correlation_id
等属性的调用请求、初始化一个client
实例,以30
为参数发起远程过程调用。
你可以根据自己想需要进行应用,具体代码可以去官网查看
http://www.rabbitmq.com/getstarted.html官网