同步通讯&异步通讯

Mq五种队列

消息可靠性(publisher、consumer消息确认)

持久化

同步通讯和异步通讯:

同步通讯:

优点:时效性比较高

缺点:耦合度高、

性能下降、

额外的资源消耗、

级联失败问题

异步通讯:

优点:不需要很强的失效性

性能的提升、

故障隔离、

耦合度低、

流量削峰

缺点:架构复杂、

需要依赖broker的可靠、安全、性能

Mq:消息中间件

追求可用性:Kafka、 RocketMQ 、RabbitMQ

追求可靠性:RabbitMQ、RocketMQ

追求吞吐能力:RocketMQ、Kafka

追求消息低延迟:RabbitMQ、Kafka

Rabbitmq的常见角色:

Publisher:生产者

Consumer:消费者

Queue:队列

Exchange:交换机

Rabbitmq五种消息队列:

Basicqueue 基本消息队列

Workqueue 工作消息队列

(发布订阅)

Fanout exchange 广播

Direct exchange 路由

Topic exchage 主题

Springamqp:

SpringAMQP是基于RabbitMQ封装的一套模板,并且还利用SpringBoot对其实现了自动装配

Springamqp提供的三个功能:

自动声明交换机,队列,及其绑定关系

基于注解的监听模式、异步接收消息

封装rabbittemplate工具,用于发送消息

Basic queue队列流程:

配置rabbitmq的连接信息到application.yml

Publisher调用rabbittemplate的convertandsend方法把队列名称和消息发送出去

Consumer使用rabbitlistener注解监听publisher发送的队列

Work queue队列流程:

一个publisher对应多个consumer,每个consumer平均分配publisher的消息。可以修改consumer的配置文件使每个consumer只能获取一条消息,处理完才能获取下一条消息

Fanout exchange队列:

编写配置类声明交换机和队列的关系。

其他不变

Direct exchange队列:

消息发送方不变调用rabbittemplate的send方法发送消息。多一个key,根据key进行路由

接收方使用rabbitlistener注解绑定关系:

@rabbitlistener(bindings=@Queuebinding(
Value=@Queue(name=”q1), 队列名称
Exchange=@Exchange(name=”e1”,type=Excahngetypes.DIRECT), 交换机名称
Key={“red}/”blue” key
))
Topic exchange队列:
与direct基本无差别。区别在routingkey上topic的key可以使用通配符
#:代表多个或0个词
*:代表一个词
默认的传递对象会被序列化。需要在配置类中配置json转换器:
@Bean
Public Messageonverter jsonMessageConverson(
Return new Jackson2JsonMessageconverter();
)

消息可靠性:

Publisherconsumer消息确认

消息持久化

死信交换机

Mq集群

消息可靠性:

消息丢失的原因:

发送时丢失:

生产者发送的消息未送达exchange

消息到达exchange后未到达queue

MQ宕机,queue将消息丢失

consumer接收到消息后未消费就宕机

Rabbitmq解决方法:

生产者确认机制

mq持久化

消费者确认机制

失败重试机制

配置流程:

Publisher配置

1、
application.yml
publish-confirm-type:开启publisher-confirm,这里支持两种类型:
simple:同步等待confirm结果,直到超时
correlated:异步回调,定义ConfirmCallback,MQ返回结果时会回调这个ConfirmCallback
publish-returns:开启publish-return功能,同样是基于callback机制,不过是定义ReturnCallback
template.mandatory:定义消息路由失败时的策略。true,则调用ReturnCallback;false:则直接丢弃消息
2、
全局ReturnCallback
Consumer配置:
定义ConfirmCallback
持久化:
交换机持久化配置:
@Bean
public DirectExchange simpleExchange(){
    // 三个参数:交换机名称、是否持久化、当没有queue与其绑定时是否自动删除
    return new DirectExchange("simple.direct", true, false);}
队列持久化:
@Bean
public Queue simpleQueue(){
    // 使用QueueBuilder构建队列,durable就是持久化的
    return QueueBuilder.durable("simple.queue").build();
}
消息持久化:
可以设置消息的属性(MessageProperties),指定delivery-mode:PERSISTENT
消费者确认:
manual:手动ack,需要在业务代码结束后,调用api发送ack。
auto:自动ack,由spring监测listener代码是否出现异常,没有异常则返回ack;抛 出异常则返回nack
none:关闭ack,MQ假定消费者获取消息后会成功处理,因此消息投递后立即被删除
失败重试:
在开启重试模式后,重试次数耗尽,如果消息依然失败,则需要有MessageRecovery接口来处理,它包含三种不同的实现:
RejectAndDontRequeueRecoverer:重试耗尽后,直接reject,丢弃消息。默认就是这种方式
ImmediateRequeueMessageRecoverer:重试耗尽后,返回nack,消息重新入队
RepublishMessageRecoverer:重试耗尽后,将失败消息投递到指定的交换机
比较优雅的一种处理方案是RepublishMessageRecoverer,失败后将消息投递到一个指定的,专门存放异常消息的队列,后续由人工集中处理。
1)在consumer服务中定义处理失败消息的交换机和队列
@Bean
public DirectExchange errorMessageExchange(){
    return new DirectExchange("error.direct");
}
@Bean
public Queue errorQueue(){
    return new Queue("error.queue", true);
}
@Bean
public Binding errorBinding(Queue errorQueue, DirectExchange errorMessageExchange){
    return BindingBuilder.bind(errorQueue).to(errorMessageExchange).with("error");
}
2)定义一个RepublishMessageRecoverer,关联队列和交换机
@Bean
public MessageRecoverer republishMessageRecoverer(RabbitTemplate rabbitTemplate){
    return new RepublishMessageRecoverer(rabbitTemplate, "error.direct", "error");
}