2016年5月28日,华为开发者汇南京站在安德门黑马路演中心圆满落幕。本次沙龙议题增加到六个,时间安排上也从之前的半天扩展到全天。讲师有来自华为、苏宁、途牛的多位好手,议题涵盖”通讯即服务“、”内源开发“、”探索性测试“、”容器技术”、“电商平台迁移”、“订单架构优化”。
来自途牛网订单研发中心副总经理高建给大家带来的是《途牛价格中心的架构》。一开始笔者以为他只是要说IT架构,听到一半才发现高建的厉害之处 —— 他很熟悉业务!
高建从旅游行业的定价特点、价格中心的计算方法、价格中心的实时计算与存储架构等方面给大家上了一堂生动的“旅游行业线上业务架构”课程。通过这个议题,我们也能看出:作为一个技术人员,对业务的理解程度是可以决定自己今后职业高度的。
现场实录:
大家好,我叫高建,非常高兴能跟大家做一个分享。我来自途牛,在途牛待了六年,基本途牛80%的系统我都接触过,都有带过团队做过开发。今天主要给大家介绍途牛的价格中心,这个是针对一个具体问题的说明或者是分享,可能会讲的比较细一点,所以有任何问题我们随时交流。
其实每个电商系统都会有价格中心,但是途牛作为一个旅游电商,它的价格中心还是有一些特点的。首先我们看一下旅游行业价格中心有一些怎样的特点?这是一个去马代的线路,首先一个产品会有团期的概念,可能有6月份、7月份、8月份,有三个月或者六个月的团期,每个团期会有一个价格。这里的价格也是不固定的,会有很多的因素影响。比如去马代,马代的产品是由酒店和机票组成的,机票又有ABC三个选项,酒店又有豪华房、海景房,不同房间的选项,这些因素的变化都会引起界面上显示的价格的变化。现在价格中心最重要的任务是让客户能够准确的看到上面的促销价,以及每一个团期的最低价,让用户更加准确。不然的话用户在上面订了一个产品一千块,等他下单的时候变成九百块,这时候他就会非常郁闷,一定会引起投诉,我们价格中心主要是解决这个问题。
旅游很大的趋势就是碎片化,比如我们的资源包括这么多,最重要的就是机票和酒店,慢慢的也会有门票、签证、保险,跟团是一个打包资源,最近我们又加了一些新的资源,比如像通信、领队、火车票等等。碎片化越来越严重,也就是说用户在旅游的时候选择的资源会越来越丰富。不像以前我整体打包一个给你,你就去海南,跟团去玩就好了,现在用户需求越来越多,这是我们面临的问题。
资源越多,价格计算也就越复杂。这是我们价格中心所要计算的价格,首先是产品起价,在线上每一个产品如果在列表上面最后都有一个产品起价,这是所有团期当中最低的价格。这个起价也包括促销前的价格和促销后的价格,一般我们会呈现促销后的价格。这是团期起价,每一个团期会有不同的价格。我们设计的这个价格还会有成本起价,举个简单的例子,我们有一个金陵酒店的总统套房,总统套房可能会从多个供应商当中采购,每个供应商给出的价格也会不一样,我们做售卖的时候对于用户来说会选择一个价格最低的供应商的资源进行售卖,这也是我们要去计算的。
这个采购定调价是今年刚刚在做的一个大的项目,对价格中心的改造。同一个资源是为了支持它更多渠道的售卖。举个简单的例子,假如说我们采购酒店,在官网上卖八百块,但是在京东上可能卖九百块,在分销渠道商可能卖八百五十块。我们会针对某一个采购来的批次,在不同的渠道、不同的售卖维度上,去设定不同的加价规则。这个规则引入进来以后,对同一个资源就引入了非常海量的售卖价。这个加价规则我们一共会有七个维度,组合起来对同一个资源就最高可能会有几万个价格,这个对我们来说也是一个非常大的挑战。因为采购定调价,我们价格中心数据量快增加了接近一百倍,大概是这样的一个数据规模。
最后一个是促销价,每一个团期还会有不同的促销方案,不同的促销方案会带来不同的促销价。前面我们主要是给大家介绍一下整个价格中心所要计算的价格到底是什么,从整体上来看最基本的首先是一个团期的最低价,有促销前和促销后的价格,还有每个团期本身的价格,以及一些团期当中资源的成本价等等,这些都是我们要计算的一些东西。接下来了解这些东西之后,我们就要看一看这个价格中心实时计算的规模,以及存储的规模。
现在大概是这样一个情况,最左侧会有一些数据库的依赖,我们依赖了大概45台数据库,这块现在主要还是外期的数据库,比如像库存的数据库,或者产品的数据库。现在为了提升读取的速度,我们现在直接读取别人的同步,采用这种方式做的。一开始也考虑到直接通过http接口访问,但是毕竟http还要比直接读取数据库要慢一些。所以后来我们直接去读取其他系统的同步。中间会有两台接口服务器,以及八台计算服务器。接口服务器主要是提供外系统查询最低价的服务,还有一些计算服务器。计算服务器主要就是当一些资源发生变化的时候,会触发一些计算,以及我们会对一些产品做全面的价格计算,都是在这些服务器上。现在我们是14台的MySQL的存储服务器,去存刚才提到的一些价格,比如说成本价啊,报价,原价,售价,促销后的价格等等,大概是这样一个,这是服务器的情况。
这是我们的计算规模,我们是从2014年8月开始价格中心的运行。到4月份平均每天被计算的次数达到八千万,团期每天被计算的次数基本达到十三亿。我们现在有的团期数是3.5亿,每个团期每天会被计算三到四次,大概是这样的一个规模。从这个数据上来看,价格中心在途牛内部系统当中是被称作数据量与计算量最大的一个系统。现在说实话也面临一些问题,我们在不断的改善。
这是促销价平均被计算的次数,我们在2016年初的时候做了一些降级处理。原先的时候,每个渠道已上线、未上线的产品都做计算,但是到今年年初算不过来了,计算服务器压力太大,后面我们做了一些降级处理,就是未上线的产品我们不参与计算,只去计算上线的产品,所以有了一些降幅。但是现在慢慢的又增长起来,我们后续还会继续做一些优化。
这是我们的存储规模,左侧会有报价库和采购库,我们也都做了一些分库分表的操作,中间是产品库和资源库。产品库和资源库我们是采用一主多从,中间的产品和资源库因为价格中心的读取量、计算量实在太大了,产品系统跟资源系统也是不堪其扰,非常郁闷。一开始我们价格中心读取数据读取的太多了,经常被读挂了。所以我们就采用了一主多从,不停的给产品系统和资源系统加很多很多从步,并且通过一些路由的策略,平均把产品数据和资源的报价数据等等读取的操作,平均达到每一个从步上面去,来减少一些负载。现在基本上是产品库一主三从,资源库一主四从,基本还能够保证不被我们爬挂,大概是这样一个情况。最后这一块是价格库,价格库我们也做了分库分表,分成了1024份。
前面主要还是属于介绍性的内容,主要是讲了我们价格中心实时计算的类型,存储规模。这边主要介绍一下我们在价格中心不断迭代过程当中的一些优化的点,这个里面应该还是会有蛮多实战性的东西。我们价格中心从2014年8月份到现在大概有四个版本的迭代,我们从一开始的时候也没有太多经验,可以从左到右分别讲一下。一开始基本是所谓的同步架构,我们主要通过http接口去资源系统当中抓取资源的最低价,从产品系统当中抓取它的加价规则,等等这样一些方式。说实话通过http接口的话,它的性能损耗是比较大的,并且也是串性的计算,复杂度也会比较高。一个产品有N个团期的话,我们采用便利的方式,这个方式也会有一些问题。带来的问题是ON的复杂度,每算一个产品的最低价的时候,它的性能消耗会比较大。
基本到第二个版本异步架构的时候,这里面我们做了一些改进。第一个我们启用MQ去异步触发。原先基本是全量,不停的全量去计算。到了第二个版本通过MQ去异步触发。比如说一个酒店房型的成本价被供应商编辑了,或者一个机票的价格被供应商编辑了,这时候触发一条消息,把这个酒店所关联的所有的产品价格都要更新一下。这时候他通过一条消息发到我们价格中心,这时候价格中心开始做计算了。第二块我们把它改成了,直接从依赖库抓数据,而不是通过http接口。引入半步计算,串性计算,这里的半步计算主要还是我们在算价格的时候分成了两步,先算资源的成本价,先把资源的成本价算出来存储在那个地方。原先的地方因为资源的成本价是不存储的,算过了就丢掉了,会引起一些性能的浪费。这时候还是串性计算,对于成本报价这种数据基本是OE的复杂度。我们把从数组的存储,从哈希改成存储,这部分稍微提升了一些性能。所以整个异步价格概括起来就是MQ出发,依赖库抓数据,半步计算,这样基本我们的性能有了翻倍的提升。
到第三个版本的迭代,我们主要引入了第一个是分库分表,图形分离。分库分表主要是把我们报价库拆成1024份,它的存储是大大提升了。第二个是冷热分离,我们做全量计算的话,对产品来说它的访问量也是有多有少。比如有些热门产品一天到晚被访问,用户很喜欢被预定,这时候我们需要确保这些产品价格的稳定性。我们也通过产品每天的PB的访问量,去给每条产品打一个标记。对热产品我们是每隔多长时间,比如每隔15分钟全量计算一遍。但是对于冷的产品来说可能就不计算了。当用户有访问的时候我们才去计算,这种虽然慢一点,但基本上用户还能计算,基本是这样一个冷热模型。
第四个我们采用了一些三维内存模型,我们在构造产品起价计算的时候,通过三维模型,其实就是构造一个数,能够很方便、很快速的抓取到产品的各项资源数据,能够提升它的一些计算速度,在多行程和多资源的时候降低了一些复杂性。基本在第三版本的时候我们从业务上引入了一个多行程的概念。一个产品可能会分成多个行程,在旅游早期,比如在2015年之前,其实一个产品只有一个行程,但是随着自有产品越来越多,一个产品会有多个行程。举个例子,我们去港澳游,比如说南京先飞香港是一个行程,香港到澳门又是第二个行程,可能澳门还会有继续的行程,可能会有多个行程。这种增加行程的概念对我们价格中心也是增加了一个维度的计算,原先只有一个行程,变成两个行程的话,这时候他的价格,计算的复杂度会乘以2。在这种多行程、多资源的情况下,通过三维内存模型,也有效的降低了它的复杂度。
这时候我们有了并发计算,因为一个产品可能会有多个行程,每个行程下面会有不同的资源组成,每个资源在不同团期的报价我们是把它作为一个最低的计算单元。这时候同一个产品下面,如果说有多个资源报价的时候,这时候会去做并发的计算,有效的提升一些性能,所以整个并发架构主要是这些改进。
我们现在所谓的叫分布式架构,主要的改动点在第二、第三点。第四点现在没有太好的应用。第二点主要是采用MQ的方式降压,简单来讲,因为外部可能会有非常多的数据请求进来,比如要求我们重新计算价格。原先我们是一个数据提供者,多个数据消费者。因为他要取数据消费的时候,有时候可能会存在大家都去取到同一条数据计算,这样会浪费一些性能。我们在MQ通过一些锁机制,确保同一个产品的最低价同时只能够被一个消费者消费,通过一些锁机制的设定,可以确保一对一的计算,也可以做一些压力的降低。
第三点主要是分布式的内存存储,分布式内存存储是怎么样一个应用场景呢。比如说产品资源的价格做一些变更的时候,我们现在主要是通过定时的抓从步的数据,知道变更了,应该说它是一个变动式的计算。我们怎么去更加实时的做这个计算,我们是希望在资源变价的时候,它的某一个资源价格变更了,我们就可以直接把数据通过MySQL(23:02)的方式,去读取MySQL(23:07)的方式,把这个变更的数据抓取到。抓取之后我们再去实时的对资源所在的产品进行价格变更。这块主要是把底层数据的变更,通过MySQL(23:32)解析的方式知道它的变更,知道变更之后能够更加及时的做一些数据计算,主要是这样一个过程。
第四个NoSQL的存储我们现在没有太多的用。这就是我们整个架构中心四步架构的优化,大概是这样的一些点。
这个主要是三维数据模型,就不详细讲了。
这个是我们的实时并发计算,我们在内存当中构造了一个数,每一个产品可能有多个行程,行程1、行程2。一个行程下面资源也有不同的组合方式,每个资源下面有团期,应该说每一个R就是我们的最小计算单元。我们通过并发会有一个行程池管理这些计算单元,做一些并发计算。
还有最后五分钟,我简单介绍一下,这是我们整体的架构。前面讲了这么多,从整体上看可以分成左边和右边,上面是一些外部系统的数据库,我们有一层适配器,这块我们现在还做的比较弱,但是未来我们会不断的加强,主要是做一些留空的策略,这些外部系统如果有资源变价的话,会直接进到我们的MTO里面。MTO首先会做每个资源的成本计算,做完之后会通过下面的分发节点,路由到不同的MTO当中去,做串性的计算,在串性的节点当中顺序的把每一个产品取出来,最后做一些数据存储。大概整个是这样一个架构。
这块跟前面差不多,我就不详细讲了,高并发场景下的问题及其解决办法,这个是一些我们在过程当中遇到的问题,我简单讲一下。我们途牛在2015年之前还是南北机房的问题,我们在南京有一个机房,在北京有一个机房,价格中心最多的还是在给北京机房的比如说网站、APP系统提供服务,所以在这个里面会导致带宽被占的问题。比如北京的请求量非常大的时候,后续很多价格数据,这时候南北京带宽被占满了。这个在当时也是蛮难的问题,也就是因为这个问题,我们在2015年初的时候决定把南北京机房合并了,是在2015年8月份,现在我们途牛所有的机器都在南京机房里面。
在当时的情况下,也就是做冷热分离,对于冷数据可能是只有被访问的时候才会被计算,热数据是定时批量的计算。第二个是并发查询,更新时连接不够用。刚才我们看到的图当中有一个并发计算单元,一个产品下面会挂很多资源,在资源数比较少的时候还OK。但是在一个产品上面,如果挂的资源数超过10个,甚至15个的时候,它对依赖库,可能瞬间的把依赖库连接数给占满了。这时候可能就导致其他的一些计算很难进行,就被等待。这时候我们做了一个连接数的控制,就把每一个并发计算单元所拥有的连接数控制在4个,能够让单个计算的稍微慢一点,但是你不要影响别人,大概是这样的情况。
其他我们也做了一些实时分析、离线分析等工作,这个就不详细介绍了。
今天基本演讲就到这边,大家有没有什么问题。
提问:我来问一个问题,你们家的数据选用的是MySQL,一般数据库要么选的是甲骨文,一般选的是(29:47),你们家选用的是MySQL,我想请你介绍一下MySQL的优点和缺点,甲骨文有什么缺点?
嘉宾:MySQL一般基本都是开源的数据库,首先MySQL是开源的,对于构建成本来说,因为一开始基本互联网公司都没钱,成本会低一点,一个甲骨文动辄几十万,甚至上百万,我们是买不起的,这是第一点。第二个,MySQL上面非常灵活,它的数据同步,主从同步的机制,可以让我们很快速的横向的扩展我们的应用。但是说实话甲骨文我没有非常深入的应用,所以这块你说甲骨文有什么缺点,我没有办法回答你。
提问:我想问一下比如你们是做旅游的,以前听说南北机房是分开的,你们现在做了一个整合,如果在某个时段,马上快暑假了,七日游肯定会很多,或者自驾游。如果大量的涌入时段,你做了促销,大量的数据进行访问服务器的话,你那边有没有方式保证你那个服务器是正常的,或者说到一个时候会有一些瘫痪或者怎么样。
嘉宾:这是每家电商公司都必须有的技能,刚才苏宁的同事也讲了很多,我们其实跟他们也差不多。首先会有流控,前端会有流量控制,最简单的例子,你的IP不可能同时一分钟访问多少次,如果访问多少次我就把你限流了,就要求你输入验证码,这是第一块。第二块像后端的缓存,基本上互联网公司都是读多写少,所以基本所有的页面,商品页,首页等等,这些都是放在缓存里面的,这个缓存当然也会有分级,有大的缓存和小的缓存,应该说大的页面的缓存,小的数据的缓存。后端还会有一些分布式的服务去提供给这些缓存,当它失效的时候来用。这个要讲起来是蛮复杂的。
提问:我想问一下你们这边有没有遇到,比如我们把平时的业务数据从业务系统里面抽出来,抽到大数据,做OLAP之后,再重新放出来做存储MPP的模式,这种场景。
嘉宾:会。
提问:这种时候我们在数据,惯性数据出来之后,做了OLAP,再重新做MPP的话,MPP这块是用什么技术。
嘉宾:您说的MPP是什么?
提问:大规模并发网络,比如说我们重新把这个业务开放。
嘉宾:我了解。举个例子,我们途牛产品的排序其实就是通过这种方式做的,比如说产品的排序说实话是一个很复杂的规则,它需要算每一个产品的权重,这个权重又是通过很大量的数据,比如说可能是用户的点评,或者是每天被访问的次数,等等很多很多的维度数据一起算出来的。这时候的数据我们就是把它抽取出来,通过OLP的方式把它分析出来。最终我们会通过OLP,其实就是输出一张数据表,比如每个产品会对应它的一个权重的最终值。输出这样一张数据表之后,当然前端会有构建一些服务了,这个可能和一些普通的高并发的应用差不多。比如首先是主从,一主多从,去增强数据库的并发量,前端可能也会有多个实例,去承载更多的并发量,大概是这样的一种情况。
提问:我们这边MPP本身也是SQL兼容的,还是有专门的?
嘉宾:我们就是SQL兼容的,我们就是直接输出一些数据。
提问:直接输出到那个库里面。
嘉宾:对。
提问:高老师,看了你的分享之后,发现价格计算这块也挺复杂的。因为这个业务逻辑复杂,引入了很多制度性的东西,采用很多制度手段,但是这样从制度的角度出发,感觉太复杂化了。现在随着云计算、云存储这些东西的成熟之后,是不是里面优化的东西可以去掉,这样就直接一点,我就关心我的业务逻辑,没考虑导致后面的服务不方面吗,投入这么大。
嘉宾:你说考虑往云上面迁移。
提问:现在很多问题是不是没有那么复杂。
嘉宾:首先是业务逻辑的复杂性,因为旅游行业确实没办法降低。我们确实在目前价格中心,资源这块是蛮大的瓶颈,比如计算资源和存储资源这一块。比如说云计算能够帮我们动态的扩容,我们也可以考虑往这方面做一些迁移。但是目前我们在途牛主要还是考虑私有云的方案。
提问:现在不是好多大公司都在推云计算吗,我自己没有亲身的感受,但是这块目前的性能来看还是达不到你刚才说的要求吗,现在是一个阶段。
嘉宾:能不能达到要求还是要看具体的情况。
提问:宽带啊,存储啊,我现在听到的、感受到的都有大的发展。我一直觉得把业务逻辑,把技术的东西搞的太复杂了,我想简单,就关心业务。
嘉宾:所以这块确实是可以考虑往云上面迁移,因为云的弹性对我们来说是非常非常大,现在我们途牛也在构建自己的私有云。
提问:两个问题。第一个,我想问一下途牛有没有什么软件、工具可以开源出来,有这个计划。第二个,有没有类似开放平台这样子的,可以支持其他更扩大一个生态圈的计划。
嘉宾:第一个开源是实话我们暂时还没有,我们内部有在做一些项目了,但是还没有最终开源出来,后面也是一个方向。第二个,是否有一些开放平台,我们有,这个可能没有大规模的宣传,主要是在供应链这一块,我们有一些开放的API可以支持,比如让我们的供应商把产品、订单这样一些数据接入到我们的系统当中去。最近也在做所谓的叫低类,就是自己生产的一些系统,这样的一些系统就是你说的能够把它产品订单都能够开放出去的平台,这个应该也是我们2016年、2017年这两年的战略重点。
主持人:因为时间的关系,我们先问答到这边,掌声谢谢高老师。
==========================
价格的数据量:分库分表
售价=基础价+营销策略
售价+日期=起价
起价的大量计算,MQ
=========================
1.统一数据访问入口;
2.价格的更新问题,MQ+redis+数据库;
3.价格查询计算服务:基础价+营销策略的大量计算;
4.起价:MQ后计算,存于数据或缓存中,不需要准确;
5.营销策略的复杂度:过滤器+规则+优先级。
6.价格的数据量问题:分库分表,按商品,当日以前的日期数据清理或归档。