深度好文-从12306.cn谈大网站架构与性能优化

12306.cn网站挂了,被全国人民骂了。我这两天也在思考这个事,我想以这个事来粗略地和大家讨论一下网站性能的问题。因为仓促,而且完全基于本人有限的经验和了解,所以,如果有什么问题还请大家一起讨论和指正。(这又是一篇长文,只讨论性能问题,不讨论那些UI,用户体验,或是是否把支付和购票下单环节分开的功能性的东西) 业务 任何技术都离不开业务需求,所以,要说明性能问题,首先还是想先说说业务问题。 其一,有人可能把这个东西和QQ或是网游相比。但我觉得这两者是不一样的,网游和QQ在线或是登录时访问的更多的是用户自己的数据,而订票系统访问的是中心的票量数据,这是不一样的。不要觉得网游或是QQ能行你就以为这是一样的。网游和QQ 的后端负载相对于电子商务的系统还是简单。 其二,有人说春节期间订火车的这个事好像网站的秒杀活动。的确很相似,但是如果你的思考不在表面的话,你会发现这也有些不一样。火车票这个事,一方面会伴随着大量的查询操作,更BT的是下单的时候需要对数据库很多的一致性的操作,一方面是从起点到终点各个分段票的一致性,另一方面,买的人路线、车次、时间选择有很多,会不停地改变下单方式。而秒杀,直接杀就好了,没有那么多查询和一致性的问题。另外,关于秒杀,完全可以做成只接受前N个用户的请求(完全不操作后端的任何数据, 仅仅只是对用户的下单操作log),这种业务,只需要在内存cache中放好可秒杀的数量,还可以把数据分布开来放,100产品,10台服务器一台放10个,无需在当时操作任何数据库。可以订单数够后,停止秒杀,然后批量写数据库。而且秒杀的商品不多。火车票这个不是像秒杀那么简单的,春运时间,几乎所有的票都是热门票,而且几乎是全国人民都来了,而且还有转车业务,多条线的库存都要做事务操作,你想想吧,这有多难。(淘宝的双十一也就3百万用户,而火车票瞬时有千万级别甚至是亿级别的)(更新:2014年1月11日:来了淘宝后,对淘宝的系统有了解,淘宝的秒杀活动,本质上是用输验证码并在CDN上把用户直接过滤掉了,比如:1千万个用户过滤了只剩2万个用户,这样数据库就顶得住了) 其三,有人拿这个系统和奥运会的票务系统比较。我觉得还是不一样。虽然奥运会的票务系统当年也一上线就废了。但是奥运会用的是抽奖的方式,也就是说不存在先来先得的抢的方式,而且,是事后抽奖,事前只需要收信息,事前不需要保证数据一致性,没有锁,很容易水平扩展。 其四,订票系统应该和电子商务的订单系统很相似,都是需要对库存进行:1)占住库存,2)支付(可选),3)扣除库存的操作。这个是需要有一致性的检查的,也就是在并发时需要对数据加锁的。B2C的电商基本上都会把这个事干成异步的,也就是说,你下的订单并不是马上处理的,而是延时处理的,只有成功处理了,系统才会给你一封确认邮件说是订单成功。我相信有很多朋友都收到认单不成功的邮件。这就是说,数据一致性在并发下是一个瓶颈。 其五,铁路的票务业务很变态,其采用的是突然放票,而有的票又远远不够大家分,所以,大家才会有抢票这种有中国特色的业务的做法。于是当票放出来的时候,就会有几百万人甚至上千万人杀上去,查询,下单。几十分钟内,一个网站能接受几千万的访问量,这个是很恐怖的事情。据说12306的高峰访问是10亿PV,集中在早8点到10点,每秒PV在高峰时上千万。 多说几句: 库存是B2C的恶梦,库存管理相当的复杂。怀疑,你可以问问所有传统和电务零售业的企业,看看他们管理库存是多么难的一件事。不然,就不会有那么多人在问凡客的库存问题了。(你还可以看看《乔布斯传》,你就知道为什么Tim会接任Apple的CEO了,最主要的原因是他搞定了苹果的库存周期问题) 对于一个网站来说,浏览网页的高负载很容易搞定,查询的负载有一定的难度去处理,不过还是可以通过缓存查询结果来搞定,最难的就是下单的负载。因为要访问库存啊,对于下单,基本上是用异步来搞定的。去年双11节,淘宝的每小时的订单数大约在60万左右,京东一天也才能支持40万(居然比12306还差),亚马逊5年前一小时可支持70万订单量。可见,下订单的操作并没有我们相像的那么性能高。 淘宝要比B2C的网站要简单得多,因为没有仓库,所以,不存在像B2C这样有N个仓库对同一商品库存更新和查询的操作。下单的时候,B2C的 网站要去找一个仓库,又要离用户近,又要有库存,这需要很多计算。试想,你在北京买了一本书,北京的仓库没货了,就要从周边的仓库调,那就要去看看沉阳或 是西安的仓库有没有货,如果没有,又得看看江苏的仓库,等等。淘宝的就没有那么多事了,每个商户有自己的库存,库存就是一个数字,并且库存分到商户头上了,反而有利于性能扩展。 数据一致性才是真正的性能瓶颈。有 人说nginx可以搞定每秒10万的静态请求,我不怀疑。但这只是静态请求,理论值,只要带宽、I/O够强,服务器计算能力够,并支持的并发连接数顶得住10万TCP链接的建立 的话,那没有问题。但在数据一致性面前,这10万就完完全全成了一个可望不可及的理论值了。 我说那么多,我只是想从业务上告诉大家,我们需要从业务上真正了解春运铁路订票这样业务的变态之处。 前端性能优化技术 要解决性能的问题,有很多种常用的方法,我在下面列举一下,我相信12306这个网站使用下面的这些技术会让其性能有质的飞跃。 一、前端负载均衡 通过DNS的负载均衡器(一般在路由器上根据路由的负载重定向)可以把用户的访问均匀地分散在多个Web服务器上。这样可以减少Web服务器的请求负载。因为http的请求都是短作业,所以,可以通过很简单的负载均衡器来完成这一功能。最好是有CDN网络让用户连接与其最近的服务器(CDN通常伴随着分布式存储)。(关于负载均衡更为详细的说明见“后端的负载均衡”) 二、减少前端链接数…

解决MySQL sleep连接太多

  执行show processlist;后打印出大量状态为sleep的连接,可能会有两三百个, 这些都是客户端和 数据库通信后没有释放的。大量的连接会严重拖慢系统速度,阻塞新的MySQL连接建立, 甚至造成MySQL报错, 无法响应。 问题产生的根源有以下3种情况 1.使用了太多持久连接 2.程序中,没有及时关闭mysql连接 3.数据库查询不够优化,过度耗时 最根本的办法是从以上3种情况排查 1.程序中,不使用持久链接,即使用mysql_connect而不是pconnect 2.程序执行完毕,应该显式调用mysql_close 3.只能逐步分析系统的SQL查询,开启慢查询日志,找出低效的SQL语句,然后优化 这是从研发角度排查,如果不方便在代码方面变更, 又想解决问题, 那么就要依靠mysql本身的超时功能解决,命令行键入 mysql> 显示全局变量,如 “%暂停%”;…

再做 Oracle 11gR2 RAC+DG4

第3部分已完成RAC主库到dg备库的日志同步. 这部分将配置dg备库 应用同步过来的日志. 接着完成RAC和dg角色互换. 查看备库是否应用日志 SQL> 选择序列# ,名称 ,从v $ archived_log应用; SEQUENCE#名称已应用 ———- ———————————————————————- ——— 24 +FLASH / phydb / archivelog / 2016_06_23 / thread_1_seq_24.264.915256125否 22 +FLASH / phydb / archivelog / 2016_06_23 / thread_1_seq_22.262.915256125 NO 23…

再做 Oracle 11gR2 RAC+DG3

上一部分配置了dg备库asm磁盘组,RAC主库准备, 这一部分继续dg备库准备,初始化文件, 控制文件,数据库文件恢复, standby logfile创建,RAC主库到dg备库日志同步等内容 将node1节点/rman_backup下面的数据库备份文件, 初始化文件,控制文件, 归档日志全部拷贝的dg的/rman_backup下面 这是node1 /rman_backup/下的备份文件 将这些文件通过FTP,或者其他方式传送到dg备库的/rman_backup目录下,传送完成如下: 物理备库创建口令文件 dg编辑.bash_profile如下: 导出PATH导出TMP = / tmp导出TMPDIR = $ TMP导出ORACLE_HOSTNAME = dg.localdomain导出ORACLE_SID = phydb导出ORACLE_BASE = / u01 / app / oracle…

再做 Oracle 11gR2 RAC+DG2

这一部分开始创建dg备库的asm磁盘组,然后执行RAC主库准备工作。 dg备库切换到grid用户,执行asmca开始配置 创建DATA磁盘组,这是将来存放数据的. 稍等片刻创建成功 用同样的方法创建FLASH磁盘组,完成如下:   dg切换到oracle用户,查看一下刚才创建的磁盘组 su -grid sqlplus / 作为sysdba从v $ asm_diskgroup中选择名称; 名称 ———————————————————————————— DATA GRIDDG FLASH 可见ASM磁盘组创建成功 挂载刚才创建的磁盘/dev/sde 由于格式化成了ext3分区,因此可以直接挂载到/rman_backup目录下…

再做 Oracle 11gR2 RAC+DG1

在https://www.roamway.com/1273.html 中,已配置好RAC数据库, 这次在RAC双机基础上配置DataGuard服务, 可以实现主库和备库之间快速切换, 提供容灾备份能力. 这一部分,我们需要部署好dataguard系统平台, 配置好ASM服务,然后安装单节点grid, 最后安装好oracle软件. 详情如下: 1. 安装操作系统, 这次依旧采用OEL5.5 x64 , 本地磁盘20GB, 主机名dg.localdomain , ip地址 192.168.137.159 ,不启用iptables和selinux. 定制时选择如下安装包: 桌面环境: GNOME桌面…

linux设置别名网卡 转载

  什么是ip别名? 用windows的话说,就是为一个网卡配置多个ip。 when 什么场合增加ip别名能派上用场? 布网需要、多ip访问测试、特定软件对多ip的需要…等等. how 下面通过几个例子简单介绍一下如何使用ifconfig命令给网卡配置ip别名。 至于IP/掩码/DNS/网关/路由的配置,请见路由器/Linux主机/win下主机的路由配置汇总篇。 注意:要注意你的配置是立即生效还是永久的。 一、首先为服务器网卡配置静态ip地址 #ifconfig eth0 192.168.6.99 网络掩码 255.255.255.0 upeth0 …

很重要的安全规范

Web安全原则 1. 认证模块必须采用防暴力破解机制,例如:验证码或者多次连续尝试登录失败后锁定帐号或IP。 说明:如采用多次连续尝试登录失败后锁定帐号或IP的方式,需支持连续登录失败锁定策略的“允许连续失败 的次数”可配置,支持在锁定时间超时后自动解锁。 2. 对于每一个需要授权访问的页面或servlet的请求都必须核实用户的会话标识是否合法、用户是否被授 3. 权执行这个操作,以防止URL越权。 说明:防止用户通过直接输入URL,进行URL越权,请求并执行一些页面或servlet;建议通过过滤器实现。 4. 登录过程中,往服务器端传递用户名和口令时,必须采用HTTPS安全协议(也就是带服务器端证书的SSL)。 只提供本机接入、登录,做设备管理使用的场景暂时不要求。 说明:如果在客户端和服务器间传递如帐号、口令等敏感数据,必须使用带服务器端证书的SSL。由于SSL对 服务端的CPU资源消耗很大,实施时必须考虑服务器的承受能力。 5. 对用户的最终认证处理过程必须放到服务器进行。 6. 用户产生的数据必须在服务端进行校验;数据在输出到客户端前必须先进行HTML编码,以防止执行恶意 代码、跨站脚本攻击。对于不可信的数据,输出到客户端前必须先进行 HTML 编码。 7. 使用主流Web安全扫描工具扫描Web服务器和Web应用,不存在“高”级别的漏洞。 8. 非嵌入式产品的Web应用,应使用预编译语句PreparedStatement代替直接的语句执行Statement, 以防止SQL注入。 数据库安全 外购数据库、开源数据库、自研数据库都应进行安全配置,保证不出现安全漏洞。 1. 数据库口令禁止使用数据库厂商的缺省口令,且口令复杂度需满足“口令安全要求”。…