MQ是什么
是一种跨进程的通信机制,用于上下游传递消息
什么时候用MQ
举个例子:现在有三个任务A、B、C
- A需要B的结果作为条件;
- B需要C的结果作为条件;
执行的顺序是C - B - A
原来的解决方案:
- C在18:00执行:B先执行,然后默认C要执行20分钟,但是因为B可能不确定C要执行多久,所以可以预留10分钟额外时间
- B在18:30执行:B也默认20min能执行完,但是A不知道B20min能不能执行完,所以预留10min
- C在19:00执行
这样执行弊端很大
- 比如说要是C执行时间超过半小时,那么程序就会出错;
- 再比如说我要是改C的执行时间那么BA的执行时间都要改
- 再者说预留了一部分时间,就算是C 10min执行完了,那么B也要等半小时之后执行
故MQ出现了,使用MQ执行的流程:
- C先执行,执行完毕后会给MQ发一个我执行完了
- B从MQ上接收到C执行完了,然后直接就开始执行B,执行完B之后,B向MQ发送一个我也执行完了
- A从MQ上接收到B也执行完了,那么就可以立刻执行A
好处:
- 不需要预留空闲资源,上游执行完毕之后,下游就可以直接继续执行
- 就算是很多的任务也会按照顺序逐个执行
- 不受执行时间的影响
MQ 优点:
- 异步处理 - 相比于传统的串行、并行方式,提高了系统吞吐量。
- 应用解耦 - 系统间通过消息通信,不用关心其他系统的处理。
- 流量削锋 - 可以通过消息队列长度控制请求量;可以缓解短时间内的高并发请求。
- 日志处理 - 解决大量日志传输。
- 消息通讯 - 消息队列一般都内置了高效的通信机制,因此也可以用在纯的消息通讯。比如实现点对点消息队列,或者聊天室等。
MQ 缺点
- 一致性问题
比如说有三个系统ABC ,AB执行完毕了,但是C执行失败了,导致数据不一致 - 系统复杂度提高
比如说要处理一致性问题,消息不可重复消费问题等 - 系统可用性降低
MQ也是系统本身的一部分,要是MQ挂了,你的系统也跟着挂了
ActiveMQ:
使用java编写的队列,但是也提供PHP,c,c++,Python等客户端支持,支持主从复制,集群
工作模型两种:queue和topics
- queue:多对一,可以有多个提供者发消息,消费者消费一条就移除一条,一个queue里可以有多个消费者
但是她们必须标记都再一个messageGroup中,这样会逐个发送给每个消费者,消费者不会消费相同数据,每条消息被
消费一次 - topics:广播,提供者发送消息,每个消息都包含一个topic,消费者定义topic,所有订阅的topic都会收到消息
- 订阅分为持久订阅和不持久订阅,持久订阅当消费者断开之后,再连上会接收没接受的消息,不持久
断开这段时间的消息就不会接收到
boot整合ActiveMQ
提供者:
-
启动类添加@EnableJms
-
定义消息队列
@Configuration
public class BeanConfig {//定义存放消息的队列
@Bean
public Queue queue() {
return new ActiveMQQueue(“ActiveMQQueue”);
}
} -
使用
@Autowired
private JmsMessagingTemplate jmsMessagingTemplate;
…
jmsMessagingTemplate.convertAndSend(queue, name);
…
消费者:
@Autowired
private JmsMessagingTemplate jmsMessagingTemplate;
@JmsListener(destination = "ActiveMQQueue")
public String testMessage(String message){
System.out.println("成功接受" + message);
return message;
}
RabbitMQ
是一个使用erlang编写的AMQP(高级消息队列协议)的队列,功能完善,性能好
消费者:
- 配置:
#rabbitmq配置
spring.rabbitmq.host=ip
spring.rabbitmq.port=port
spring.rabbitmq.username=name
spring.rabbitmq.password=pwd - 接收类添加@RabbitListener注解
@RabbitListener(queue=“消费对列名”)
public void test(String message){
…
}
提供者:
@Autowired
private AmqpTemplate amqpTemplate;
public void send(){
amqpTemplate.converAndSend(“mq名称”,“数据”);
}
方式二:
amqpTemplate.converAndSend(“type”,“tocken”,“数据”);
kafka:
消费者:
一般做大数据使用
@KafKaListener(topics = {“名称”})
public void test(){
…
}
对比
– | ActiveMQ | RabbitMQ | Kafka |
---|---|---|---|
开发语言 | Java | Erlang | Scala/Java |
时效性 | ms级 | 微秒级(延迟最低) | ms以内 |
吞吐量 | 万级 | 万级 | 十万级 |
持久化 | 支持少量堆积 | 支持少量堆积 | 支持大量堆积 |
性能稳定性 | 好 | 好 | 较差 |
管理界面 | 一般 | 较好 | 无 |
维护者 | Apache | Mozilla/Spring | Apache |
集群方式 | 支持简单集群模式,比如’主-备’,对高级集群模式支持不好。 | 支持简单集群,'复制’模式,对高级集群模式支持不好 | 天然的‘Leader-Slave’无状态集群,每台服务器既是Master也是Slave |