rabbitmq图形demo
生产者:就是发送消息一方
消费者:就是接受消息一方
broker:这里可以理解为rabbitmq服务,里面分了交换器和队列
消息的传递
rabbitmq的六种工作模式
channel 信道:
信道是生产消费者与rabbit通信的渠道,生产者publish或是消费者subscribe一个队列都是通过信道来通信的。信道是建立在TCP连接上的虚拟连接,什么意思呢?就是说rabbitmq在一条TCP上建立成百上千个信道来达到多个线程处理,这个TCP被多个线程共享,每个线程对应一个信道,信道在rabbit都有唯一的ID ,保证了信道私有性,对应上唯一的线程使用。
类似概念:TCP是电缆,信道就是里面的光纤,每个光纤都是独立的,互不影响。
exchange 交换机和绑定routing key:
exchange的作用就是类似路由器,routing key 就是路由键,服务器会根据路由键将消息从交换器路由到队列上去。
exchange有多个种类,常用的有direct,fanout,topic
。前三种类似集合对应关系那样,(direct)1:1,(fanout)1:N,(topic)N:1
- direct: 1:1类似完全匹配
- fanout:1:N
可以把一个消息并行发布到多个队列上去,简单的说就是,当多个队列绑定到fanout的交换器,那么交换器一次性拷贝多个消息分别发送到绑定的队列上,每个队列有这个消息的副本。 - topic N:1 ,多个交换器可以路由消息到同一个队列。根据模糊匹配,比如一个队列的routing key 为*.test
,那么凡是到达交换器的消息中的routing key 后缀.test都被路由到这个队列上。
队列(queue):
1、推模式:通过AMQP的basic.consume命令订阅,有消息会自动接收,吞吐量高
2、拉模式:通过AMQP的bsaic.get命令
注:当队列拥有多个消费者时,队列收到的消息将以循环的方式发送给消费者。每条消息只会发送给一个订阅的消费者
持久化(duration)
开启持久化功能,需同时满足:消息投递模式选择持久化、交换器开启持久化、队列开启持久化.
确认机制(ack)
1、发送方确认模式:消息发送到交换器–发送完毕–>消息投递到队列或持久化到磁盘异步回调通知生产者
2、消费者确认机制:消息投递消费者-ack-删除该条消息-投递下一条
注:收到ACK前,不会把消息再次发送给该消费者,但是会把下一条消息发送给其他消费者
工作模式
simple模式
简单一对一
1.消息产生消息,将消息放入队列
2.消息的消费者(consumer) 监听 消息队列,如果队列中有消息,就消费掉,消息被拿走后,自动从队列中删除(隐患 消息可能没有被消费者正确处理,已经从队列中消失了,造成消息的丢失,这里可以设置成手动的ack,但如果设置成手动ack,处理完后要及时发送ack消息给队列,否则会造成内存溢出)。
work工作模式
一对多,即一个队列拥有多个消费者
消息产生者将消息放入队列消费者可以有多个,消费者1,消费者2同时监听同一个队列,消息被消费。C1 C2共同争抢当前的消息队列内容,谁先拿到谁负责消费消息(隐患:高并发情况下,默认会产生某一个消息被多个消费者共同使用,可以设置一个开关(syncronize) 保证一条消息只能被一个消费者使用)。
publish/subscribe发布订阅(共享资源)
这个就是结合fanout的交换机模式来使用,这个交换机下的队列可以被广播消息。
routing路由模式
消息生产者将消息发送给交换机按照路由判断,路由是字符串(info) 当前产生的消息携带路由字符(对象的方法),交换机根据路由的key,只能匹配上路由key对应的消息队列,对应的消费者才能消费消息;
topic 主题模式
类似路由模式,不同的是可以采用通配符的方式来匹配routingKey。匹配上的话消息就会被转发到这些队列中。
通配符:#
代表一个/多个单词,用.
分隔的是一个单词,*
只能匹配一个单词。
比如“hello.#”能够匹配到“hello.123.456”,但是“hello.*”只能匹配到“hello.123”
队列(queue)
就是存放消息的容器。
多个消费者可以订阅同一个队列,队列中的消息会被轮询发给这些消费者,不会发生重复消费问题。
如果在direct模式下多个队列绑定了同一个exchange,然后routingKey和bindingKey都是一样的,这个时候就会发生消息广播的情况,和fanout模式一样。
交换器(exchange)
生产者发送消息后,这个消息首先是到达了exchange
交换器中,然后交换器将消息按照路由规则转到一个或者多个队列中。如果找不到对应的队列,那么这个消息可能会返回给生产者或者直接丢弃(看具体配置)。
常用的交换器类型有四种
fanout:把消息路由到指定的exchange下面的所有队列中,即广播消息
direct:把消息路由到routingKey和bindingKey完全一致的队列中
topic:可以模糊匹配,2个'.'
分隔开的称为一个单词,‘#’
匹配一个单词,‘*’
匹配多个单词(可以是零个),这个路由匹配规则要写在交换器和队列绑定的routingKey(bindingKey)中。
headers:用的比较少,而且性能不高,使用的时候需要匹配message里header里的参数,匹配形式在绑定交换机和队列的时候决定
生产者发送消息的时候会指定一个routingKey
,它配合交换器绑定队列时指定的bindingKey
来联合使用。这个bindingKey
并不是在所有情况下都生效,比如交换器是fanout模式下,就会忽略这个bindingKey
将消息路由到所有绑定这个交换器的队列里。
通常我们在发送消息时的routingKey
和交换器绑定队列时的bindIngKey
是一致的,因为我们一般默认用的direct
模式。不过topic
模式下routingKey
和bindIngKey
就需要模糊匹配了.
springboot下的demo
maven依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
配置队列和交换机
生产者
@GetMapping("sendTestNormalQueue")
public String sendTestNormalQueue(String msg) throws JsonProcessingException {
Map<String,Object> map = new HashMap<>();
map.put("msg", msg);
//这里demo用的是路由模式,需要给队列绑定交换机,但是其实不给队列显示绑定交换机的话,mq会给这个队列绑定一个默认交换机,绑定的路由键(routing key)名称与队列名称相同。
rabbitTemplate.convertAndSend("normalExchange", "normalRoutingKey", map, new MessagePostProcessor() {
@Override
public Message postProcessMessage(Message message) throws AmqpException {
//可以在消息后置处理器里设置消息超时时间,这个在死信队列可以实现延时消息
message.getMessageProperties().setExpiration("5000");//时间单位是毫秒
return message;
}
});
log.info("发送消息");
return msg;
}
消费者