当前位置: 首页 > 后端技术 > Python

饿了么外卖中心语言栈改造总结

时间:2023-03-26 02:09:55 Python

前言:本文介绍了饿了么外卖中心从python语言栈向java语言栈转型的大致过程。本总结为其他应用服务的改造提供了一些参考。文笔不好,欢迎搬砖。背景饿了么并入阿里集团。为与集团内部系统高效对接,方便利用集团优势技术资源,更好融入阿里集团技术生态,饿了么交易中心于上半年上线了交易领域。阿里巴巴集团四大应用语言栈改造项目,将为阿里集团本地生活服务平台打下坚实的技术平台基础。此外,随着业务量的激增,饿了么平台支持的品类不仅仅是最初的外卖商品,整个交易中心也需要进行比较大的重构,以快速应对复杂多变的业务需求。本文中的配送中心是饿了么交易领域的四大应用之一。在准备开展相关工作之前,首先要了解我们要从一个系统变成什么样的系统,新系统在哪些方面比旧系统做得更好。同时要保证新旧系统的无缝切换,做到没有业务感,不影响交易系统的稳定性。系统价值外卖订单的业务特点是重交易。c端用户可以完成从下单到选餐再到骑手送餐的全过程。目前大部分可以在半小时左右完成,对实时性要求很高。整个订单交易流程大致分为:1.添加购物车确认订单,2.订单生成及订单支付,3.订单收货及订单发货,4.可能的售后退款。为了更好地服务用户,对四大系统的稳定协同提出了很高的要求。上面说到,我们知道fulfillment链接对于交易订单的价值是什么,也就是将外卖订单对应的餐点配送给用户。从技术上讲,交货屏蔽了交易订单的所有其他履行细节,使订单更加准确。专注于订单业务。内核分析接下来,我们进一步详细分析改造前的投放系统所承载的功能。如上图所示,原配送业绩字段包括三大板块:1.订单对接能力线模块2.商户订单信息模块3.部分金额计算模块可以看出,原系统承载的功能并没有真正专注于订单交付流程。该怎么办?转型重建是机遇。商户下单返回订单,金额计算下沉到结算。这两部分的相关改造和重构这里不再赘述,相关部分也已经由小弟团队完成。其实,在配送和履行合同中需要注意什么已经很明显了:将外卖订单配送到产能线,才能完成合同的配送和履行。基于刚才提取的交付和性能核心领域,我们对主要场景用例进行了详细梳理。如下图所示,可以看出在配送过程中主要涉及四个角色:1.商户2.订单3.履约能力线4.用户配送提供的主要支持能力有:1.几乎订单派送能力2.运单状态同步能力3.运单信息公开能力4.表现方式切换能力5.运单状态广播到达下游能力等部分运单取消或异常管理。系统核心用例分析如下图所示:更详细的系统用例梳理或系统上下游交互时序在此不再一一列举。需要说明的是,大流量系统的改造遇到重构,需要走得够远、够稳,前期细致的调研工作和功能对接过程非常重要。特别是生产环境已经运行核心功能系统数年,实际业务情况复杂。例如,要对系统接口能力进行改造重构,必须详细掌握接口含义、场景等。至此,我们的目标很明确:1.语言栈改造,2.在这个过程中,把不属于交付的东西从原来的系统中分离出来,让交付领域更干净。结合交付未来可能的发展方向,实现交付运力的复用,扩充履约运力线。这就对整个交付的快速迭代对接提出了更高的要求。另外,我们在领域建模和设计思想的指导下也做了一些实践性的尝试,所以有了如下的框架。系统设计改造是将python方言转换为java方言,下发系统核心能力不变。通过接口维度的抽象聚合产生能力的复用,利用业务框架扩展点的特性,实现能力线的能力扩展。拆分后的业务框架应该如下图所示:系统架构业务框架结合目前的基础组件支持,不难给出如下系统内部模块划分:各组件模块的简要说明:api:中业务框架上游系统接入层对外暴露合约屏蔽细节,对内定义系统能力。starter:启动项目service:rpc服务leakagedomain:核心业务能力的实现,聚合层infra:基础数据支撑能力层extension:合约性能扩展层tester:这里的单元测试包,我们可以按照设计和既定计划进行编码向上。好了,代码完成并测试了。从研究到开发历时两个半月。代码仓库总行数约4.7w行,提交约1000次,完成63个接口+16个消息消费入口的改造迁移。一共测了117+个Bug,期间有悲欢离合,打两点以上很正常。事业上的重要一笔。这时候特别想起我和超哥@双超周末股份联盟设计在北边14楼的小黑屋边,和明龙@张明龙并肩作战对接服务界面,和小博@徐晓波早晚一起做压测观察总结题号。这两天分析反馈完善优化,当然还有杰哥@汤良杰的用例设计全面细致,bug经常查到根源,codereview逻辑检查一丝不苟,独具慧眼。这些都栩栩如生。一起来,非常感谢。------不由自主的感觉≧◇≦平滑过渡第一步改造工作在代码测试后完成,流量稳定平滑过渡到新服务,让上下游无感是转型过程中面临的另一大挑战。话说回来,实现系统语言改造前后的平滑过渡,其实就是为我们系统改造前后的用户SLA(ServiceLevelAgreement)提供一致的保证。这里简单说一下系统服务的SLA。上表是衡量业界几个级别的高服务可用性。例如,当服务可用性为三个九时,每年宕机的统计概率约为8.76天。另外,我们需要明确的是,不同的系统、不同的场景、不同的用户规模,对系统可用性的要求是不同的。比如一些业务的支付链路场景可能tps不是很高,但是作为交易的核链路必须保证高可用。如何保证或提高系统服务的SLA?明确了我们的目标之后,接下来就是拆解目标,量化目标。你无法衡量它,你无法修复它并改进它。一般来说,影响系统服务可用性的重要因素有两个:MTBF:MeanTimeBetweenFailures,系统服务平均无故障时间。MTTR:MeanTimeToRecover,系统服务的平均故障恢复时间。因此,大致可以概括为这样一个函数关系:可能无法给出准确的数学描述,但可以做定性分析:恢复时间因子与系统可用性正相关,故障间隔因子负相关与系统可用性相关。也就是说:_当出现问题时,恢复时间应尽可能短,并尽可能降低故障频率以增加故障间隔。基于以上理论,我们在做系统的平滑过渡和无缝切换时,无论是资源使用、业务内部逻辑实现、灰度解决方案,都需要重点关注这两方面。接下来,我们将从这两点入手,分析转型过程中的挑战以及我们应该如何应对。快速响应,减少恢复时间要让恢复时间尽可能短,首先我们要保证流量切换过程中的流量规模在前期出现问题的时候尽量小,即即,需要一个相对合理的灰度渐变方案。其次,当出现问题时,我们需要能够第一时间切换回原来的系统,以免反应太慢而造成大量的增量问题,即我们需要一个响应迅速、高效的切换回滚方案。由于转换过程中涉及到的接口和消息消费入口较多,后期还需要考虑到可能耗时的排查问题和快速定位。根据灰度梯度的合理制定,根据业务特点,我们选择了初期相对冷门的城市(订单量少),对各产能标准业务进行逻辑验证。经过标准产品的验证,表明我们新迁移实现的逻辑与原系统是一致的。然后我们拉取当前的订单城市分布,根据城市订单分布的比例制定灰度梯度,由小到大逐渐递增。为了高效响应切回,我们应该有一个通用开关来控制流量,切回应该是一键控制的。为了快速排除故障,灰度列表生命周期内的操作可以在单个应用程序内自关闭,这样就不需要确认灰度列表的某个状态是去原系统服务还是去新的系统服务故障排除时的系统服务。另外,我们也希望写操作的灰度和查询的灰度可以分开。当写入的数据完全一致时,我们会开放新数据的灰度,新的接口查询,将风险降到最低。因此,我们采用了如下老系统服务代理方案:如上图所示,订单系统在创建订单时,根据既定的灰色计划,读取配置并标记订单。灰色方案分为预标注产品、门店维度验证,后期会根据城市的订单配送维度进行配置。如果新系统服务出现问题,可以一键切断灰度流量,止住增量出血的问题。然后,原始交付旧服务标识标记由代理转发。如果订单没有迁移标记,则按原流程操作处理,否则转发到新的配送中心进行新的业务操作处理。对应的消息监控流程也参考了订单标记,保证了同一个订单的发送流程可以在一个应用中完成,有利于后处理流量上来后快速定位问题。另外,我们的界面灰度处理是写和校验分开的。整个迁移过程大致分为三个阶段,如下图所示:第一阶段为灰度写入阶段,灰度策略:餐厅维度、城市维度小规模灰度读取流量以旧服务为准,出现问题及时切断灰度写流量,逻辑回滚到老服务。第二阶段为灰度查询阶段。灰度标注流量以新业务为准,非灰度标注流量以旧业务为准。灰度策略:每个查询界面按百分比逐渐增加灰度比例。第三阶段是迁移阶段。读写灰度完成。原系统的旧服务只是一层代理。接下来就是将上游系统迁移到新服务上,去除对原系统服务的依赖,完成迁移。尽最大努力降低失败的风险。平均故障间隔是后验持续时间数据。为了使间隔尽可能长,需要每天进行发布控制、风险检查和持续监控。1.在发布控制过渡期间,新的系统服务必须遵循发布sop。饥饿农场的sop发布已经达成共识。我们只要严格遵守即可,这里不再赘述。2.风险检查系统逻辑检查,多人多次codereview。所有主要场景自动化用例在变更发布前均已通过。定期压力测试。3.对部署机器、缓存集群、消息队列、数据库表等基础资源进行多级持续监控和对标。业务曲线成功率、日环比、周环比、曲线波动率,监控主接口入口流量到下游出口流量的转化率。业务系统成熟后,还需要监控各项服务响应时间指标。系统中很多情况下,重试都是基于异常中断,这必然会给系统的异常点带来很多噪音。为此,我们还需要细化对每个中断异常的管理,排除不必要的干扰。一致性问题在改造的过程中,我们实际上是在优化和迁移数据模型的同时进行的。为了保证新旧系统行为属性的一致性,我们还面临以下挑战:灰度数据需要在新旧配送系统数据库表中进行双写,如何保证底层的一致性双方的数据?底层数据的一致性并不代表对外服务接口的数据是一致的。如何保证双边服务应用层数据的一致性?如何保证订单的Apollofulfillmentline与交付的上下游数据的最终一致性以及如何验证?没有其他方法可以确保一致性,只能通过比较。但是在做比对的时候还要考虑到,比对本身只是我们验证迁移系统正确性和稳定性的一部分,属于绕过,并不是生产环境必须的功能。也就是我们要考虑这部分功能对现有系统可能造??成的压力。这部分压力应在系统校验完成后进行切换,并根据系统性能随时调整压力。不需要因为验证就把生产应用拖下来。所以,我们对比的基本要求是:一键开关机,可监控可追溯。除了这些共性之外,还应该具体做以下几点:对于底层数据的比对:比对是准实时的,比如只比对30分钟前的数据。比对数据是基于时间段采样的,比如只比对10分钟内产生的数据。为便于控制,可根据情况适时调整上述策略。即可以调整准实时偏置,也可以调整分段采样窗口的大小。具体实现方案如下:对于应用层数据比对:代理层收到请求后,比对是异步的,不影响接口响应的耗时。比较粒度更小,应该细化到接口。识别灰度数据,只做有效比较。具体实施方案如下:无论是数据层面还是接口层面的比较不一致,都应该立即分析不一致的原因。解决根本原因,逐步降低噪音,直到比较差异在可接受的范围内。上下游数据最终一致性:检查全量数据的骨干链路最终一致性。经过数据的准实时比对和接口的实时异步比对,基本可以确认新旧系统的能力和行为属性的对等。但稳定比什么都重要,需要t+1数据验证才能100%确定。即从全局数据的角度来看新旧系统转换的影响。这里以中继链路多天成功率为例简单说明。如下图所示,多日单的成功率基本在99.9977%左右。可以认为新旧系统代理切换投放的成功率基本稳定。截至日后撰写本文时,饿了么配送中心已经完成了整个系统的语言转换,100%的流量已经切换到新系统,处于流量的第三阶段交换。结合日常系统维护和需求迭代的实践,我们还需要对以下几个方面进行更深入的思考:逻辑是“Puretranslation”,后期维护过程非常痛苦,所以我们需要多次重构来实现代码层面的和谐。持续监控降噪,不断细化监控粒度,监控是服务稳定的基石。配送中心数据市场的建设,可以从数据层面量化和观察我们的配送质量。数据驱动的数字化运营优化了我们的流程,并从基于数据的思维中改进了我们的服务。该方法论积累了上述所有内容。服务系统的改造和迁移是开发者的理解和认知,项目的稳定落地是开发者常规方法的应用。可以简单地进一步细化为以下方法论:细研,满足业务的客观问题和系统是复杂的,细研的准备是必须的。持续监控,感知系统质量是服务质量衡量的第一步,持续监控才能让性能更稳定。互联网系统服务的平稳过渡、高可用和稳定是没有商量余地的。找到问题的根本原因并加以解决。小问题可能隐藏大错误。认真对待根本原因,review->summary->improve。总结业务再认知。关于认知提升的几点:对于每一个工程师来说,开发高并发、高流量的系统既是挑战也是机遇。始终保持积极的学习态度,提升自己的软素质。在分布式的情况下,承认系统不是绝对100%可靠的,每个环节都必须考虑如果“失败”了怎么办。我们需要根据不同的场景在AP和CP之间做出选择。比如双链路调用保证可靠,异步重试保证顺序最终一致。出了问题,快速恢复是一个永恒的话题。没有“如何”最快,只有“这个”更快。立即恢复准确定位。如何减少这个过程的耗时值得进一步思考。作者信息:李杰,昵称向婷,现任饿了么外卖系统负责人。本文作者:李杰原文链接本文为云栖社区原创内容,未经允许不得转载。