陈玉石
摘要:OTA是用户在线差旅平台,一般包含机票、火车票、酒店的预定,具有相当的业务复杂度,对数据的准确性、实时性有很高的要求。各电商或者其他品类的渠道增加这样的产品具有很高的业务复杂度和运营复杂度,为此我们研发了一套组件式在线票务平台,标准化了用户鉴权模式、支付模式和订单模式[1],既支持以H5或PCWEB的方式和第三方对接,也支持以接口的方式和渠道侧对接,大大丰富了渠道侧的产品能力和运营能力。
1、平台架构
在线票务平台分为用户面、管理面和运营面,三面隔离。用户面为渠道侧客户的Portal,管理面为渠道侧管理Portal,运营面为平台运营Portal。用户面接入的Portal分为H5和PCWeb类型,前端采用vuemint轻量级框架。用户面的Portal分为机票预定前端FlightPortal、火车票预定前端TrainPortal、酒店预定前端HotelPortal,分别对应不同的二级域名;渠道侧前端CustomerPortal,运营前端OperatorPortal,也分别对应不同的二级域名以及鉴权方式。
编排层包含用户面机票编排层、用户面火车票编排层、用户面酒店编排层,用户面的三个编排层彼此独立,不能互相调用,只能由前端发起编排层的调用。渠道侧编排层和运营面的编排层也彼此独立,不能相互访问。
从前端到编排层经过网关鉴权,下文有对鉴权的叙述。编排层下是各个原子层服务,包含机票查询服务FlightQueryService、机票标准数据查询服务FlightFIQueryService、机票OTA查询服务FlightOTAQueryService、机票自有数据查询服务FlightCrawlerQueryService等,火车票的原子层服务包含火车票查询服务TrainQueryService、火车OTA查询服务TrainOTAQueryService、火车票自有数据查询服务TrainCrawlerQueryService等;酒店查询服务包含HotelQueryService,酒店OTA查询服务HotelOTAQueryService,酒店自有数据查询服务HotelCrawlerQueryService。订单模块包含机票订单服务FlightOrderService、火车票订单服务TrainOrderService、酒店订单服务HotelOrderService;标准订单原子服务OrderService,订单服务既支持正向订单也支持逆向订单。
平台还包含网关鉴权服务AuthService,各个业务的边缘服务FlightEdgeService、TrainEdgeService、HotelEdgeService。和财经相关的服务包含商品服务ProductService,合同结构化服务ContractService,结算服务SettleService,自有数据模块对接各个平台的数据服务接口,统一整合后存储到NoSQL数据库中,商品、订单等服务采用关系型SQL数据库,各个原子服务彼此不能互相调用,通过编排层统一调用或通过MQ实现数据状态的一致性。
前端所有的操作全部打点,打点的数据内容不包含用户个人数据,打点的数据上报到大数据中心BGC,但是不进行用户的画像。管理面所有的操作日志全部打点,并接受审计,管理面的日志数据存储期限为三年,用户面的日志存储期限为一年。
平台的配置中心服務为ConfigService,ConfigService对接Redis;各个服务的异步通信模块采用MQ(ActiveMQ)进行,前端的查询数据存储于ElasticSearch;所有数据的存储由各个微服务完成,各个查询服务定时同步增量数据到ElasticSearch,前端各个预定模块例如机票、火车票、酒店的数据来源是ElasticSearch,ElasticSearch提供数据并进行集合运算。
2、鉴权设计
平台采用插件的方式对接到渠道侧,需要和渠道侧打通用户登录、支付和订单模块。用户进入渠道侧的APP或者其他前端后,通过授权进入我们的预定页面,鉴权的方式采用Auth2.0[2],每一个进入预定首页的用户都需要进行授权。授权后用户访问预定各票务首页,Portal获取会话的cookie;如果没有获取到cookie,则直接拉起用户的授权页,如果有cookie则校验cookie中的token,token存在有效期,如果过了有效期,依然拉起授权页。
用户的请求将会携带token,网关对token进行解析,Portal不解析token,token的密钥存储于配置中心,解析的结果包含用户相关信息,例如userId、domain,domain对应了渠道名。用户对后台所有的非静态请求都必须基于网关,每次请求都会进行鉴权。渠道侧用户在Auth后,302到网关进行二
次鉴权,网关获取到用户的userId、domain以及token,会再次调用渠道侧提供的接口进行鉴权,鉴权后根据算法生成AuthToken,设置到header中。后台调用接口必须要有该AuthToken,否则将返回失败;AuthToken的有效期是30分钟,30分钟内调用将重新刷新该token,如果调用间隔超过30分钟,将会重新进行鉴权操作。
3、支付模块设计
用户在机票、火车票、酒店前端完成查询并选择好对应的产品后,将创建订单拉起支付,一般来说支付能力由渠道提供,平台也提供支付能力,两种模式的差别主要在于流水和结算,如果渠道需要锁定流水,则渠道提供支付能力,并且和平台进行T+N的结算模式;如果渠道不需要锁定流水,则平台提供支付能力,和渠道进行反向T+N的结算。
支付模块的拉起可以分为拉起原生或H5的支付模块,拉起之前必须要创建订单,首先在平台创建订单,创建成功后调用渠道侧的创单接口,并获取到订单号,由渠道侧的订单号来拉起支付,拉起支付后产生一个支付流水号存入库中,订单完成后进行结算,结算的依据就是订单号、支付流水号。
4、订单模块设计
用户购买机票、火车票、酒店产品会产生订单,如果只在平台产生订单,则渠道侧无法进行支付,也无法感知这一笔交易的存在;如果只在渠道侧产生订单,则平台无法感知这一订单的存在,并且无法进行后期的运营工作。所以一笔订单在平台侧创建后也必须要在渠道侧进行创建,用户提交订单请求后,首先在平台侧创建订单,创建成功后,调用渠道侧创建订单,调用渠道侧的接口的鉴权采用AccessToken模式,token来源于用户登陆后从渠道侧获取的Token,该token需要定时刷新,数据存储在Redis中,设置失效时间,如果失效了则用户提交订单的时候会报错返回授权页;如果没有失效,则刷新token的失效时间。
渠道侧除了提供创单接口,还需要提供取消订单、支付完成、申请退款、退款完成、订单完成等接口。机票、火车票、酒店的预定和普通的电商商品预定有差别,电商商品支付完成后即完成预定流程,但是票务的预定只是占座成功,酒店的预定需要前台确认,因此需要产品提供方二次确认。确认的操作是个异步的过程,时间跨度最长可以是小时级别,所以订单在创建后,仍然需要定时任务调用各个航空公司预定查询接口、火车票预定查询接口、酒店的预定查询接口,如果预定失败,则通过MQ发送失败消息,各个原子层服务订阅MQ消息,并进行相应的处理,既要取消平台侧订单,也需要取消渠道侧订单。
订单支付完成后,需要进行出票的操作,机票、火车票、酒店的出票操作也是异步流程,既有自动化的出票方式,也有人工的出票方式,出票时限由具体的业务性质决定,机票的出票时限是飞机起飞前一个小时,火车票的出票时限是15分钟,酒店的出票时限是1个小时。其中机票的出票存在风险,一般90%以上的票要求30分钟内出完,当机票的出票时长超过1个小时或者临近出发6个小时以内,则进入预警列表,必须要人工介入,否则当乘客到场无票则视为重大事故。
订单的逆向操作即退票操作,是运营最繁重的工作;当用户申请退票后,首先判断是否可以退票,如果可以退票则需要进行确认,因为机票、火车票、酒店存在很复杂的退票规则,根据退票规则会产生手续费,所以必须要用户确认手续费后再进行真正的退票操作。其中退票规则最复杂的是机票,例如CA1580航班退票规则是20-120-50-24-70,代表的含义是如果用户在机票起飞之前120小时退票,则收取机票款的20%的手续费;如果是机票起飞前24小时到120小时内申请退票,则收取机票款的50%的手续费;如果是机票起飞前24小时内含起飞后申请退票,则收取机票款70%的手续费。不同航司不同航班的退票规则区别很大,退票规则也在不断变化,用户在预定的时候就需要把退票规则推送给用户,因此该规则存在履行态和当前态,两者可能不一致,用户的订单以履行态为基准,用户预定的时候以当前态为基准。
当用户确认退票后,则进行计算流程,计算出用户的手续费和应退金额,创建逆向订单,逆向订单必须经过审核流程,客服审核后确认退款,则需要进行两次调用,一次是调用票务方的退票接口,例如各个航司的退票接口,火车票平台的退票接口,酒店平台的退票接口;然后启用定时任务查询退票的状态,查询到退票成功后调用渠道侧的逆向订单接口,渠道侧的逆向订单接口完成最终的为用户退款操作;如果平台侧收款,则退款操作由平台侧完成。
就票务订单而言可能存在多个订单子项,例如机票的订单包含机票款、燃油费、机建费、保险费、行李费、其他费,如果是儿童,儿童的费用和成人的费用还有差别,儿童一般是按照标准仓位的50%计算费用。那么一个订单包含多个项目,在不同场景下退票的规则是不一样的,所以就要求在逆向的场景下,可以针对子项进行退款,但是不同渠道平台的支持程度不一样,所以在设计上,既要支持以总账的形式完成和结束订单,也要支持以子项的形式操作订单。
5、查询模块设计
就票务平台而言,最復杂的场景有两个,一个是逆向的订单场景,一个就是查询。机票、火车票、酒店的查询规则差别很大,其中最复杂的是机票的查询场景。机票的查询的要求是实时性和准确性。因为平台存在多个数据源,包含官方标准仓位价格数据源、各个供应商的折扣数据数据源、自有折扣仓位数据源、航司官网数据源等,机票的价格既需要参考所有的数据源,也要保证实时性。
机票的查询难度在于数据量大,变动快,如果前端直接查询后端数据源接口,则会产生很大的查询时长,因为这包含多个数据源的查询结果计算,这是用户不能接受的。机票大约有5000个航班,用户预定周期跨度为一年,数据量在180万左右;如果以二八原则来约束,即80%的机票预定都在一个月内,也有15万的数据量,这样的数据量难以做到实时,平台以500个线程不断轮询各个数据源接口,以增量的形式更新数据,每个数据的更新平均时长是5S,则一轮数据更新平均需要25分钟;再进一步以二八原则约束,即用户大部分的查询都会集中在热门航线,例如北京上海航线、上海深圳航线、深圳北京航线等,那么这样就完全可以保证“热门航线3个月数据的实时性”,这个实时性体现在数据3分钟可以更新一轮;次热门航线数据10分钟可以更新一轮;非热门航线数据1个小时更新一轮。
数据从数据源获取后,经过查询服务的原子层服务接口汇总、计算,统一更新到ElasticSearch模块中,前端用户查询的是ElasticSearch服务,查询的结果可以进行集合运算,查询的响应时长如果不计算网络传输时长可以保证200ms的响应速度。
6、结算模块设计
结算的主体是渠道和平台,结算模块的设计点包含两个部分,一个是合同结构化,一个是结算单的推送。合同结构化将渠道和平台的合约以结构化的形式呈现,例如双方的分润模式、结算周期,分润模式支持阶梯分润,结算模式支持T+N(N>=0),N既可以支持天数,也可以支持小时数。结算单的推送时机是在订单完成的情况下进行推送,订单完成包含订单的正向完成和逆向完成;完成后根据各个渠道提供的推送接口要求进行推送,订单模块提供结算数据并生产MQ消息,结算模块订阅MQ消息并完成推送。
7、结语
组件式在线票务平台提供了多重数据源的实时查询能力、票务的预定能力和结算能力,并且打通了渠道侧的用户和订单模块,能够以配置的方式,提供标准化的接入模型[3],该方案目前已经接入了数十个自有流量渠道,预定首页的日访问UV达到40w/天。
参考文献:
[1]董恒铄.企业信息化管理中计算机网络技术的运用分析[J].计算机产品与流通,2020(05):11.
[2]蔡宝玉.计算机网络安全技术在电子商务中的应用[J].计算机产品与流通,2020(05):18.
[3]周成就.互联网模式下的计算机应用探讨[J].计算机产品与流通,2020(04):55.