专栏名称: 钱皓频道
从VC视角观察互联网新趋势,分析背后原因与影响的新媒体分析平台,已有80多万互联网从业者与投资人关注
目录
相关文章推荐
胡说成理  ·  鸿蒙生态,“紧耦合”改变了什么? ·  7 小时前  
3D科研绘图  ·  Blender 4.4正式发布! ·  21 小时前  
风动幡动还是心动  ·  英伟达暴跌! ·  2 天前  
国家数据局  ·  地方动态 | 陕西着力推进数据资源高效开发利用 ·  2 天前  
国家数据局  ·  地方动态 | 陕西着力推进数据资源高效开发利用 ·  2 天前  
51好读  ›  专栏  ›  钱皓频道

饿了么:业务井喷时,订单系统架构这样演进

钱皓频道  · 公众号  · 科技自媒体  · 2016-08-25 21:16

正文

本文根据石佳宁在InfoQ举办的2016ArchSummit全球架构师(深圳)峰会上的演讲整理而成。


石佳宁,饿了么后台支撑研发部负责人 ,目前任职于饿了么,现任平台研发中心-后台支撑部门负责人,主要负责饿了么外卖订单、统一客服系统、BD销售以及管理工 具、代理商管理平台等系统的设计和研发工作。


先自我介绍一下,我于2014年加入饿了么,那时正是饿了么飞速发展的起始点。我一直从事后台领域的研发,比如BD系统、客服系统和订单系统,现在专注交易架构相关的工作。


今天要讲的内容主要分为两大部分。第一部分是在高速增长和愈加复杂的交易场景下,饿了么订单的服务架构是如何演进的,究竟是什么支撑我们的发展。


快速增长下的业务场景


具体讲之前,我先介绍一下我们的场景,因为 脱离具体的场景所有架构演进没有任何意义 。上面这两个图表不是饿了么的数据,是第三方分析整个外卖市场的数据图。左边的图表是从2011年开始,整个O2O市场以及外卖的份额逐年增加。2013年和2014年的时候发生了比较大的飞跃,饿了么也是在这个时间段订单量开始猛增。右边的图表是用户注重外卖平台的因素分布。


从图中可以看到,用户很在意配送速度,在意交易的时效性。对于O2O或者饿了么订单,交易的要求比传统电商的高,因为交易一般一两个小时就结束了。在2014年初,饿了么订单量只有日均10万单,到2014年底超过百万,这是一个质的飞跃,10万订单的量级和百万订单的量级的要求非常不一样。在2015年突破了日均300万,到今年5月单日峰值突破500万。


快速发展涉及很多问题。 我们是一家创业公司,业务发展非常快,可能准备不是很充分,比如说监控、日志、告警、框架、消息、数据库,很多基础设施还在建设之中。在这个过程中出现一些问题是在所难免的,对系统的要求不是不能挂、不能出问题,而是出了问题要第一时间能恢复。这是整个系统架构的前提。


服务架构的演进



图中所示是订单的早期架构图,比较简单。 这个架构在2014年的时候支撑了日均10万的订单,是一套很不错的架构,依然在很多系统中完美运行。但是对于后来发展的场景,它已经曝露问题了,比如业务逻辑严重耦合、代码管理很困难,因为数据库都在一起,操作变更很难追溯。


更进一步的是,性能的瓶颈只能是靠服务器去硬抗,从物理架构到逻辑架构,都已经成为业务发展的掣肘了。于是,为了业务的发展,我们做了一些演进的工作。


演进工作的核心就是一个字“拆”,跟“拆”对等的就是分治的思想 。怎么拆分呢?面向服务有很多拆分原则。我将拆分过程中最具帮助和指导性的点罗列了以下几条。

  • 第一是明确的定义。 之前也确实犯了一些错误,为了拆而拆。其实我们需要更明确,什么才算是一个服务?服务一定具有非常独立的技术能力或者业务能力,而且一定意义上能够很抽象。

  • 第二是松耦合。 最基本的松耦合就是Customer的消费不依赖于Provider的某一个特定实现,这样服务器的内部变更不会影响外部消费,消费者可以切换到其他服务能力的提供方,这是最基本的松耦合。还有时间上的松耦合或者位置上的松耦合,我们希望的松耦合是消费方和服务方是可以分离的。

  • 第三是基于领域的认知,这对于整个产品起到非常大的作用。 因为当时整个饿了么所有系统是在一起的,基于领域的认知,在面向用户的维度和面向商户的维度做了切分,还有基于交易链路做了切分。

  • 第四是单一职责和关注分离。 简单说,我们希望一个服务或者一个模块拥有单一的能力,而不是承担过多的职责,否则责任不清晰,导致能力也不清晰。

  • 最后一点是可被验证的结果。 在订单拆分的过程中我们犯了一些错误,当时认为这样拆分是没有问题的,但是过一、两个月,并没有带来效率和能力的提升,反而是跨团队的要求越来越多,能力要求也越来越多。这时候可能是拆错了。如果是一个好的拆分一定有利于发展,拆分之后的发展是更迅速的。

基于这几条原则,我们对饿了么的整体服务做拆分之后,如上图所示,架构就有了一些变化,看起来跟刚才架构区别不大。把Order Service做了分离。当时拆分虽然比较垂直,但是用户、商户、金融、订单等还是有一些横向交互。

一个接口有一个非常明确的Owner,一个表、一个库也能保证仅有单一的操作方,让我感受比较直接的是,为服务的治理奠定了基础,以后可以针对某项特定业务做一些降级、熔断,以及单独的监控。拆分实际上是让各自模块的掌控力变得更强了,对业务起到更好的支撑作用。

这时每个部门或者每个团队都负责自己独立的领域,代码和数据都拆分完毕是不是就可以了?但是后来发现好像还不对。因为虽然大的领域上确实已经干净了,但是在小的领域上依然问题很多,订单并不仅仅只有一张表,一个单一的模块,其实还有很多复杂的内容。

在一些技术工作上,这些问题曝露得并不是那么明显,那时候大家对于一些领域认知或者业务边界的认识还是模糊的,没有人界定这些。但是当更进一步地去发展一个领域的时候,还是会有职责不清晰或者能力模糊的地方。我们思考,还要基于业务进行更细腻的规划。

于是我们把订单本身做了一些业务层次的拆分,拆分之前首先要确认订单到底在整个系统中,尤其是交易系统、O2O系统中承担什么角色,担负什么职责。

在这个思考过程中,我们的认知大概是以下四点。

第一,订单是整个交易链路的核心 ,围绕了一些相关服务,比如金额计算服务、催单服务、售中异常服务等,我们希望这些服务之间有明确的区别。

第二,订单实时处理是整个链路的中心 ,我们将这个过程定义得尽量简洁。一笔交易中,订单被推进得越复杂,说明系统设计得越复杂,出问题的概率也会越高。所以我们希望订单核心流程非常简单、轻薄,把复杂的东西剥离出来,把简单和复杂明确成两个部分。

第三, 考虑到交易的时效性和异常场景越来越复杂, 将交易分成正向交易流程和逆向交易流程两个部分 。正向交易流程,99%的订单会根据这个流程走完生命周期;逆向交易流程,比如说退单要求时效性比较低,处理会牵扯多方业务可能很复杂,所以通过一个逆向的交易流程来解决。

第四,能够在功能和业务上独立的部分,尽可能抽象为单独的模块或服务 。简单来说,比如催单的服务,它其实对交易链路无法起到推进作用,它只是一个动作或者附带服务,我们把它单独抽象出来,为后面的发展做出铺垫。

基于这些之后,我们对订单进行完整的认知,对订单的服务架构和业务架构做成图中的样子,大概是三层。下面一层是基本数据;中间层是正向逆向的流程、最核心的状态和最关联的交易链上耦合的服务;上层是用户服务、商户服务,包括跟交易链相关的,比如饿了么最近推出的“准时达”的服务。

我们同时对其他服务模块也做了演进。一些是之前设计的不合理,如图所示是当时缓存服务的逻辑架构,节点比较多。简单解释一下最初的做法: 提交订单的时候清除缓存,获取订单的时候如果没有缓存的话,会通过消息机制来更新缓存。中间还有一个Replicator,起到重复合并的作用。

后来我们发现,本来可以轻量级实现的内容,但是用了相对复杂的实现,链路长,组件多,受网络影响非常大。一旦一个节点缓存数据不一致,感知会比较困难,尤其是业务体量大的时候。

业务体量小的时候同时处理的量并不多,问题曝露并不明显,但是体量变大的时候,这个设计立刻带来很多困扰。所以我们对缓存做了简化,就是把不必要的内容砍掉,做一个最基本的缓存服务。

这是一个最基本的缓存的套路,在数据库更精准的情况下更新缓存,如果从DB获取不到就从缓存获取。这个架构虽然简单了,但是效率比之前高很多,之前数据库和缓存之间延迟在200毫秒左右,而这个简单实现延迟控制在10毫秒以内。

之前订单最大的瓶颈是在数据库,我们主要做了DAL中间层组件。图中这个中间件对我们影响非常大,日均300万单的时候数据库量比较大,引入DAL中间件做什么呢?有几个作用:数据库管理和负载均衡以及读写分离,水平分表对用户和商户两个维度做评估,为用户存储至少半年以上的数据。解决了数据库的瓶颈,系统整体负载能力提升了很多。







请到「今天看啥」查看全文