面向面试知识-消息队列

面向面试知识-消息队列

参考文章:消息队列(mq)是什么?、重复消费
老坑还没填完,就又开一个新坑:
Rocket MQ;Message Queue。

起始问题

  1. 为什么引入MQ?
  2. MQ适用于哪些场景下的哪些问题?
  3. MQ会遇到哪些问题?
  4. 如何解决这些问题?

为什么引入MQ?

  1. 异步处理:将连续的多任务异步处理面向面试知识-消息队列_第1张图片
    优化为:面向面试知识-消息队列_第2张图片

;比如:订单微服务,需要远程访问商品库存微服务,但是这样远程的整体响应速度较慢,为了解决速度慢的问题,可以加MQ进行异步处理。。如果异步处理失败怎么办?

如果用线程池,会出现:
a) 业务过多,每次加一个,要调用一个接口还要重新发布系统,效率低下。

  1. 解耦;如果库存微服务挂了,存在于MQ中的消息可以在其重启后,继续执行消息,即解耦;
  2. 削峰:虽然延长了处理时间,但是一定程度上保证了服务不挂掉;当系统处理不过来时,队列一定程度上可以削峰;
    面向面试知识-消息队列_第3张图片
    有了MQ之后,订单微服务在完成支付之后,只需要将支付成功的消息放入消息队列中,其他相关服务订阅消息,只要监听到该消息,就依次进行业务处理。异步处理+解耦,极大的加快了订单微服务的速度。
    如果只管订单微服务系统,那如果积分或者短信出错怎么办?:涉及到分布式事务知识点,以后再来填坑。

MQ的主要缺点

系统复杂度

是否涉及耦合的问题?:也就是之前的解耦主要指的是哪方面的解耦?
多了个中间件,就需要考虑各种问题,比如重复消费、消息丢失、顺序消费等,用了之后就是贼烦。
详情见文章:

数据一致性

分布式系统的通病
在MQ中,有分布式事务,把下单、优惠券、积分等都放在一个事务中,要么一起成功,要么一起失败。

可用性

后续展开;

如何选择中间件

比如主流的Kafka、Active MQ、Rabbit MQ、RocketMQ这几种
面向面试知识-消息队列_第4张图片
RocketMQ与Dubbo都是出自阿里之手,其架构设计很相像。
Kafka是消息队列的标杆,在其他类似于大数据领域也有很好的表现。
没有最好的技术,之后最合适的技术。不要为了用技术而用。

你的项目中,结合MQ实现了什么功能?

补充内容

  • 同步与异步:同步,比如进程A调用进程B,A在B完成之前一直等待,就是同步;A在B工作期间干别的事,就是异步。
    面向面试知识-消息队列_第5张图片
    面向面试知识-消息队列_第6张图片
    同步可以是同一线程也可以是不同线程;
    异步调用通常是和I/O操作等耗时较高的任务如影随形,像磁盘文件读写、网络数据的首发、数据库操作等。
    面向面试知识-消息队列_第7张图片
    异步的函数调用方,可以在函数调用之后继续执行其他内容。

消息的重复消费和顺序消费:

面向面试知识-消息队列_第8张图片
如果有服务发生错误,比如积分系统,则对应的重试机制会抛出异常,让重新发送一次。如果重新发送消息,其他的活动也都能看到这条“新”消息,如何避免重复消费该消息呢?
面向面试知识-消息队列_第9张图片
接口幂等

幂等(idempotent、idempotence)是一个数学与计算机学概念,常见于抽象代数中。
在编程中一个幂等操作的特点是其任意多次执行所产生的影响均与一次执行的影响相同。幂等函数,或幂等方法,是指可以使用相同参数重复执行,并能获得相同结果的函数。这些函数不会影响系统状态,也不用担心重复执行会对系统造成改变。
例如,“setTrue()”函数就是一个幂等函数,无论多次执行,其结果都是一样的.更复杂的操作幂等保证是利用唯一交易号(流水号)实现.

面向面试知识-消息队列_第10张图片
帅气面试官您好,一般幂等,我会分场景去考虑,看是强校验还是弱校验,比如跟金钱相关的场景那就很关键呀,就做强校验,别不是很重要的场景做弱校验

强校验:比如你监听到用户支付成功的消息,你监听到了去加GMV是不是要调用加钱的接口,那加钱接口下面再调用一个加流水的接口,两个放在一个事务,成功一起成功失败一起失败。每次消息过来都要拿着订单号+业务场景这样的唯一标识(比如天猫双十一活动)去流水表查,看看有没有这条流水,有就直接return不要走下面的流程了,没有就执行后面的逻辑。

弱校验:这个简单,一些不重要的场景,比如给谁发短信啥的,我就把这个id+场景唯一标识作为Redis的key,放到缓存里面失效时间看你场景,一定时间内的这个消息就去Redis判断。

顺序消费

一般都是同个业务场景下不同几个操作的消息同时过去,本身顺序是对的,但是你发出去的时候同时发出去了,消费的时候却乱掉了,这样就有问题了。

有时遇到这种情况:把所有的操作消息怼到队列里面去,然后慢慢消费的,那问题就来了呀,我们在数据库同时对一个Id的数据进行了增、改、删三个操作,但是你消息发过去消费的时候变成了改,删、增,这样数据就不对了。

面向面试知识-消息队列_第11张图片
生产者消费者一般需要保证顺序消息的话,可能就是一个业务场景下的,比如订单的创建、支付、发货、收货。
一个topic下有多个队列,为了保证发送有序,RocketMQ提供了MessageQueueSelector队列选择机制,他有三种实现:
面向面试知识-消息队列_第12张图片
选择哈希,根据订单号将对同一行数据的操作(创建、支付、发货、收获)映射到同一队列中,进而都在同一消费者端消费。
==为了保证消息的顺序,需要同步,只有当订单的创建消息发送成功,才发送支付消息。==这样就保证了消息的顺序性。
RocketMQ的topic内的队列机制,可以保证存储满足FIFO,剩下的只需要消费者顺序执行。

RocketMQ仅保证顺序发送,顺序消费由消费者业务保证!!!

能聊一下分布式事务吗?

分布式事务在现在遍地都是分布式部署的系统中几乎是必要的。
事务是恢复和并发执行的基本单位:要么一起执行,要么都不执行的一组数据库操作的集合。
事务的隔离级别、ACID(原子性、一致性、独立性 隔离性、持久化)

原子性:一个事务是一个不可分割的工作单位,包括的操作要么都做,要么都不做。
一致性:事务必须是使数据库从一个一致性状态变到另一个一致性状态。
隔离性:一个事务的执行不能被其他事务干扰。即某一事务的内部操作以及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。
持久性:一个事务一旦提交,对数据库中的数据的改变就应该是永久性的。接下来的其他操作或故障不应该对其有任何影响。

分布式事务,保证积分、优惠券等的相关业务的正确运行。

2pc,两段式提交:
面向面试知识-消息队列_第13张图片

最终一致性

面向面试知识-消息队列_第14张图片
好复杂:

  • 业务主动方本地事务提交失败,业务被动方不会受到消息的投递。
  • 只要业务主动方本地事务执行成功,那么消息服务一定会投递给下游的业务被动方,并最终保证业务被动方一定能成功消费该消息(消息成功或失败,即最终一定会有一个最终态)。
    离开业务的技术没有意义,离开技术的业务没有底气
    没有最完美的系统,只有最适合的系统。

你可能感兴趣的:(java,后端开发,MQ,面试,java-rocketmq)