消息队列相关知识点

消息队列的使用场景:异步,消峰,解耦

实现异步为什么考虑使用消息队列而不是线程和线程池去做呢?

使用线程和线程池的话耦合度高,出问题排查也麻烦,流程里面随便一个地方出问题搞不好会影响到其他的点

主流的消息队列中间件主要有,Kafka、ActiveMQ、RabbitMQ、RocketMQ 等这几种

通过吞吐量,以及部署方式而言ActiveMQ和RabbitMQ是远远不如天然分布式架构的RocketMQ 和Kafka的,并且RocketMQ 和Kafka都是高可用的分布式架构,而且数据多个副本的数据也能做到0丢失

消息队列的缺点:重复消费、消息丢失、消息的顺序消费

重复消费问题可以采用接口幂等来解决,接口幂等采用强校验或弱校验实现

接口幂等就是同样的参数调用我这个接口,调用多少次结果都是一个,你加销售额同一个订单号你加一次是多少钱,你加N次都还是多少钱。

接口幂等处理流程

一般幂等,需要分场景去考虑,看是强校验还是弱校验,比如跟金钱相关的关键场景,就做强校验,不是很重要的场景做弱校验。

强校验采用“需要更新的业务表”+“流水接口/日志接口”两个放在一个事务,成功一起成功,失败一起失败,每次消息过来都要拿着“单据号”+“业务场景/单据类型”这样的唯一标识去“流水/日志表”查,看看有没有这条“流水/日志”,有就直接return不要走下面的流程了,没有就执行后面的逻辑。

强校验代码示例

public void process(String orderId){
	try{
		// 查询这个订单是否存在这个活动加销售额的流水
		Object gmvFlow = getFlowByOrderId("orderType" + orderId);
		if(Objects.isNull(gmvFlow)){
			// 不存在流水 去加销售额和加流水 注意这两个在一个事务 回滚一起回滚
			addGmvAndFlow(orderId);
		}else{
			// 存在流水证明加过了 返回就好了
			return;
		}
	} catch (Exception e){
		// 发送异常 触发消息队列框架重试机制
	}
}

不重要的场景,比如发短信采用弱校验,具体实现方式
把”id“+”场景唯一标识/单据类型“作为Redis的key,放到缓存里面,失效时间看具体场景,一定时间内的这个消息就去Redis判断

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

 通过RocketMQ的MessageQueueSelector的HASH取模法保证消息的顺序消费

让同一个订单发送到同一个队列中,再使用同步发送,只有同个订单的创建消息发送成功,再发送支付消息(一个消费成功了再发下一个)。这样,我们保证了发送有序

RocketMQ的topic内的队列机制,可以保证存储满足FIFO(First Input First Output 简单说就是指先进先出),剩下的只需要消费者顺序消费即可。

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

这里很好理解,一个订单你发送的时候放到一个队列里面去,你同一个的订单号Hash一下是不是还是一样的结果,那肯定是一个消费者消费,那顺序就可以得到保证

下单流程可能涉及到10多个环节,付钱成功了,但是优惠券扣减失败了,积分新增失败了,但是这些都在不同的服务怎么保证大家都成功呢?

例如

采用分布式事务中的两段式提交保证分布式系统数据的一致性

类似于媒婆,就是通过MQ消息中间件协调多个系统,在两个系统操作事务的时候都锁定资源但是不提交事务,等两者都准备好了,告诉消息中间件,然后再分别提交事务

例如


用于个人学习记录

转载自

字节跳动面试官这样问消息队列:分布式事务、重复消费、顺序消费,我整理了一下_敖丙-CSDN博客

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值