面试进阶:如何设计一个MQ
前言
如何设计一个XXX?在面试时我们经常遇到这样的问题。实际上,不管是设计什么,数据库也好,MQ也好,rpc框架也好,我们想要实现其功能,一般来说是比较好实现的,数据库最基本的保存数据的功能,我们写个文件就好,rpc框架,我们用http传输完全可以实现,MQ同样也是如此。
实际上问题的难点在于,我们如何将其设计的高可用,高性能,可伸缩,如何在完成功能的基础上支持更高级的特性,如数据库的事务,MQ的exactly once,等等。
所以这一类问题,实际上考察的是我们的整体的一个架构能力,以及对常用的开源组件的原理的熟悉程度。
以MQ为例
我们知道MQ最基本的功能是传输消息,做一个缓冲。生产者发送消息至MQ,消费者从MQ拉取消息,实际上一个队列就可以实现这个功能。在这个队列的基础上,我们考虑增强其功能。
首先是如何将其实现为可伸缩的,如何能够在需要时对其进行扩容,如何增加其吞吐量。解决方法当然就是加机器,加机器可不是简单的堆叠就好了,我们要设计成分布式的系统。那么如何设计呢?这里就可以借鉴各个开源MQ的分布式架构了。以kafka为例,我们将消息抽象,分为broker -> topic -> partition这么几层,每个broker作为单独的一个存储节点,存储几个topic的某个partition。这时候数据量太大,容量不够用了怎么办呢?有了这个架构就好解决了,我们加几台机器,给要扩容的topic加几个partition,问题就简单的解决了。
那么高可用怎么保证的呢?这个的实现方式思路都是比较一致的,我们搞几个副本不就好了,每个broker我们搞两个副本,在这三个里选出一个性能最好的来作为master,剩下的两个作为slave,生产数据消费数据我们都从master里做,master同步到slave后操作才算完成,再搞个zookeeper来做监控,看哪个master节点挂了马上选出一个新的master来,这样就保证了整个系统的高可用,副本越多,越不容易出问题。
至于性能上怎么优化,则要看具体的应用场景,常用的可能就是mmap来读写发送数据,追加写文件提升效率等等。
剩下的就是我们MQ常常需要考虑的那几个问题了,消息重复,消息丢失,消息堆积,等等。
- 消息重复 消息重复两种可能,一种是生产者发送给MQ的消息重复了,一种是消费者重复消费了MQ里的消息,其实单单靠MQ是无法解决这个问题的,因为对于一条消息而言MQ很难知道这是一条重复的消息,除非消息有一个UUID可供鉴别,因此去重,或者说做幂等通常由生产者消费者协同来做,在消费者侧由数据库主键或者redis来做去重。而MQ需要保证每一条消息的准确送达。
- 消息丢失 这个问题如何解决呢?我们可以引入一个confirm机制,对于生产者,每发送一条消息到MQ,MQ收到后,发送一个confirm给生产者,对于没收到confirm的消息,生产者进行重新发送,这样保证了生产者到MQ消息的不丢失。那么MQ内部如何保证呢?我们有了之前的副本容错机制,不放心的话我们可以再加一层保险,将其持久化到硬盘,写入完成后MQ发送confirm给到生产者,这样就不会丢失了。对于消费端同样也是如此,消费端消费完成后,提交一个confirm给到MQ,MQ就知道消费完成。
- 消息堆积 消息堆积一般是由于消费者挂掉了或者消费者消费过慢引起的。这样的问题实际上也不是单独MQ就能够解决的。一般遇到这种问题,我们会恢复消费者的消费速度,多布几个消费节点,同时MQ的通量不够的情况下也会紧急扩容,这就利用到了上文说到的可伸缩性。当把堆积的消息处理完成后,再回复MQ和消费者至原来的状态。
本文地址:https://blog.csdn.net/GaleZhang/article/details/108205046
下一篇: 黄龙风景区门票多少钱 黄龙风景区旅游攻略