主题:【原创】好吧,给一个铁道部订票系统的正确答案 -- 布老虎
铁路上一个重要的特点是:“从河南郑州到江苏徐州的票有可能是从北京出发终点站在上海”。如果这张票数据放到河南服务器,那么,从北京到郑州的座位就查不到,被浪费了;如果放到北京,那么从河南中心查的话,是查不到这张票的。如果想要避免这两种情况,就必须线路上每一站都放上资源,这又涉及到数据同步问题。如果不想数据同步,就只能所有经停河南的省的服务器都查询一遍,这与数据集中放置到一台服务器的差别不大。上面分析的是读操作部分,在缓存足够大的情况下,这几种方案读效率差不多。现代数据库写是不会阻塞读的(参考数据库的MVCC方案,很多数据库用的都是这个)。
关键问题是写,当多个写操作并发的锁定同一行数据时,只要一个事务被提交,其他的就要全部重来(读已提交)或者回滚(可串行化),大量相互竞争的写操作不断重来回滚,就会耗尽数据库连接资源,最终读的连接也进不去了。最终看似是读失败,实质是写操作阻塞造成的连接失败。
解决这种问题的核心思路就是人为设计一个并发事务串行化队列。无论供应商吹嘘的多么复杂,本质上就是这个。淘宝用开源数据库,某些高并发的地方就是这么干的。
中国不少行业的数据规模都是全球最大最复杂的,比如电信(以至于要分省运营)、铁路(世界负载最高,调度最困难、最乱、最复杂)、证券(金融创新虽不及美国,但小账户、小合约太多,又是世界上最钟爱短线的市场,散户化特征明显)。东部某发达省某银行曾经从印度引进过据称是使用Java先进技术开发的银行业务系统,结果每到高峰时段就会出现10分钟以上的延迟和停摆,断断续续解决了两年没有解决,最后忍无可忍换掉了供应商。印度公司从来没有想到,中国东部一个县的交易量就已经能赶上别人一个国家。
尤其是可以有效降低全表扫描的查询负载。在有索引的条件下,这个查询负载降低不明显。
写操作的问题是,竞争+并发,一个事务提交会导致其它事务重做或者回滚。用一个粗略的方法计算,假设有10个事务竞争一行数据,假设他们全部能成功提交,那么,并行事务(假设到所有事务在最终提交前发生回滚)最终耗费的运算资源是10+9+8+7+6+5+4+3+2+1=45;如果这10个事务是串行提交的话,那么耗费资源是1+1+1+1+1+1+1+1+1+1=10。
由于大量的数据库连接资源被浪费到回滚上。数据库连接池会被迅速耗尽。最终导致读数据连接也无法接入。
春运的时候竞争只会比这个强。
无论分多少个表,对于同一行的竞争是无法规避的。现代数据库对资源的锁定都是按照行来的(行锁),并且写不会阻塞读。分表(分区)对于写竞争改善不大。
如果写操作对资源的锁定是按照表来的话,那么你的想法非常有意义。不过现代数据库大多不是这样。
核心问题是解决写操作竞争。可以搜索"MVCC"参考一下数据库的并发控制原理。
铁路方面做的还是不错的。不过他们没有互联网系统从小做大的机会。
几乎上线没多久,就碰上了互联网公司十几年才能辛辛苦苦发展来的交易规模。而时间没有给他们慢慢修改逐步适应交易量的机会。
阿里巴巴的交易系统先后用了4套架构,从早期的LAMP到Oracle到分布式到现在的自建架构,用了10年时间,还碰上了大大小小的问题。
铁路上线不到一年,就碰上了春运,然后发现原来的需求估计严重不足。
说实话,99%的公司,你给他2000万,他们只会做的更差
我不懂数据库,更不懂你们说的那些名词,不过根据我所知道的一些最基本的原理想来,你的主帖内容至少有2个问题:
1,没有抓住核心问题。竞争的核心资源是"座位",对“座位”资源的read/modify/write的机制——也就是你所说的“占座位”——是整个系统的瓶颈——你轻描淡写一笔带过了。我怀疑你可能并不理解问题的实质。
2,对可能面对的问题严重估计不足。“当然肯定存在这样的二百五,事先没往铁道部的系统里存钱,要订座了才开始存钱。”这个是必然发生的大概率的事情,你只是简单的把这种可能归结于“用户是250”.....
当然,我是外行,随便说说我的印象而已。
你想现在线上都是标明起始终点站的
也能计座位数的
说明后台里并不是动态分段,而是人工分段分好了输入。
比如我买上海到南京200张,那后台就是上海到南京200张
而不是上海到北京200张然后你可以选终点站是南京还是济南的那种。
不知道说明白了没有。
那也有短期内爆发式增长,也能应付的来的网站
10年前业界对大数据访问没有经验,10年后已经有一定的积累,不太可能再从0开始,这个成本不得了。
应该说可以从业界拿到一定的数据标准然后做负载测试,然后发现这个问题。
解决办法其实非常多。我只是觉得他们可能从需求到最后的测试都没有或者有意忽视这个问题。
应该说,业界比较知名的公司会告诉你2000万可以做什么,不能做什么,而不是拿了钱拍完胸脯忽悠完了最后再搞钓鱼工程。
世界上没有钱解决不了的问题。既然技术上有未解难题,通过改变需求规避掉不就可以了么。。
据我所知,客户提出强人所难的要求那简直太多了,耐心的解答也是工作的一部分。
考虑到这个单子还是给铁道部自己人继续做的,我觉得还是让铁道部自己去考虑怎么解决吧。就我现在随便考虑下,解决办法最起码3,4种,他们会想出来的。
不愿意嫁码农(如果为真),肯定不是因为什么从业信誉。常识来讲,肯定是因为收入和工作福利的关系嘛。
大气候影响小气候,这个年头,技术民工就是苦逼的代名词。现在都向往土豪了嘛。
我不是行家,上面的术词和系统大多不了解,对铁路售票系统更没关注过。就我的常识,业务和技术是两个大方向,要求码农人人懂业务,是小作坊的方式。大的系统,需求分析和架构设计是专门人员负责,有架构师,技术总监的晒。
至于不能用指针多态,多态。和要求非常高没有必然关系的。这个更多是从软件工程角度,经济效益角度的要求。在应用软件层面,用起来不划算。
从帖子看,似乎你只接触过行业软件,对通用软件,系统软件不大了解。一杆子打倒软件男要不得啊。虽然我已经不做码农很多年。
BTW,西河现在政治氛围太浓了。站队太多了。虽然这里本来也不是技术论坛。
中国的软件业比不上老美,这是不需要讨论的。毛主席说,比不上就比不上嘛,有什么关系呢。
作为外行,看了一下slate的相关报道,貌似问题还是更深层次的,层层转包,外行领导内行。55个承包商,没有懂行的总负责人。
有很多例子是难以想象的。
1.用户名要包含数字,但是做网页的不知道这个要求,所以用户注册时不知道,结果出了错误,返回的错误信息也不明确。
2.当流量太大时,错误信息根本不是平常人懂的语言。其实网页源码里面都有,诸如“请打某某电话注册”之类的话,但不知道被谁注释掉了。对了,有好事者发现,那个电话很好记,1-800-F1UCKYO。我还纳闷呢,美国人喜欢用这种方法记电话,为什么不弄个好记的。
还有人说要改5百万行代码,好消息是这只占整个代码的百分之一。据说windows vista也只有五千万行代码。这是什么高科技网站啊。当然了,代码的数量并不一定说明什么问题。
“东部某发达省某银行曾经从印度引进过据称是使用Java先进技术开发的银行业务系统,结果每到高峰时段就会出现10分钟以上的延迟和停摆,断断续续解决了两年没有解决,最后忍无可忍换掉了供应商。印度公司从来没有想到,中国东部一个县的交易量就已经能赶上别人一个国家。”
Java先进技术?这尼玛啥JB玩意,我怎么从来没听说过?这典型的JVM excessive GC,那帮堆业务逻辑代码的猪根本没有控制流量的概念。Java根本不能用于大数据处理,你得小心对付。
这尼玛还要两年?Trading floor上down机老子最多只有5分钟。
看到这个帖,又到网上搜索了一下一些相关的思考,看到这样一句话:
我觉得这句话说到了根本。现行提前N天售票模式本质上还是为窗口排队的购售票模式定制的。考虑到排队的成本,这种模式对购票者基本上还是公平的。到了电子时代就完全不是这么回事了,因为排队的成本基本为0,另外还有软件外挂加塞,这种提前N天售票的模式的公平意义已经失去了。既然如此,不如改改售票模式,将预售期索性拉得长一点,让购票者抢无可抢。旅客最早可购票日期为旅客行程确定的日子,而非铁路放票的日子,这样购票日期就充分离散化了。为了避免让票贩子钻了空子,可以配套一些措施,譬如:
1.预售票的改签、退票费用固定为20%(或者更高);
2.因为预售期极长,不可避免有人退票。可以加入电子排队机制供暂时没有买到票的人排队,一旦有人退票,排在前面的人可以自动成交。此机制一则可以防范黄牛先退再买的操作手段,二则可以增强铁路部门的计划性,如果排队的人数较多,可以就此增开临时列车。
3.凭二代证上车。此机制用以防止黄牛购票让乘车人买个短途票实名进站然后凭从黄牛手中购买的长途票坐上真正要的车的座位,焦点访谈有揭露。
铁道部自己内部有票控计划部门,每一列车次在各站的可售票都是预先订好的,不会允许你随便买哪一段的票。比如北京到广州的车次,每站可以卖多少票都是预先计划好。如果不事先计划好,那么有人恶作剧把武汉到长沙段的票全部买断,北京到广州,郑州到广州的票也用不着卖了。
这尼玛是基本常识stree smart,不知道这帮人回滚啊锁死啊之类的吵什么。听着很像大三的学生,刚刚上完数据库原理,学了一肚子的consistency之类的东西,用了用MySQL和Postgresql,看了我老的雄文,觉得白学了,不忿,上来乱吵,神秘兮兮地乱夸了Oracle和Java一通(这两现在一家了),显得很有内涵,据说开源软件没一样有用,最终还得用Postgresql和Java,因为他俩是闭源软件的典范,秒杀任何开源软件。
我老这苦口婆心不辞辛劳地给广大群众在技术上把关,实在应该收费了。
布老虎兄的业务流程还不如目前线上的业务流程,光是预存费用到铁老大这个做法就不知道要增加多少成本.
轻轻松松一句话"预存",增加了这个业务,得一堆功能.
1.有预存了是吧,那用户存多少钱得有个地方记录吧,就多了用户账户这个业务对象.
2.有了用户账户这个业务对象,得把它管起来吧.得知道里面的钱是怎么来的,怎么没的.得做账户流水.
3.有了账户流水,还得知道这个流水对不对,跟实际订单合不合的起来,这个得对账.(目前线上系统虽然也要做对账,但是只要拿自己的订单和银行的流水对就行了.增加了用户账户这个概念,还得对用户账户和铁老大自己账户的出入帐,明显多了一个环节)
4.用户账户余额你得让用户查吧,用户账户余额最准确的来源是从账户流水统计,但是出于性能考虑,每次事实从账户流水统计明显太吃性能.那就得做账户日结,每天给账户计算一个余额,当前余额就从日结金额和当日流水里查,这就快多了.
5.用户说我不买了要把预存账户里的钱退回去,这得提现.从目前系统看,铁老大并不是只结银联,其他不管的做法.而是把银联当成资金渠道之一,其他机构还得接.那好了,每个资金渠道的提现接口都得开发一遍
6.这样还没算上铁老大的账务人员的增加的人工工作量,这是个招人的好理由;
我个人认为,铁老大的售票系统的方案可行不可行,好不好,从技术上来说还是要看写并发处理的好不好.而布老虎兄明显没有描述这个细节.
怎么可能?
1.有预存了是吧,那用户存多少钱得有个地方记录吧,就多了用户账户这个业务对象.
-- 不懂,有问题吗?这不是很普通的数据库操作吗?
2.有了用户账户这个业务对象,得把它管起来吧.得知道里面的钱是怎么来的,怎么没的.得做账户流水.
-- 不懂,有问题吗?这不是很普通的数据库操作吗?
3.有了账户流水,还得知道这个流水对不对,跟实际订单合不合的起来,这个得对账.(目前线上系统虽然也要做对账,但是只要拿自己的订单和银行的流水对就行了.增加了用户账户这个概念,还得对用户账户和铁老大自己账户的出入帐,明显多了一个环节)
-- 不懂,有问题吗?这不是很普通的数据库操作吗?
4.用户账户余额你得让用户查吧,用户账户余额最准确的来源是从账户流水统计,但是出于性能考虑,每次事实从账户流水统计明显太吃性能.那就得做账户日结,每天给账户计算一个余额,当前余额就从日结金额和当日流水里查,这就快多了.
-- 怎么会吃性能?Sharding/前端cache不就是对付刷屏的吗?你们这种对数据库的使用方法(用的是最简单的操作,一步都不敢动,稍微变一点花样就晕头转向,不行啊)
5.用户说我不买了要把预存账户里的钱退回去,这得提现.从目前系统看,铁老大并不是只结银联,其他不管的做法.而是把银联当成资金渠道之一,其他机构还得接.那好了,每个资金渠道的提现接口都得开发一遍
-- 所有的正规一点的网站,都有Master/Visa/Discover/AmEx/PayPal的接口,这里面为什么会有困难?不懂。
6.这样还没算上铁老大的账务人员的增加的人工工作量,这是个招人的好理由;
-- 这个软件处理系统会增加人工工作量,嗯,有意思。