加入收藏 | 设为首页 | 会员中心 | 我要投稿 云计算网_泰州站长网 (http://www.0523zz.com/)- 视觉智能、AI应用、CDN、行业物联网、智能数字人!
当前位置: 首页 > 综合聚焦 > 创业热点 > 经验 > 正文

换个思路看12306,其核心模型设计思路到底复杂在哪里?

发布时间:2016-02-29 20:43:04 所属栏目:经验 来源:InfoQ
导读:元宵节结束,年就真的过完了。挥别故里,回到打拼的城市,理性思维是否也跟着工作状态一起回归了呢?每一年的春运都是对 12306 的一次大考,抛去盲从和偏见,让我们用工程

12306设计 12306网站 12306订票

编者按:本文作者汤雪华,网名 netfocus,2006年 毕业于浙江大学,目前住在杭州。对 DDD,以及 CQRS 架构比较感兴趣。目前一直致力于开发和完善 ENode、EQueue。文章首发于微信公众号InfoQ(ID:infoqchina)。

元宵节结束,年就真的过完了。挥别故里,回到打拼的城市,理性思维是否也跟着工作状态一起回归了呢?每一年的春运都是对 12306 的一次大考,抛去盲从和偏见,让我们用工程师的思维重新打量、从业务分析的角度去探讨,12306 的核心模型设计思路和架构设计到底复杂在哪里?

为什么我要研究这个问题?

春节期间,无意中看到一篇文章,文章中讲到 12306 的业务复杂度远远比淘宝天猫这种电商网站要复杂。后来自己想想,也确实如此。所以,很想挑战一下 12306 这个系统的核心领域模型的设计。一般的电商网站,购买都是基于商品的概念,每个商品有一定量的库存,用户的购买行为是针对商品的。当用户发起购买行为时,系统只需要生成订单并对用户要购买的商品减库存即可。但是,12306 就不是那么简单了,具体复杂在哪里,我下面会进一步分析。

另外一个让我写这篇文章的原因,是我发现也许是否是因为目前 12306 的核心领域模型设计的不够好,导致用户购票时要处理的业务逻辑异常复杂,维护数据一致性的难度也几百倍的上升,同时面对高并发的订票也难以支持很高的 TPS。我觉得,越是复杂的业务,就越要重视业务分析,重视领域模型的抽象和设计。如果不假思索,凭以往经验行事,则很可能会被以往的设计经验先入为主,陷入死胡同。

技术人员往往更注重技术层面的解决方案,比如一上来就分析如何集群、如何负载均衡、如何排队、如何分库分表、如何用锁,如何用缓存等技术问题,而忽略了最根本的业务层面的思考,如分析业务、领域建模。我认为越是复杂的业务系统,则越要设计一个健壮的领域模型。如果一个系统的架构我们设计错了,还有补救的余地,因为架构最终沉淀的只是代码,调整架构即可(一个系统的架构本身就是不断演进的);而如果领域模型设计错了,那要补救的代价是非常大的,因为领域模型沉淀的是数据结构及其对应的大量数据,对任何一个大型系统,要改核心领域模型都是成本非常高的。

本文的重点不是在如何解决高并发的问题,而是希望从业务角度去分析,12306 的理想模型应该是怎么样的。网上目前谈 12306 的文章貌似都是千篇一律的只谈技术,不谈业务分析和如何建模的。所以我想写一下自己的设计和大家交流学习。

1、需求概述

12306 这个系统,核心要解决的问题是网上售票。涉及到 2 个角色使用该系统:用户、铁道部。用户的核心诉求是查询余票、购票;铁道部的核心诉求是售票。购票和售票其实是一个场景,对用户来说是购票,对铁道部来说是售票。因此,我们要设计一个在线的网站系统,解决用户的查询余票、购票,以及铁道部的售票这 3 个核心诉求。看起来,这 3 个场景都是围绕火车票展开的。

查询余票:用户输入出发地、目的地、出发日三个条件,查询可能存在的车次,用户可以看到每个车次经过的站点名称,以及每种座位的余票数量。

购票:购票分为订票和付款两个阶段,本文重点分析订票的模型设计和实现思路。

其实还有很多其他的需求,比如给不同的车次设定销售座位数配额,以及不同的区段设置不同的限额。但相比前面两个需求来说,我觉得这个需求相对次要一些。

2、需求分析

确实,12306 也是一个电商系统,而且看起来商品就是票了。因为如果把一张票看成是一个商品,那购票就类似于购买商品,然后每张票都有库存,商品也有库存的概念。但是如果我们仔细想想,会发现 12306 要复杂很多,因为我们无法预先确定好所有的票,如果非要确定,那只能通过穷举法了。

我们以北京西到深圳北的 G71 车次高铁为例(这里只考虑南下的方向,不考虑深圳北到北京西的,那是另外一个车次,叫 G72),它有 17 个站(北京西是 01号站,深圳北是 17号站),3 种座位(商务、一等、二等)。表面看起来,这不就是 3 个商品吗?G71 商务座、G71 一等座、G71 二等座。大部分轻易喷 12306 的技术人员(包括某些中等规模公司的专家、CTO)就是在这里栽第一个跟头的。实际上,G71 有 136*3=408 种商品(408 个 SKU),怎么算来的?如下:

如果卖北京西始发的,有 16 种卖法(因为后面有 16 个站),北京西到:保定、石家庄、郑州、武汉、长沙、广州、虎门、深圳。。。。都是一个独立的商品,同理,石家庄上车的,有 15 种下车的可能,以此类推,单以上下车的站来计算,有 136 种票:16+15+14....+2+1=136。每种票都有 3 种座位,一共是 408 个商品。

为了方便后面的讨论,我们先明确一下票是什么?

一张票的核心信息包括:出发时间、出发地、目的地、车次、座位号。持有票的人就拥有了一个凭证,该凭证表示持有它的人可以坐某个车次的某个座位号,从某地到某地。所以,一张票,对用户来说是一个凭证,对铁道部来说是一个承诺;那对系统来说是什么呢?不知道。这就是我们要分析业务,领域建模的原因,我们再继续思考吧。

明白了票的核心信息后,我们再看看 G71 这个车次的高铁,可以卖多少张票?

讨论前先说明一下,一辆火车的物理座位数(站票也可以看成是一种座位,因为站票也有数量配额)不等于可用的最大配合。所有的物理座位不可能都通过 12306 网站来销售,而是只会销售一部分,比如 40%。其余的还是会通过线下的方式销售。不仅如此,可能有些站点上车的人会比较多,有些比较少,所以我们还会给不同的区间配置不同的限额。

比如 D31 北京南至上海共有 765 张,北京南有 260 张,杨柳青有 80 张,泰安有 76 张。如果杨柳青的 80 张票售完就会显示无票,就算其他站有票也会显示无票的。每个车次肯定会有各种座位的配额和限额的配置的,这种配置我目前无法预料,但我已经把这些规则都封装近车次聚合根里了,所有的配置策略都是基于座位类型、站点、区间配置的。关于票的配置抽象出来,我觉得主要有 3 种:

  1. 某个区段最多允许出多少张;
  2. 某个区段最少允许出多少张;
  3. 某个站点上车的最多多少张。

当用户订票时,把用户指定的区段和这 3 种配置条件进行比较,3 个条件都满足,则可以出票。不满足,则认为无票了。下面举个例子:

(编辑:云计算网_泰州站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

推荐文章
    热点阅读