当前位置: 首页 > 科技观察

《漫谈 MQ》设计MQ的三大难点

时间:2023-03-12 03:43:24 科技观察

本文转载自微信公众号《我脑子炸了》,作者陈建宇。转载本文请联系BrainJinJianYu公众号。大家好,我是炸鱼。前段时间我们分享了《漫谈 MQ》《要消息队列(MQ)有什么用?》的第一期,感觉打开了一个新世界。但很快就有朋友意识到这不太好。MQ既然承接了多个系统,是不是应该会出现一些问题?他拥有所有这些,甚至更糟。如下:今天我们就进一步聊一聊在设计MQ时可能遇到的几大难点,以及业界有哪些解决方案来应对。综上所述,设计MQ有几个难点。至少存在三个难点。堪称网络经典,也是面试官最喜欢问的问题:高可用性:代表系统的可用性。高可用性通常是通过提高系统的容错能力来实现的,从而减少系统停机时间。高并发:是指设计上保证系统可以同时并行处理很多请求。在同一时间点,很多用户同时访问同一个系统、API、URL。高可靠性:代表一个系统或组件能够满足预期的条件(例如:备份、故障处理、数据存储和访问),比较经典的有4个9等标准。高可用如之前评论区留言的兄弟截图所说。虽然请求不会直接去到系统A、B、C、D。但是,请求实际上是通过异步的方式发送到MQ的,而且MQ可以持续加载,多个系统都在请求MQ。可以认为压力是单个系统同步调用的两倍以上。同时,MQ还需要维护消费者关系,存储大量已有的和新增的消息。这是一个典型的场景,两者都需要。这样,新一轮的问题就出现了。就是要保证MQ的高可用,否则很容易被压垮到宕机,或者负载过高,导致一些难以想象的延迟。如何保证MQ的高可用是个大问题。高并发方面对高并发的要求其实和高可用场景是一样的。既然所有的业务系统都是异步的,自然他不会像同步阻塞一样“等”你。比如我有个朋友喜欢批量清洗多租户数据。商业计划不是很克制。几十、几百、几千万的数据都是用Go语言写的。复制for-loop+gofunc只是一个穿梭。它会在几秒钟内进入MQ。如果多几个业务系统这样做,MQ的并发度会比较高,光是维护就很头疼。后面很可能出事了,年底就3.25了。因为MQ非常依赖业务,所以是标准的核心基础设施。如何保证MQ能承受高并发是个大问题。高可靠性对于MQ来说,高可靠性的诉求可以从几个角度来理解。如下:消息必须可靠:“我”发送的消息必须能够可靠地到达MQ,MQ必须能够正确地让消费者接收到push或pull。存储要靠谱:“我”发过来的消息,还在MQ上的时候就应该存储好。如果不能发送到MQ,就会因为数据量大而丢失。或者查询很慢。可靠处理:发送消息后,可能会出现异常。发了信息,可能是网络抖动,没收到。上面我们列出了三个“可靠”的内容。本质上,对于MQ来说,每个领域都要保证它的可靠性,否则一查问题就真的崩溃了。再高一点,还会有“高性能”的要求,但我们不在这方面展开。设计完MQ会遇到的三大难点,解决方案的核心流程就清晰了。我们需要了解现代MQ的基本应用程序架构会是什么样子。MQ包括以下三类角色:Producer:负责生产消息。消费者(Consumer):负责消费消息。Server(Broker):负责消息的存储和处理,是MQ的核心部分。扩展自队列(Queue),因为功能不局限于队列属性。其核心流程如下:核心流程生产者(Producer)向服务器(Broker)发送消息,服务器存储消息,核心逻辑处理等。然后根据之前注册的消费关系(例如:订阅),推送消息或拉。即消费新闻。消费消息完成后,向服务端返回一个确认(ACK)。如果一定时间内没有收到ACK,就会触发服务器的重试机制。服务器判断消息已经被处理,删除消息并记录。为三个高层设计高可用在高可用中,主要是针对服务端(Broker)。目前常见的是保证服务器可以水平扩展,跨集群部署。因此,相应地,必须支持服务的注册和发现机制,以及负载均衡(保证服务器端压力均衡)。这就构成了MQ高可用的基本维护。设计高并发从高并发来说,服务器必须包含一个队列(Queue),它会起到缓冲的作用。但是单点的流量可能还是太大了。所以通常会结合RocketMQ、Kafka的Partition等topic来划分队列,起到分而治之的作用。设计高可靠性在高可靠性方面,主要关注消息发送、消息存储、消息处理三个部分。在消息发送方面,将结合SDK和服务端,使用消息发送和消费的确认(ACK)机制和重试机制来实现消息的可靠性。在消息存储方面,常见分为:分布式缓存、分布式文件系统、数据库方案等,目前主流会采用写磁盘的方式,即把消息体添加到日志文件中,然后配合索引文件做快速消息搜索。与MySQL数据库的存储方式有一定的相似之处。小结在今天的文章中,我们介绍并解释了MQ设计中常见的三个难点(其实还有很多,后面会介绍。。。)。同时,也分析了业界常见的解决方案。了解了这些细节之后,我们在实际应用MQ的时候就不会那么无助了。因为大家经常遇到的,消息丢失,或者消息重试导致裂变导致宕机。它往往来自于这些你忽略的设计细节。哪怕只是在客户端做一些简单的配置,这些知识你也该懂了:)