作者: 周新宇&陈涛&李凯
阿里云 RocketMQ 轻量版(MNS)消息队列是一个轻量、可靠、可扩展且完全托管的分布式消息队列服务。MNS 能够帮助应用开发者在他们应用的分布式组件上更轻量的传递数据、通知消息,构建松耦合系统。无需管理开销,而且模型简单,拆箱即用,自动横向扩容,无需管理分区等复杂的逻辑运维,是一款 Serverless 消息队列产品。
MNS 重点聚焦在基准消息队列的核心能力建设,MNS 经过多年迭代与打磨,尽管内部极为复杂,但一直努力保持其在客户端的简单易用,围绕轻量和集成两个命题,着力建设更易用的消息队列产品。
核心优势
MNS 围绕轻量消息队列,提供一系列的轻量级能力。为企业和开发者降低消息产品的复杂度,减少运维开销,提供更易上手的消息队列服务。
轻量模型
MNS 提供 1:1 和 1:N 两种轻量模型,可根据场景自行选择需要的模型方式,学习成本低,上手快。无需理解复杂的概念模型,无需刻意学习,几分钟即可快速上手。
MNS 模型轻量主要体现在资源的操作方面,创建和删除等都配置有极简的 API,同时与数据链路的 API 属于同一个 SDK,方便用户像收发消息那样进行资源的创建。相反,很多云产品资源的 API 都采用了新的管控 SDK,使用门槛较高。
此外,MNS 的模型和资源是一一对应的,比如使用队列模型仅需要创建一个 Queue,非常易于上手和使用,而其他一些同类型产品,对于同一个模型会有实例、主题、队列、分区等多个资源。
轻量协议
采用 HTTP RESTful 标准协议,接入方便,跨网络能力强,天然拥有支持多语言访问的能力。官方 SDK 覆盖各大主流语言,包括 C++,C#,.Net,Python,PHP 和 Java,社区贡献也有用 Go,Node 等 。
同时访问协议简单通用,即使不想依赖云产品提供 SDK ,也可以很容易通过简单的编码来访问 API,接入成本低,开发效率高。
轻量计费
MNS 是 Serverless 轻量计费,相较于按照实例付费,MNS 提供更加轻量的 Serverless 计费方式。按照请求量和资源占用情况付费,用多少付多少,无需为额外预留资源买单;同时提供每个月拥有 2000 万次 API 免费调用额度。这种完全后付费的定价方式可以为企业节约大量闲置资源。
轻量运维
MNS 可以根据应用情况进行弹性扩展,因此,无需担心容量规划和预配置。每个队列的消息数量不限,而且标准队列能提供几乎无限的吞吐量(QPS 范围内);提供 Serverless 化弹性服务,高效快捷,无需对资源做预留,随取随用,实时扩缩;更适合产品集成与瞬时队列场景。
同时 MNS 提供完善的消息监控消息告警等能力,支持高可靠性和高稳定性,消除管理和运维时的复杂性和研发开销。
基本模型
MNS 是一个融合了点对点(P2P)和发布订阅(Pub/Sub)两种消费模型的消费系统,其中 MNS 的「队列」是 P2P 消费模型的实现,「主题」是 Pub/Sub 消费模型的实现。
MNS 也是业界鲜有的同时提供两种混合消费模型的云产品,用户可以通过「队列」或者「主题」来实现大部分对消息系统的需求。
队列(P2P 模型)
队列模型提供高可靠、高并发的一对一消费模型,即队列中的每一条消息都只能够被某一个消费者消费。队列就像一家旋转寿司店。寿司店中有多个寿司师傅(生产者)在制作精美的寿司,每一份寿司都是独特的,顾客(消费者)可以从传送带上拿取中意的寿司进行食用(消费)。
队列是 MNS 的顶级资源,也是消息的存储实体,有完整的阿里云资源的生命周期,以及完善的权限控制机制。围绕队列有三个核心概念:
- 生产者(Producer):生产者负责将消息发送到指定的队列上,一个队列接受分布式的生产者并发投递消息。
- 队列(Queue):队列模型对应的物理资源,也是消息的存储实体,MNS 通过一个分布式的存储集群来提供队列的分布式存储能力。
- 消费者(Consumer):消费者负责从指定的队列通过轮询的机制获取消息,一个队列接受分布式的消费者并发地消费消息,同时保证同一条消息在可见时间内只会被一个消费者消费。
主题(Pub/Sub 模型)
主题模型提供一对多的发布订阅模型,支持消息通知。主题就像一份报纸,多个读者到邮局订阅了这份报纸。当报纸推出最新一期时,读者(包括邮局的合作伙伴)可以选择以下方式来获取:
- 让邮局投递员将报纸都投递(推送)到家里(特定的地址)。
- 去就近的报刊亭(订阅点)自行获取报纸(报纸会先被邮局投递员集中送到各个报刊亭)。
主题是 MNS 的另一个顶级资源,其也具备消息的存储能力,对应的 Topic 资源具备完整的阿里云资源的生命周期,以及完善的权限控制机制。围绕主题也有三个核心概念:
- 生产者(Producer):生产者除了可以把消息发送至队列,也可以把消息发送到主题上,主题也接受分布式的生产者并发投递消息。
- 主题(Topic):主题模型对应的物理资源同样具备消息的存储能力。
- 订阅(Subscription):可以为每个主题创建多个订阅,每个订阅将收到 Topic 上的完整消息,订阅的下游可以是多种类型的订阅者,用户往往通过订阅的能力将主题中的消息扇出至多个队列。
功能特性
MNS 作为一款成熟的消息产品,面向主题和队列提供了多种功能特性,能够深入到应用的架构当中,帮助用户降低业务流程开发的复杂度,让业务专注于业务逻辑的开发。比如多种消息类型的支持,方便用户快速实现定时、优先级相关的业务逻辑。
多种消息类型的支持
MNS 队列支持普通消息、延迟消息、优先消息这 3 种消息类型。
普通消息是最基础的消息类型,当一条普通消息发送到了 MNS 之后,这一条消息就会在队列中等待用户的拉取进行消息的消费。
对于延迟消息,用户可以在发送的时候指定期望这条消息的延迟时间,当到了设定的延迟时间后,那么就可以消费到这条消息。同时,在发送了延迟消息之后,除了可以获取到消息的一些基本属性之外,还可以获取到一个消息句柄,当期望提前取消掉这条延迟消息的时候,我们可以使用这个消息句柄进行 Delete。Delete 过后,这条消息就不会再投递出来。通过延迟消息,用户可以轻松的实现一个分布式的延迟调度系统,在拥有高精度延迟的同时,实现超高的可扩展性和可用性。
对于优先消息,我们在发送消息的时候可以指定消息的优先级,优先级的取值范围为 1 到 16。优先级的取值越小,那么这条消息的优先级就越高。需要注意的是,优先消息并不保证消息的顺序性,优先级越高的消息拥有更容易被消费的可能性,并不意味着优先级低的消息一定会在优先级高的消息消费完成之后才能够被消费。
高效的长轮训机制
对于 消息队列 MNS 来说 ,用户需要主动进行消息的拉取,如果拉取的频率过低,那么就会导致消息的延迟;相对应的,如果拉取的频率过高,那么又会带来过多无效的API调用。
为解决这个问题,MNS 队列提供了长轮训的机制,可以在一定程度上减少无效 API 的调用,同时保证消息的及时性。当用户拉取消息的时候,可以设置这次请求拉取消息的 waitseconds,客户端则会以设置的时间挂一个长轮训请求到服务端。如果在长轮训期间发现有消息可以被消费,就会立即返回;如果没有,就会最多等待长轮训时间结束之后返回。但需要注意的是,虽然我们可以使用长轮训来减少无效的 API 调用,但整体上还是需要一定的消息拉取的并发度,以保证消息的及时性。
灵活的消息生命周期管理
对于队列中的一条消息,其会具有可见、不可见、删除这 3 种状态。当消息发送到队列中后,这条消息就处于可见的状态,等待消费者来拉取。当消息被消费者拉取出来之后,消息会进入一段“不可见时间”,在这段“不可见时间”里面,这条消息是不会被再次的拉取出来。但如果在“不可见时间”里面这条消息没有被删除,那么这一条消息就会再次的可见,并可以被消费者再一次的从队列中拉取出来。
除此之外,当有消费者消费到消息,在处理的过程中突然出现问题,例如宕机,那么这一条消息则会在“不可见时间”结束之后再一次的可见,可以被其他的消费者再次消费到。
这里可能就存在一个矛盾点,用户可能期望有消费者宕机之后,没有被正确处理的消息能够尽快的由其他消费者消费下去,但又由于本身的业务处理时间可能有时候较长,可能会超过队列上所配置的默认的“不可见时间”,导致消息的重复消费。那么,为解决这种场景,MNS 也为用户提供了可以在消息维度修改某一条消息的“不可见时间”功能。
当用户收到了一条消息,发现这条消息处理的时间较长会超过队列所配置的“不可见时间”的时候,用户可以通过消息的句柄主动调用,修改这一条消息的不可见时间。例如上图,将这一条消息的不可见时间进行了延长,留给了业务更多的处理时间。当然,同之前的消息消费一样,当这条消息处理完成之后,也需要调用删除消息的接口,进行消息消费成功的确认。
消息多订阅推送
MNS 主题提供了一对多广播消息的能力,我们可以为一个主题创建多个订阅,路由到不同的 Endpoint。用户只需要将消息发送到主题,就可以将这个一条消息推送到多个订阅中去。
其次,在一对多广播消息的能力的基础上,在订阅中,MNS 还支持订阅带有特定标签的消息。我们在创建订阅的时候可以指定这个订阅所关心的消息的 Tag,这样当 MNS 进行消息推送的时候,就会自动进行消息的过滤,仅将这个订阅所关心的 Tag 推送出去。
为了保证消息投递的可靠性,用户可以对每个订阅配置推送策略,可以指定使用退避重试策略或者指数衰减重试的策略。
对于退避重试策略,当消息推送失败的时候,会重试 3 次,每一次的重试间隔时间为 10 到 20 秒的随机值。对于指数衰减重试,整体的重试时间为 1 天,每次的重试时间间隔是指数递增的(1 秒,2 秒,4 秒,8 秒,...)。
最后,我们还可以配置推送的消息的格式,我们可以在创建订阅的时候,指定推送格式为 XML、JSON 或者 SIMPLIFIED。对于 XML 和 JSON,推送给订阅的消息内容,除了会包含发送到主题的消息之外,还会添加例如 MessageID、TopicName、SubscriptionName 等属性。而对于 SIMPLIFIED,则是直接将发送到主题的消息进行转发,不会添加额外的属性。
接入协议
MNS 以 HTTP 协议对外提供服务,包含近 30 个 RESTful 的 API,但核心业务场景往往使用 3 个左右的 API 就可以完成研发,非常易于上手。
另外,用户既可以直接根据 API 进行自行的封装,也可以直接使用官方所提供的的 SDK 进行集成。用户仅只需要依赖一个 SDK 就可以完成从服务的开通、资源的创建、再到消息的收发。
在多语言 SDK 方面,MNS 提供了 8 种主流语言的 SDK,包括 Java、Python、C#、Node、PHP、C++、Go 等,同时也支持采用 Java 领域标准的 JMS SDK 接入 MNS。
适用场景解析
相较于 RabbitMQ,ActiveMQ,Kafka 等开源消息队列,RocketMQ 轻量版 MNS 摒弃了非常复杂的概念模型及臃肿繁多的协议,通过简单模型,通用的 HTTP RESTful 标准协议即可高效完成消息领域的典型场景。提供完全免运维的消息集成方案,显著降低开发和维护成本,提升新业务开发效率。
消息广播(Fanout)场景解析
- 背景信息
轻量消息队列 MNS 提供队列(Queue)和主题(Topic)两种模型,基本能满足大多数应用场景。队列提供的是一对一的共享消息消费模型,采用客户端主动拉取(Pull)模式。
主题模型提供一对多的广播消息消费模型,采用服务端主动推送(Push)模式。
推送模式的好处是即时性能较好,但需暴露客户端地址来接收服务端的消息推送。有些情况下有的信息,例如企业内网,无法暴露推送地址,希望改用拉取(Pull)的方式。虽然消息服务 MNS 不直接提供这种消费模型,但可以结合主题和队列来实现一对多的拉取消息消费模型。
- 解决方案
通过创建订阅,让主题将消息先推送到队列,然后由消费者从队列拉取消息。这样既可以做到一对多的广播消息,又可避免暴露消费者的地址。
超大消息传输(Claim Check)场景解析
- 背景信息
消息服务 MNS 的队列的消息大小最大限制是 64 KB,这个限制基本能够满足在正常情况下消息作为控制流信息交换通道的需求。但是,在某些特殊场景下,消息数据比较大时,就只能采用消息切片的方式。
下面是不做消息切片,通过 OSS 来实现传递大于 64 KB 的消息的解决方案。
- 解决方案
生产者在向消息服务 MNS 发送消息前,如果发现消息体大于 64 KB,则先将消息体数据上传到 OSS。
生产者把数据对应的 Object 信息发送到消息服务 MNS。
消费者从消息服务 MNS 队列里读取消息,判断消息内容是否为 OSS 的 Object 信息。
判断消息内容是 OSS 的 Object 信息,则从 OSS 下载对应的 Object 内容,并作为消息体返回给上层程序。
简单事务消息场景解析
背景信息:一些业务场景需要保证本地操作和消息发送的事务一致性,即消息发送成功,本地操作成功。如果消息发送成功,本地操作失败,那么发送成功的消息需要回滚。操作流程如图所示:
- 解决方案
消息发送成功,事务操作成功时操作步骤如下所示:
- 生产者发送一条事务准备消息到事务消息队列;
- 生产者发送操作日志消息到操作日志队列,日志中包含步骤1消息的消息句柄;
- 生产者执行本地事务操作成功;
- 生产者请求修改消息延迟时间,使消息对消费者可见;
- 生产者向操作日志队列确认操作日志,删除日志消息;
- 消费者从事务消息队列中接收事务消息;
- 消费者处理事务消息;
- 消费者请求删除事务消息。
消息过滤(Message Filter) 场景解析
- 背景信息
一些场景中需要根据消息内容把消息推送到不同的推送目标,为了达到这一功能,您可以创建多个主题,并为每个主题设置相应的推送目标,但是这样会增加额外的成本,并且增加了运维的复杂度。为了避免这种情况,消息队列 MNS 提供了消息过滤标签功能。您可以只创建一个主题,并在创建订阅时设置不同的消息过滤标签,结合消息的消息过滤标签,MNS 就可以把消息推送到不同的推送目标中。
- 解决方案
图示例场景中,在主题 Topic 1 创建 3 个消息过滤标签不同的订阅,Subscription 1、Subscription 2 和 Subscription 3。这 3 个订阅的推送目标分别是 Queue 1、Queue 2 和 Queue 3。
- 消息的消息过滤标签和订阅的消息过滤标签一致。消息过滤过程如下:
消息服务 MNS 将 Message 1 推送到队列 Queue 1;
消息服务 MNS 将 Message 2 推送到队列 Queue 2。
- 订阅没有消息过滤标签。消息过滤过程如下:
消息服务 MNS 将 Message 1推送到队列 Queue 3;
消息服务 MNS 将 Message 2 推送到队列 Queue 3;
消息服务 MNS 将 Message 3 推送到队列 Queue 3。
客户案例及最佳实践
在线交易 - 应用解耦 - 削峰填谷(典型场景 )
- 场景描述
淘宝/天猫主站最为核心的系统是交易系统,每一笔交易订单数据都会有几百个下游业务系统的关联,包括物流、购物车、积分、直充、阿里妈妈、流计算分析等,整个系统庞大而且复杂,架构设计稍有不合理,将直接影响主站业务的连续性。
- 异步解耦
如此复杂且庞大的系统,若上、下游业务系统紧耦合,那么任意一个子系统不可用都将直接导致核心交易系统不可用;
通过消息队列实现上、下游业务系统松耦合,那么,即便下游子系统(如物流系统)出现不可用,也不会影响到核心交易系统的正常运转;
- 削峰填谷
通过消息队列不仅可以起到系统间解耦的作用,更能在大促、秒杀等大型活动中起到削峰填谷的作用。
每年天猫双11凌晨,保证核心交易系统的业务处理能力始终为重中之重,每秒数十万笔的交易订单处理能力,且逐年线性增长;然而相对的,各大物流系统、银行的支付系统的业务处理能力却有限,若不能进行流量缓冲将直接引发这些系统的崩溃。因此,利用消息队列强大的消息堆积能力则可以很好的起到削峰填谷的作用,将系统压力全部转移到消息队列,从而释放物流、支付等系统的压力,保证业务的正常运转。
直播录制 - 合流 - 转码(Serverless 场景 )
场景描述:视频的直播录制,合流,转码是在线教育和在线直播领域的刚需场景,通过 MNS 可以对 FC Serverless 资源进行在线调度,帮助客户实现异步直播流录制,合流转码等复杂场景。
在线游戏场景
- 场景描述
游戏场景存在大量强交互场景的数据流转,对消息中间件的稳定性和端到端延迟要求极高,自建消息中间件压力大、不稳定。游戏场景存在大量的指令传输以及定时任务,自建逻辑无法解决热点问题。
通过 MNS 可以实现从游戏网关指令到后台消息协议的转换,同时 MNS 也支持后台逻辑服、工会、战斗服之间的异步解耦拆分。
总结
MNS 围绕轻量消息队列,提供一系列的轻量级能力。为企业和开发者降低消息产品的复杂度,减少运维开销,提供更易上手的消息队列服务。
作为阿里云 RocketMQ 的轻量版,填补了 RocketMQ 在轻量化和易用性的不足。尽管 MNS 版本伴随 RocketMQ 经过多年迭代与打磨,内部极为复杂,但一直努力保持其在客户端的简单易用。为企业和开发者降低消息产品的复杂度,减少运维开销提供更易上手的消息队列服务,是 MNS 的产品使命和愿景。
MNS 产品训练营活动火热报名中
为了帮助大家由浅入深的对阿里云消息队列 MNS 有更加全面的了解,同时期望消息队列 MNS 能够帮助大家解决日常工作和生产的问题,特推出消息队列 MNS 产品训练营课程,课程中不仅有对产品简单形象的介绍,还有“首秀”的动手实践学习课程。
参与本次消息队列 MNS 训练营,您可以学习并收获到:
- 消息队列 MNS 的基础概念及特性
- 消息队列 MNS 的最佳实践及案例
- 基于 MNS,0 基础轻松构建 Web Client
除了学习层面的收获,活动期间,完成所有参营任务且考试通过的前 20 名同学可获得(若成绩相同按考试时间顺序排名),即可免费获得小米充电宝。活动时间:8 月 10 日 - 8 月 31 日(工作日期间)。
点击此处,立即报名吧~