2021年6月23日

博时基金基于 RocketMQ 的互联网开放平台 Matrix 架构实践
作者|伍振河 博时基金互联网金融部架构师 、曾志 博时基金互联网金融部开发主管 随着近两年业绩的抢眼,公募基金迎来了乘风破浪式的发展,截至 2021 年 1 月底,资产管理规模已破 20 万亿,创下了历史新高。 在中国新经济高质量及科技创新发展的背景下,众多金融类的互联网平台与基金公司展开合作。互联网金融科技与传统金融业务的融合,促使传统金融公司的信息技术系统更加开放。 据此,2020 年,博时基金互联网金融部启动了互联网开放平台 Matrix 的建设工作。 博时基金互联网开放平台 Matrix 建设背景与目标 1、传统金融架构遇到的问题与挑战 传统的金融系统架构受到了互联网化的挑战,主要表现在以下几个方面: 1) 互联网入口缺乏管控 有多个团队提供不同形式的互联网服务,接口协议和权限管控方式不一致。当服务和接口越来越多时,API 管控能力不足的问题将会突显。 2) 系统较为封闭,开放能力不足 传统基金行业系统生态较为封闭,与合作伙伴开放生态的能力有待提升。 3) 金融场景化封装能力不足 传统基金行业系统普遍依赖于底层数据库提供的 ACID 特性实现事务一致性。微服务化之后,这套机制对金融场景化的产品包装能力显得捉襟见肘。 2、系统建设目标 1)多渠道统一安全接入 为自有系统与运营厂商提供标准化统一接入,实现内外部 API 统一的管控。 Matrix 开放给经过博时互联网平台资质认证后的第三方平台使用,需要根据第三方平台识别的不同身份,进行接口级别权限管控。 2)提供开放能力 搭建开放平台,与合作伙伴共建开放生态。在得到 Matrix 平台的授权后,第三方平台开发者可以通过调用博时基金互联网开放平台的接口能力,为第三方平台提供基金产品信息查询、注册开户、积分兑换、基金申赎、资产查询、联合登录等全方位服务;第三方平台可以根据自身实际情况自由选择或组合 APP 、微信公众号、微信小程序、H5 等前端方式对接。 3)封装基金行业特色功能 应用层实现分布式事务框架以保证整体事务的一致性。基于此,封装优惠购、投资陪伴等复杂的金融场景化功能,让开发者专注于业务开发,提升客户的投资体验。 Matrix 建设思路 1、总体架构 1)互联网架构图 基于 Spring Cloud 微服务套件和 RocketMQ 消息中间件,搭建的企业级云原生架构。 2、关键组件 1)API 网关 API 网关是微服务架构重要组件之一,是服务唯一入口。API 网关封装内部系统架构,横向抽离通用功能,如:权限校验、熔断限流、负载均衡等。通过 API 网关可以把内部 API 统一管控起来。 目前博时基金的互联网业务接入入口主要分为 3 类: 面向自营业务的博时基金移动端 APP 和 H5 。 面向合作伙伴的 OpenAPI 。即作为开放平台的入口,服务的 OpenAPI 会提供有条件的访问限制(时间、流量、频率),需要考虑流量控制、安全认证、接口授权方面的管理。 面向企业内部管理系统的 API ,提供企业内部系统访问。 Matrix 的 API 网关基于 Spring Cloud Gateway 构建,SCG 内置的 Route、Predicate 和 Filter 模块可以方便扩展出路由转发、统一鉴权等跨横切面的功能。基于内外部网络隔离的需求,我们独立部署了两套网关,其中 Kylin 网关提供互联网接入。Phoenix 网关用于域内系统接入,提供域账户的访问权限控制。 2)认证中心 为了保护 OpenAPI 的安全,避免恶意访问、未授权访问、黑客攻击等导致的安全隐患,开放平台需要增加授权认证模块。同时,在博时的内部的应用系统之间,也有单点登录的需求。统一的认证中心是微服务架构的必备组件。 Matrix 基于 OAuth2 协议构建了统一认证中心,实现用户、应用、接口的统一认证和鉴权。OAuth2 核心思路是通过各类认证手段认证用户身份,并颁发 Token ,使得第三方应用可以使用该令牌在限定时间、限定范围访问指定资源。Matrix 支持 OAuth2 的 Authorization Code 、Resource Owner Credentials 和 Client Credentials 三种授权类型,根据不同的应用场景,采用不同的授权类型颁发 Token ,为开放平台的安全保驾护航。 3)RocketMQ 消息中间件 技术选型 在技术选型过程中,我们主要考虑以下几点: 首先必须是国产化的产品,其次是比较流行并且社区活跃度高的开源产品。 另外,重点关注的 MQ 特性: 消息可靠传递,即确保不丢消息。 分布式事务,需要支持分布式事务,降低业务的复杂性。 性能,我们的场景主要是在线的金融类业务,需要 MQ 具备支持金融级的低延迟特性。 最后,从架构演进的角度来考虑,需要无缝对接我们的混合云架构,最终我们选择了 RocketMQ。 RocketMQ 是阿里巴巴自主研发及双 11 交易核心链路消息产品,提供金融级高可靠消息服务。在开源方面,开源 RocketMQ 已经完成了云原生技术栈的集成,包括Knative 中的事件源,Prometheus 的 Exporter,K8s 的 Operator 等;也支持了微服务框架 SpringCloud 以及函数计算框架 OpenWhisk ;同时开发了很多 Connector 作为 Sink 或者 Source 去连接了 ELK、Flume、Flink、Hadoop 等大数据和数据分析领域的优秀开源产品。 在 Matrix 开放平台,RocketMQ 主要有三类应用场景。 1) 用于金融产品的场景化包装 业务场景: 典型的业务场景如优惠购,基民通过优惠购功能申购基金,可将交易费率降为0。简单来说就是先购买博时货币基金,再通过快速转购的方式买入目标基金,豁免相关转换费率。 实现原理: Matrix 基于 RocketMQ 的事务消息搭建了一个高可靠、高可用的事务消息平台事务中心,涉及业务流程如下: 第一阶段是 Prepare ,即业务系统将 RocketMQ 的半事务消息发送到事务中心,事务中心不做发布,等待二次确认。Prepare 完成之后,业务系统执行主事务,即购买货币基金,成功后 commit 到事务中心,由事务中心投递消息到从事务。如果主事务失败,就投递 rollback 给事务中心。 反查机制: 由于网络抖动、业务系统重启等原因,可能导致事务消息的二次确认丢失。此时需要依赖反查机制恢复整个分布式事务的上下文。RocketMQ 提供的 Message Status Check 机制正是为解决分布式事务中的超时问题而设计的。事务中心的反查机制流程主要是,先检查事务中心的内部状态,再通过反查接口检查本地事务的执行结果,恢复事务上下文后,正常推进后续的流程。 依赖于 RocketMQ 提供的事务消息,事务中心在应用层实现了分布式事务,大大提升了对金融产品的场景化包装能力。 2) 用于系统间解耦 业务场景: 部门 A 负责根据市场、产品和客户的陪伴场景输出优质的陪伴内容,部门 B 负责把这些陪伴内容触达到不同的渠道和用户。 实现原理: 部门 A 的陪伴事件触发服务和部门 B 的陪伴触达服务之间通过 RocketMQ 消息进行业务解耦,即双方没有依赖关系,也不必同时在线。 3) 异步调用 业务场景: 异步调用的使用场景比较多,如用户注册、用户关键行为跟踪等。其中用户行为跟踪场景,在服务端异步记录用户的关键行为及相关属性,可为用户分等级运营和精准营销打下基础。 实现原理: 将非核心的业务流程异步化可以减少系统的响应时间,提高吞吐量,是系统优化的常用手段。RocketMQ 提供了高效的通信机制,业务系统使用起来非常方便。 总结与未来展望 随着互联网技术在金融领域的不断渗透和金融创新业态的发展,公募基金互联网业务需要不断进行流程改造、模式创新及服务能力升级,在优化场景体验的基础上,持续打造基于平台、场景和产品三位一体的互联网服务平台。 Matrix 经过一年多的建设,目前已具备多渠道统一接入、第三方生态互联互通、基金特色交易场景化封装等功能特性。Matrix 通过建设有品质、有温度的陪伴,从技术上和体验上,让用户理解风险,理解投资,进而为客户持续创造价值。 在未来,将会有更多的合作伙伴接入 Matrix ,希望我们能一起畅游在创新科技的星辰大海中,合作共赢。 活动推荐 阿里云基于 Apache RocketMQ 构建的企业级产品消息队列RocketMQ 5.0版现开启活动: 1、新用户首次购买包年包月,即可享受全系列 85折优惠! 了解活动详情:
作者:伍振河、曾志
#行业实践

2021年6月16日

RocketMQ 千锤百炼--哈啰在分布式消息治理和微服务治理中的实践
背景 哈啰已进化为包括两轮出行(哈啰单车、哈啰助力车、哈啰电动车、小哈换电)、四轮出行(哈啰顺风车、全网叫车、哈啰打车)等的综合化移动出行平台,并向酒店、到店团购等众多本地生活化生态探索。 随着公司业务的不断发展,流量也在不断增长。我们发现生产中的一些重大事故,往往是被突发的流量冲跨的,对流量的治理和防护,保障系统高可用就尤为重要。 本文就哈啰在消息流量和微服务调用的治理中踩过的坑、积累的经验进行分享。 作者介绍 梁勇 ( 老梁 ) ,《 RocketMQ 实战与进阶》专栏联合作者、参与了《 RocketMQ 技术内幕》审稿工作。ArchSummit 全球架构师大会讲师、QCon 案例研习社讲师。 当前主要在后端中间件方向,在公众号【瓜农老梁】已陆续发表百余篇源码实战类文章,涵盖 RocketMQ 系列、Kafka 系列、GRPC 系列、Nacosl 系列、Sentinel 系列、Java NIO 系列。目前就职于哈啰出行,任职高级技术专家。 聊聊治理这件事 开始之前先聊聊治理这件事情,下面是老梁个人理解: 治理在干一件什么事? 让我们的环境变得美好一些 需要知道哪些地方还不够好? 以往经验 用户反馈 业内对比 还需要知道是不是一直都是好的? 监控跟踪 告警通知 不好的时候如何再让其变好? 治理措施 应急方案 目录 1. 打造分布式消息治理平台 2. RocketMQ 实战踩坑和解决 3. 打造微服务高可用治理平台 背景 裸奔的 RabbitMQ 公司之前使用 RabbitMQ ,下面在使用 RabbitMQ 时的痛点,其中很多事故由于 RabbitMQ 集群限流引起的。 积压过多是清理还是不清理?这是个问题,我再想想。 积压过多触发集群流控?那是真的影响业务了。 想消费前两天的数据?请您重发一遍吧。 要统计哪些服务接入了?您要多等等了,我得去捞IP看看。 有没有使用风险比如大消息?这个我猜猜。 裸奔的服务 曾经有这么一个故障,多个业务共用一个数据库。在一次晚高峰流量陡增,把数据库打挂了。 数据库单机升级到最高配依然无法解决 重启后缓一缓,不一会就又被打挂了 如此循环着、煎熬着、默默等待着高峰过去 思考:无论消息还是服务都需要完善的治理措施 打造分布式消息治理平台 设计指南 哪些是我们的关键指标,哪些是我们的次要指标,这是消息治理的首要问题。 设计目标 旨在屏蔽底层各个中间件( RocketMQ / Kafka )的复杂性,通过唯一标识动态路由消息。同时打造集资源管控、检索、监控、告警、巡检、容灾、可视化运维等一体化的消息治理平台,保障消息中间件平稳健康运行。 消息治理平台设计需要考虑的点 提供简单易用 API 有哪些关键点能衡量客户端的使用没有安全隐患 有哪些关键指标能衡量集群健康不健康 有哪些常用的用户/运维操作将其可视化 有哪些措施应对这些不健康 尽可能简单易用 设计指南 把复杂的问题搞简单,那是能耐。 极简统一 API 提供统一的 SDK 封装了( Kafka / RocketMQ )两种消息中间件。 一次申请 主题消费组自动创建不适合生产环境,自动创建会导致失控,不利于整个生命周期管理和集群稳定。需要对申请流程进行控制,但是应尽可能简单。例如:一次申请各个环境均生效、生成关联告警规则等。 客户端治理 设计指南 监控客户端使用是否规范,找到合适的措施治理 场景回放 场景一 瞬时流量与集群的流控 假设现在集群 Tps 有 1 万,瞬时翻到 2 万甚至更多,这种过度陡增的流量极有可能引发集群流控。针对这类场景需监控客户端的发送速度,在满足速度和陡增幅度阈值后将发送变的平缓一些。 场景二 大消息与集群抖动 当客户端发送大消息时,例如:发送几百KB甚至几兆的消息,可能造成 IO 时间过长与集群抖动。针对这类场景治理需监控发送消息的大小,我们采取通过事后巡检的方式识别出大消息的服务,推动使用同学压缩或重构,消息控制在 10KB 以内。 场景三 过低客户端版本 随着功能的迭代 SDK 的版本也会升级,变更除了功能外还有可能引入风险。当使用过低的版本时一个是功能不能得到支持,另外一个是也可能存在安全隐患。为了解 SDK 使用情况,可以采取将 SDK 版本上报,通过巡检的方式推动使用同学升级。 场景四 消费流量摘除和恢复 消费流量摘除和恢复通常有以下使用场景,第一个是发布应用时需要先摘流量,另外一个是问题定位时希望先把流量摘除掉再去排查。为了支持这种场景,需要在客户端监听摘除/恢复事件,将消费暂停和恢复。 场景五 发送/消费耗时检测 发送/消费一条消息用了多久,通过监控耗时情况,巡检摸排出性能过低的应用,针对性推动改造达到提升性能的目的。 场景六 提升排查定位效率 在排查问题时,往往需要检索发了什么消息、存在哪里、什么时候消费的等消息生命周期相关的内容。这部分可以通过 msgId 在消息内部将生命周期串联起来。另外是通过在消息头部埋入 rpcId / traceId 类似链路标识,在一次请求中将消息串起来。 治理措施提炼 需要的监控信息 发送/消费速度 发送/消费耗时 消息大小 节点信息 链路标识 版本信息 常用治理措施 定期巡检:有了埋点信息可以通过巡检将有风险的应用找出来。例如发送/消费耗时大于 800 ms、消息大小大于 10 KB、版本小于特定版本等。 发送平滑:例如检测到瞬时流量满足 1 万而且陡增了 2 倍以上,可以通过预热的方式将瞬时流量变的平滑一些。 消费限流:当第三方接口需要限流时,可以对消费的流量进行限流,这部分可以结合高可用框架实现。 消费摘除:通过监听摘除事件将消费客户端关闭和恢复。 主题/消费组治理 设计指南 监控主题消费组资源使用情况 场景回放 场景一 消费积压对业务的影响 有些业务场景对消费堆积很敏感,有些业务对积压不敏感,只要后面追上来消费掉即可。例如单车开锁是秒级的事情,而信息汇总相关的批处理场景对积压不敏感。通过采集消费积压指标,对满足阈值的应用采取实时告警的方式通知到应用负责的同学,让他们实时掌握消费情况。 场景二 消费/发送速度的影响 发送/消费速度跌零告警?有些场景速度不能跌零,如果跌零意味着业务出现异常。通过采集速度指标,对满足阈值的应用实时告警。 场景三 消费节点掉线 消费节点掉线需要通知给应用负责的同学,这类需要采集注册节点信息,当掉线时能实时触发告警通知。 场景四 发送/消费不均衡 发送/消费的不均衡往往影响其性能。记得有一次咨询时有同学将发送消息的key设置成常量,默认按照 key 进行 hash 选择分区,所有的消息进入了一个分区里,这个性能是无论如何也上不来的。另外还要检测各个分区的消费积压情况,出现过度不均衡时触发实时告警通知。 治理措施提炼 需要的监控信息 发送/消费速度 发送分区详情 消费各分区积压 消费组积压 注册节点信息 常用治理措施 实时告警:对消费积压、发送/消费速度、节点掉线、分区不均衡进行实时告警通知。 提升性能:对于有消费积压不能满足需求,可以通过增加拉取线程、消费线程、增加分区数量等措施加以提升。 自助排查:提供多维度检索工具,例如通过时间范围、msgId 检索、链路系统等多维度检索消息生命周期。 集群健康治理 设计指南 度量集群健康的核心指标有哪些? 场景回放 场景一 集群健康检测 集群健康检测回答一个问题:这个集群是不是好的。通过检测集群节点数量、集群中每个节点心跳、集群写入Tps水位、集群消费Tps水位都是在解决这个问题。 场景二 集群的稳定性 集群流控往往体现出集群性能的不足,集群抖动也会引发客户端发送超时。通过采集集群中每个节点心跳耗时情况、集群写入Tps水位的变化率来掌握集群是否稳定。 场景三 集群的高可用 高可用主要针对极端场景中导致某个可用区不可用、或者集群上某些主题和消费组异常需要有一些针对性的措施。例如:MQ 可以通过同城跨可用区主从交叉部署、动态将主题和消费组迁移到灾备集群、多活等方式进行解决。 治理措施提炼 需要的监控信息 集群节点数量采集 集群节点心跳耗时 集群写入 Tps 的水位 集群消费 Tps 的水位 集群写入 Tps 的变化率 常用治理措施 定期巡检:对集群 Tps 水位、硬件水位定期巡检。 容灾措施:同城跨可用区主从交叉部署、容灾动态迁移到灾备集群、异地多活。 集群调优:系统版本/参数、集群参数调优。 集群分类:按业务线分类、按核心/非核心服务分类。 最核心指标聚焦 如果说这些关键指标中哪一个最重要?我会选择集群中每个节点的心跳检测,即:响应时间( RT ),下面看看影响 RT 可能哪些原因。 关于告警 监控指标大多是秒级探测 触发阈值的告警推送到公司统一告警系统、实时通知 巡检的风险通知推送到公司巡检系统、每周汇总通知 消息平台图示 架构图 看板图示 多维度:集群维度、应用维度 全聚合:关键指标全聚合 RocketMQ 实战中踩过的坑和解决方案 行动指南 我们总会遇到坑,遇到就把它填了。 1. RocketMQ 集群 CPU 毛刺 问题描述 RocketMQ 从节点、主节点频繁 CPU 飙高,很明显的毛刺,很多次从节点直接挂掉了。 只有系统日志有错误提示 20200316T17:56:07.505715+08:00 VECS0xxxx kernel:[] ? __alloc_pages_nodemask+0x7e1/0x96020200316T17:56:07.505717+08:00 VECS0xxxx kernel: java: page allocation failure. order:0, mode:0x2020200316T17:56:07.505719+08:00 VECS0xxxx kernel: Pid: 12845, comm: java Not tainted 2.6.32754.17.1.el6.x86_64 120200316T17:56:07.505721+08:00 VECS0xxxx kernel: Call Trace:20200316T17:56:07.505724+08:00 VECS0xxxx kernel:[] ? __alloc_pages_nodemask+0x7e1/0x96020200316T17:56:07.505726+08:00 VECS0xxxx kernel: [] ? dev_queue_xmit+0xd0/0x36020200316T17:56:07.505729+08:00 VECS0xxxx kernel: [] ? ip_finish_output+0x192/0x38020200316T17:56:07.505732+08:00 VECS0xxxx kernel: [] ? 各种调试系统参数只能减缓但是不能根除,依然毛刺超过 50% 解决方案 将集群所有系统升级从 centos 6 升级到 centos 7 ,内核版本也从从 2.6 升级到 3.10 ,CPU 毛刺消失。 2. RocketMQ 集群线上延迟消息失效 问题描述 RocketMQ 社区版默认本支持 18 个延迟级别,每个级别在设定的时间都被会消费者准确消费到。为此也专门测试过消费的间隔是不是准确,测试结果显示很准确。然而,如此准确的特性居然出问题了,接到业务同学报告线上某个集群延迟消息消费不到,诡异! 解决方案 将" delayOffset.json "和" consumequeue / SCHEDULE_TOPIC_XXXX "移到其他目录,相当于删除;逐台重启 broker 节点。重启结束后,经过验证,延迟消息功能正常发送和消费。 打造微服务高可用治理平台 设计指南 哪些是我们的核心服务,哪些是我们的非核心服务,这是服务治理的首要问题 设计目标 服务能应对突如其来的陡增流量,尤其保障核心服务的平稳运行。 应用分级和分组部署 应用分级 根据用户和业务影响两个纬度来进行评估设定的,将应用分成了四个等级。 业务影响:应用故障时影响的业务范围 用户影响:应用故障时影响的用户数量 S1:核心产品,产生故障会引起外部用户无法使用或造成较大资损,比如主营业务核心链路,如单车、助力车开关锁、顺风车的发单和接单核心链路,以及其核心链路强依赖的应用。 S2: 不直接影响交易,但关系到前台业务重要配置的管理与维护或业务后台处理的功能。 S3: 服务故障对用户或核心产品逻辑影响非常小,且对主要业务没影响,或量较小的新业务;面向内部用户使用的重要工具,不直接影响业务,但相关管理功能对前台业务影响也较小。 S4: 面向内部用户使用,不直接影响业务,或后续需要推动下线的系统。 分组部署 S1 服务是公司的核心服务,是重点保障的对象,需保障其不被非核心服务流量意外冲击。 S1 服务分组部署,分为 Stable 和 Standalone 两套环境 非核心服务调用 S1 服务流量路由到 Standalone 环境 S1 服务调用非核心服务需配置熔断策略 多种限流熔断能力建设 我们建设的高可用平台能力 部分限流效果图 预热图示 排队等待 预热+排队 高可用平台图示 中间件全部接入 动态配置实时生效 每个资源和 IP 节点详细流量 总结 哪些是我们的关键指标,哪些是我们的次要指标,这是消息治理的首要问题 哪些是我们的核心服务,哪些是我们的非核心服务,这是服务治理的首要问题 源码&实战 是一种比较好的工作学习方法。 活动推荐 阿里云基于 Apache RocketMQ 构建的企业级产品消息队列RocketMQ 5.0版现开启活动: 1、新用户首次购买包年包月,即可享受全系列 85折优惠! 了解活动详情:
作者:梁勇
#行业实践

2021年6月15日

阿里云中间件首席架构师李小平:企业为什么需要云原生?
前天我参加了信通院的云原生产业大会,参加会议的企业非常多,并且来自于各行各业,我在会场上非常感慨。我想起 2019 年的时候,我在搜索引擎上搜索“云原生”这个词,那时的搜索频率还比较低,而 2019 年又是云原生在国内开始飞速发展的一年。而今年的云原生会场上,已经有非常多的企业来参加,这些企业在技术、产品、生态中都在应用云原生,所以说,整个云原生已经从最开始的技术变成了行业,现在发展成了比较大的产业,并且这个产业的规模每年以非常快的速度在增长。 在今天,可能有很多咨询机构、企业,或者是个人开发者都在解读云原生,也许很多人对云原生都有比较深入的认识了。大家都可以认同的是,云原生肯定与云有关,但是它改变了什么,为企业带来什么价值呢?最核心的点应该是可以改变企业的应用架构;还有一种可能是不改变应用架构,只是把整个运维体系基于云原生进行重塑。但所有的这些,背后的目的都是为了加速企业的价值创造过程,简单的说,和制造企业改良生产线是一样的,核心点就是改良我们作为软件企业的生产线。 阿里在云原生的实践从 2006 年就开始了。我们在做云原生的过程中积累了很多经验,我们认为,今天云原生对于企业数字创新主要提供了多个价值: 一是资源弹性。弹性这个词大家很容易理解,实际上弹性有不同的层面。比如说基于虚拟机的弹性,提供的弹性能力是分钟级的。如果基于这些技术的应用是毫秒级的,那么分钟级只解决了资源弹性问题,整个应用高可用问题还需要进一步解决。如果说弹性到了应用的层面,到了毫秒级,高可用问题也得到一定程度的解决。 除此以外,系统的稳定性也是大家非常关注的方面。云原生就是把整个软件构造过程中非功能性特性拉出来放到云原生产品上去,帮助应用开发从非功能性处理过程中解脱出来,更多的专注在功能性。同样的,云原生有很多工具理念,可以让我们变得更好,整个软件开发从代码到上线的时间大幅缩短。同样的,今天在基于云原生可观测性上面我们会积累非常多的数据,这些数据可以结合机器学习这些能力,帮助我们改善企业的用户体验。这些对于业务来讲会带来比较大的价值。 阿里云原生的实践历程 今天,云原生在 CNCF、国内相关的开源、还有三方组织的推动下,可以使得一家企业在做技术选型的时候有非常多的选项。大家通常会面临一个问题,在这么多选择里面,要真正达到生产可用的目的到底选谁?特别是当我们的业务需要在非常短的时间内就上线,在业务高速发展的阶段,我们应该选什么样的架构,选什么样的开源开放的产品,这个是摆在广大企业技术决策者以及架构师面前的难题。 在云原生领域中,阿里云是相对比较早开始做自研的。从 2006 年到 2009 年互联网的中间件开始发展,到阿里云正式成立,整个过程中我们通过云原生解决很多业务问题。通过应用云原生相关技术,从早期很好地支持了淘宝的高速发展,到了 2015 年以后很好地支持了阿里的中台建设,以及到今天随着阿里巴巴整个生产系统、核心系统全部 100% 上云,这个过程中我们运用的云原生技术,像容器技术、微服务技术支持的规模都是百万级以上。 相关调研显示,这样的云原生落地规模在全球范围内都是非常领先的。实际上,对于很多企业来讲,也许用不到这些规模,但是阿里通过解决这样的大规模下的性能、稳定性问题,积累了非常多的硬核技术,最终能够把这些技术转变成了产品,通过阿里云对外输出,服务于各行各业的广大客户。 我们认为,云原生对于整个软件的改变,或者对软件公司的开发流程的改变是非常深刻的。首先 K8s 已经变成了软件交付的标准界面,它改变的不止是运维,而是从 CICD 到后续发布上线整个生产链条。由于所有生产流程得到改变,以及很多企业通过云原生技术重塑了软件架构,使得软件架构从传统架构变成了新的、我们称之为现代化的应用架构,因此云原生可以通过这种生产工具的改良进一步改变企业的生产关系,最终影响企业,使得企业在软件开发过程中得到了极大的提速。 阿里云在云原生实践过程中,积累了很强的技术竞争力,体现在这些方面: 一、我们有非常多领先的技术解决云原生领域里面的稳定性问题、可靠性问题,大规模下的高并发问题等。同时,我们会把所有的这些技术通过开源开放的形式输出。我们知道,在云原生的世界,企业需要的是开源开放的技术,而不是被像阿里这样单独一个厂商所锁定的技术。这个过程中我们基于开源开放技术标准积累了很多产品的硬核能力。在产品上,除了大家看到的基于云原生应用架构里,还包括云原生数据库、云原生大数据等。 在云原生相关的领域有比较多的测评,在这些测评里,例如阿里云容器产品 ACK,在去年 Gartner 评测中拿到满分,全球厂商中只有两个厂商拿到满分,阿里云是其中之一。今年,阿里云再次入选 Gartner 容器竞争格局。在新兴的计算形态领域中,今年阿里云进入 Forrester FaaS 领导者象限,函数计算获得了全球 FaaS 产品最高分。 在可观测性里,阿里云代表国内云厂商进入 Gartner APM 象限。所有这些三方评估从另外一个层面反映了阿里云产品的能力。容器架构上,我们基于开源开放的 K8s 技术体系,基于阿里云的硬件做深度的优化,在比较多的领域和场景里为广大 K8s 应用提供服务。我们把在 K8s 集群里面超大规模集群管理的能力输出到 ACK 产品里面,使得阿里云的客户在管理集群的时候,可以摆脱大规模集群的管理复杂性问题。 比如完美日记,作为美妆行业的独角兽公司,他们的业务发展速度非常快,但在业务快速发展过程中,他们面临的问题就是在大促的场景中怎么更好地预留资源,以及在大促时怎么样比较好地解决新上线的功能,以及需求的稳定性问题。在这个过程中,他们利用 PTS 作为压测,所有应用跑在 ACK 平台上面,通过压测模拟大促的流量,从而能够把整个大促从需要投入较大的状态提升到具备可以常态化的做大促压测的能力,也通过这个能力使得系统稳定性相关问题得到快速收敛。 云原生中间件 从微服务、消息到各种应用工具以外,根据企业常见的 IT 场景,云原生中间件也提供了很多解决方案。阿里云中间件诞生于集团内的大规模调用场景,同时兼容开源,并且融入了更多产品能力,例如在整个大促过程中表现优异的可观测性、高可用能力等,都属于云原生中间件产品体系。 同样在中间件领域里,我们也和较多企业客户有相应的合作。畅捷通是一家做 SaaS 的企业,迄今已经为超过四百万的小微企业做了云管。ToB 类型的应用复杂度较高,最大的问题就是整个软件的发布频率是非常快的,怎么样在高频软件发布下面能够比较好的解决软件的各种 BUG,或者解决设计上的不足带来的稳定性的问题,这是在前期探讨过程中畅捷通提出来的关注点。通过应用云原生中间件,不仅解决了整个应用的可观测性问题,并且让应用具备 360 度无死角可观测能力,通过应用探测能够快速发现在整个压测过程中各种可能的不稳定风险,从而使得相应风险得到快速的收敛。 Serverless 很多学术机构在 Serverless 领域深入研究,我们预感 Serverless 极有可能会成为下一代主流技术趋势。阿里云在 Serverless 领域里做到业界领先的毫秒级计费,以及在整个阿里云底层做深度优化,使客户的应用真正达到了智能的弹性、极致的运维和大幅提升开发效率。阿里云也和许多企业客户达成深度合作,进行 Serverless 落地实践,通过帮助客户将应用迁到 Serverless 技术体系上,达到比较快的应用部署;同时,把应用的稳定性问题、运维都委托给 Serverless 这样的云产品去解决。 解决方案 云原生在快速发展过程中,只有通过不断的技术创新、产品创新,才有可能使得云原生技术更好的服务于广大的企业客户。今天,阿里云对外发布四大解决方案:全链路压测解决方案、异地多活解决方案、资源混部解决方案、可观测解决方案。这些解决方案可以高效地解决在传统领域里还没有很好解决的问题。比如全链路压测,大家都知道全链路压测是个好东西,比较大的问题是在应用压测过程中使应用改造最小,甚至不要做改造,所以这次阿里云升级的全链路压测就可以帮助企业应用解决这些问题。 今天企业在不断深入地使用云以后,不管公有云还是专有云上,都会碰到整体 CPU 利用率不高的问题,混部就使得各种离线任务和在线任务可以部署在一起,各自享用资源调度的优势,使得整体机房的 CPU 利用率得到比较大的提升。在这个过程中要解决混部之后带来的稳定性问题、资源占用问题。阿里是比较早地应用大规模的混部,像支撑电商双十一的云原生产品。今天我们也是把混部能力变成解决方案对外输出。 大家都知道,阿里是比较早实现了单元化的架构,通过单元化架构实现了多活。今天我们把单元化整体的架构能力作为多活的解决方案。同时,这样的多活不仅可以支持自有数据中心、私有云的场景,也能够支持公有云和混合云场景实现整个应用的多活。 可观测性一直都是大家特别关注的话题,因为通过可观测性使得我们可以主动发现在系统的运行过程中可能出现的各类风险。今天,阿里云升级的可观测性方案包括从拨测到各种前端的性能监控,一直延伸到后端应用,甚至延伸到云服务里。 产品升级 除了解决方案的创新以外,我们在相应的云原生产品上面也做了比较多的升级。容器 ACK 备份容灾中心全新发布,为容器用户提供集群、应用和数据的完整性保护: 1、支持自动分析应用依赖的元数据及存储,实现秒级创建应用+数据的一致性快照; 2、支持创建备份计划,自动按预设时间点创建备份; 3、完全兼容 Kubernetes,并支持多集群、多地域、跨数据中心进行备份和恢复。 容器镜像 ACR 发布企业级 Serverless 构建服务,大幅提升云原生制品的构建效率和体验: 1、支持多操作系统、多架构镜像的矩阵构建,支持大规模并发任务构建。 2、支持多级缓存的构建加速,平均构建提速 30%。 3、支持自动构建加速镜像,实现 AI 等大镜像秒级按需加载,平均启动时间减少 60 %。 在微服务领域,越来越多的应用考虑采用服务网格技术。用户希望服务网格在开源技术之上有更强的微服务治理能力,因此阿里云推出专业版 ASM Pro,具备增强多协议支持,提升动态扩展能力,精细化服务治理,完善零信任安全体系。专业版相比去年发布的普通版,在性能及规模上均有显著提升,与开源的差异化竞争力进一步增强,降低用户在生产环境落地服务网格的门槛。 Gartner 预测,未来事件驱动将成为业务开发的主流架构。企业客户上云过程中对于低代码、无服务器弹性应用架构,如何轻量集成众多异构云服务的数据流有着明确的痛点和诉求。基于此趋势,阿里云发布了事件总线 EventBridge 这款产品,其目标在于统一阿里云云服务、第三方 SaaS 厂商、用户自定义的事件标准,通过标准、弹性、轻量的核心能力帮助用户快速低成本获取并处理海量事件,驱动业务开发。 在过去的一段时间,我们对 EventBridge 的产品能力做了进一步的扩充和升级: 在事件生态集成的规模方面,新增 60+ 云产品官方事件源接入,涵盖计算、存储、网络、数据库等主流云产品; 在事件触达和处理方式上,内置了十多种过滤匹配转换逻辑,并且新增了跨网络、跨地域、跨账号等深度触达方式,方便企业大客户做深层次的安全、隔离等定制; 在此基础上,阿里云 EventBridge 首次推出事件驱动应用中心,内置常见的事件驱动应用模板,用户无需代码和部署即可简单配置完成常见的事件 ETL 处理、数据同步等场景功能。 阿里云拥有最广泛的云原生客户群体。随着更多的企业客户上云,将有更多复杂的场景,对于云原生技术、产品以及云原生理念提出更高的要求。阿里云希望跟社会各界的朋友一起在云原生领域里面做更多的探索,希望通过云原生技术,真正为企业带来更多的业务价值,助力企业整体的业务创新。 活动推荐 阿里云基于 Apache RocketMQ 构建的企业级产品消息队列RocketMQ 5.0版现开启活动: 1、新用户首次购买包年包月,即可享受全系列 85折优惠! 了解活动详情:
作者:李小平
#行业实践 #云原生

2021年6月14日

云原生消息队列RocketMQ:为什么我们选择 RocketMQ
说起消息队列,ActiveMQ、RabbitMQ、RocketMQ、Kafka、Pulsar 等纷纷涌入我们的脑海中, 在如此众多的开源消息队列产品中,作为一名合格的架构师如何给出高性价比的方案呢?商业化的产品暂不纳入选项中。 接下来我将从选型要素、RocketMQ 的优势两个方面解释为什么选择 RocketMQ 。 选型要素 首先从公司、消息队列服务提供者(一般是中间件团队)、最终用户三个角度来简单总结分析。 一、从公司层面看, 关注如下几点: 1. 技术成本 技术成本,一般包含服务器成本、二次开发成本、后期维护成本等,言而总之:都是钱。 服务器目前基本都使用云服务器,不同的云厂商的相同配置的服务器性能也有一定差异, 服务器成本一般需要了解:云厂商机器性能、云厂商优惠、所需服务器配置、服务器台数、单台服务器目前的价格、单台服务器优惠后的价格等。 2. 人力成本 人力成本,一般包含现有技术人员成本、新人招聘成本。 新的技术选型对于目前的技术人员接受程度怎么样,学习的难易程度怎样等,都是需要考虑的。如果太难的话,上线周期会变长、业务需求实现速度慢,甚至有人直接离职。 新人招聘成本,一般招聘一个新人有如下几个过程:简历筛选、预约面试、数轮面试、发 offer 、接受 offer 、正式入职、试用期、转正。这中间涉及到猎头成本、人力资源沟通成本、面试成本、新人入职后环境适应成本等等。 3. 其他 目前处于不同阶段的互联网公司对于技术成本、人力成本有着不一样的要求,但是很多有一定规模的公司实际上还是用“买买买”的心态来对待的:只要业务发展快速,买服务器、招人都不是问题,如果成本高了就做技术降成本、裁员。这不仅是员工之痛,也是业务之痛,更是公司之痛。 二、从中间件组层面看, 关注如下几点: 1. 稳定 公司级的服务首要的一点就是稳定。拥有稳定的组件、稳定的服务,业务才能有条不紊的进行。所以说,无论什么时候, 稳定都是王道。 2. 功能支持 不同的业务场景需要的功能也不尽相同,通常我们会考虑重试、死信机制,位点重置,定时延迟消息、事物消息,主从切换,权限控制等方面。 3. 性能 目前包含写入延迟和吞吐。 4. 管理平台 首先需要满足最终用户接入、查看、排障,管理员管控 topic 、消费者方便等。管理平台有现成的最好,方便二次开发 。 5. 监控、报警 监控报警是否完善、是否方便接入公司内部自研体系,或者行业的事实标准 Prometheus 。 6. 运维 & 支持 & 开源社区 如果产品上线后, 大部分时间,我们都是在做运维&支持。运维包含服务部署、迁移、服务升级、解决系统 Bug 、用户使用答疑、管理平台和监控报警平台升级等。 7. 其他 我们除了依赖自身以外,也可以借助社区的力量,同一个问题可能别人遇到过并且提交过 PR ,已经得到解决,我们就可以以此作为借鉴。所以社区的活跃情况也是非常重要的考虑。 三、从最终用户(一般包含业务后端研发以及他们的 Leader )看 1. 稳定性 对于业务的研发和他们的 Leader ,他们的核心任务是实现业务逻辑。如果一个服务三天两头总是有问题, 对于他们来说是比较致命的,所以稳定性是比较核心的一部分。 2. 改造现有项目的难度 旧项目改造其实是业务研发接入新中间件实际操作最多的部分。 3. 新项目接入是否便捷 是否便捷接入跟他们的工作量有着直接的关联。 4. 与目前的 App 微服务框架兼容怎样 新项目的接入和公司微服务框架兼容都比较容易。一般中间件在提供服务时都会考虑业务研发接入的便利性。 RocketMQ 的优势 下面将按照选项要素的要求, 分析 RocketMQ 在这方面的优势。 一、RocketMQ 如何解决和友好面对公司层面的诉求 1. 技术成本 就技术成熟度而言,在经历阿里双十一数万亿洪峰、微众银行、民生银行、蚂蚁金服、平安、字节跳动、快手、美团、京东、网易等各种行业大厂的考验后,就不言而喻了。 RocketMQ 对于服务器的配置要求不高, 普通的云主机都可以。曾经我们验证 8C 16G 500G SSD 的 2 主 2 从的集群,发送 tps 可以到 4~5w ,消费 tps 峰值 20w +,稳定在 8w~9w 。并且,还能根据业务实际的需求无感的横向扩展。 综合而言, 技术成本相对可控且人才多。 2. 人力成本 人力成本主要是现有的技术人员的学习成本、招新人的成本。 RocketMQ 是 java 开发的,代码也非常稳定、有条理,各个版本之间除了功能有差异之外,Api 、传输协议几乎没有太多变化,对于升级而言也更加方便。 java 也是目前中间件采用的比较主流的语言,使用的技术人员非常广泛。RocketMQ 在金融行业比如:微众银行、民生银行、蚂蚁金服、平安; 其他行业公司,比如阿里、字节跳动、快手、美团、京东、网易等与大量中小企业都在使用,候选人范围相对较大。 RocketMQ 社区也比较活跃,钉钉群、微信群、QQ 群众多,社区文档非常丰富和完善,原理剖析视频、文档也非常多,非常易于学习和入门。 下面是钉钉群,欢迎大家加群留言、答疑。 对于 java 方面的消息队列方面的人才相比 C/C++、C、Python、Go 等还是更多的:主流的 Kafka 是 scala + java、pulsar 是 java ,对于招聘也有极大的优势。 综合而言,RocketMQ 技术员对于人力成本比较友好。 二、从中间件组层面看,RocketMQ 是如何提供优秀的能力,为业务保驾护航呢? 1. 稳定性 金融级可靠、阿里双十一稳定支持万亿级消息洪峰,在笔者之前所在公司也有过 2 年+零事故的佳绩。 2. 功能丰富,支持的场景众多 重试、死信机制,友好、无感的业务重试机制。 顺序消息、事物消息 万级 Topic 数量支持 消息过滤 消息轨迹追踪 主从自动切换 原生支持 Prometheus 监控 原生支持易用管理平台:RocketMQ Console 访问权限控制(ACL) 3. 性能 RocketMQ 可以支持 99.9% 的写入延迟在 2 ms ,其他的开源消息队列中间件基本都是大于 5 ms ;目前大部分消息队列中间间都支持横向扩展,吞吐上横向扩展几乎都可以满足。RocketMQ 的在滴滴做的性能测试: _ _, 大家参考。 发送、消费 tps 和 kafka 一个数量级,Topic 数量剧增对于性能影响较小。 4. 管理平台 RocketMQ Console 原生支持: 5. 监控、报警 RocketMQ Exporter 原生支持 Prometheus: 6. 运维 & 支持 & 开源社区 无 zk 等第三方依赖,开箱即用 社区钉钉群、微信群、QQ 群非常活跃,钉钉群、微信群有问必答。 社区最近新来一位小姐姐 Commiter ,团队也在不断壮大。 综合看来,RocketMQ 稳定、可靠、性能好,开箱即用,不依赖 Zookeeper ,系统的稳定性更高,复杂度更小。监控报警等周边设施完善,场景支持全,社区活跃、文档丰富,是中间件团队的不二之选。 三、对于最终用户:业务研发、业务研发 Leader,他们的核心担忧是提供的技术是否稳定可靠、是否快速方便的接入 从中间件组层面看这个问题时,RocketMQ 稳定、可靠,那对于接入是否友好呢? RocketMQ 提供 java 原生客户端、Spring 客户端,C++ 客户端、Python 客户端、Go 客户端等多类型、多语言的客户端,对于各种项目都可以统一接入。 微服务框架中 Spring Cloud 基本已经成为事实标准,RocketMQ 支持 Spring boot Starter 和 Spring Cloud Function 等多种方式融合入微服务框架,对于 Spring 体系支持更加方便快捷。 Kafka vs RocketMQ 实际中,很多人应该面临过 RocketMQ vs Kafka ,Kafka 适合对于延迟不敏感、批量型、Topic 数量可控、对于消息丢失不敏感的场景。比如大数据场景的 MySQL2Hive、MySQL2Flink 的数据流通道,日志数据流通道等。 RocketMQ 适用于金融转账消息、订单状态变更消息、手机消息 Push 等业务场景。这些场景 Topic 数量通常过万,对于消息延迟和丢失极度敏感,数据通常是论条处理。对于海量数据的问题,一般地横向扩容完全可以解决。 合适的场景选择合适的产品,万能的产品是不存在的,都是折中,都是取舍。 作者介绍 李伟,Apache RocketMQ 社区 Commiter ,Python 客户端项目负责人, Apache RocketMQ 北京社区联合发起人,Apache Doris Contributor 。目前就职于腾讯,主要负责 OLAP 数据库开发,对分布式存储系统设计和研发有丰富经验,也热衷于知识分享和社区活动。 RocketMQ 学习资料 阿里云知行实验室提供一系列的 RocketMQ 在线实操环境,包含操作文档、ubuntu 实验环境,大家随时尝试玩玩: Apache RocketMQ 开源入门最佳实践: 《RocketMQ 分布式消息中间件:核心原理与最佳实践》随书实战:_ 在 Spring 生态中玩转 RocketMQ: 实验预览图如下: 其他资源 RocketMQ vs. ActiveMQ vs. Kafka: RocketMQ 源码: RocketMQ Exporter 源码: RocketMQ Spring 源码: RocketMQ C++ 客户端源码: RocketMQ Python 客户端源码: RocketMQ Go 客户端源码: RocketMQ Console 源码: RocketMQ Flink Connector 源码: RocketMQ 如何保证消息可靠: 大揭秘!RocketMQ 如何管理消费进度: 活动推荐 阿里云基于 Apache RocketMQ 构建的企业级产品消息队列RocketMQ 5.0版现开启活动: 1、新用户首次购买包年包月,即可享受全系列 85折优惠! 了解活动详情:
作者:李伟
#行业实践

2021年4月3日

阿里的 RocketMQ 如何让双十一峰值之下 0 故障?
2020 年双十一交易峰值达到 58.3 W 笔/秒,消息中间件 RocketMQ 继续数年 0 故障丝般顺滑地完美支持了整个集团大促的各类业务平稳。2020 年双十一大促中,消息中间件 RocketMQ 发生了以下几个方面的变化: 云原生化实践:完成运维层面的云原生化改造,实现 Kubernetes 化。 性能优化:消息过滤优化交易集群性能提升 30%。 全新的消费模型:对于延迟敏感业务提供新的消费模式,降低因发布、重启等场景下导致的消费延迟。 云原生化实践 1. 背景 Kubernetes 作为目前云原生化技术栈实践中重要的一环,其生态已经逐步建立并日益丰富。目前,服务于集团内部的 RocketMQ 集群拥有巨大的规模以及各种历史因素,因此在运维方面存在相当一部分痛点,我们希望能够通过云原生技术栈来尝试找到对应解决方案,并同时实现降本提效,达到无人值守的自动化运维。 消息中间件早在 2016 年,通过内部团队提供的中间件部署平台实现了容器化和自动化发布,整体的运维比 2016 年前已经有了很大的提高,但是作为一个有状态的服务,在运维层面仍然存在较多的问题。 中间件部署平台帮我们完成了资源的申请,容器的创建、初始化、镜像安装等一系列的基础工作,但是因为中间件各个产品都有自己不同的部署逻辑,所以在应用的发布上,就是各应用自己的定制化了。中间件部署平台的开发也不完全了解集团内 RocketMQ 的部署过程是怎样的。 因此在 2016 年的时候,部署平台需要我们去亲自实现消息中间件的应用发布代码。虽然部署平台大大提升了我们的运维效率,甚至还能实现一键发布,但是这样的方案也有不少的问题。比较明显的就是,当我们的发布逻辑有变化的时候,还需要去修改部署平台对应的代码,需要部署平台升级来支持我们,用最近比较流行的一个说法,就是相当不云原生。 同样在故障机替换、集群缩容等操作中,存在部分人工参与的工作,如切流,堆积数据的确认等。我们尝试过在部署平台中集成更多消息中间件自己的运维逻辑,不过在其他团队的工程里写自己的业务代码,确实也是一个不太友好的实现方案,因此我们希望通过 Kubernetes 来实现消息中间件自己的 operator 。我们同样希望利用云化后云盘的多副本能力来降低我们的机器成本并降低主备运维的复杂程度。 经过一段时间的跟进与探讨,最终再次由内部团队承担了建设云原生应用运维平台的任务,并依托于中间件部署平台的经验,借助云原生技术栈,实现对有状态应用自动化运维的突破。 2. 实现 整体的实现方案如上图所示,通过自定义的 CRD 对消息中间件的业务模型进行抽象,将原有的在中间件部署平台的业务发布部署逻辑下沉到消息中间件自己的 operator 中,托管在内部 Kubernetes 平台上。该平台负责所有的容器生产、初始化以及集团内一切线上环境的基线部署,屏蔽掉 IaaS 层的所有细节。 Operator 承担了所有的新建集群、扩容、缩容、迁移的全部逻辑,包括每个 pod 对应的 brokerName 自动生成、配置文件,根据集群不同功能而配置的各种开关,元数据的同步复制等等。同时之前一些人工的相关操作,比如切流时候的流量观察,下线前的堆积数据观察等也全部集成到了 operator 中。当我们有需求重新修改各种运维逻辑的时候,也再也不用去依赖通用的具体实现,修改自己的 operator 即可。 最后线上的实际部署情况去掉了图中的所有的 replica 备机。在 Kubernetes 的理念中,一个集群中每个实例的状态是一致的,没有依赖关系,而如果按照消息中间件原有的主备成对部署的方案,主备之间是有严格的对应关系,并且在上下线发布过程中有严格的顺序要求,这种部署模式在 Kubernetes 的体系下是并不提倡的。若依然采用以上老的架构方式,会导致实例控制的复杂性和不可控性,同时我们也希望能更多的遵循 Kubernetes 的运维理念。 云化后的 ECS 使用的是高速云盘,底层将对数据做了多备份,因此数据的可用性得到了保障。并且高速云盘在性能上完全满足 MQ 同步刷盘,因此,此时就可以把之前的异步刷盘改为同步,保证消息写入时的不丢失问题。云原生模式下,所有的实例环境均是一致性的,依托容器技术和 Kubernetes 的技术,可实现任何实例挂掉(包含宕机引起的挂掉),都能自动自愈,快速恢复。 解决了数据的可靠性和服务的可用性后,整个云原生化后的架构可以变得更加简单,只有 broker 的概念,再无主备之分。 3. 大促验证 上图是 Kubernetes 上线后双十一大促当天的发送 RT 统计,可见大促期间的发送 RT 较为平稳,整体符合预期,云原生化实践完成了关键性的里程碑。 性能优化 1. 背景 RocketMQ 至今已经连续七年 0 故障支持集团的双十一大促。自从 RocketMQ 诞生以来,为了能够完全承载包括集团业务中台交易消息等核心链路在内的各类关键业务,复用了原有的上层协议逻辑,使得各类业务方完全无感知的切换到 RocketMQ 上,并同时充分享受了更为稳定和强大的 RocketMQ 消息中间件的各类特性。 当前,申请订阅业务中台的核心交易消息的业务方一直都在不断持续增加,并且随着各类业务复杂度提升,业务方的消息订阅配置也变得更加复杂繁琐,从而使得交易集群的进行过滤的计算逻辑也变得更为复杂。这些业务方部分沿用旧的协议逻辑(Header 过滤),部分使用 RocketMQ 特有的 SQL 过滤。 2. 主要成本 目前集团内部 RocketMQ 的大促机器成本绝大部分都是交易消息相关的集群,在双十一零点峰值期间,交易集群的峰值和交易峰值成正比,叠加每年新增的复杂订阅带来了额外 CPU 过滤计算逻辑,交易集群都是大促中机器成本增长最大的地方。 3. 优化过程 由于历史原因,大部分的业务方主要还是使用 Header 过滤,内部实现其实是aviator 表达式。仔细观察交易消息集群的业务方过滤表达式,可以发现绝大部分都指定类似MessageType == xxxx这样的条件。翻看 aviator 的源码可以发现这样的条件最终会调用 Java 的字符串比较String.compareTo()。 由于交易消息包括大量不同业务的 MessageType,光是有记录的起码有几千个,随着交易业务流程复杂化,MessageType 的增长更是繁多。随着交易峰值的提高,交易消息峰值正比增长,叠加这部分更加复杂的过滤,持续增长的将来,交易集群的成本极可能和交易峰值指数增长,因此决心对这部分进行优化。 原有的过滤流程如下,每个交易消息需要逐个匹配不同 group 的订阅关系表达式,如果符合表达式,则选取对应的 group 的机器进行投递。如下图所示: 对此流程进行优化的思路需要一定的灵感,在这里借助数据库索引的思路:原有流程可以把所有订阅方的过滤表达式看作数据库的记录,每次消息过滤就相当于一个带有特定条件的数据库查询,把所有匹配查询(消息)的记录(过滤表达式)选取出来作为结果。为了加快查询结果,可以选择 MessageType 作为一个索引字段进行索引化,每次查询变为先匹配 MessageType 主索引,然后把匹配上主索引的记录再进行其它条件(如下图的 sellerId 和 testA )匹配,优化流程如下图所示: 以上优化流程确定后,要关注的技术点有两个: 如何抽取每个表达式中的 MessageType 字段? 如何对 MessageType 字段进行索引化? 对于技术点 1 ,需要针对 aviator 的编译流程进行 hook ,深入 aviator 源码后,可以发现 aviator 的编译是典型的Recursive descent,同时需要考虑到提取后父表达式的短路问题。 在编译过程中针对 messageType==XXX 这种类型进行提取后,把原有的 message==XXX 转变为 true/false 两种情况,然后针对 true、false 进行表达式的短路即可得出表达式优化提取后的情况。例如: 表达式: messageType=='200tradepaiddone' && buyerId==123456 提取为两个子表达式: 子表达式1(messageType==200tradepaiddone):buyerId==123456 子表达式2(messageType!=200tradepaiddone):false 具体到 aviator 的实现里,表达式编译会把每个 token 构建一个 List ,类似如下图所示(为方便理解,绿色方框的是 token ,其它框表示表达式的具体条件组合): 提取了 messageType ,有两种情况: 情况一:messageType == '200tradepaiddone',则把之前 token 的位置合并成true,然后进行表达式短路计算,最后优化成 buyerId==123456 ,具体如下: 情况二:messageType != '200tradepaiddone',则把之前 token 的位置合并成 false ,表达式短路计算后,最后优化成 false ,具体如下: 这样就完成 messageType 的提取。这里可能有人就有一个疑问,为什么要考虑到上面的情况二,messageType != '200tradepaiddone',这是因为必须要考虑到多个条件的时候,比如: (messageType=='200tradepaiddone' && buyerId==123456) || (messageType=='200tradesuccess' && buyerId==3333) 就必须考虑到不等于的情况了。同理,如果考虑到多个表达式嵌套,需要逐步进行短路计算。但整体逻辑是类似的,这里就不再赘述。 说完技术点 1,我们继续关注技术点 2,考虑到高效过滤,直接使用 HashMap 结构进行索引化即可,即把 messageType 的值作为 HashMap 的 key ,把提取后的子表达式作为 HashMap 的 value ,这样每次过滤直接通过一次 hash 计算即可过滤掉绝大部分不适合的表达式,大大提高了过滤效率。 3. 优化效果 该优化最主要降低了 CPU 计算逻辑,根据优化前后的性能情况对比,我们发现不同的交易集群中的订阅方订阅表达式复杂度越高,优化效果越好,这个是符合我们的预期的,其中最大的 CPU 优化有32%的提升,大大降低了本年度 RocketMQ 的部署机器成本。 全新的消费模型 —— POP 消费 1. 背景 RocketMQ 的 PULL 消费对于机器异常 hang 时并不十分友好。如果遇到客户端机器 hang 住,但处于半死不活的状态,与 broker 的心跳没有断掉的时候,客户端 rebalance 依然会分配消费队列到 hang 机器上,并且 hang 机器消费速度很慢甚至无法消费的时候,这样会导致消费堆积。另外类似还有服务端 Broker 发布时,也会由于客户端多次 rebalance 导致消费延迟影响等无法避免的问题。如下图所示: 当 Pull Client 2 发生 hang 机器的时候,它所分配到的三个 Broker 上的 Q2 都出现严重的红色堆积。对于此,我们增加了一种新的消费模型 —— POP 消费,能够解决此类稳定性问题。如下图所示: POP 消费中,三个客户端并不需要 rebalance 去分配消费队列,取而代之的是,它们都会使用 POP 请求所有的 broker 获取消息进行消费。broker 内部会把自身的三个队列的消息根据一定的算法分配给请求的 POP Client。即使 Pop Client 2 出现 hang,但内部队列的消息也会让 Pop Client1 和 Pop Client2 进行消费。这样就 hang 机器造成的避免了消费堆积。 2. 实现 POP 消费和原来 PULL 消费对比,最大的一点就是弱化了队列这个概念,PULL 消费需要客户端通过 rebalance 把 broker 的队列分配好,从而去消费分配到自己专属的队列,新的 POP 消费中,客户端的机器会直接到每个 broker 的队列进行请求消费, broker 会把消息分配返回给等待的机器。随后客户端消费结束后返回对应的 Ack 结果通知 broker,broker 再标记消息消费结果,如果超时没响应或者消费失败,再会进行重试。 POP 消费的架构图如上图所示。Broker 对于每次 POP 的请求,都会有以下三个操作: 对应的队列进行加锁,然后从 store 层获取该队列的消息; 然后写入 CK 消息,表明获取的消息要被 POP 消费; 最后提交当前位点,并释放锁。 CK 消息实际上是记录了 POP 消息具体位点的定时消息,当客户端超时没响应的时候,CK 消息就会重新被 broker 消费,然后把 CK 消息的位点的消息写入重试队列。如果 broker 收到客户端的消费结果的 Ack ,删除对应的 CK 消息,然后根据具体结果判断是否需要重试。 从整体流程可见,POP 消费并不需要 reblance ,可以避免 rebalance 带来的消费延时,同时客户端可以消费 broker 的所有队列,这样就可以避免机器 hang 而导致堆积的问题。 活动推荐 阿里云基于 Apache RocketMQ 构建的企业级产品消息队列RocketMQ 5.0版现开启活动: 1、新用户首次购买包年包月,即可享受全系列 85折优惠! 了解活动详情:
作者:愈安
#行业实践 #高可用