工作队列的主要任务是:避免立刻执行资源密集型任务,然后必须等待其完成,把任务封装后发给队列,
后台不断的从队列中取出任务然后执行,当多个工作进行是,任务会被工作进程共享执行。
RabbitMQ中实现round-robin 分发消息:
RabbitMQ会一个一个的发送信息给下一个消费者(consumer),而不考虑每个任务的时长等等,一次性分配。
平均的每个消费者将会获得相等数量的消息。导致一个问题当多个消费者时,终止一个进程会发现消息丢失, 导致消息没被处理;
RabbitMQ支持消息应答(message acknowledgments)。消费者发送应答给RabbitMQ,告诉它信息已经被接收和处理,然后RabbitMQ可以自由的进行信息删除。
1、 消息应答(message acknowledgments)
boolean autoAck=false;
channel.basicConsume(queue_name, autoAck, new DefaultConsumer(channel)
// 处理完后手动答应
channel.basicAck(ev, false);
2.消息持久化(Message durability)
为什么要持久化呢?有没有发现一个问题当你服务器关闭之后你在重启的时候发现消息都没了。就是这样的如果我们的RabbitMQ服务被停止或者异常退出我们的消息会丢失。
a、我们需要声明它为持久化的
channel.queueDeclare("task_queue", durable, false, false, null);//第二个参数设置为true;已经存在的队列无法修改其属性
b、发送消息需要表示我们的信息为持久化 MessageProperties.PERSISTENT_TEXT_PLAIN
channel.basicPublish("", queue_name, MessageProperties.PERSISTENT_TEXT_PLAIN, SerializationUtils.serialize(object));
3.公平转发(Fair dispatch)
保证在接收端一个消息没有处理完时不会接收另一个消息,即接收端发送了ack后才会接收下一个消息。在这种情况下发送端会尝试把消息发送给下一个not busy的接收端。
channel.basicQos(1);
消费者
后台不断的从队列中取出任务然后执行,当多个工作进行是,任务会被工作进程共享执行。
RabbitMQ中实现round-robin 分发消息:
RabbitMQ会一个一个的发送信息给下一个消费者(consumer),而不考虑每个任务的时长等等,一次性分配。
平均的每个消费者将会获得相等数量的消息。导致一个问题当多个消费者时,终止一个进程会发现消息丢失, 导致消息没被处理;
RabbitMQ支持消息应答(message acknowledgments)。消费者发送应答给RabbitMQ,告诉它信息已经被接收和处理,然后RabbitMQ可以自由的进行信息删除。
1、 消息应答(message acknowledgments)
boolean autoAck=false;
channel.basicConsume(queue_name, autoAck, new DefaultConsumer(channel)
// 处理完后手动答应
channel.basicAck(ev, false);
2.消息持久化(Message durability)
为什么要持久化呢?有没有发现一个问题当你服务器关闭之后你在重启的时候发现消息都没了。就是这样的如果我们的RabbitMQ服务被停止或者异常退出我们的消息会丢失。
a、我们需要声明它为持久化的
channel.queueDeclare("task_queue", durable, false, false, null);//第二个参数设置为true;已经存在的队列无法修改其属性
b、发送消息需要表示我们的信息为持久化 MessageProperties.PERSISTENT_TEXT_PLAIN
channel.basicPublish("", queue_name, MessageProperties.PERSISTENT_TEXT_PLAIN, SerializationUtils.serialize(object));
3.公平转发(Fair dispatch)
保证在接收端一个消息没有处理完时不会接收另一个消息,即接收端发送了ack后才会接收下一个消息。在这种情况下发送端会尝试把消息发送给下一个not busy的接收端。
channel.basicQos(1);
代码:生产者和消费者
package com.mq.test;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
public class MQUtil {
public Channel channel;
public Connection connection;
public String queue_name;
public MQUtil(String queue_name) throws IOException, TimeoutException {
this.queue_name=queue_name;
//获取连接工厂
ConnectionFactory factory=new ConnectionFactory();
//设置ip
factory.setHost("localhost");
//创建连接
connection=factory.newConnection();
//创建频道
channel=connection.createChannel();
/**
* 第一个参数;queue,
* 第二个参数durable,
* 第三个参数exclusive,
* 第四个参数 autoDelete
* 第五个参数 Map<String, Object> arguments)
*
*/
channel.queueDeclare(queue_name, true, false, false, null);
}
//关闭连接
public void close() throws IOException, TimeoutException{
channel.close();
connection.close();
}
}
package com.mq.test;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
import com.rabbitmq.client.MessageProperties;
/**
* message send class
* @author rommr
*
*/
public class Poduction extends MQUtil {
public Poduction(String queue_name) throws IOException, TimeoutException {
super(queue_name);
}
//发送消息
public void sendMessage(String messge) throws IOException {
//发送消息MessageProperties.PERSISTENT_TEXT_PLAIN使消息durable
channel.basicPublish("", queue_name, MessageProperties.PERSISTENT_TEXT_PLAIN, messge.getBytes());
}
public static void main(String[] args) throws IOException, TimeoutException {
Poduction p= new Poduction("msg_queues");
for(int i=0;i<20;i++){
p.sendMessage("hello word "+i);
}
//关闭连接
p.close();
}
}
消费者
package com.mq.test;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
import com.rabbitmq.client.AMQP.BasicProperties;
import com.rabbitmq.client.DefaultConsumer;
import com.rabbitmq.client.Envelope;
/**
* 消费端
* @author rommr
*
*/
public class ConsumerRead extends MQUtil{
public ConsumerRead(String queue_name) throws IOException, TimeoutException {
super(queue_name);
}
public void read() throws IOException{
//QueueingConsumer consumer = new QueueingConsumer(channel); 已经过时 会导致内存溢出
//开启答应机制
boolean autoAck=false;
//保证在接收端一个消息没有处理完时不会接收另一个消息,即接收端发送了ack后才会接收下一个消息。在这种情况下发送端会尝试把消息发送给下一个not busy的接收端。
channel.basicQos(1);
// channel.basicConsume(queue_name, autoAck, new Consumer() {
//
// @Override
// public void handleShutdownSignal(String arg0, ShutdownSignalException arg1) {
// // TODO Auto-generated method stub
//
// }
//
// @Override
// public void handleRecoverOk(String arg0) {
// // TODO Auto-generated method stub
//
// }
//
// @Override
// public void handleDelivery(String arg0, Envelope envelope, BasicProperties arg2, byte[] arg3) throws IOException {
// try {
// Thread.sleep(1000);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
// System.out.println("消息是:"+ new String(arg3));
//
// long ev=envelope.getDeliveryTag();
//
// // 处理完后,手动答应
// channel.basicAck(ev, false);
//
// }
//
// @Override
// public void handleConsumeOk(String arg0) {
// // TODO Auto-generated method stub
//
// }
//
// @Override
// public void handleCancelOk(String arg0) {
// // TODO Auto-generated method stub
//
// }
//
// @Override
// public void handleCancel(String arg0) throws IOException {
// // TODO Auto-generated method stub
//
// }
// });
/**
*
* 实现消费端的类DefaultConsumer 该类实现了Consumer接口中的方法
* 该子类的对象可以在basicConsume 调用中传递以设置订阅:
*
*/
channel.basicConsume(queue_name, autoAck, new DefaultConsumer(channel){
@Override
public void handleDelivery(String arg0, Envelope envelope, BasicProperties arg2, byte[] arg3) throws IOException {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("消息是:"+ new String(arg3));
long ev=envelope.getDeliveryTag();
// 处理完后手动答应
channel.basicAck(ev, false);
}
});
}
public static void main(String[] args) throws IOException, TimeoutException {
new ConsumerRead("msg_queues").read();
}
}