消息队列 | 青训营笔记

59 阅读7分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 14 天

消息队列概述

消息队列(Message Queue,简称MQ)是指保存消息的一个容器,其实本质就是一个保存数据的队列。

消息队列是分布式系统中重要的组件,主要解决应用解耦,异步消息,流量削峰等问题,实现高性能,高可用,可伸缩和最终一致性的系统架构。目前使用较多的消息队列有ActiveMQ,RabbitMQ,ZeroMQ,Kafka,MetaMQ,RocketMQ等。

Untitled.png

应用场景

消息队列主要用于在分布式系统中存储转发消息,下面主要介绍消息队列在实际应用中常见的使用场景,包括异步处理,应用解耦,流量削峰和日志处理等。

异步处理

异步处理是将一些非核心的业务流程以异步并行的方式执行,从而减少请求响应时间,提高系统吞吐量。以下单为例,用户下单后需要生成订单记录、修改库存记录、通知商家等一系列业务处理。假设三个业务节点的处理时延如下图所示,不考虑网络等其他开销,并行的时间明显小于串行的时间。这样就大大提高了系统的吞吐量。

Untitled 1.png

应用解耦

应用解耦是解除应用系统之间的耦合依赖。通过消息队列,使得每个应用系统不必受其他系统影响,可以更独立自主。

Untitled 2.png

流量削峰

这种场景中系统的峰值流量往往集中于一小段时间内,所以为了防止系统被短时间内的峰值流量冲垮,往往采用消息队列来削弱峰值流量,相当于消息队列做了一次缓冲,

Untitled 3.png

日志处理

日志处理也是消息队列一个常见的使用场景,解决大量日志传输的问题。

Untitled 4.png

设计架构

MQ 的整体架构一般涉及三类角色,分别是 Producer 消息生产者,Broker 消息处理中心,Consumer 消息消费者,如下图所示。

Untitled 5.png

Producer 消息生产者:负责产生和发送消息到 Broker;

Broker 消息处理中心:负责消息存储、确认、重试等,一般其中会包含多个队列;

Consumer 消息消费者:负责从 Broker 中获取消息,并进行相应处理;

消息传递模式

消息队列一般有为两种消息传递模式:点对点模式或者发布/订阅模式。

点对点模式:消息生产者将消息发送到队列中,消息消费者从队列中接收消息。消息可以在队列中进行异步传输。它的特点在于:

  • 每个消息只用一个消费者,即一旦被消费,消息就不再在消息队列中;
  • 生产者和消费者之间在时间上没有依赖关系;
  • 消费者在成功接收消息后需向队列应答成功;

发布/订阅模式:发布订阅模式是通过一个内容节点来发布和订阅消息,这个内容节点称为主题(topic),消息发布者将消息发布到某个主题,消息订阅者订阅这个主题的消息,主题相当于一个中介。主题是的消息的发布与订阅相互独立,不需要进行基础即可保证消息的传递,发布/订阅模式在消息的一对多广播是采用。消息生产者(发布)将消息发布到topic中,同时有多个消息消费者(订阅)消费该消息。和点对点方式不同,发布到topic的消息会被所有订阅者消费。

消息队列产品选型

Kafka

Kafka 是 Apache下的一个子项目,使用scala实现的一个高性能分布式Publish/Subscribe消息队列系统,基本架构如下图所示

Untitled 6.png

Kafka 具有以下特性:

  • 快速持久化:通过磁盘顺序读写与零拷贝机制,可以在O(1)的系统开销下进行消息持久化;
  • 高吞吐:在一台普通的服务器上既可以达到10W/s的吞吐速率;
  • 高堆积:支持topic下消费者较长时间离线,消息堆积量大;
  • 完全的分布式系统:Broker、Producer、Consumer都原生自动支持分布式,依赖zookeeper自动实现复杂均衡;
  • 支持Hadoop数据并行加载:对于像Hadoop的一样的日志数据和离线分析系统,但又要求实时处理的限制,这是一个可行的解决方案。

它的优点在于:

  1. 客户端语言丰富:支持Java、.Net、PHP、Ruby、Python、Go等多种语言;
  2. 高性能:单机写入TPS约在100万条/秒,消息大小10个字节;
  3. 提供完全分布式架构,并有replica机制,拥有较高的可用性和可靠性,理论上支持消息无限堆积;
  4. 支持批量操作;
  5. 消费者采用Pull方式获取消息。消息有序,通过控制能够保证所有消息被消费且仅被消费一次;
  6. 有优秀的第三方KafkaWeb管理界面Kafka-Manager;
  7. 在日志领域比较成熟,被多家公司和多个开源项目使用。

但也存在一些明显的缺点:

  1. Kafka单机超过64个队列/分区时,Load时会发生明显的飙高现象。队列越多,负载越高,发送消息响应时间变长;
  2. 使用短轮询方式,实时性取决于轮询间隔时间;
  3. 消费失败不支持重试;
  4. 支持消息顺序,但是一台代理宕机后,就会产生消息乱序;
  5. 社区更新较慢。

RocketMQ

RocketMQ 是阿里系下开源的一款分布式、队列模型的消息中间件,原名Metaq,3.0版本名称改为RocketMQ,是阿里参照kafka设计思想使用java实现的一套mq。同时将阿里系内部多款mq产品(Notify、metaq)进行整合,只维护核心功能,去除了所有其他运行时依赖,保证核心功能最简化,在此基础上配合阿里上述其他开源产品实现不同场景下mq的架构,目前主要多用于订单交易系统。

Untitled 7.png

RocketMQ 的特点包括:能够保证严格的消息顺序、提供针对消息的过滤功能、提供丰富的消息拉取模式、高效的订阅者水平扩展能力、实时的消息订阅机制、亿级消息堆积能力。

它的优点在于:

  1. 单机支持1万以上持久化队列;
  2. RocketMQ的所有消息都是持久化的,先写入系统PAGECACHE,然后刷盘,可以保证内存与磁盘都有一份数据,而访问时,直接从内存读取。
  3. 模型简单,接口易用(JMS的接口很多场合并不太实用);
  4. 性能非常好,可以允许大量堆积消息在Broker中;
  5. 支持多种消费模式,包括集群消费、广播消费等;
  6. 各个环节分布式扩展设计,支持主从和高可用;
  7. 开发度较活跃,版本更新很快。

缺点在于:

  1. 支持的 客户端语言不多,目前是Java及C++,其中C++还不成熟;
  2. RocketMQ社区关注度及成熟度也不及rabbitMQ等;
  3. 没有Web管理界面,提供了一个 CLI (命令行界面) 管理工具带来查询、管理和诊断各种问题;
  4. 没有在MQ核心里实现JMS等接口;

参考资料:

史上最强消息队列MQ万字图文总结! - mikechen的互联网架构