RabbitMQ是一个消息代理,从“生产者”接收消息并传递消息至“消费者”,期间可根据规则路由、缓存、持久化消息。“生产者”也即message发送者以下简称P,相对应的“消费者”乃message接收者以下简称C,message通过queue由P到C,queue存在于RabbitMQ,可存储尽可能多的message,多个P可向同一queue发送message,多个C可从同一个queue接收message。
- 简单示例
![](https://i-blog.csdnimg.cn/blog_migrate/dc1d55d156c1fe6fed2623ab90258570.png)
-- =============connection====================
ConnectionFactory factory=new ConnetionFactory();
factory.setHost("ip");
factory.setPort(5672)
factory.setVirtualHost("/vhost_app1");
factory.setUserName("userName");
factory.setPassword("password");
-- =============send==========================
//获取通道
Channel channel=connection.createChannel();
//声明队列
channel.queueDeclare("队列name",false,false,false,null);
//发送消息
channel.basicPublish("","队列name",null,"消息内容msg");
//close
channel.close();
connection.close();
-- =============receive 轮询模式==========================
QueueingConsumer consumer=new QueueingConsumer(channel);
channel.basicConsume("队列名称",true,consumer);
//无限轮询
while(true){
Delivery delivery=consumer.nextDelivery();
String msg=new String (delivery.getBody());\
}
-- =============receive监听模式================
DefaultConsumer consumer=new DefualtConsumer(channel){
@Override
public void handleDelivery(Strong consumerTag,Envelope envelope,
BasicProperties properties,byte[] body) throws IOException{
String msg=new String(body,"utf-8");
}
}
work queues
将耗时的消息处理通过队列分配给多个consumer来处理,我们称此处的consumer为worker,我们将此处的queue称为Task Queue,其目的是为了避免资源密集型的task的同步处理,也即立即处理task并等待完成。相反,调度task使其稍后被处理。也即把task封装进message并发送到task queue,worker进程在后台运行,从task queue取出task并执行job,若运行了多个worker,则task可在多个worker间分配。
#若存在多个consumer每个consumer的负载可能不同,有些处理的快有些处理的慢
#RabbitMQ并不管这些,只是简单的以round-robin的方式分配message
#这可能造成某些consumer积压很多任务处理不完而一些consumer长期处于饥饿状态
#可以使用prefetch_count=1的basic_qos方法可告知RabbitMQ只有在consumer处理并确认了上一个message后才分配新的message给他 #否则分给另一个空闲的consumer
channel.basic_qos(prefetch_count=1)
但是,我们不想丢失任何任务,如果有一个消费者挂掉了,那么我们应该将分发给它的任务交付给另一个消费者去处理。
为了确保消息不会丢失,RabbitMQ支持消息应答。消费者发送一个消息应答,告诉RabbitMQ这个消息已经接收并且处理完毕了。RabbitMQ就可以删除它了。
如果一个消费者挂掉却没有发送应答,RabbitMQ会理解为这个消息没有处理完全,然后交给另一个消费者去重新处理。这样,你就可以确认即使消费者偶尔挂掉也不会丢失任何消息了。
没有任何消息超时限制;只有当消费者挂掉时,RabbitMQ才会重新投递。即使处理一条消息会花费很长的时间。
消息应答是默认打开的。我们通过显示的设置autoAsk=true关闭这种机制。现即自动应答开,一旦我们完成任务,消费者会自动发送应答。通知RabbitMQ消息已被处理,可以从内存删除。如果消费者因宕机或链接失败等原因没有发送ACK(不同于ActiveMQ,在RabbitMQ里,消息没有过期的概念),则RabbitMQ会将消息重新发送给其他监听在队列的下一个消费者。
-- =============receive woker队列模式================
channel.queueDeclare("队列name",false,false,false,null);
channel.basicQos(1);//告诉mq服务处理完再分配下一个mq
Consumer consumer=new DefaultConsumer(channel){
@Override
public void handleDelivery(Strong consumerTag,Envelope envelope,
BasicProperties properties,byte[] body) throws IOException{
try{
String msg=new String(body,"utf-8");
channel.basicAck(envelope.getDeliveryTag(),false);//处理完成回调应答
}cath(Exception e){
}
}
}
channel.basicConsumer("队列name","autoAck|false",consumer);//监听队列关闭自动应答