• 大浏览量系统的静态化架构设计


    1. 引言 

    Web开发如何应对大流量是必须考虑的问题,例如当前的12306网站、淘宝的秒杀系统等都是Web系统会遇到的典型问题。尤其是一些突发流量更是会考验我们系统抗压的能力,所以在设计系统时要考虑很多因素,例如网络结构,网卡瓶颈,系统依赖,缓存,数据一致性等。所以接下来将以淘宝为例,讲述如何大浏览量的系统的静态化架构。

    1. 淘宝大浏览量商品详情系统简介

    什么是大浏览量系统?以java系统为例,正常的用户请求要支撑20w/sQPS(每秒查询率)。根据Alexa全球排名,淘宝目前排名第13位,日均PVPage View)约有25亿,日均独立IP访问约有1.5亿,其中item.taobao.com域名对应的Detail系统约占总PV25%。可以说Detail系统是目前淘宝中单系统访问量最高的系统,当前每秒约有20KB的请求到达淘宝的服务器后端。

    下面介绍这个大浏览量系统的基本情况:

    页面大小45KB,压缩后15KB,峰值带宽2Gbps,服务端页面平均RT15ms.

    静态化改造之前,淘宝的前台系统结构:

     

    1.前台系统基本结构

    前面的Http请求经过负载均衡设备分配到某个域名对应的应用集群,经过Nginx代理到JBoss或者Tomcat容器,由他们负责具体处理用户的请求。目前这些大浏览量的系统大部分需要读取的数据都已经直接走K/V缓存了,不会直接从DB中获取数据。还有一部分应用逻辑会走远程的系统调用。淘宝有一套高性能的分布式服务架构(HSF框架)来提供系统之间的服务调用。

    目前淘宝前台系统都是基于JavaMVC框架开发的(自己的WebX框架)如图所示:

     

    2.前台系统基本结构

    1. 系统面临的挑战

    随着淘宝网站的壮大,系统也面临越来越多的挑战,有些是业务发展带来的挑战,比如双1112的大型活动,秒杀活动等突发流量的冲击。还有一些非正常的访问请求,例如网站经常受到攻击和恶意请求。这些流量有些是可以预测的,有些是不可预测的,不可防范的。

    像这种流量突然暴增的情况对系统的冲击很大,有时候流量瞬间可达20w/sQPS,所以如何让系统更好更稳定的运行是一个大的挑战。

    1. 大浏览量的系统的静态化改造

    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的形式。

     

    如何组装动态内容:

    两种方式获取:ESICSI

    ESIWeb代理服务器上做动态请求内容,并将请求插入到静态页面上去。对服务端性能有影响但是用户体验好。

    CSI:发起一个异步JS单独向服务端获取动态内容。这种方式使服务端性能更好,但是稍有延迟,用户体验稍差。

    4.4 几种静态化方案的设计与选择

    考虑的问题:

    ·是否一致性hash分组?使用则可能会导致热点问题,导致网络瓶颈。

    ·是否使用ESI?使用对性能有影响,但用户体验好。

    ·是否使用物理机?内存更大,cpu更好,但是使集群相对集中,导致网络风险增加。

    ·谁来压缩,在哪压缩?增加Cache,必然增加数据的传输。

    ·网卡选择?成本问题。

    根据这几个问题,可分别采用如下几个方案:

    方案1 采用Nginx+Cache+Java结构的虚拟机单机部署

    结构图如下:

     

    3.Nginx+Cache+Java虚拟机单机部署结构图

    这是最简单的静态化方案,只需要在正常的架构上加一层Cache就行,优缺点如下:

    优点:

    ·没有网络瓶颈,不需要改造网络

    ·机器增加,没有网卡瓶颈

    ·机器数增多,故障风险减少

    缺点:

    ·机器增加,缓存命中率下降

    ·缓存分散,失效难度增加

    ·CacheJBoss都会抢内存

    这种方案虽然简单,但是能够解决热点商品的访问问题。

    方案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节点即可。

    节点条件:

    ·靠近访问量比较集中的地方

    ·离主站较远

    ·到主站的网络好且稳定

    ·容量大

    1. 总结

    本次主要以淘宝的Detail为背景,介绍了静态化架构的设计,其中面临的问题和解决办法,虽然主要以Detail系统为例,但其实架构的设计思路对所有大型的系统都是适用的。

     

    惭愧,一年就写了两篇博客,最近在找实习,又想到写博客了....

    本次博客直接摘自许令波的深入分析JavaWeb技术内幕的最后一章。有兴趣的话大家可以去看看这本书,写的真的不错。

  • 相关阅读:
    AMF序列化技巧
    为什么用ByteArray序列化的对象如此小?
    解决Asp.net中翻页问题的自定义用户控件
    新建对象:反射会调用构造函数,clone不会调用构造函数
    Java 的传值小例子
    JDK中设计模式
    tryfinally中的返回值
    c++类中的常量(注意)
    创建有个性的对话框之MFC篇(转)
    用VC在IE浏览器的工具条上添加命令按钮(转 可以借鉴)
  • 原文地址:https://www.cnblogs.com/Ugly-bear/p/8679302.html
Copyright © 2020-2023  润新知