和面试官聊一聊中间件

面试官

我看你项目中使用了中间件,你说一下为什么使用中间件,使用中间件有什么好处和坏处,怎样注意避免,以及各中间的原理。以及中间件是如何做到那么快的可靠性,在我们做服务的时候有什么可以借鉴到项目中

我:好的,面试官老师,我们引入中间件主要解决异步,解耦,和削峰,异步是进程间的异步,解耦是应用程序间的解耦,例如仓库和物流和积分之间的关系可以利用一个中间件的技术,将他们都解耦出来,那削峰就是秒杀活动,将消息直接存入中间件中记录下来。
使用中间件使得编码变得复杂,系统的可靠性及其依赖中间件的稳定运行,增加系统的复杂性,以及数据一致性问题。

面试官

那怎么解决这些问题呢?

我:Rabbit MQ是没有分布式的,但是镜像集群可以高可用,kafka的高可用就是天然的,采用topic划分partion,存在broker上,0.8没有HA,后来加入副本机制,可以先写入leader上,follower主动来取数据,然后返回给生产者消息。
Rabbit MQ弄丢数据可以开启事务,但是吞吐量会下来,可以开启cinfirm模式,异步回调接口通知
为保证Rabbit MQ本身服务的稳定性可以开启持久化
Rabbit MQ提供ack机制,提供给别的消费组

kafka的消费设置 副本数大于2,从节点树大于1,acks=all ,retries=max无限次重试

面试官

既然让消息最少一次,就要保证幂等性问题,你怎么设计你的幂等性

我:一般设计一个全局id(雪花),然后存入redis中,消费过就不再处理,数据库id的唯一性。
面试官:

介绍一下kafka吧,以及为什么kafka的效率就是高,是你,你怎么设计。

1、我们认识kafka是主题topic的消息中间件,采用分区partition,分区的作用是分布式存储,可以并行写
2、Kafka也不是partition一有数据就立马将数据写到磁盘上,它会先缓存一部分,等到足够多数据量或等待一定的时间再批量写入(flush)。
3、Kafka集群中的broker在zk中创建临时序号节点,序号最小的节点(最先创建的节点)将作为集群的controller,负责管理整个集群中的所有分区和副本的状态:

  • 当某个分区的leader副本出现故障时,由控制器负责为该分区选举新的leader副本。
  • 当检测到某个分区的ISR集合发生变化时,由控制器负责通知所有broker更新其元数据信息。
  • 当使用kafka-topics.sh脚本为某个topic增加分区数量时,同样还是由控制器负责让新分区被其他节点感知到。
    前提是:消费者没有指明分区消费。当消费组里消费者和分区的关系发生变化,那么就会触发rebalance机制。这个机制会重新调整消费者消费哪个分区。

4、在触发rebalance机制之前,消费者消费哪个分区有三种策略:

  • range:通过公示来计算某个消费者消费哪个分区
  • 轮询:大家轮着消费
  • sticky:在触发了rebalance后,在消费者消费的原分区不变的基础上进行调整。

5、 HW俗称高水位,HighWatermark的缩写,取一个partition对应的ISR中最小的LEO(log-end-offset)作为HW,consumer最多只能消费到HW所在的位置。另外每个replica都有HW,leader和follower各自负责更新自己的HW的状态。对于leader新写入的消息,consumer不能立刻消费,leader会等待该消息被所有ISR中的replicas同步后更新HW,此时消息才能被consumer消费。这样就保证了如果leader所在的broker失效,该消息仍然可以从新选举的leader中获取。
kafka消费快

面试官:

描述一下Rocket MQ的具体流程

我:主要分以下几步:
● 1 )启动NameServer,NameServer启动后开始监听端口,等待Broker、Producer、Consumer连接。
● 2 )启动Broker时,Broker会与所有的NameServer建立并保持长连接,然后每 30 秒向NameServer定时发送心跳包。
● 3 )发送消息前,可以先创建Topic,创建Topic时需要指定该Topic要存储在哪些Broker上,当然,在创建Topic时也会将Topic与Broker的关系写入到NameServer中。不过,这步是可选的,也可以在发送消息时自动创建Topic。
● 4 )Producer发送消息,启动时先跟NameServer集群中的其中一台建立长连接,并从NameServer中获取路由信息,即当前发送的Topic消息的Queue与Broker的地址(IP+Port)的映射关系。然后根据算法策略从队选择一个Queue,与队列所在的Broker建立长连接从而向Broker发消息。当然,在获取到路由信息后,Producer会首先将路由信息缓存到本地,再每 30 秒从NameServer更新一次路由信息。
● 5 )Consumer跟Producer类似,跟其中一台NameServer建立长连接,获取其所订阅Topic的路由信息,然后根据算法策略从路由信息中获取到其所要消费的Queue,然后直接跟Broker建立长连接,开始消费其中的消息。Consumer在获取到路由信息后,同样也会每 30 秒从NameServer更新一次路由信息。不过不同于Producer的是,Consumer还会向Broker发送心跳,以确保Broker的存活状态。

面试官:

描述一下Rocket MQ的读写队列

例如,原来创建的Topic中包含 16 个Queue,如何能够使其Queue缩容为 8 个,还不会丢失消息?可以动态修改写队列数量为 8 ,读队列数量不变。此时新的消息只能写入到前 8 个队列,而消费都消费的却是16 个队列中的数据。当发现后 8 个Queue中的消息消费完毕后,就可以再将读队列数量动态设置为 8 。整个缩容过程,没有丢失任何消息。

面试官:

其实MQ是可以实现事务的,你是否知道,怎么设计的?

我:什么是分布式事务,是指Spring 提供的也有事务的方法,比如 @Transactional 注解,但是在微服务当中,每个服务都是一个独立的jvm,两个jvm 之间没办法相互去控制,所以分布式事务的概念
你要知道什么是可靠生产:就是使用确认机制
如果投递成功则回状态成功,否则失败重发,重发失败则是消息问题
增加冗余表确认投递成功
你要知道什么是可靠生消费:就是使用利用死信队列
解决方案:
1.队列绑定一个死信队列。
2.当消息消费的时候遇到异常,利用MQ的nack机制把消息丢弃到死信队列。
3.监听死信队列中的消息进行业务处理或者人工干预。
会遇到以下问题:
a.幂等性问题:定时重发会造成消息的重复发送。可以使用唯一主键,或者redis 的分布式锁。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值