对于网上购票系统12306,如果你是架构师,你会怎么办?-论坛精彩回复整理


过年之前的12306事情很火,特意发帖讨论,收益匪浅,今天特对发帖各位的回复进行了总结,并将精彩回复附后:

 

1、分省或车次进行分拆,将现在集中地售票,变成分省的售票,分散压力;


2、才用排队的思路和分拆子系统的方式,前段才用大量的HTTP服务器作用排队服务器,和银行的排队拿号一个道理,提示你之前还有多少用户,通过有好的提示,减少用户抱怨;

3、才用NOSQL技术,比如才用memcache或集群,减少完全通过oracle


4、租用第三方的云平台,通过硬件的提高来提高并发;

 

 

 

 

 

 

 

最近12306事情搞的很火,做个小讨论,看看各位参与度如何?

12306概况

1、采用CDN分发技术

2、据业内人士说,采用oracle通用数据库

3、同时并发大概在500万左右

4、专业互联网分析网站 Alexa 的统计显示,12306的访问量排名从3个月前的第1059位跃居至目前的第115位。1月9日,Alexa 统计估算的12306网站独立用户访问比例,已占到全球的0.86%,3个月间访问增速达627.5%。

5、系统从2011年6月份开始运行

 


 

如果您是这个项目的系统架构师或者成员,您会怎么办?

 

myreligion回复到:

售票有什么复杂的?查询车次可以分开,甚至用varnish直接代理缓存了是不是?

每个车票,余量等实时数据,可以根据车次完美的分拆,是不是?基本固定的东西,用redis,用memcached都可以做的很不错,是不是?

对于没有完美事务的nosql和缓存,差几个人进入后续订票,数据库二次校验下提示他失败就行了。

车次可以分散开,票可以提前分配好,事务可以完美的分解成每张票的行锁,互不干涉。

唯一的业务复杂就是中间有很多站,要分区卖。这其实也很容易解决,好比这样:

1. 数据库预存储1张票 北京->上海

2. 用户A锁定此票,但选择是 济南->南京

3. OK, 把这张票的行程记录为 济南->南京,出票给他。

4. 系统自动在插入2张新票可用:北京->济南 , 南京 >上海

5. 等待其他用户购买。

看,每张票都是完美的行锁,并发什么的有什么影响。程序只要发现有锁,不用等待,直接告诉用户票已经卖掉,或者继续寻找下一个没有加锁的票。

 

linliangyi2007回复到

 

关于排队的思路,我昨天在隔壁帖子中就给出了基本的思路了

引用

1.排队等待子系统
  
  如此大的并发量不是简单的群集能承受的,因此,系统需要一个缓冲区,就好比在窗口面前排队一样,在进入订票流程前,应该有个排队处理系统,简单的页面,让电脑面前的用户知道自己的请求已经提交,系统慢,大概还需要几分钟才能受理你的订票请求。

  如果大家玩过wow,下过魔兽的副本,就知道有个副本排队系统了,这样也一样。
  此系统需要大量的HTTP前端服务器,接受用户请求,但不需要很复杂的业务逻辑。

2.订票流程处理子系统

   进入该子系统的用户开始正式的订票流程,如,填写各种表单。该子系统关键在于需要一张表,用来记录用户已经订出的票,扣除系统剩余票数,这样不至于用户交钱了票没了。只有用户取消订票时,将票退回系统。
   同时,该系统应该记录用户在订票流程的日志。


3.订票确认与分发子系统
   用户完成所有信息填写后,进入该子系统,该系统负责最终登记用户的订票信息,并正式的将票据出售,同时从用户的资金账户中扣除钱款,并在系统中锁定票号。
    用户将从这个系统中,最终确认自己的购买的票据时间,票据,出发到达等信息,即提供最终票务状态的查询。


剩下的具体设计,如,数据库集群设计,负载均衡设计,动态服务扩展设计,高可用性设计,高速缓存设计,这些议题大家平时都在讨论,这里就不多说了。

大方向设计出来了,小细节的可选方案就灵活了。我就不信这样的设计会出现钱扣了,票没出的情况...

 

qq123zhz回复到

1、可以采用activeMq来排队。。
2、采用读写缓存分离,采用memcached,复杂一点就memcache集群,设置主从缓存以及缓存服务器优先级,类似sina的sea。
3、配置多台备用缓存服务器,在春运的情况下加入备用缓存服务器到memcached集群中。

 

 

抛出异常的爱:

1.如果秒杀在设计方案上是个伪命题......
2.显示方式以域名区分.
bj_sh.12306.com\2012\1\20_21_22,返回北京到上海的20号到22号之间的可用车次最多七天.
sh_bj.12306.com\page\1返回上海到北京的可用车次可案星期翻页
这样可以水平集群.不同压力使用不同服务器与策略.

3.用户一般不需要注册用户.所以只需要有身份证号,姓名,手机号,在前台用一个隐藏域保存不用存数据库就可以减少集群的压力
4.先行使用支付宝支付.如果有票那么就可以支付.并等待(1小时一次公布)
5.使用撮合算法.撮合最大可能性.并去掉已购票的身份证号,手机号
6.用户查寻放票榜,不成交的号进入下次池中
7.支付宝将支付后的定单完成.不点击完成的号成为不成交号进入下次池中,
8.如果一直没有买中的票则从支付宝退款.
9.可以短信提示注册号 增高 机器人刷票.成本

 

kjj回复到

我就觉得你们在讨论一个莫须有的问题
本人觉得网站这样原因有很多,主要有下面
a  巨量人数访问, 目前除了非死不可 等 在短期内这样大啊访问数罕有,可以解释排名问题得到证据
b 被你们忽略的zf的办事作风,有能力的公司并得不倒认同
c b点原因很很快挫败正确意见,因为这种人会得到领导的信任
d 团队领导里有蠢驴!!

所谓什么技术架构,啦选型啦啥的,根本不是问题所在!!!!

 

 

 

zshui_2007回复到

很多人没有仔细想过可能的业务,或者是基于技术的基础来讨论,没有立足点,怎么展开

1.如果放在内存中可以解决问题,那意味着当年的数据库可以根本考虑不要,nosql的出现,也是因为爬出搜索的需要,但也只是部分借用了内存的作用;
2.所有的讨论,是建立在铁路部门最早是有自己的一套核心的售票系统的,在没有12306之前,代售点就在网上卖票了,只是现在12306把代售点搬到了每个可以联网的PC上;
  因此,考虑票是以什么样方式来发售的,怎么样来保证查询票是有效的,这个实时性还是应该有的,不然让系统去排队,有什么意义;负载不能解决的,加前置机、加排队子系统一样无助于解决问题,只是把问题爆发的时间点往后延长了一点。

 

 

baidu的一个架构师给出的一个方案


对于一个理想的在线服务系统,应该包括几方面的能力。1) 单机高性能,也就是所谓的c10k能力。2) 良好的scalability。简单来说,就是加机器可以提升系统性能。3) 稳定输出,特别在极限情况下。4) 良好的自管理自运维能力,在故障、升级或扩容时尽量减少人工介入。

但是,并不是所有的服务都*需要*在以上4个方面做得很好,也不是所有的互联网公司都*有能力*在这4个方面做得很好,甚至很多工程师或架构师都没有*意识*到需要考虑这些方面。

所以,前一篇文章中我的建议是:

a) 可以先不考虑1,因为要提高单机性能难度很大,而效果却并不明显,通过加点机器即可取得同样效果。当然,作为一个old-fashioned engineer,我个人很喜欢做这样的事情。百度的快照库是我到百度后做的第一个系统,单机性能比旧系统提升了10倍以上。

b) 在业务不太复杂的情况下,加机器是最容易提升scalability的方法。我不了解具体的火车票业务模型,不太好讨论,但通常只要能把锁和正常的业务逻 辑decouple,问题就不大了。谈到锁,多说两句。用它来保证的同步互斥,是并行系统中最基本的问题。有很多种做法,难度迥异。比如一些lock- free patterns,如果工程师的志向不在于此,不建议尝试。在实际中,按照我的review经验,只要能分解掉那把全局大锁,效果就很好了。

c) 最重要的是sustained throughput。在峰值压力情况下,平滑过渡,可以有效避免雪崩效应,大幅提升用户体验。我提了一些做法,很多朋友说这在通信系统中也是常用的。有 兴趣的朋友也可以去研究一下queuing theory,看看latency和throughput是怎样的关系。

d) 在小规模时可以先不考虑自管理自运维能力。随着机群的扩展,故障处理、扩容减容以及服务调度等等逐渐成为最头疼的问题,而这正是分布式系统所要解决的最难的问题。对于大互联网公司来说,应该深有体会。

相对于普通的在线服务,搜索引擎的规模和复杂度要高出一到两个量级,很多考虑问题的出发点也不一样。习惯了这样的思考方式后,我也不太敢直接来设计一个火车票售票系统,over-design就麻烦了,呵呵。所以,以上根据系统的设计原则给出一些建议,希望有用。

 

 


joeyhacker回复到

根本不在用什么技术, web负载是最大问题, 就算后端技术再牛前端响应不了也没用.. 其实觉得在写一个防ddos的防火墙一样, 同时面对无数请求, 还要保持事务, 哈哈. 这种问题可不是拍脑袋想的.  如果我设计的话, 直接做成异步离线应用, 客户端提交的数据通过验证后直接写入服务端的高速异步队列, 等待服务端处理结果推送回客户端. 这样的好处就是可以解决web端刷页面的问题和响应速度, 但客户端提交的数据有可能被封包, 还有客户端提交数据成功后也可能没票...     

hu97086回复到

呵呵,我花了2个小时终于买到票了!
痛恨之余我也在考虑如何建立铁路售票系统,以下是我一些分析,见笑了!

一切系统设计从业务出发:

1、铁路售票系统极限压力极大(春节、10.1等期间),而平时压力并不大。所以我们还是建立廉价且可插拔水平扩展的系统,这样就

不用平时也维系这样庞大的系统;

2、售票业务本身并不是很复杂,主要包括注册、登录、查询车次、查询订单、买票(预订票、确认支付并订票、发邮件短信);

3、业务量大小依次可能是买票(系列),查询车次,订单,登录,注册等。但春节期间瞬间访问量是几万甚至10W,所以确保处理这样

的系统,单从技术角度将是比较困难而且费用很高。

4、业务中最重要是买票(系列)业务,所以必须要保证买票中预订、支付、确认的事务性,这样不仅提高软件效率,也提高客户体验

度,否则发生一系列后续不必要的业务压力(退钱、重复购买、重复支付、重复确认,重复查询等等)!




比较理想的方案:有序、有效的排队处理所有业务。
排队系统:--春节时期启用
1、访问买票网站,填写姓名和手机后,提示用户排队,并等待手机通知。将这一信息以手机号码Hash值保存到内存缓存中(Memcache redis等),有过期限制,不允许重复登陆,可以控制队列长度;
2、但队列处理到当前用户时,给用户手机发送授权码,用户凭此完成登录,买票等一系列操作。
3、当用户完成买票时,退出系统,并且在队列中清除该信息。
4、其实,排队系统也是一个可插拔、水平扩展的系统,能实现负载均衡、failover等功能。
买票系统:--处于一个完全可控的状态
1、由于排队系统,后端的买票系统不会出现超过容量的访问,所以对他的设计是简化了很多,游刃有余!
2、设计可水平扩展的系统,便于在分布式扩展:缓存技术和异步技术(邮件通知等)--具体参见方案二
3、确保买票(系列)业务的事务性,提高效率和客户体验度。

方案二:极致的海量数据处理方案--构建分布式、水平扩展的系统
任何系统都是妥协需求和设计的结果--我们不太可能设计出简单、功能超强、不出错、廉价且能满足任何极限情况的系统。我们要处理的技术问题是:超大访问导 致的超大业务处理能力,超大访问导致的数据库处理能力跟不上。我们的技术手段有分布式集群服务、缓存、业务水平分割和异步;
1、分布式集群服务:最简单的的方式就是硬件--F5等设备(当然也可以采用LVS),由于购票业务相对简单,可以把前台服务功能在一个Application中完成,这样扩展集群服务也相对简单--加大开启新一台服务器,不过还是可以在软件结构上做一定的改进。
2、缓存和水平分割
a、对象--12日内所有火车、时间、站点信息(要处理成数字化),大致是5000趟火车*12天*2000座位(一列火车)和区间是否已订信息,对于Memcache也应该是不大的。
b、使用--依据站点和时间查询车次和余票情况;买票时先锁定本Memcache,进一步提交给Oracle RAC完成真实买票动作,完成后async同步所有Memcache服务器。
c、水平扩展--开启新一台Memcache,注意需要实现在线变更Memcache集群并通知LoadBalance设备。
3、异步
a、异步Memcache同步。
b、异步的买票成功通知--邮件和短信。
4、Oracle RAC--还是值得使用的,尤其是巨量访问情况下,保持稳定和安全,不过交给DBA吧。

 

 

cfans回复到

租借淘宝的云服务,订票多的时间正好是淘宝活动和交易比较少的时候。


 

 

其他帖子的一些回复:

chenjunxt:

12306订票问题:
1 不能登陆
为了防止过多的人刷票和过多的查询对服务器造成压力过大,而设置的这一愚蠢的限制,减少人登陆就能减少刷票请求了,哪来的这么SB的思路.
2 提交定单不成功
因为订票请求很快,订票处理可能跟以前的票务系统处理,可能需要花时间,假如一秒对一列车有10万请求,而对订票处理,可能一个订票交易就需要 10ms,那样就只能一秒处理100个订票,这里就会提示订单过多,叫人累死累活的一直提交,反过来又有刷票程序,让别人跟这个刷票程序比速度,简直是坑 爹呀.

MD,怎么说我也是网络订票呀,怎么要学愚蠢电话订票的开通多少线路,让人通过多次拨打增加打进几率来竞争呢

12306解决方案:
1 登陆
正常验证用户名,密码,验证码登陆(验证码可以单独服务器生成,减少压力)
2 用户session
用户量峰值比较大,可以使用memcashe之类的缓存管理.
3 票务查询
站到站的查询
全部才1000多个站,每两点之间的连接车次都缓存,
对每列车的票务查询,可以固定一个间隔段更新一次,也保存在缓存
这样对所有查询的返回就是迅间
4 订票
每个用户可以对一个车次提交一笔订单,最多5个人,但是最多有一笔成功订票而没付款的订单,每次放票的时候就按照每躺列车的订单随机的抽取订票的 成功还是不成功,订票成功就发短信通知在规定时间内付款,时间到了没付款就当作放弃订单处理,有取消的成功订单就可以退回存票系统.
这样就可以防止刷票机和人竞争票的不合理,也可以节省别人宝贵的时间,也不会再有这里多无聊的人来刷暴你的12306了.

 


鱼言风语的解决方案

铁道部的12306订票网站是近期的一个热点,在iteye已经有几个帖子讨论了。

看了大家的讨论,有些观点我很受启发。同时我又有自己的一些想发,这里专门开个帖子阐述一下我的解决方案:

1、 整体采用排队的思路,化并发为串行。假设有10台排队服务器,每台用NoSQL数据库和内存队列可以满足100万人的排队。而到数据库的并发数就降低到了 10。如果Oracle每秒处理的票数为100的话,每天可以卖出1000万张票。如果铁道部几千万的单子采购的硬件做不到的话,那真的要拉出来打屁屁 了。

有个帖子说了排队的缺点,我后面会阐述如何解决这些缺点。

2、采用预付费的付款方式。购票人通过网银预先存好购票款,买到票的时候从预付款里扣;留好退钱的帐号,任何时候都可以退钱。

预付费的好处包括:
  一,把多系统很难实现的事务转为单个数据库实例上的事务,杜绝出现钱扣了票没买到的现象;
  二,可以架个单独的账务服务器,分流网络流量;
  三,减少出现一个人排多个队这种情况。

3、购票人一次排队可以为最多5个人买票,但是这5个人是绑定的,就是要么都买到,要么都买不到(为家庭考虑)。购票人可以购买往返票。往返均可 以设定5种购票选项,比如:优先选择19日上午10点D111次,其次19日下午15点D222次,再次20日上午10点D111次,等等。这样解决了有 人说的排队排到了票却没了的问题。

4、后台服务器要根据票的剩余情况,维护排队服务器的队列。要采用类似LinkedHashMap的数据结构,当某趟车没票了,要能很方便的把受影响的排队号找出来,把它们的购票选项去除。当一个排队号的所有购票选项都没有了,就把它从队列中移除。

要开通短信通知平台(每个排队收个0.5~1元短信费,应该都能接受吧?),及时通知购票者购票的变动情况,比如:买到了,没票了等。这也能减少购票者去频繁刷新网站。

5、其它的再有就是采用静态页面+二进制的AJAX(hessian,protocol buffer)等方式,减轻大家查询余票信息的网站的压力。

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值