在这个神奇的国度,每个地方都有拥堵问题,公交站台,景区门口,银行柜台,甚至食堂窗口,大家都用同一种办法来解决这个问题:排队。所以我一直很纳闷,12306 为什么一开始没有实现排队的功能,是领导拍了脑袋?还是有其它不为人知的原因?
废话少扯,还是说正经的吧。
Redis 用在这里,不仅仅是一个 NoSQL 存储工具,简直是一个完美的解决方案。下面我就来详细描述一下我想象中的一个架构:
LVS 接入,同时将 https 协议转成 http 协议。 按照网上流传的 2kw 的预算,F5 恐怕是用不起了,不过也没事,LVS 加硬件 SSL 卡,50w 预算绝对拿下。
varnish 反向代理。cache 住大部分的静态资源,每台机器 3w/s 的 rps 应该可以比较轻松的应对。即使按照 30w/s 的峰值能力计算,也就 10 台机器,30w 预算
Nginx 服务静态资源,有 2 台足够,6w 预算
Tomcat 服务动态请求,这个量会比较大。但可以从这几个方面入手去减少资源消耗:第一,使用 ajax 请求,而不是页面刷新,减少单个请求的 size;第二,做好频率检测和控制,对于部分用工具来刷的用户,甚至可以采取惩罚措施,以减少无谓的资源消耗。保守估计,20 台机器左右,这个数字要看领导们对于“用户体验”的要求程度。
Redis 服务器,96G / 台,价格也就 3w 出头。预算 10 台,将 2kw 注册用户全部加载到内存,将 2k 车次全部加载到内存,将每个车次的每个座位的状态都加载到内存,将每个在线用户都加载到内存,应该都还有内存剩余。为什么要写磁盘呢?大不了给 Redis 服务器配置双电源,再配一个电池!
DB 服务器。最重要的 db 服务器,“铁道部”的系统,如果不是 DB2 那就应该是 Orcale 了,应该是连硬件到软件一起买的解决方案吧。这个我没有用过,甚至都没有见过,所以不好估计预算了。如果用我们比较熟悉的 mysql,用户系统应该是一个单独的库;车次信息应该是一个单独的库,而且基本上是只读;车票信息应该有区分当前库和历史库,当前库用来存未售出的车票信息,或者近期刚刚售出的车票信息,数据量小,支持快速读写,以及更新,历史库用来存历史上的车票信息,存档性质;订单信息单独一个库,读写量都不会太大。除了车票信息的当前库建议用 SSD ,其它的库采用普通的硬件就行,预算不会超过 5w/台,按照 1M3S 的标准配置,总体的机器台数在 20 以内,预算 100w 左右。值得一提的是,车票信息的当前库,需要按照车次(甚至是车次+日期)进行分库分表。想提高实时性,提升用户体验,减少投诉?增加当前库的机器投入即可。
硬件设备应该就是这样了,接下来说说一些值得一提的实现细节。
当前 12306 系统一个很受人诟病的实现就是无法登录。用户打开登录页,输入了用户名密码,还耐心的填好了验证码,点击提交,再耐心的等了 30 秒,结果,弹出一个无比丑陋的对话框,说“当前访问用户过多,请稍后尝试”,太坑人了!以至于某公司甚至给做了一个“12306登录助手”出来。让用户登录进来,给他们能买到票的希望,是减少投诉的一个很重要的方面。这个其实一点也不难:将用户信息都加载到 Redis 内存,简单点,key 就是 email,value 就是密码加密串(亲,不能是明文哦!),用 cookie 而不是 session 进行身份验证,用 ajax 而不是刷新页面的方式提交数据和返回应答,这么一来,即使 2 kw 用户同时都登录进来,也只需要三五台 tomcat ,20分钟就搞定了。
用户登陆进来之后,不能立即就给出太多的输入框,让用户输入查询,那样对系统的消耗比较大,不划算。应该先让用户通过出发站和到站,查询好车次(单独的车次信息库,全部加载到内存供查询),选择好乘车日期,然后——点击“取号”按钮,拿一个号,进行排队。是不是很熟悉?去银行开卡,汇款啥的,不都是这么办的么!将每个“车次+发车日期”作为一个单独的队列进行排队,其实就是将火车站售票窗口给移动到互联网页面上而已!想提升用户体验?那就每个登录用户可以同时排 3 个队吧,比如我,想买 18 号或者 19 号的 K21,那我就同时在 “K21+18号发车” 和 “K21+19号发车” 2 个队伍里排着好了。
用户既然已经在排队了,那后台处理就很灵活了:根据 db 的承载能力,将用户有序的带到查余票和下订单的页面(后面命名为 “售票厅” 吧)即可。用户在排队页,用 ajax 请求定期轮询,server 端返回有 3 种:当还没有轮到该用户时,返回当前队列前面还有多少人,这个车次还剩多少张卧铺,多少张硬座等等,当然,这些信息都不是实时更新的,而是定期由后台线程或进程进行更新。读取的时候,只是一个缓存 get 操作而已。另一种就是已经轮到该用户,这个时候,给一个30秒或者60秒的订票时间窗口,要求在这个时间内完成查询和下单操作:查询的时候并不做任何的 lock 操作,而是仅仅显示 db select 的结果(这个地方,可能需要 select master 库),填写完票数,点击提交的时候,才做真正的 lock,随机选择座位,update db,update redis 。这个步骤是直接操作 db,不做任何的缓存,但因为是根据 db 的能力放进来的量,所以性能风险反而最小。还有一种状态,就是该用户的号已经过期,或者订票时间窗口过期,很简单,重新取号,重新排队。
具体到 Redis 操作,大约会是这样:
用户:key 为 user:abc@test.com ,value 就是 md5(email + password) ,用户登陆的时候,只需要做一次 get ,即可验证登陆是否成功。
用户参与排队的时候,给用户分配一个 token,token 中建议包含加入排队的时间。
为每个“车次+日期”建立一个队列:key 为 train:queue:k21:20120118 , value 是一个 list ,用户点击“排队”按钮,加入队尾,用 lpush token,后台进程根据 db 负载,从队伍头取出一个用户带入查票和下单页面用 rpop token 即可。后台一个定时任务,定期扫描队伍,更新每个人前面的人数,供查询使用。
为每个“车次+日期”建立一个“售票厅”:key 为 train:selling:k21:20120118 , value 是一个 hash ,field 即 token,value 为过期时间。后台进程定期从队列中 rpop 出一个或多个用户,hset 到 hash 里。并且还需要一个后台进程,定期从售票厅里清除出过期的 token
用户在排队页面,使用 token 作为参数来查询自己的状态:首先 hget 售票厅,确认是否已经轮到自己了,如果没有,则再获取前面还有多少人,预估还需要排队多久,车次还剩下多少票等等信息。如果已经轮到自己,则显示“下一步”按钮,将用户带到售票厅。这一步需要做好安全验证,防止有人采取技术手段绕过排队,直接进入售票厅。
如果不希望用户不停的按刷新按钮,消耗服务器资源?那就来一招狠的:用户每次刷新,则将他在排队中的位置往后排一个!不过采取这样的措施之前,别忘了在醒目位置提醒用户“注意节约我们的带宽资源”!
用户真正下单买票,这是纯粹的业务逻辑,这里就不再细说。下单买票完成后,记得更新一下余票信息缓存即可。
这样的系统很难做么?难,也不难。有的地方因为业务逻辑太复杂,不得不做一些改变,比如亚马逊为了应对圣诞购物季,建了一块云,比如淘宝为了双11双12的秒杀,买了一堆的机器;也有的地方因为各种其它的原因,无法做到完美,比如 12306,比如新浪微博。不过无论现实如何,在我们技术人员的心里,永远保留着一颗追求完美的心,永远保留一股追求更好的劲头,就够了。
- 浏览: 219354 次
- 性别:
- 来自: 广州
文章分类
- 全部博客 (397)
- j2se (28)
- nio (3)
- 易错点 (3)
- 面试ssh (9)
- ssh整合 (11)
- jbpm+spring (2)
- js (15)
- 高级技术 (59)
- swing (3)
- 数据库 (16)
- hibernate (18)
- spring (19)
- 开发网站知识点 (9)
- jbpm (4)
- json (5)
- 设计模式 (22)
- 自定义标签 (1)
- j2ee (9)
- lucene (3)
- cahce (11)
- maven (5)
- html5 (1)
- 多数据源 (10)
- 页面聊天 (9)
- 富客户端 (1)
- android (13)
- aop+拦截器+jms (13)
- 框架整合 (1)
- 非阻塞io (24)
- 暂时不看 (13)
- webservice (3)
- oracle (3)
- 算法 (4)
- 协程 (2)
- netty (1)
- 爬虫 (0)
- 高级基础 (1)
- JVM调优总结 (12)
- 知识点技巧 (1)
- REST (0)
- 基础 io (2)
- dubbo (8)
- 线程 (1)
- spring源码 (2)
- git (1)
- office (2)
最新评论
-
sjzcmlt:
,写的挺好的啊
一个完整的负载均衡的例子 . -
他大姨妈:
网上大部分例子都是直接通过IdleStateHandler来实 ...
Netty的超时机制 心跳机制
发表评论
-
WebLogic11g-单双向SSL配置(以Springside3为例)
2016-03-27 09:45 5652、观察weblogic方便开发部署提供的演示秘钥库 ... -
WebLogic11g-半小时让你的domain集群化
2016-03-27 09:39 725其实网上关于weblogic集群的资料非常多【大 ... -
解决nginx负载均衡的session共享问题
2016-03-27 09:29 483查了一些资料,看了一些别人写的文档,总结如下,实现ngin ... -
JProfiler学习笔记
2016-03-20 10:36 473JProfiler学习笔记 一、安装JProfile ... -
使用阻塞式队列处理大数据 excel
2016-03-20 11:05 705前言 我们都知道,JAVA对于文本文件在读时是独占的,即 ... -
RMI是什么
2016-03-14 10:21 625(14) RM ... -
Java 高并发缓存与Guava Cache
2016-03-13 21:59 812一.背景 缓存是我们在开发中为了提高系统 ... -
Dubbo与Zookeeper、SpringMVC整合和使用(负载均衡、容错)
2016-03-13 21:13 465互联网的发展,网站应用的规模不断扩大,常规的垂直应用架构已无 ... -
轻量级分布式 RPC 框架
2016-03-13 15:31 495目录[-] 第一步 ... -
exe4j 可以很容易吧一个 jar 打包成 exe
2015-11-02 19:45 0一、背景 exe4j 可以很容易吧一个 jar 打包 ... -
如何预估服务器带宽需求【转】
2015-06-07 13:35 669PC=PV/T*C*t*f其中,PC是并发数,T是观测时间 ... -
年终培训关于磁盘冗余阵列、热备、群集、负载均衡、云计算、F5、Nginx等的概念和基本原理
2015-06-07 12:52 550在系统部署实施过程中,客户往往会关注系统的可用性方 ... -
年终知识分享——大型项目架构
2015-06-07 12:25 529... -
分布式缓存服务器设计原理
2015-06-07 11:48 8271.数据是如何被分布到多个服务器上的?(一致性哈希算法) ... -
Apache2.2.x+Tomcat6.x+jk2.x做集群配置
2014-10-18 10:43 452【Middleware】☆★之Apac ... -
单点登录SSO
2014-10-22 21:34 523摘要 :单点登录( ... -
java批量处理数据
2014-06-08 13:51 704程序清单ImproveReadFile .java ... -
大型网站技术架构
2014-06-06 09:38 617看完了有一本书,就 ... -
关于敏捷开发的总结 .
2014-06-06 09:38 429•用例一完全能够运行后再开发用例二。厨房里有一种说法正好可以印 ... -
应聘java项目经理经常遇到的问题
2014-06-06 09:38 651司最近招项目经理,我负责一面。下面是我面试的部分问题,有些问题 ...
相关推荐
通过分析和理解这份源码,开发者可以了解12306购票系统的架构、功能实现、数据交互以及用户体验设计等方面的知识。 【标签】虽然没有提供具体的标签,但我们可以推断出以下几个关键标签: - UWP(Windows Universal...
基于微信小程序的电影购票系统开题报告.zip 基于微信小程序的电影购票系统开题报告.zip 基于微信小程序的电影购票系统开题报告.zip 基于微信小程序的电影购票系统开题报告.zip 基于微信小程序的电影购票系统开题报告...
基于springboot+vue.js的购票系统毕业设计.zip基于springboot+vue.js的购票系统毕业设计.zip基于springboot+vue.js的购票系统毕业设计.zip基于springboot+vue.js的购票系统毕业设计.zip基于springboot+vue.js的购票...
在My12306系统中,Servlet可能被用来处理用户登录验证、查询车票、购票等操作,与JSP协同工作,实现前后端的交互。 HTML5是现代网页的标准,其强大的新特性如离线存储、多媒体支持和表单控件改进,为My12306系统...
sql的电影院购票系统).zipsql的电影院购票系统).zipsql的电影院购票系统).zipsql的电影院购票系统).zipsql的电影院购票系统).zipsql的电影院购票系统).zipsql的电影院购票系统).zipsql的电影院购票系统)....
帮助用户完成互联网在线购票,提高居民买票效率以及减少售票人员工作。项目基础架构采用 JDK17、SpringBoot3 和 SpringCloud Alibaba 构建,完成会员注册、车票查询、车票下单以及支付等业务 毕业设计是高等教育阶段...
使用C++实现命令模式来构建12306购票系统,可以提高系统的灵活性和可维护性。 首先,我们要理解命令模式的主要组成部分: 1. **命令接口**(Command Interface):定义了命令的基本操作,所有具体命令类都应实现这...
总的来说,12306数据库系统设计是一项复杂的工程,涵盖了用户交互、数据管理、流程优化等多个方面,旨在提升铁路购票体验,简化购票过程,提高服务效率。在设计过程中,团队面临了各种挑战,如网站复杂性、数据安全...
# 基于Spring Boot框架的12306购票系统 ## 项目简介 12306购票系统是一个基于Spring Boot框架开发的高效、稳定的购票系统。该系统旨在为用户提供便捷的火车票购买服务,涵盖了从用户登录、车票查询、订单创建到支付...
基于springboot-vue.js的购票系统源码.zip 基于springboot-vue.js的购票系统源码.zip 基于springboot-vue.js的购票系统源码.zip 基于springboot-vue.js的购票系统源码.zip 基于springboot-vue.js的购票系统源码.zip ...
1. **简洁购票网址**:使用简洁的购票网址,如https://dynamic.12306.cn/otsweb/main.jsp,此网址没有多余的图片、CSS和JS,能够更快加载。 2. **支付宝订票**:通过支付宝的应用中心,可以找到“火车票代购”服务...
火车购票系统需求分析.doc
《构建模拟12306铁路购票系统的Java技术解析》 在信息技术日益发达的今天,模拟12306铁路购票系统是一项具有挑战性的实践项目,它涉及到多种核心技术的运用,如用户登录注册、购票流程、信息安全管理以及支付功能等...
总结起来,12306_ticket_helper.crx是一个为12306购票提供便利的Chrome扩展,通过自动化和优化购票流程,极大地提高了用户的购票体验。在享受其便利的同时,用户也应注意隐私保护,确保使用的扩展是安全可靠的。
“hack12306”这个名字暗示了该库可能用于处理12306火车票预订系统的数据或实现与12306接口的交互。12306是中国铁路客户服务中心的官方网站,提供在线购票、改签、退票等服务。由于12306的接口并非完全开放,因此,...
基于javaweb的电影院在线选座购票网站项目源码.zip基于javaweb的电影院在线选座购票网站项目源码.zip基于javaweb的电影院在线选座购票网站项目源码.zip基于javaweb的电影院在线选座购票网站项目源码.zip基于javaweb...
描述中提到“python实现的12306小助手,可以完成很多内部人员才能看到的购票信息”,这暗示了该工具可能具有一定的高级功能,比如实时票源监控、余票分析等,这些信息通常普通用户难以获取。此外,“适合毕业论文...
毕业设计基于Spring Boot的电影院购票系统项目源码,大致分为管理员、用户端、客户服务端,难度适中,新手也可自己操作,二次开发也可以,高分必看。毕业设计基于Spring Boot的电影院购票系统项目源码,大致分为管理...