一、传统Http协议调用接口存在的缺陷
Http协议基于请求响应模式
-
传统同步方式实现会员注册
会员注册–>数据库新增插入会员信息–>调用优惠券接口赠送优惠券–>调用第三方短信接口
缺点:1、响应时间长2、事务问题,出现异常难以回滚 -
使用多线程优化
会员注册–>数据库新增插入会员信息–>开启两个线程同时处理调用优惠券接口赠送优惠券和调用第三方短信接口
优点:响应时间减少
缺点:1、得写一套补偿机制(纪录错误,定时补发,重试,会存在幂等性问题,xxl-job任务调度)2、线程太多,cpu性能不是很好,高并发情况下超过线程池连接数会等待
- 使用消息中间件异步形式
会员注册–>数据库新增插入会员信息–>发送两个消息给消息中间件,
两个消费者消费
优点:流量削峰,异步,解耦,即使消费者突然宕机,消息也不会丢失,缓存在消息中间件中,消息中间件会把持久化到硬盘
二、消息中间件常见问题
1、消息幂等性
2、分布式事务
3、消息顺序性
4、延迟队列:消息过期,回调方法主动查询订单状态
5、重复消费:手动ACK
6、公平队列:设置每个消费者每次只能消费一条消息,这样就实现了,因为消费快的性能好,消费速度快。
7、死信队列:(1)消息过期:没有消费者消费,主动查询状态(2)消息堆积:队列满了,MQ拒绝接收存放消息,消费太慢也会(3)消费者多次消费同一个消息失败:消费者出bug,这些信息都会被发送到死信交换机上
8、消息持久化:防止宕机把消息持久化到硬盘,持久化完成之后再手动ack,代码创建要手动开启持久化,控制台创建默认开启持久化,交换机和队列都必须开启持久化,binding才会持久化
9、主动推拉:第一次启动主动和中间件建立连接,主动拉取消息,之后MQ主动推送
10、投递消息失败:MQ宕机,MQ拒绝接收消息(队列满了)
三、消息中间件的四大作用
队列不存在,自动创建队列
Virtual host:虚拟主机,相当于redis的库,使用原因:多个团队同时使用一个rabbitmq的情况下,消息容易重名,乱套了,使用Virtual相当于独立的rabbitmq服务器
1、流量削峰:消息一个一个消费,不会一下子撑爆服务器
2、解耦:只关心交换机,类似注册中心,统一管理
3、自动重试补偿:服务器出错自动重试
4、异步:异步发送消息效率高
四、ActiveMQ、RabbitMQ、RocketMQ、Kafka的区别?
ActiveMQ:不支持高并发,遵循JMS规范,安装方便,可能会丢失消息
RabbitMQ:一万多的并发量,Erlang语言编写的,用的人少,不好扩展,协议,使用AMQP协议,支持windows和linux
RockerMQ:十几万的并发量
Kafka:十几万的并发量
Redis也可以做消息中间件,只是他是专业做缓存的,专业人做专业事。
五、RabbitMQ解决订单超时问题
1、使用redis超时key比较麻烦些,要在数据库中额外增加一个字段
2、任务调度,xxl-job,定时查看订单状态,订单多的情况,效率低
3、RabbitMQ中使用延迟队列,投递的消息设置有效期,有效期结束之后把消息交给死信交换机,死信交换机转发给死信队列,死信队列交给思想消费者,通过订单ID查询订单状态
六、RabbitMQ常用的五种模式
1、点对点通讯:一个生产者一个消费者
2、工作模式:一个生产者多个消费者
3、路由模式,key
4、发布与订阅模式:扇形
5、主题模式
第六种是RPC,忽略
七、如何合理的选择重试规则
场景一:消费者获取下消息后,调用第三方接口失败
需要重试
场景二:消费者获取下消息后,因为代码问题抛出异常
,需要改动代码才能修复的,不需要重试,需要重新发布版本
通过表记录日志来补偿
八、重试多次失败如何解决?
重试过程会通过aop拦截异常,不会去打印错误日志,重试多次失败再打印日志
1、删除消息,把消息交给死信队列处理
2、日志表记录,人工补偿