2018 年初,大麦决定将电商体系整体融入阿里电商平台,到目前大麦基于阿里共享电商平台体系的商品占比 89%,交易占比超过 90%,全部热门项目抢票已经在跑在这个链路上,在这个时间点来从技术角度回顾一下整个变迁的过程。“星环”是阿里的共享平台接入不同业务方的产品技术体系,大麦的融入也正是基于星环的能力。
一、背景
首先来看下在项目启动之前的一些背景情况,主要是当时大麦交易所处的一个状态,以及我们为什么选择去做这件事情。
2017 年底,大麦主交易流程已经迁移到集团内,在交易核心链路上替换了大麦原有的技术体系,大大的提升了交易体系稳定性。上线后,交易方面以及大型抢票再也没有出现过 P2 及以上的故障了。但是从产品技术看来依然存在很多问题:
若干依赖服务(尤其是商品、库存)依然在大麦机房,是重大的稳定性隐患
交易容量问题,由于商品库存仍然在大麦机房,库存扣减能力比较低,遇到周杰伦演唱会这样的大型抢票,存在大量限流,用户体验很差
与共享电商体系互相独立,无法让大麦借力集团的商业元素
纵观上述几个问题,如果我们让大麦电商整体融入共享电商技术体系,都会迎刃而解。尤其是第三个方面,在大麦面临外部竞争对手逐渐强烈的赶超趋势,如何借力阿里巴巴的商业生态元素来发展,成为大麦战略上的重点。
我们一直相信,大麦电商体系融合到共享电商平台,是一个正确的发展方向。但是在最开始的阶段,大家还是有一些犹豫的。大麦有一些来自飞猪的产品技术同学。飞猪所承载的旅行业务同样是一个和淘宝、天猫差异很大的垂直电商。当时飞猪也没有融入到共享平台,可以看到原因肯定是多个方面,但是之前共享体系还没有足够好的开放能力来容纳差异很大的业务是其中一个重要的原因,其中一个典型的例子是,共享体系是不允许业务方随意外调服务的。
到 2018 年,共享交易已经把平台和业务的边界逐步划分开来,建立了一套平台提供基础能力,业务自行扩展实现差异化逻辑的标准。经过实际调研看到这些进展之后,更加坚定了我们迈出融合这一步的信心。因而在 2018.02 开始,大麦和共享同学正式启动了“候鸟”项目,大麦交易进入一个全新的阶段,整个大麦电商体系也完全进入了一个新的纪元。
二、交易模块化框架 TMF 与星环
基于 TMF 的交易定制
在 2018.02 项目启动的时候,星环尚未完全就绪。大麦业务的差异化定制,主要还是基于交易模块化框架(TMF)在共享交易的各个应用中做定制来实现的。
TMF 的逻辑是,一次请求来到交易,首先识别业务身份,搞明白是谁家的业务,然后在业务流程运行过程中,相应的业务能力扩展点被执行,达到差异化定制的目的。业务身份的识别标准往往会是商品、类目或者其上的一些属性。例如大麦的业务身份,对应的识别标准是,商品上有一个标。
基于 TMF 来定制,以交易下单服务 buy2 为例,我们需要实现一个扩展包,其中的主要内容是:
业务身份识别:大麦基于商品标来识别
扩展点定制:例如大麦定制了资金流走即时到账
buy2 的大概结构是:
入口服务->业务流程(BPM)->业务活动->业务能力->能力扩展点。
大麦针对 buy2 的扩展包,就是针对上述能力扩展点的实现,请求经过业务身份识别确定是大麦业务后,大麦会走到这些相关的扩展点实现。
这里其实会埋下一个伏笔,就是在商品查询出来之前,其实是不知道业务身份的。这个会影响后面监控、问题排查等方面的一些做法。
星环与业务定制
星环是个很大的东西,涵盖了需求沟通机制、业务定制、容器化、质量保障多个方面。全面的知识还是要从星环的文档和与星环团队的沟通中获得。这里只是我们作为大麦一个业务方在使用过程中看到的一些侧面。
TMF 框架本身的开放性,已经能够支撑业务方在共享的体系下实现自己的定制,对想要借力共享体系,但是又有一定差异的业务来说,是非常好的。而后面的星环继承和发展了这种开放性,在我看来主要针对以下几个问题:
TMF 阶段,业务方需要给各个共享应用分别实现定制包
因为上述原因,业务需要清楚的知道共享体系的内部结构
整体运行在一套基础资源上面,不同业务互相之间影响产生的稳定性隐患
星环架构师毗卢讲市面上复杂的 SAAS 系统,背后的物理结构是非常复杂的,而使用者要定制一些逻辑的时候,是不需要理解其背后的物理结构的。星环在扩展方面也肩负着向这个方面演化的使命。在 TMF 时代电商体系每个应用都有一套扩展点,每个业务方需要的话都要为多个共享应用实现扩展包。星环抽象了一个叫做“商业能力”的层次出来,统一全部业务能力的扩展点,最终实现定制方基于一套扩展点来定制一个包,部署到共享各个系统中这样的效果。
具体来说,例如“基础交易”是一个商业能力,他的定制点,包含了商品、交易多个方面,很多扩展点。涉及多个共享应用。商业能力扩展点这一层,包含了上述多个方面的扩展点,业务方通过这个统一的层次提供的语义来扩展,而在其背后,星环的实现层会把原始的业务能力的扩展点,桥接到星环商业能力的扩展点上来。
三、容器化与发布流程
星环里面一个重要的事情是容器化。按照星环网站上的说法,目标是四个:
业务自治:业务方独自完成业务的设计开发、测试和部署运行
业务隔离:业务与 &业务/业务 &平台隔离再不担心业务变更互相影响
业务动态部署:业务方可以在线进行发布和部署,快速响应业务需求
业务快速恢复:业务应用发布上线平台保留历史版本,可在线版本回退
这个事情涉及从系统逻辑结构,到发布方式的一系列变化。从这些变化里面可以了解到“容器”究竟是什么。
ClassLoader 隔离
阿里共享业务平台的应用以 buy2 为例,作为一个大容器,业务方例如大麦的定制包作为一个子应用,就是一个子容器。
每一个子容器都有自己独立的 ClassLoader。这个 classLoader 以平台的 ClassLoader 为 parentClassLoader,同时,自己内部基于配置知晓自己这个业务 APP 的 jar 包在哪里。
我们知道 Tomcat 作为一个容器是违背了双亲委派模型的,优先加载应用的类,从而实现 WEB-INF/lib 以及 WEB-INF/classes 类的优先级更高,而星环的容器没有这样做,依然是原本的双亲委派模型。这样做的结果是:
对于平台已经存在的类,会使用平台公共的实例
对于仅存在于业务 APP 包中的类,平台层找不到,所以会加载业务 APP 中的类
这个方式有优有劣。优点在于尽可能的共用了平台层面所能提供的类定义,可以控制 metaspace 的大小。在另外一个方向上,阿里中间件的 Pandora 隔离容器使用类似 tomcat 的机制以插件的 class 优先,从而做到各插件类路径隔离,从 2017 年开始要求 metaSpace 要配置 512M 了。而且,星环容器所承载的业务方子容器量会远超过 Pandora 所加载的插件量,如果不做这个控制,诸如 commons.lang 下面的类也是一个容器一份,MetaSpace 要的内存简直无法接受。
上述优势从另外一个角度看恰好又成了一个潜在的威胁。各方 APP 所以依赖的一些公共的三方包,甚至集团内提供的二方包,具体在系统启动起来之后使用的版本,是有互相影响的。两个 APP 使用了相同的三方包的场景下,实际上最终平台是按照 maven 的就近原则来打包其中一个到 war 中,于是实际过程中,一个 APP 升级该三方包,也就影响到了另外一个 APP。实际上导致容器隔离不彻底。当然,这只是一个权衡。实际上如果真完全以 Pandora 模式,又会出现平台 export 哪些类给到业务 APP 的细节问题。
独立的 Spring 子容器
Spring 的容器也做了类似上述结构的父子关系,不用担心各个 APP 内的 bean 之间的冲突。一个结果是,子容器里面仅包含业务 APP 中所定义的 bean。那么,类似限流、降级这样的平台层自动代理的一些事情,在子容器里面是没有的。如果你的业务 APP 希望使用到限流、降级,那么你需要在业务 APP 的 spring 文件中引入相关的 bean 定义。
自主热发布
共享应用由于结构、业务及其复杂,发布一次的时间,非常长,这是一个极其痛苦的过程。以 buy2 为例,一次构建几分钟,一次部署要 10 几分钟到半个小时的时间。相比于业务方自己的小应用一次构建加部署 5 分钟以内,这个时间简直长的要命。曾经看沈洵很久之前的 PPT,讲阿里做服务化这个事情,说服务化之前淘宝整体是一个大应用,构建部署一次够出去抽根烟,回来还没完事儿。服务化分拆应用之后,这个事情有了大大的改善。但是整个体系演化到今天,昨日重现了。
基于 classLoader 隔离和 Spring 子容器,整个业务 APP 的热发布成为可能。所谓热发布就是在不停 tomcat 的情况下,把一个业务的变更发布到线上。一次热发布过程大约如下:
应用 offline 当然要首先让流量不再进来
下载更新应用的 jar 包,这个过程使用了目标应用的主干配置项来替换 jar 包中的引用
容器销毁-重建,过程中抛弃了原有的 classLoader 和 spring 子容器,创建了新的实例
应用 online
热发布大大缩短了业务构建部署的时间,基本上一次构建部署 5 分钟内搞定。相比之前每次 war 部署,幸福的像是回到了伊甸园。
实际上平台一次 war 发布经常需要几个小时的时间,这其中固然有分批的因素,但是本身应用构建、启动慢也是一个重要的原因。从稳定行方面来讲,线上发现一个问题,如果改代码、 war 发布,这样的时间加起来几乎足以似的问题变成故障,小故障升级成大故障。有了热发布,腰不酸了,腿不疼了,轻轻松松搞定发布。线上问题发现到改动、恢复时间也大大缩短。但是热发布的逐步完善过程还是很快的,最初有一些限制,后来都逐步优化掉了:
静态配置项变化,不能热发布。目前已经使用了对应变更的配置项得以解决
依赖包变化不能热发布。这个事情曾经想过用 fatjar 来解决,后来已经支持附属 jar 发布,大麦已经在使用
前端交互协议组件奥创的修改不能热发布。这个事情使用新奥创得以解决,大麦 19 年完成了切换
热发布上线后,大麦不能热发的场景,大多数是奥创改动和依赖包改动。现在正在解决依赖包的问题。
目前,业务定制改动后,发布的时候还是要勾选一下要发布的目标系统,例如 buy2。未来的方向应该是业务方不用关心改动发布到共享的什么系统里面去。
独立分组与环境隔离
大麦在 buy2 上划分了独立分组。后面飞猪等业务方也都是用了独立分组。星环目前采用中间件提供的环境隔离方案把业务方的流量隔离到目标独立分组。
首先 buy2 给大麦划分了一个独立机器分组叫做 buy2_damai_host。
然后,大麦的流量通过三种方式路由到大麦独立分组:
nginx 路由,部分流量在公共分组的 nginx 层可以识别到 url 参数或者 Header,然后走到 buy2_damai_host 的 Java
Java 兜底路由,部分流量只能在 buy2host 这个机器分组里面把商品查出来之后,才能识别到是大麦的业务,此时再通过一次 RPC 调用,走到大麦分组
RPC 调用路由,大麦自己的 Java 应用在调用 buy2 的 RPC 服务之前,可以通过设置路由相关的鹰眼标来指定调用到大麦分组
大麦最初采用独立分组是基于物理隔离和降低运维成本的考虑。发展到现在,独立分组这个事情主要看到以下几个点(包括优势和问题):
优势一:独立分组让大麦只关心自己分组的机器,在遇到某些问题的时候,处理起来比较方便。共享应用动辄几千台机器,查个问题需要好久。但是,独立分组大麦也就 100 多个机器,查问题成本完全不是一个水位。
优势二:独立分组让大麦的监控可以只关心大麦分组,这个事情详细在下一小节来描述。
优势三:独立分组带来的物理隔离,让大麦在自己的分组上开启一些特殊的能力不用担心影响别的业务方,具体参考下面的问题排查小节。
优势四:独立分组在平台整体 war 发布的时候,可以自主控制发布节奏。一般来说平台整体的发布因为应用众多,所以分批较多,而且间隔也经常拉的很长,经常跨天。一些需要快速生效的问题修复场景,这个过程慢的让人捉急。独立分组对应在应用发布平台上是一个独立的环境,发布单也是独立的,因而可以在保障稳定的前提下继续发布,提高发布效率。同时独立分组也带来一些困扰,这也是目前大麦和共享同学还在想办法优化的一些事情:
一方面,共享的应用都是单元化的,这个独立分组也要保障多个单元的容量,在单元化流量调整的一些场景下,需要密切的做好沟通,避免特定单元容量不足引发问题。
另外一方面,独立分组还是带来了一定的资源浪费。大麦业务的流量有个特点是大型抢票来的时候(每周几次)流量瞬间很高,而无大型抢票的时候流量低的不好意思说。为了维持大抢容量,独立分组必须有足够的资源配置。
目前大麦仅在 buy2 上做了独立分组,其他几个应用都还没有做。飞猪和新零售做的多一些。
四、监控
监控部分,说三个方面:
系统监控
系统监控说的是 cpu、load、网络这些方面。对于做了独立分组的应用,可以在集团监控平台上针对这个分组配置一个虚拟应用,看起来和其他应用没什么区别,看起来很方便。如果没有独立分组,那么系统监控这个事情,基本上就只能是平台层面关注了。
业务监控
共享的主要应用都会有统一的业务监控以及对应的大盘。但是这些大盘的视角都是平台视角,大麦这样一个小业务放在里面,典型的效果就是下单全部失败,成功率曲线也看不出来明显的下跌。
所以必须做业务线视角的监控和大盘。因而大麦参考共享的监控大盘配置了自己的业务监控。包括渲染量、下单量以及相关的成功率、错误码等方面。
这里面有一个日志数据筛选的事情也经历了一些变化过程。早期,大麦是在日志里面过滤有大麦业务身份的数据,然后基于过滤出的日志内容做监控。后来发现,对于走到业务身份识别逻辑之前就报错了的请求,在这些日志里面是不可能有业务身份数据的。所以就修改成了拿 buy2_damai_host 上的所有数据来做监控。正好环境隔离方案上线后,大麦分组不再会有别的业务的流量,所以这样做是完备的。
可以看出来,上述逻辑严重依赖独立分组。没有独立分组的业务或者应用,会存在一个问题,代码走到业务身份识别之前出现的问题,是很难做到业务方独立的监控里面的。
另外一个实践是,对于大麦这样一个小业务,平时的请求量非常低。以渲染为例,平时 1 分钟也就几十个请求。渲染失败的原因里面,类似库存不足、超过限购数量、相同身份证已经购买过之类的这样的原因,如果都作为请求失败来看的话,成功率的曲线会很难看。基本上跌的很多,真正的线上问题会被淹没。所以大麦在 GOC 监控里面,会把类似库存不足这样的错误码排除出去,从而做到一个基本上维持 100%成功率的曲线。
这样做能够达到曲线跌了一般来说就是真出事儿了。这不是一个完备的方案,但是实践下来证明是有效的。
异常监控
一个应用的异常堆栈日志是应用是否正常的重要表征。有新的异常出现或者某类异常大量飙升的时候,基本上可以判断有问题了。一个好的实践是,系统异常打堆栈,业务异常(例如库存不足)不打堆栈,这样能够让应用的异常量维持一个比较低的水平。大麦技术团队经常会使用鹰眼团队提供的监控产品来看共享应用的异常信息。根据某一类型的异常突增这样的信息来分析判断问题。
五、问题排查工具
技术团队的工作里面,线上杂七杂八的问题的排查工作,一直以来都是重要的组成部分,而通过工具建设来提升问题排查效率也是技术团队一直追求的事情。这个方面大麦以往有一些实践,融入共享之后也在共享的体系下共建了一些能力,这里分享出来。
这里描述的“问题”,一般是指两个方面,一个是用户或者客服、业务同学反馈过来的一些问题场景。例如某某用户具有购买资格但是下单提示不能购买,或者某某订单没有用到一个优惠。另外一个方面是业务监控发现的,例如某一类错误码突增。
问题排查过程要基于已知的这些少量的信息,去追踪还原当时的场景。典型的想法是去机器上找日志。但是这种方式效率比较低,且会把这个工作局限在技术人员身上,无法给到上层。
阿里的鹰眼的业务日志是一个很好的工具,现在大家也经常可以拿着订单号、traceId 来查询一些链路上的日志。但是会有一些局限:一来,没有订单号的场景,例如订单确认页打开失败,这种无从查起;二来,很多时候是没有 traceId 的……
大麦和共享协同建立的天秤业务日志查询工具,能够做到基于自定义的索引来打日志、查询。目前大麦和飞猪用的挺好。
效果
我们做到可以根据一个错误码,查询这个错误码产生的链路日志(利器),根据某一次请求失败的日志详情来判断问题的具体原因。可供查询的日志数据里面实际上包含了 3 个部分的日志:
1)交易下单应用的入口服务和依赖服务的拦截日志,
2)交易下单应用的入口异常日志
3)业务扩展包中自主打的一些日志
业务 APP 可以自主打印一些指定格式的日志。日志内容、索引都是自定义的。配置采集之后即可在一个统一的页面上查询。
怎么实现的
上述日志最终都是通过一个通用的二方包打到磁盘上,然后通过日志采集服务采集投递到了阿里云的日志服务 SLS 里面(需要各业务方自己提供 LogStore,并承担成本)。然后基于 SLS 的能力提供查询。
更进一步
大麦基于上述日志,做了一层格式化和语义转换,把技术人员才能看懂的信息,转换成为非技术同学也能看懂的说法,从而把一部分问题的排查交给了测试乃至业务同学。
六、尾声
大麦通过把整个电商融入阿里共享电商平台,稳定性、性能上都得到了大幅的提升。在产品能力上也自然而然的可以低成本的借助共享的各种基础设施,在这个基础上,大麦的业务也在逐步尝试与淘系共舞。过程中有很多抉择、取舍,这篇文章也是希望从技术过程的角度尝试对一个小业务如何融入大平台做一个分享,希望有类似场景读者,不论是做平台还是做业务,能够有所收获。
作者简介:
阿里文娱高级技术专家 江新
相关链接
评论