WEB应用

小网站最简单实用的动静分离优化方案

Jager · 2月3日 · 2018年 · · 12302次已读

很久没写文章了,博客已经长草了,今天挤点时间分享一些小干货,也是回应一下不少站长朋友的留言问题。

有不少站长朋友问张戈博客的静态文件为啥是另外一个域名?有啥好处?如何实现?

小网站最简单实用的动静分离优化方案

其实这算是一种动静分离的做法,不过我这里用了偷懒的办法实现,而非彻底的动静分离,不过最终效果的区别并不大。

先啰嗦一下动静分离的概念和好处。

一、动静分离

我们的网站简单来说分为 2 种数据资源,一种是动态的数据,即 PHP 等程序语言实时吐出来的数据,在网页内容上主要是 HTML 代码,另一种则是静态资源,比如图片、css、js、视频等(当然,图片等资源也可能是实时动态生成的,比如 PHP 缩略图,这里就不展开讨论了)。

一般网站初建,因为流量小、业务简单等原因,都默认将两种数据放到一台服务器上提供服务。访问量大到一定程度之后,就可能出现带宽不足、甚至磁盘高 IO 等问题。这时,作为运维工程师或者架构师就会给出动静分离优化的建议了。做法并不复杂,运维工程师会将图片等静态资源同步到另一台 WEB 服务器,然后新增绑定一个二级域名,比如 static.domain.com,最后让开发将网页代码中的静态资源替换成这个二级域名即可。

这样一来,图片等静态资源的访问就落到了新增的服务器上,从而分担了大部分访问数据流量和 IO 负载,我们还可以针对性的给静态资源 WEB 做一些优化,比如 JS/CSS/图片压缩、内存缓存、浏览器缓存等等。进一步,我们还可以将静态资源接入 CDN,实现资源就近访问。

小网站最简单实用的动静分离优化方案

可以用一张图来表示:

二、好处分析

1、常规做法的好处

从上文的通俗解释来看,很明显的一个好处就是解决带宽问题,像博客圈子里的服务器,绝大部分主机都是国内的小管道云服务器(带宽小于 2M),并发访问量上来之后,就能很明显的感觉到带宽成为了瓶颈。

不过,博客圈大部分都是“一穷二白”,一般都不愿意再买一台服务器来专门承载静态资源,而且多台服务器之间的数据同步等日常维护问题也变相提高了折腾门槛。因此,国内大部分小博客都热衷于套一层 CDN 来解决带宽问题,确实是一个很好的解决方案。在《分享张戈博客的 WordPress 优化方案,缓解国内云服务器配置低下的问题》一文中,也是特别提到了这一茬。

2、本文分享方案的好处

上文说张戈博客使用了一种偷懒的方案,做法很简单:网站只用一台服务器,但是会新增绑定一个和主站完全不一样的二级域名,比如张戈博客主站是 zhang.ge,而二级域名用的是 res.zgboke.com,并且给这个二级域名套了一层 CDN

这样做又有什么好处?和直接套一层 CDN(比如云加速)有什么不同?

  • 第 1 个好处:显而易见比常规动静分离成本更低,分离前后服务器数量不变
  • 第 2 个好处:解决主站直接使用一级域名带来的 cookies“污染”,即静态资源不会再带上主站的 cookies 数据,减小了体积。这个在上文提到的优化方案一文中也着重提到,详细就不再赘述;
  • 第 3 个好处:这个方案对于网站内容没法备案又想体验国内 CDN 加速快感的网站绝对是福音!很多网站因为内容特殊(邪恶脸)没法完成备案,所以无法使用国内的 CDN,那么就可以用本文分享的方法,直接花钱买一个备过案的垃圾域名,做好动静分离,然后将这个二级域名接入国内的 CDN,网站速度绝对可以得到质的飞跃,是不是爽歪歪?
  • 第 4 个好处:这个和第二个比较类似,主要针对在百度云加速购买了付费套餐的朋友。因为,对于一般流量的网站,你只需要在百度云加速给一个域名购买一个专业版,那么就可以分离多个二级域名给 N 个网站使用,那么多个人合买一个专业版完全不成问题吧?当然,现在百度云加速也学聪明了,现在流量限制 50G/天(我开始用这个方案的时候无此限制),但是对于普通网站已经很够用了!!!
  • 第 5 个好处:CDN 配置更加比较简单,因为这种静态二级域名,接入 CDN 之后,完全不用考虑缓存规则的问题,因为直接设置成全部缓存就好了!简单粗暴。

三、部署教程

原理贼简单,就是在服务器上利用反向代理新增了一个新网站,内容则是反向代理了我们的主站,从而实现了 2 个域名共享相同的网站数据。

Vhost 示范规则如下:

server
    {
        listen 80;
        # HTTPS 配置略
        server_name res.zgboke.com; # 改成实际二级域名
        index index.html index.htm index.php default.html default.htm default.php;
        root  /data/wwwroot/zhang.ge;
        # 图片等静态资源请求代理到本地主站(关键配置)
        location ~* .*\.(js|css|png|jpeg|jpg|bmp|ico|ogg|ogv|svg|svgz|eot|otf|woff|woff2|mp4|ttf|rss|atom|zip|tgz|gz|rar|bz2|doc|xls|exe|ppt|tar|mid|midi|wav|bmp|rtf)$ {
                add_header Access-Control-Allow-Origin *; # 解决字体跨站问题
                add_header Access-Control-Allow-Headers X-Requested-With;
                add_header Access-Control-Allow-Methods GET,OPTIONS;
                proxy_pass http://127.0.0.1; # 如果是启用了 https 的网站,这里最好改成 https://127.0.0.1,避免主站加了非 https 协议的跳转配置,导致不成功。
                proxy_set_header  X-Forwarded-For $remote_addr;
                proxy_redirect off;
                proxy_set_header Host zhang.ge; # 这里改为实际主站域名(必须)
                expires max;                       # 设置浏览器 304 缓存为最长期限
        }
        # 为这个二级域名额外设置一个 robots 文件
        location ~ (robots.txt) {
                rewrite /robots.txt /resrobots.txt last;  # 在网站根目录新增一个 resrobots.txt,内容和七牛 CDN 类似,禁止搜索引擎抓取非静态资源(resrobots.txt 内容参考:https://zhang.ge/5104.html)
        }
        # 如果通过静态域名访问的是非静态资源,比如访问了我们的文章页面,则跳到主站对应的页面。
        location / { 
            if ( $request_uri !~* .*\.(js|css|png|jpeg|jpg|gif|bmp|ico|ogg|ogv|svg|svgz|eot|otf|woff|woff2|mp4|ttf|rss|atom|zip|tgz|gz|rar|bz2|doc|xls|exe|ppt|tar|mid|midi|wav|bmp|rtf)) 
                {
                rewrite ^(.*)$ $scheme://zhang.ge$1 permanent; # zhang.ge 修改为实际主站域名
            }
        }
        location ~ /\. { deny  all; access_log off; log_not_found off; }
        access_log /data/wwwlogs/res.zgboke.com.log access;
}

这样就在本地新增了和主站共用一份数据的二级域名,只提供静态资源访问,其他访问都跳到主站对应页面。

完成新增后,只需要使用以前分享的七牛 CDN 代码或者 CDN 插件,将网站的静态资源替换为这个新二级域名,比如以前分享的纯代码版,加到 functions.php 即可完成替换:

/**
 * WordPress CDN 代码版 By 张戈博客
 * 原文地址:https://zhang.ge/4905.html
**/

function QiNiuCDN(){
    function Rewrite_URI($html){
        $domain = 'zhang\.ge';   //填写主站域名,小数点前需要加上反斜杠转义
        $static = 'res.zgboke.com'; //填写二级静态域名
        //更多静态资源需要替换,可以将后缀加到后面的括号,使用分隔符分割
        $html = preg_replace('/http(s|):\/\/'.$domain.'\/wp-([^"\']*?)\.(jpg|png|gif|bmp|jpeg|css|js)/i','//'.$static.'/wp-$2.$3',$html);

        return $html;
	}
    
    if(!is_admin()){
        ob_start("Rewrite_URI");
    }
}

add_action('init', 'QiNiuCDN');

完成部署后,我们网站的前台页面中的图片、js 等静态资源链接就全部换成了新的二级域名了

Tips:其他部署方法

如果网站未启用 https,完全可以更简单,只需要在我们的主站 vhost 配置的 server_name 参数中新增一个域名即可,比如:

server_name zhang.ge res.zgboke.com;

当然,强迫症患儿们,还可以根据域名判断,来进行上述 Vhost 类似跳转,此处就不展开了。

同样的,对于虚拟主机来说,只需要在虚拟主机控制面板中新增一个二级域名绑定即可。但是这个方法不适用于 https 站点,因为一般的 https 证书并不能用于 2 个完全不一样域名。

最后,我们将这个二级域名接入 CDN 即可,接入方法就不啰嗦了,自己折腾吧!

45 条回应
  1. 明月登楼 2018-2-3 · 22:50

    哦,这个方法比较有新意!不错,有空试试看!

    • 懿古今 2018-2-4 · 9:20

      一个百度云加速专业版可以绑定多个二级域名,你的站点非常适合使用

      • avatar
        Jager 2018-2-4 · 9:27

        几个人合租一个即可,每个人使用一个二级域名,代理价500多,5个人合租每人就100/年了,实惠得很。

        • 龙笑天 2018-2-5 · 16:56

          666 还可以这样玩啊~ :shock:

        • 明月登楼 2018-2-6 · 8:49

          哎,我正在申请独立域名呢!备案都快下来了!

  2. 明月登楼学习笔记 2018-2-3 · 22:51

    最近正在备案独立域名,到时可以试试看!

  3. 柯善康 2018-2-4 · 1:22

    博主你好,我按照此文章进行配置,结果所有的Request最终还是到了主域名,并非资源域名。

    • 柯善康 2018-2-4 · 1:29

      网站启用了HTTPS。我的nginx配置文件如下

      server
      {
          listen 80;
      	listen 443 ssl;
          server_name res.firen.cc; # 改成实际二级域名
          index index.php index.html index.htm default.php default.htm default.html;
          root /home/wwwroot/mrksk.com/wordpress;
          
          #SSL-START SSL相关配置,请勿删除或修改下一行带注释的404规则
          #error_page 404/404.html;
          #HTTP_TO_HTTPS_START
          if ($server_port !~ 443){
              rewrite ^(/.*)$ https://res.firen.cc$1 permanent;
              #rewrite ^(/.*)$ https://$host$1 permanent;
          }
          #HTTP_TO_HTTPS_END
          ssl_certificate    /etc/letsencrypt/live/res.firen.cc/fullchain.pem;
          ssl_certificate_key    /etc/letsencrypt/live/res.firen.cc/privkey.pem;
          ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
          ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
          ssl_prefer_server_ciphers on;
          ssl_session_cache shared:SSL:10m;
          ssl_session_timeout 10m;
          error_page 497  https://res.firen.cc$request_uri;
          #error_page 497  https://$host$request_uri;
      
          #SSL-END
          
          #禁止访问的文件或目录
          location ~ ^/(\.user.ini|\.htaccess|\.git|\.svn|\.project|LICENSE|README.md)
          {
              return 404;
          }
          # 图片等静态资源请求代理到本地主站(关键配置)
          location ~* .*\.(js|css|png|jpeg|jpg|bmp|ico|ogg|ogv|svg|svgz|eot|otf|woff|woff2|mp4|ttf|rss|atom|zip|tgz|gz|rar|bz2|doc|xls|exe|ppt|tar|mid|midi|wav|bmp|rtf)$ {
                  add_header Access-Control-Allow-Origin *; # 解决字体跨站问题
                  add_header Access-Control-Allow-Headers X-Requested-With;
                  add_header Access-Control-Allow-Methods GET,OPTIONS;
                  proxy_pass http://127.0.0.1;
                  proxy_set_header  X-Forwarded-For $remote_addr;
                  proxy_redirect off;
                  proxy_set_header Host mrksk.com; # 这里改为实际主站域名(必须)
                  expires max;                       # 设置浏览器304缓存为最长期限
          }
          # 为这个二级域名额外设置一个robots文件
          location ~ (robots.txt) {
                  rewrite /robots.txt /resrobots.txt last;  # 在网站根目录新增一个resrobots.txt,内容和七牛CDN类似,禁止搜索引擎抓取非静态资源(resrobots.txt内容参考:https://zhang.ge/5104.html)
          }
          # 如果通过静态域名访问的是非静态资源,比如访问了我们的文章页面,则跳到主站对应的页面。
          location / { 
              if ( $request_uri !~* .*\.(js|css|png|jpeg|jpg|gif|bmp|ico|ogg|ogv|svg|svgz|eot|otf|woff|woff2|mp4|ttf|rss|atom|zip|tgz|gz|rar|bz2|doc|xls|exe|ppt|tar|mid|midi|wav|bmp|rtf)) 
              {
                  rewrite ^(.*)$ $scheme://mrksk.com$1 permanent; # zhang.ge 修改为实际主站域名
              }
          }
          location ~ /\. { deny  all; access_log off; log_not_found off; }
          access_log  /home/wwwlogs/res.firen.cc.log;
      }
      • avatar
        Jager 2018-2-4 · 8:41

        联系下我QQ,或者贴一下主站配置看看

        • avatar
          Jager 2018-2-4 · 9:17

          原因已定位,LZ的主站对非https的访问全部跳转到了主站,所以出现了跳转问题。
          解决办法很简单,新增二级域名的vhost,反向代理到主站的时候走https即可,即http://127.0.0.1 改为 https://27.0.0.1 (已更新到vhost代码注释当中)

  4. 笛声 2018-2-4 · 9:12

    对于图片过多的网站,cookie携带确实是个大问题 ,很值得按文中的方法折腾,我自己的博客就用不着了。

    • avatar
      Jager 2018-2-4 · 9:17

      cookies瘦身也只是好处之一,主要是有些人有一些特殊的需求 :grin:

  5. 沈唁志 2018-2-4 · 9:19

    之前折腾过七牛云融合CDN,但是好像还是配置有问题失败了就没折腾,默默的去用了腾讯的CDN

    • avatar
      Jager 2018-2-4 · 9:20

      腾讯的好啊,感谢支持。 :mrgreen:

  6. 憧憬点滴记忆 2018-2-4 · 15:17

    可以的,我目前所有的资源都是通过CDN缓存着,一个月50G的免费流量将就着用 :mrgreen:

  7. 西枫里博客 2018-2-4 · 20:43

    现在备过案的垃圾域名如果在原IDC商上解除了绑定,会被IDC商取消接入,备案被注销后,就gameover了。

    • avatar
      Jager 2018-2-4 · 21:33

      大部分IDC不会主动注销,除非遇到空壳域名巡检等动作才可能。比如阿里云,之前咨询过客服并不会主动注销备案。当然,如果觉得垃圾域名不靠谱,那就老老实实找一个域名挂一个简单页面做个备案就好了,然后给无法备案的目标域名使用,从而解决大问题。

  8. Alliot 2018-2-4 · 22:26

    好办法! 不过强迫症表示会将反代也做https。。。。不然页面中引用了http的静态资源会提示网页包含不安全内容。。。。

    • avatar
      Jager 2018-2-5 · 8:03

      你说的不对吧,浏览器只认最直接请求到的那一层,也就是说二级域名只要对外启用了https就不会有你说的不安全提示问题,除非这个域名开启了HPKP机制,对全程访问进行https校验,否则是没问题的。
      比如,很多CDN都可以设置回源协议是http还是https,如果主站是启用了https的,那么反代当然也推荐使用https回源了

      • Alliot 2018-2-6 · 16:45

        感谢,实验了一下,发现自己说的不对,感谢张大哥纠正!

  9. 小C博客 2018-2-5 · 14:02

    还有一种更简单的,不需要在服务器上做nginx反代,直接通过绑定新二级域名(非主站)七牛来操作静态文件,也可以达到这种效果,同时还可以在套一个免费CDN,这样七牛的流量也省了!

    • avatar
      Jager 2018-2-5 · 14:07

      嗯,其实七牛就类似这种模式,不过他会缓存一份到他那边的各个CDN节点。你这种做法相当于是七牛给你做了一层反代了。不过我记得七牛应该是要用备案的域名。

  10. 时光在路上 2018-2-5 · 22:39

    好久没更新了,这篇文章挺好,我好像茅塞顿开了。不过还有个问题想向你请教:动静分离,上面的二级域名funcitons.php的设置,你是怎么排除一些js文件的呢?因为有些js不能放到CDN上面,否则会出错,引来更麻烦的设置。

  11. 亦或YIH 2018-2-6 · 10:42

    博主前段时间博客不能访问,现在恢复啦 :razz:

  12. 瓦工哦 2018-2-8 · 20:57

    非静态资源跳转的那几行是不是和防止镜像网站的那个img标签重复?

    • avatar
      Jager 2018-2-9 · 14:40

      重复有什么关系呢?nginx这个针对任何请求生效,而img那个只针对浏览器生效。

  13. alexa 2018-2-9 · 14:57

    这样做法是文件都在一台服务器上,最好是不是将静态资源放到独立服务器,在用上腾讯cdn等套上,会不会更好?或者将静态资源放到又拍,七牛,腾讯oss?

    • avatar
      Jager 2018-2-9 · 15:21

      文章说了这是偷懒的做法,简单快速实现动静分离,你说的是更彻底的做法,那就不是一台服务器可以搞定的了。还是仔细看下文章呐。。。

  14. Yvon 2018-2-9 · 16:21

    感谢分享,一直在关注你,学习了不少知识 :mrgreen:

  15. puffbaby 2018-2-10 · 11:23

    现在是在服务器用的pagespeed做的优化,也做了用二级域名优化静态资源。有没有什么比较好的支持HTTPS的CDN啊?而且换证书比较方便。然而用的是Let's Encrypt的自动更新证书,去CDN换证书好麻烦。

  16. 明月登楼 2018-2-11 · 13:29

    其实就是将七牛的“动静分离”给本地化了! :grin: :mrgreen:
    这个思路很先进高效!性价比也很高! :lol: :wink:

  17. 明月登楼学习笔记 2018-2-11 · 14:01

    越想博主这个构思越感觉好牛逼的一个思路!
    哈哈,可以解决 CDN 造成的各种规则不兼容的问题!

  18. 米扑博客 2018-2-13 · 11:54

    每一篇都解决问题,每一篇都是经典 :grin:

  19. 狂放 2018-2-18 · 12:17

    cookies的确是个问题,不过有没有别的方案啊

  20. 武胜婚庆公司 2018-3-13 · 9:43

    写得不错,收获很大.

  21. 极客库 2019-2-28 · 0:28

    新建的小站点,用了下腾讯的cos放图片,比较纠结的是腾讯云,免费额度够用很久了

  22. 老威 2019-3-24 · 16:42

    有一事不明,二级域名res指向了主站了,自然域名绑定A记录也是指向了主站的IP,那么res域名又要开启CDN,CDN要求是做cname解决,那么“A”记录与“CNAME”记录冲突了,是不是这样

    • avatar
      Jager 2019-3-24 · 17:23

      如果不用MX记录应该是没冲突问题,如果要用MX那二级域名得找个其他域名,比如我的博客。

      • 水哥 2019-5-27 · 14:39

        感谢分享,我也遇到A记录和别名冲突问题,试了几个域名都不行

  23. 欧文斯 2019-8-21 · 13:37

    其实很想实现文章页和评论分离,但是出现各种问题,头疼

  24. jack 2019-12-14 · 10:48

    学到一招,嘿嘿嘿嘿

  25. shamo 2019-12-16 · 17:24

    张戈你好,我启用之后无法加载JS和CSS,还有图片也无法显示,请问是什么原因

  26. tlanyan 2020-8-31 · 8:34

    现在备案域名没之前方便了,阿里云转移后主体不一致,很快备案就失效了

  27. Heresy 2021-7-4 · 13:43

    学习了,好好消化一下,希望对我的网站有效果。VPS在国外的福音啊

  28. edi 2021-12-13 · 19:19

    web端使用这个方法完全OK,请问哥rest-api里要咋做