马蜂窝消息总线于 2017 年 11 月份上线,截至目前,已经被电商、酒店、大交通、社区等多个技术团队投入到生产环境的使用中。
近一年时间里,消息总线经历过几次比较重要的功能迭代,承担了 PHP 在线服务异步、削峰、解耦的大部分任务。
这篇文章的目的主要是和大家交流下马蜂窝消息总线的设计原因、实现原理以及未来规划,希望能和有潜在需求的研发同学一起探讨。
在消息总线上线前,马蜂窝大部分业务中的异步需求是通过 Redis 队列来实现。随着消息量增加,经常会出现消息积压、不同消息之间互相影响的问题。为解决这些问题,电商研发团队开始规划和设计消息总线。
为什么会有消息总线,而不是让业务系统直接用 PHP 或者其他语言对接 RabbitMQ,Kafka 这样的消息系统?
「消息总线和直接使用消息系列有什么实际的区别?」,这是很多研发同学一开始不太理解的地方。假如只是为了用一个性能更好的消息系统代替 Redis,确实并不需要消息总线的这个角色。
但当我们从实际业务角度出发,对公司整体技术架构和开发场景的梳理时,发现如果直接让业务系统对接消息系统,并不是一个很好的方式,并且至少会面临以下问题:
总体来说,直接使用消息系统可以被看成是一个面向技术的接入方式;而消息总线则期望通过隐藏部署、分组和通信等细节,实现一个面向业务的接入方式。
消息总线隐藏了消息发送、路由、分组、存储、消费负载、通信、高可用等一些列问题。对使用者来说,只需要在发送端调用一个 SDK 消息发送方法,在消费端提供一个 PHP 消费方法即可。
图1 马蜂窝消息总线架构设计
马蜂窝消息总线当前使用 RabbitMQ 作为消息引擎,在发送端提供了 SDK,作为消息总线的 Broker 角色,包含了消息路由分组的功能,负责消息的 Publish。
消息的订阅关系,目前是持久化在 MySQL 中,在消息发送时会根据订阅关系把消息投递到对应的业务消费者。
而在消费端,并没有直接用 PHP 去接入 RabbitMQ,而是使用 Deliver 服务集群 (Golang 服务) 来负责把 AMQP 协议转为 HTTP 协议,然后通过 PHPService 进行消费 PHP 代码的执行。
这个方案在设计时,同时考虑到了未来系统规模扩展后的消息分组,以及关键环节的可替代性。
SDK 充当了消息服务 Broker 的角色,可以控制消息的路由、分组。未来在微服务体系中可以保持整体架构不变,只采用其他方案实现 Broker。
可以根据业务场景对接不同的消息引擎,比如对业务一致性要求高的业务使用 RabbitMQ,而对并发要求较高的可以使用 Kafka。对业务来说是无感知的。
Deliver 和 Application Service 之间可扩展更多的通信协议,支持应用更灵活的消费方式,包括支持未来在微服务中的消费服务。
为了保证消息在消息总线内各环节流转时减少复杂度,能够被统一处理,消息体被设计为统一的结构。主要分为以下 3 个部分:
图2 消息体的定义
点对点模式是业务中常用的一种异步模式,
图3 点对点消息模式
业务应用把不需要在同步请求中执行的逻辑放到异步去执行。发送消息的业务需要明确处理消息的接收者 (消费的 PHP 方法)。消息在发送时需要明确指定唯一的一个 Receiver。
当前通过消息总线 SDK 提供的 invoke 方法可以指定消费的应用方法。
图4 发布订阅(广播)
App 1 的应用只负责发出消息,至于什么业务需要关注,下游业务应用自己订阅该消息就可以。很大程度上减少了上游业务和下游业务的耦合程度和开发调试成本。
消息总线使用 DB 来进行消息订阅关系的存储,上游业务的消息经过消息总线 Broker 时会根据订阅关系,裂变为 Receiver 是订阅应用的多条消息。这样的消息裂变方式使消息后续在消息总线流转时目标明确,在进行消费负载,消费确认,失败重试等场景时可以按照 Receiver 进行隔离。
同样调用方可以使用 SDK 提供的 pub 方法进行消息的发送,订阅方通过消息管理系统进行消息订阅的申请。
很多使用消息总线的同学比较关心不同消息之间是否会相互干扰,比如由于某个消息短时间内大量涌入是否会造成其他消息被阻塞。
通过前面架构的介绍,可以看到所有的消息经过 Broker 时可以进行路由、分组。消息总线未来会根据业务和消息量来做一些物理隔离,保障业务之间不会相互影响。
而在一个分组内,消息总线也有一些机制保障分组内的不同消息不会相互影响。
图5 防消息干扰机制
消息经过 Broker 默认会进入一个 Online Queue 的队列中,Deliver 集群中会有多个 Deliver 监听 Online Queue。在 Deliver 服务内,通过 Dispatcher 来控制消息总并发消费量,以及同类型消息的并发消费量。当某种类型的并发消息数量超过阈值时,就会被转发到 Offline Queue,避免消费 Worker 都被同一个类型的消息占用。而 Offline Queue 会被独立的 Deliver 服务监听进行消费,不影响 Online Queue 的消费。
为了保证消费时的高可用,Deliever 群在负责进行消费协议转换之外,也做了一些策略来保证消费端的高可用。
◆ 熔断
在消息一段时间内失败数量超过阈值时,停止对队列的消费,避免由于服务抖动和线上故障引起的大面积消息。
◆ 消费失败
熔断后,Deliver 服务会对后端应用服务健康度进行监控,在服务恢复后可自动恢复消费。
◆ 系统失败重试
消息总线服务发生故障时,可对期间的失败消息采用重试策略进行重试,避免由于基础服务问题造成的消费失败。
◆ 业务失败重试
在业务应用消费时产生业务异常,可在订阅消息时指定是否进行重试。消息总线会对需要失败的消息按照一定的时间周期进行多次重试。
◆ Graceful 重启
Deliver 实现了 Graceful 重启和退出,保障当前正在消费的消息都处理完成后才会进程退出。
图7 未来演进方向
当前消息总线在功能上经过近一年的迭代,已经基本稳定。但在消息管理,监控,统计等环节对开发者来说还不够友好,接下来一段时间会着重优化系统的易用性。
目前已经在规划以下方向的优化改进:
开发者可以通过消息管理系统进行新增消息,订阅消息 (加入权限的审核) 等操作,代替当前手工提 issue 的方式。
开发者可以通过系统关注到自己消息的消费情况,并及时接收到消息处理异常的报警。
完善监控体系,提供更精细维度的系统监控数据。
关于在微服务架构内提供消息总线服务,也已经在计划当中。包括在微服务内进行消息发送和使用某个微服务进行消息的消费。未来整个消息总线计划会往下图的架构进行演进,增加对多语言和不同架构服务的支持。适应更多的业务开发场景,提供更稳定,友好的消息总线服务。
另外对消息引擎的技术选型,未来也会考虑接入 Kafka,RocketMQ 等其他消息队列服务。根据不同业务场景的消息特性,在发布时选择进入不同的消息队列服务。比如对可靠性,数据安全性要求高的消息会进入 RabbitMQ,而对高吞吐量的消息可以进入 Kafka。但对消息的发送方和订阅方来说都可以不用关心这些细节,仍然按照统一的方式进行接入。
马蜂窝消息总线服务当前也在不断迭代中,在很多地方还有不少没有考虑到的问题。欢迎大家多提宝贵意见,您可以扫描下方二维码订阅「马蜂窝技术」更多内容。
本文作者:梁亮,马蜂窝电商研发团队技术专家。
微信关注“马蜂窝技术”公众号,阅读更多技术干货。
Original url: Access
Created at: 2019-03-04 08:42:54
Category: default
Tags: none
未标明原创文章均为采集,版权归作者所有,转载无需和我联系,请注明原出处,南摩阿彌陀佛,知识,不只知道,要得到
java windows火焰图_mob64ca12ec8020的技术博客_51CTO博客 - 在windows下不可行,不知道作者是怎样搞的 监听SpringBoot 服务启动成功事件并打印信息_监听springboot启动完毕-CSDN博客 SpringBoot中就绪探针和存活探针_management.endpoint.health.probes.enabled-CSDN博客 u2u转换板 - 嘉立创EDA开源硬件平台 Spring Boot 项目的轻量级 HTTP 客户端 retrofit 框架,快来试试它!_Java精选-CSDN博客 手把手教你打造一套最牛的知识笔记管理系统! - 知乎 - 想法有重合-理论可参考 安宇雨 闲鱼 机械键盘 客制化 开贴记录 文本 linux 使用find命令查找包含某字符串的文件_beijihukk的博客-CSDN博客_find 查找字符串 ---- mac 也适用 安宇雨 打字音 记录集合 B站 bilibili 自行搭建 开坑 真正的客制化 安宇雨 黑苹果开坑 查找工具包maven pom 引用地 工具网站 Dantelis 介绍的玩轴入坑攻略 --- 关于轴的一些说法 --- 非官方 ---- 心得而已 --- 长期开坑更新 [本人问题][新开坑位]关于自动化测试的工具与平台应用 机械键盘 开团 网站记录 -- 能做一个收集的程序就好了 不过现在没时间 -- 信息大多是在群里发的 - 你要让垃圾佬 都去一个地方看难度也是很大的 精神支柱 [超级前台]sprinbboot maven superdesk-app 记录 [信息有用] [环境准备] [基本完成] [sebp/elk] 给已创建的Docker容器增加新的端口映射 - qq_30599553的博客 - CSDN博客 [正在研究] Elasticsearch, Logstash, Kibana (ELK) Docker image documentation elasticsearch centos 安装记录 及 启动手记 正式服务器 39 elasticsearch 问题合集 不断更新 6.1.1 | 6.5.1 两个版本 博客程序 - 测试 - bug记录 等等问题 laravel的启动过程解析 - lpfuture - 博客园 OAuth2 Server PHP 用 Laravel 搭建带 OAuth2 验证的 RESTful 服务 | Laravel China 社区 - 高品质的 Laravel 和 PHP 开发者社区 利用Laravel 搭建oauth2 API接口 附 Unauthenticated 解决办法 - 煮茶的博客 - SegmentFault 思否 使用 OAuth2-Server-php 搭建 OAuth2 Server - 午时的海 - 博客园 基于PHP构建OAuth 2.0 服务端 认证平台 - Endv - 博客园 Laravel 的 Artisan 命令行工具 Laravel 的文件系统和云存储功能集成 浅谈Chromium中的设计模式--终--Observer模式 浅谈Chromium中的设计模式--二--pre/post和Delegate模式 浅谈Chromium中的设计模式--一--Chromium中模块分层和进程模型 DeepMind 4 Hacking Yourself README.md update 20211011
Laravel China 简书 知乎 博客园 CSDN博客 开源中国 Go Further Ryan是菜鸟 | LNMP技术栈笔记 云栖社区-阿里云 Netflix技术博客 Techie Delight Linkedin技术博客 Dropbox技术博客 Facebook技术博客 淘宝中间件团队 美团技术博客 360技术博客 古巷博客 - 一个专注于分享的不正常博客 软件测试知识传播 - 测试窝 有赞技术团队 阮一峰 语雀 静觅丨崔庆才的个人博客 软件测试从业者综合能力提升 - isTester IBM Java 开发 使用开放 Java 生态系统开发现代应用程序 pengdai 一个强大的博主 HTML5资源教程 | 分享HTML5开发资源和开发教程 蘑菇博客 - 专注于技术分享的博客平台 个人博客-leapMie 流星007 CSDN博客 - 舍其小伙伴 稀土掘金 Go 技术论坛 | Golang / Go 语言中国知识社区
最新评论