你尚未登录,仅允许查看本站部分内容。请登录使用邀请码注册
前端农民工

前端工程之CDN部署 14个回复 专栏 @ 架构

前端农民工 发布于 2 年前

之前发的一篇文章《变态的静态资源缓存与更新》中提到了静态资源和页面部署之间的时间间隙问题,这个问题会迫使前端静态资源发布必须采用非覆盖式。那篇文章中没有详细解释为什么会产生不可忍受的时间间隙,本文算是对它的补充。

之所以会产生部署时差,最主要的原因就是使用了CDN服务。

大型Web应用对速度的追求并没有止步于仅仅利用浏览器缓存,因为浏览器缓存始终只是为了提升二次访问的速度,对于首次访问的加速,我们需要从网络层面进行优化,最常见的手段就是CDN(Content Delivery Network,内容分发网络)加速。通过将静态资源缓存到离用户很近的相同网络运营商的CDN节点上,不但能提升用户的访问速度,还能节省服务器的带宽消耗,降低负载。

FgZxWG4HKrtz1XVoyQjBD73hxUmv
遍布全国的CDN节点和内容源示意图

不同地区的用户会访问到离自己最近的相同网络线路上的CDN节点,当请求达到CDN节点后,节点会判断自己的内容缓存是否有效,如果有效,则立即响应缓存内容给用户,从而加快响应速度。如果CDN节点的缓存失效,它会根据服务配置去我们的内容源服务器获取最新的资源响应给用户,并将内容缓存下来以便响应给后续访问的用户。因此,一个地区内只要有一个用户先加载资源,在CDN中建立了缓存,该地区的其他后续用户都能因此而受益。

Fl-c2Sc0PpvSata5Ni4B-onvuk6c
使用CDN缓存技术加速网络访问速度

如上图所示,之所以不同地区的用户访问同一个域名却能得到不同CDN节点的IP地址,这要依赖于CDN服务商提供的智能域名解析服务,浏览器发起域名查询时,这种智能DNS服务会根据用户IP计算并返回离它最近的同网络CDN节点IP,引导浏览器与此节点建立连接以获取资源。

结合上述两点,为了使用CDN网络缓存,我们至少要对静态资源的部署做两项改变:

  1. 将静态资源部署到不同网络线路的服务器中,以加速对应网络中CDN节点无缓存时溯源的速度。
  2. 加载静态资源时使用与页面不同的域名,一方面是便于接入为CDN而设置的智能DNS解析服务,另一方面因为静态资源和主页面不同域,这样加载资源的HTTP请求就不会带上主页面中的Cookie等数据,较少了数据传输量,又进一步加快网络访问。

CDN服务基本上已经成为现代大型Web应用的标配,这项技术“几乎”是一种对开发透明的网络性能优化手段,使用它的理由很充分,但是这里既然强调了“几乎透明”而不是“完全透明”,是因为使用CDN服务所需要的两项改变对前端工程产生了一定的影响,而这些影响我在之前的文章中已经介绍了,就是前端工程必须引入非覆盖式发布的根本原因。


前端工程多米诺骨牌

上图向大家展示了整个前端静态资源缓存技术所带来的连锁性工程问题。很多人不理解为什么要选择FIS,而不是grunt,从本质上来说,工具并么有什么差异,只是fis的设计出发点是以上这些工程问题,设计中优先考虑了现代互联网应用是如何进行工程化部署与开发的,面临的问题是哪些,基于这些问题,要怎么解决。

比如我们在上图中可以看到,整个静态资源缓存技术的最终影响的节点是前端静态资源定位问题,而且前端资源定位又会进一步影响到开发,包括代码中的模块化加载、各种资源加载等。所以fis的设计核心之一就是资源定位。比如fis的核心配置roadmap,其目的就是为了解决在前端代码中的所有资源定位问题,连接开发和部署规范:

此外,fis的静态资源表生成功能也是为了给模块化框架提供加载部署到其他域名下的路径中md5戳的资源部署路径,并建立资源之间的依赖关系。

至于文件压缩之类的功能,那只是工具问题,而非工程问题。

  • nimo

    又拜读了 fouber 的文章。
    请教一个关于前端静态资源cdn部署的问题:

    我们分为本地开发环境、测试机环境、正式机环境。

    理想状态:

    {{STATIC "filename"}} 是前端开发环境和后端开发环境都支持的资源管理语法。依赖 map.json

    本地开发环境:

    <script src="{{STATIC 'js/demo.js'}}" ></script>
    // 渲染(本地开发时不进行 md5 处理)
    <script src="/dist/js/demo.js" ></script>
    

    对文件进行 md5 处理生成 map.json

    {
    "res": {
        "js/demo": {
                "uri": "/dist/js/demo_a3js78dsd.js",
                "type": "js"
            }
        }
    }
    

    测试机环境

    <script src="{{STATIC 'js/demo.js'}}" ></script>
    // 渲染 (测试机访问测试机上的资源文件,并非cdn服务器)
    <script src="/dist/js/demo_a3js78dsd.js" ></script>
    

    测试没问题,将 map.json 文件 和 map.json 中的 res 资源 uri 发布到正式的前端静态资源服务器 cdn

    复制 map.json 到 后端正式机服务器
    检索到测试机上的 /dist/js/demo_a3js78dsd.js ,将其发布到 http://cdn.domain.com/product/version/dist/js/demo_a3js78dsd.js


    正式机环境

    <script src="{{STATIC 'js/demo.js'}}" ></script>
    // 渲染 (正式机在 map.json 中检索出 路径,并加上 cdn 的前缀)
    <script src="http://cdn.domain.com/product/version/dist/js/demo_a3js78dsd.js" ></script>
    

    本地、测试机、正式机的 {{STATIC 'js/demo.js'}} 输出结果不一样,是通过定义常量实现的。比如:

    var STATIC_ROOT = 'http://cdn.domain.com/product/version/';
    function STATIC (path) {
    var map = readFile('map.json');
        var uri = map.res[path][uri]; // /dist/js/demo_a3js78dsd.js
     if (DEV === 'local') {
        return '/' + path; // js/demo.js
        } else if (DEV === 'test') {
        return uri // /dist/js/demo_a3js78dsd.js
        } else if (DEV === 'online'){
        return STATIC_ROOT + uri; // http://cdn.domain.com/product/version/dist/js/demo_a3js78dsd.js
        }
    
    }
    

    这是我心中最理想的状态。

    1. 前端在本地开发完成,提交代码到测试机,与后端联调和测试。
    2. 确认没问题后,由后端统一发布后端代码和前端资源到正式后端服务器和前端静态资源服务器
    3. 正式环境中根据 map.json 和定义的常量拼凑输出完整路径 http://cdn.domain.com/product/version/dist/js/demo_a3js78dsd.js

    问题:

    我担心测试机代码发布到正式机后因为前端静态资源在cdn部署过程中出现问题,导致页面出错。 求教 fouber,如上方式是否可行。

    目前是前端本地开发环境开发完成以后提交后端模板代码到测试机,而前端静态资源由开发人员发布到 前端静态资源服务器。 在测试机上直接访问的就是 http://cdn.domain.com/product/version/dist/js/demo_a3js78dsd.js 。但这样每次修改代码发布到测试机时,都需要生成和发布 “md5” 文件,会产生很多开发版本的冗余文件。

    #1
  • 前端农民工

    @nimo 只要先部署静态资源到CDN服务器,然后在让后端上线模板和map.json就可以了。在单机部署的过程中,覆盖map.json的时间足够短,不用担心

    #2
  • nimo

    @前端农民工 感谢指点,请教文中提到的

    那篇文章中没有详细解释为什么会产生不可忍受的时间间隙

    具体是指的是什么样的间隔?

    #3
  • 前端农民工

    @nimo 就是这篇文章。。。 当项目采用cdn部署之后,我们的静态资源将和页面分开部署,分开的后果就是对静态资源的发布和网页发布之间有一段时间间隙,没办法保证同步,这才引来了非覆盖式

    #4
  • nimo

    @前端农民工 明白了,指的是先发布前端资源后发布页面中间的时间间隔。

    #5
  • ourfeel

    用内容摘要做非覆盖式更新 是什么意思

    #6
  • fansekey

    @ourfeel

    内容摘要

    md5 的意思,意思就是文件名后跟上 md5 戳。

    #7
  • krui

    如果CDN报错,有没有方案让其自动切换到本地资源???

    #8
  • ourfeel

    @krui 不需要考虑, 出问题这时候应该第一时间去找cdn提供商

    #9
  • krui

    由于使用的是免费的,所以我们还是做了plan B, cdn出了问题就自动切本地的。实现由后台切换到另外一个模版。

    #10
  • liuhuiashazj

    赞,云龙太牛了

    #11
  • rambo

    @nimo 问您两个问题 您的map.json是放在后台是吧? 那你前后端分离怎么做? 如果是放到cdn前端动态获取 你怎么防止map.json不被缓存

    #12
  • nimo

    @rambo

    我们前后端不是分离的,但是后端用 SVN 前端用 GIT,当git master 提交后 web hook 触发脚本使用 fis 生成 map.json ,然后将 map.json 提交到 后端svn 中,同时将静态资源发布到前端的 cdn中。

    #13
  • Thinking80s

    配图很赞,前端非覆盖式的增量更新很有必要在大型站点推行。

    #14
登录后回复,如无账号,请使用邀请码注册