- 引言
Web开发如何应对大流量是必须考虑的问题,例如当前的12306网站、淘宝的秒杀系统等都是Web系统会遇到的典型问题。尤其是一些突发流量更是会考验我们系统抗压的能力,所以在设计系统时要考虑很多因素,例如网络结构,网卡瓶颈,系统依赖,缓存,数据一致性等。所以接下来将以淘宝为例,讲述如何大浏览量的系统的静态化架构。
- 淘宝大浏览量商品详情系统简介
什么是大浏览量系统?以java系统为例,正常的用户请求要支撑20w/s的QPS(每秒查询率)。根据Alexa全球排名,淘宝目前排名第13位,日均PV(Page View)约有25亿,日均独立IP访问约有1.5亿,其中item.taobao.com域名对应的Detail系统约占总PV的25%。可以说Detail系统是目前淘宝中单系统访问量最高的系统,当前每秒约有20KB的请求到达淘宝的服务器后端。
下面介绍这个大浏览量系统的基本情况:
页面大小45KB,压缩后15KB,峰值带宽2Gbps,服务端页面平均RT约15ms.
静态化改造之前,淘宝的前台系统结构:
图1.前台系统基本结构
前面的Http请求经过负载均衡设备分配到某个域名对应的应用集群,经过Nginx代理到JBoss或者Tomcat容器,由他们负责具体处理用户的请求。目前这些大浏览量的系统大部分需要读取的数据都已经直接走K/V缓存了,不会直接从DB中获取数据。还有一部分应用逻辑会走远程的系统调用。淘宝有一套高性能的分布式服务架构(HSF框架)来提供系统之间的服务调用。
目前淘宝前台系统都是基于Java的MVC框架开发的(自己的WebX框架)如图所示:
图2.前台系统基本结构
- 系统面临的挑战
随着淘宝网站的壮大,系统也面临越来越多的挑战,有些是业务发展带来的挑战,比如双11双12的大型活动,秒杀活动等突发流量的冲击。还有一些非正常的访问请求,例如网站经常受到攻击和恶意请求。这些流量有些是可以预测的,有些是不可预测的,不可防范的。
像这种流量突然暴增的情况对系统的冲击很大,有时候流量瞬间可达20w/s的QPS,所以如何让系统更好更稳定的运行是一个大的挑战。
- 大浏览量的系统的静态化改造
4.1 静态化系统
静态化系统通常包含如下几方面的特征。
·一个页面对应的URL通常是固定的。
·页面中不能包含于浏览者相关的因素。
·页面中不包含时间因素。服务端输出的时间
·页面中不包含地域因素。
·不包含Cookie等私有数据
4.2 为什么要进行静态化设计
前面我们分析了系统面临的各种挑战,这些挑战都涉及性能优化,那性能优化为什么要进行静态化这种架构设计呢?
因为,淘宝其实已经经历了很多次系统的迭代升级,比如09年的静态文件合并,前端页面异步化和JSON化,10年的去DB依赖,引入K/V缓存和11年优化Velocity,BigPipe等都是优化的例子,但是这只是从Java系统层面上的优化,改进思路也一直是怎么更快的获取数据,并更快的将数据返回给用户。但是当将系统所有数据全部缓存,然后将结果直接返回的时候我们的系统不能满足预期的目标,也就说Java系统不可能达到每秒上万的QPS。
所以,我们判断Java系统本身已经达到瓶颈,那我们就必须跳过java系统,也就是让请求尽量不经过java系统,在前面的Web服务器层就直接返回是,所以,静态化这种架构就成了必然选择。
静态化系统改变了缓存方式,直接缓存Http连接而不是缓存数据,Web代理服务器根据请求URL直接取出对应的HTTP响应头和响应体直接返回,这个响应连Http都不用重新组装了。同样,http头也不一定需要解析,这样做到获取数据最快。还改变了缓存的地方,不是java层面的缓存了,而是web服务器层上做缓存,所以屏蔽了java层面的弱点。
4.3 如何改造动态系统
以Detail系统为例。
动静分离:
·URL唯一化。Detail系统天然就是可以做到URL唯一化,因为可以以ID做唯一标识URL.
·分离于浏览者相关的因素,是否登陆与登陆信息等可以单独拆分,动态获取。
·分离时间因素,服务端输出的时间也可以动态获取。
·异步化地域因素。把Detail系统上的地域相关的做成异步方式来获取。
·去掉Cookie.
动态内容结构化:
将动态内容json化。对于Detail系统虽然商品信息可以缓存,不需要动态获取但是也可以将关键信息做成json的形式。
如何组装动态内容:
两种方式获取:ESI和CSI
ESI:Web代理服务器上做动态请求内容,并将请求插入到静态页面上去。对服务端性能有影响但是用户体验好。
CSI:发起一个异步JS单独向服务端获取动态内容。这种方式使服务端性能更好,但是稍有延迟,用户体验稍差。
4.4 几种静态化方案的设计与选择
考虑的问题:
·是否一致性hash分组?使用则可能会导致热点问题,导致网络瓶颈。
·是否使用ESI?使用对性能有影响,但用户体验好。
·是否使用物理机?内存更大,cpu更好,但是使集群相对集中,导致网络风险增加。
·谁来压缩,在哪压缩?增加Cache,必然增加数据的传输。
·网卡选择?成本问题。
根据这几个问题,可分别采用如下几个方案:
方案1 采用Nginx+Cache+Java结构的虚拟机单机部署
结构图如下:
图3.Nginx+Cache+Java虚拟机单机部署结构图
这是最简单的静态化方案,只需要在正常的架构上加一层Cache就行,优缺点如下:
优点:
·没有网络瓶颈,不需要改造网络
·机器增加,没有网卡瓶颈
·机器数增多,故障风险减少
缺点:
·机器增加,缓存命中率下降
·缓存分散,失效难度增加
·Cache和JBoss都会抢内存
这种方案虽然简单,但是能够解决热点商品的访问问题。
方案2 Nginx+Cache+Java结构实体机单机部署
结构图如下:
图4.Nginx+Cache+Java实体机单机部署结构图
优点如下:
·没有网络瓶颈,内存大
·减少Vish机器,提升命中率
·减少Cache失效的压力
·减少Gzip的压缩
方案3 统一Cache层
结构图如下:
图5.统一Cache层架构
优点:
·减少多个应用接入使用Cache成本,接入的应用只维护自己的Java系统。
·统一Cache易于维护,比如配置,监控自动化。统一维护升级。
·共享内存最大化利用内存。
·有助于安全防护。
4.5 如何解决失效问题:
缓存问题解决了,接下来应该解决失效问题了,采用主动失效和被动失效相结合的方式。
被动失效:
主要采用处理模板变更和对时效性要求不高的数据失效,采用设置Cache时间的长度这种自动失效方式,同时也要开发后台管理界面手工失效这些cache.
主动失效:
·Cache失效中心监控数据库表的变化,发送失效请求
·Java系统发布,清空Cache
·Vm模板发布,清空Cache
失效中心通过监控关键数据对应表的变更来发送请求给Cache,从而清楚Cache,其逻辑图如下:
图6.失效中心逻辑图
4.6 服务端的静态化方案的演变:CDN化(内容分发网络)
将动态系统静态化后,将Cache前移到CDN中,效果会更好。但是面临如下几个问题:
·失效问题。CDN分布很广,秒级的时间失效大量Cache难度很大
·命中率问题。CDN是分散的,Cache移到CDN中则命中率必然下降
·发布更新问题。业务发布和问题回滚排查也是需要考虑的方面。
解决方案:
失效问题:
类比服务端静态化的失效方案,对CDN也采用类似的方式设计级联失效结构,如图:
图7.级联失效逻辑图
命中率问题:
既然所有的CDN上放Detail不可行,那么挑部分CDN节点即可。
节点条件:
·靠近访问量比较集中的地方
·离主站较远
·到主站的网络好且稳定
·容量大
- 总结
本次主要以淘宝的Detail为背景,介绍了静态化架构的设计,其中面临的问题和解决办法,虽然主要以Detail系统为例,但其实架构的设计思路对所有大型的系统都是适用的。
惭愧,一年就写了两篇博客,最近在找实习,又想到写博客了....
本次博客直接摘自许令波的深入分析JavaWeb技术内幕的最后一章。有兴趣的话大家可以去看看这本书,写的真的不错。