MessageQueue(消息队列),多用于分布式系统中各个服务之间传递消息;
1.解耦
在下面的系统架构中,采用同步方式进行交互,当其中任一系统宕机时。都会导致其他系统不可用;
采用同步方式进行交互时,需要等待其他系统的返回结果才能继续往下执行;时间较长;
面对突然的大流量,系统可能处理不了容易导致系统宕机,可以使用MQ来限制消费数量保证系统稳定运行;
1.可用性问题,由于系统/服务交互之间需要使用MQ,一旦MQ宕机那么其他系统也无法进行正常的业务流程;
2.系统复杂度,MQ的加入大大增加了系统的复杂度,以前系统之间是远程同步调用的,现在加入MQ,如何保证MQ的消息不丢失?不重复消费?
1.Work
最基本的工作模式,一个生产者多个消费者,消费者对于同一队列内的消息存在竞争关系,如100条数据有两个消费者,那么每个消费者只能消费其中一部分;
生产者
public static void main(String[] args) throws IOException {
Connection conn = MqFactory.getConn();
Channel channel = conn.createChannel();
/**
* 创建队列
* arg1:队列名称
* arg2:是否持久化队列数据
* arg3:是否私有化队列,false时所有消费者共享;true时只有第一个使用的消费者占有
* arg4:是否删除队列,连接关闭以后是否删除相应的队列;
* arg5:额外参数
*/
channel.queueDeclare(MqConstants.queue_worker,false,false,false,null);
//发送消息
for (int i = 0; i < 100; i++) {
String message="i"+ RandomUtil.randomStringUpper(5);
channel.basicPublish("",MqConstants.queue_worker,null,message.getBytes(StandardCharsets.UTF_8));
}
channel.close();
conn.close();
}
消费者
public static void main(String[] args) throws IOException {
Connection conn = MqFactory.getConn();
final Channel channel = conn.createChannel();
// channel.basicQos(1); 不设置Qos时,消息将会平均发给每个消费者;设置Qos后,会等到消费者完成后再发送;
channel.basicConsume(MqConstants.queue_worker,new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.err.println("workerConsumer1"+new String(body));
//false只确认签收当前的消息,设置为true的时候则代表签收该消费者所有未签收的消息
channel.basicAck(envelope.getDeliveryTag(),false);
}
}
);
}
2.Publish/Subscribe
订阅模式引出了交换机(Exchange)的概念,首先在rabbitMq服务端建立Exchange并且指定类型(fanout,direct,topic);
1.fanout
生产者发送消息时需要指定Exchange,不需要指定routing key,消费者接收消息时需要指定Exchange并且全量消费;生产100条,每个消费者都能消费100条;
/**
* fanout模式:
* arg1:交换机
* arg2:routing key,此时不需要指定
* arg3:额外参数
* arg4:发送的消息
*/
channel.basicPublish(MqConstants.exchange_direct,"",null,RandomUtil.randomString(5).getBytes(StandardCharsets.UTF_8));
2.direct
也就是routing 模式,生产者发送消息时指定Exchange,指定routing key;消费者同样需要指定;此时生产者生产的消息将依据routking分别转给对应的消费者
/**
* fanout模式:
* arg1:交换机
* arg2:routing key
* arg3:额外参数
* arg4:发送的消息
*/
channel.basicPublish(MqConstants.exchange_direct,"rabbitmq.message.1",null,RandomUtil.randomString(5).getBytes(StandardCharsets.UTF_8));
3.topics 模式
此时消费者只有rouking key有区别,支持通配符模式; 通配符规则:# 匹配一个或多个词,* 号匹配不多不少恰好1个词,例如:item.# 能够匹配 item.insert.abc 或者 item.insert,item. 星号只能匹配 item.insert
/**
* arg1:队列名
* arg2:交换机
* arg3:routing key
*/
channel.queueBind(MqConstants.queue_helloworld,MqConstants.exchange_direct,"rabbitmq.#")
3.Routing
上述 routing 模式
4.Topics
上述 topic模式
5.RPC