尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

铁道部信客票系统设计(二)

发布时间:2026/9/24 6:06:18

资讯中心
01
ARTICLE

铁道部信客票系统设计(二)

铁道部信客票系统设计(二)
在上一篇文章中 铁道部信客票系统设计一 里面探讨了关于数据库层面的功能性需求以及非功能性的需求在非功能性需求里面一博主 提出了没有考虑到峰值的情况这一点的确漏掉了因为我们铁道部的特殊需求在春运期间负载很大平时可能一般如果用考虑最大的情况则回存在浪费的情况如果考虑不足就像网络订票一样苦逼。就好比 铁道部春运的时候发车量大但是如果制造大量列车平时就空闲了也就很亏。机器的折旧很是块的。春运期间可以考虑紧急扩容来实现所以从设计上可以保持这种扩展性。 扩容是一项工程整体来说比较复杂。上一篇博客发表后也有博主和我探讨过一些问题也让我了解到铁道部目前的状态。由于这个纯粹是技术上的分析先不去考虑一些政治因素毕竟这个比技术复杂多了正题开始原来打算这一篇里面介绍数据库表的设计但是上一篇文章中还有很多细节问题没有解决这里面继续上一张把数据这一层在慢慢完善购票的业务流程由于购票过程中是铁道部售票系统的主要功能也是核心业务逻辑这里先从购票的业务流程开始讨论购票业务流程中相关的数据库设计简单的购票流程终端--查询余票--选择车次--确认座位--选择张数--支付--出票这里面重要的是两个环节 查询余票 和 支付过程我们先模拟以下正常网络购票过程中数据库的操作这里面先把问题简单化假设用户只买始发站到终点站的数据1 select * from 余票2 insert into 车票3 update 余票 -14 update 车票 set statusWAIT_PAY where id xxx5 update 车票 set statusPAY where id xxx电话订票类似只不过订的票不会由于过期而取消要么支付要么退票而在窗口、代售点买的票支付方式只不过是现金出票的时候自动支付。其实无论从那个终端过来的请求都会涉及到查询余票创建车票支付车票 过程考虑一中简单的情况就是用户只查询一次就选择了自己要确定的车次然后购票去支付。那么一次购票请求会至少 一次余票查询 一次余票更新一次车票insert,两次车票update这个还是最少的情况实际铁道部的业务应该比这个复杂多了。由于查询余票是购票请求的入口所有的购票请求都会优先查询余票库余票库的设计在第一篇文章中余票库没有设计成为读写分离主要是考虑的用户一定获取的是最实时信息读写分离的话读库和写库的数据有效性上面会有差异比如我更新了一个数据必须马上反映到余票上否则用户看到一个过期的数据对用户体验很不好。这个库的访问量超级大而且还会涉及到热点数据的锁定一旦同一条数据比如我这次想买Z27硬卧同时被大量用户请求根据上面分析的出票就要锁定余票表中Z27这一条记录由于一次只允许一条用户请求能够获得锁请求要必须尽快的处理除了必要的原子操作比如票数-1产生购票表其他的耗时操作就应该越少越好尽量异步化操作核心思想就是尽快的释放锁否则请求排队的线程越来越多导致数据库所有数据库的连接资源被耗尽系统会变的很慢。整理以下在设计余票库的时候在性能上提升可以从下面几个方面去考虑1 尽量减少没有必要的查询减少数据库的资源消耗2 锁的粒度越小越好3 订票事务处理越短越好消耗的业务逻辑处理越快越好争取最大的异步处理。接下来就是考虑如何通过上述思想找出具体的设计方案1 减少对数据库的查询一般情况下先会查询某日余票信息接下来就是根据查询出来的信息选择车次席位。然后张数然后订票成功。首先假设我们把余票信息缓存应用先查询缓存如果有票用户选择车次和席位这样会减少一次数据库的查询。缓存有两种方式一种是应用局部缓存每个渠道缓存票务数据这里涉及到数据的更新以及各个缓存之间的同步不及时暂时不考虑。另外一个种是分布式缓存建立缓存服务器这里面说的缓存都是指内存缓存数据库只需要和缓存服务器之间保持同步但是这样一来如果会员想获取最新的数据缓存服务器也需要保持很频繁的更新相当于要保持缓存和余票数据的同步。这个成本也是非常高。还有一个折中方案就是缓存不缓存票数而是缓存有票无票信息每次用户查询票数的时候先查缓存信息看看是否有票如果有票就查询数据查询具体的票数如果无票就不需要进行查询了这样减少了数据库的查询。同时缓存的更新也少了很多只需要在票数等于0的时候更新以下缓存数据。假设票在一分钟之内卖掉相当于只需要承受一分钟的查询请求。当缓存替代数据库作为主要查询请求处理者的时候缓存成为整个系统的瓶颈。2 减少锁的粒度当旅客选择一张票的时候我需要锁定一条记录避免同时更新造成重复出票这里说以下我记得大学的时候我从武汉买回家的票铁道部一个座位卖出三张表而且是大面积情况相当于一个车厢人数比平时多了三倍当初我以为是假票现在看来可能是重复出票了。还是拿Z27距离假设我要买20120931日期票我必须要选择一个座位那么设计的时候就可以 按照日期车次席位类型 三者确定一条记录然后锁定它。而不是值根据车次 日期这样在你买坐票的时候买卧铺的旅客就不会受到影响。PS实际铁道部售票会远远这个模型简单因为涉及到始发站停靠站终点到假设一个车次停靠 S1-S2-S3那么旅客买S1-S2 和 旅客买S2-S3 就不会收到影响我们先简化模型这里只是先提出设计的思想3 减少订票处理事务时间在整个订票业务流程中发邮件发短信计算各个站点的余票信息等比较等耗时业务操作完全异步化处理。只需要找出关键的流程如果需要保持一个事务那么通过异步确保的方式进行。这个是技术层面的东西后面在介绍。存在的问题通过分析我们给出了一个最简单的订票数据库这一层的解决方案再仔细分析其中存在的问题1 余票查询的维度并不是 车次 日期 席位类型应该还有始发站--终点站因素必须有一个非常快的算法判断是否有票然后告知应用。2 缓存是系统中的单点一旦缓存故障数据库估计承受不了3 数据库上次我说的只需要分成一个库因为上一章节建立数据库备份机制故这里面不存在单点这里面可能存在性能这里需要进行压力测试模拟测试。看看容量上线。为了继续进行设计我们假设即使在缓存存在的情况数据库没有办法处理当前的数据主要是为了应付春运。这里先解决余票库分库的问题分库考虑的原则在上一篇文章分析过但是由于这个库的数据量不大只是访问会比较频繁我们竟可能减少用户的访问为主要考虑因素铁路购票有其特殊的因素比如春节的时候从上海买去成都的票非常紧张查询量也是最大但是相反这段期间买成都去上海的票的人就会比较少查询量比较少。而春节过后上班也就相反。这个思路也就是说按照站站来分也可以按照铁路局卖的票来分。我们的思路就是尽量各个库的访问量均匀。不过也存在一个问题就是分库的扩展性比较差一旦扩容就要做改动。在谈缓存的问题一台缓存服务器不够可以部署缓存集群。至于是不是一台缓存服务器存放所有的数据还是要看数据的多少尽可能的所有数据都缓存在一台服务器上面。缓存的数据维度为 预售期、车次 、席位、始发站、终点站 、是否有票 按照道理应该可以缓存所有的数据不过这个也要看缓存的实现支持最大的内存数量。比如java实现的缓存 在32位机器上面 只能支持差不多2G的缓存空间。这里面假设一台缓存服务器能够实现所有预售期车票数据的缓存那么这里面只需要的就是在余票数据更新的时候更新所有集群的缓存数据。上面一幅图只是简单的演示了基本的架构模型。而余票的计算则是里面最为复杂的了因为新增了两个维度就是始发站-到达站。这个问题比较复杂先暂时放到下一篇文章区分析。继续分析发现上面的分析中貌似还少了一个比较重要的因素那就是渠道因素我们知道订票有窗口渠道代理售票口网站电话等等。假如每个渠道售出的票都是公平的那么肯定不合乎道理的那互联网可能就是比较占优势的如果系统设计的足够好的话对于辛苦排队的人来说相当不公平。这里面有两种解决方案1 可以设计为每个渠道进行配额比如网络订票 我给总票数的多少每个代理点我给的票数是多少等等。如果把这些因素在加入到余票信息中会变的非常复杂也不好扩展毕竟这个是属于经常变化的。设计的一个原则分离不变和易变。如果不变的和易变柔和在一起系统的扩展性就回很弱。2 可以按照请求排队按照渠道优先级进行分配这样在大多数请求排队的情况下有一些请求就回被饿死也就是部分渠道根本买不到票因为请求会被饿死。如果要我选择两种方案的我会选择第一种因为可以在不同时刻进行放票这样可以分散请求。来自互联网10点放票窗口的8点放票代理点9点。自然把流量就分开了。渠道配额管理这一块我觉得将会是最复杂的一个系统涉及到利益太多。余票库这里面我想设计的简单一点不想把复杂的渠道配额管理引入进来尽量放在外围系统中控制。评论回复1 有一些用户说这样的系统用到锁就死定了这个说法不太准确。首先在核心票数处理的情况下必须要保持数据一致性处理票数减一的情况必须使用锁所以考虑的是尽量减少锁的范围和锁超时的时间。因为一旦多出票了会给旅客带来严重的问题一个座位两张票。其次在保证数据一致性的情况下要最大程度的保证用户体验和性能2 使用NoSql其实有一定的适用范围。这个是看架构权衡的问题。我有限要保证的是数据一致性然后才是性能。NoSql对数据的一致性要求并不太严格。可以作为缓存集群的替代品。由于我个人做金融系统的对oracle比较偏爱可能做互联网sns类产品的对NoSql比较偏爱。但是两个问题领域不一样要有取舍。3 由于大部分请求都会在缓存层处理掉不会直接进入进入请求到数据库至于锁定数据库的情况会更少。这个情况下可以按照秒杀的实现方式。这一点可以专门放一篇来讲。4 对于窗口售票部分肯定考虑过了。如果网站做的好的网站的请求量肯定是最大的。你可以想象一下售票点的终端系统全国能够有多少W网络客户端有多少W 几千万应该有了吧几个终端的数量级。而且终端的话只有一个人在串行操作不会无聊到刷浏览器。而IE是个人的刷死你。还有这个是关于数据库这一层的设计还有到整体业务架构层的设计无论售票窗口互联网等渠道最终都是要进入到数据库这一层。5 分库分表要了解背后原因以及策略。其实只需要12行代码 就可以搞定12306今天先写到这里发现在这上面思考的比较多了后面再持续分析吧。还要继续开发我的ios app写文章有点超时了。ps发现无法在mac笔记本上添加图片是不是一个bug明天在上传吧。
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。