这几天同事说我的博客很卡,确实,我这个小土豆是有点用到极致了,在这个服务器我还是挂了几个站的…

而且我没有做任何优化,上次腾讯搞活动我是买了一个 CDN 的流量包,不过我当时挂上去之后就刷新一下主页就耗了 10M 流量,哇当时我的心… 看着钱就这么哗啦啦流出去了,于是我就取消了。

前几周刚好朋友送了一个域名 tzmax.com 但是没备案,肯定不能直接用的,上周老板提点了我一下,可以用 nginx 反代?绕过备案?哇咔咔咔,于是我就借用公司境外闲置服务器用一下咯,反正我博客也没多少流量(老板看到这个博客应该不会砍死我叭…)我昨天搭建反代理之后能是能访问了当然,不过还是有点小问题的,比如原博客的接口不能跨域,我暂时没有去折腾解决。

我发现一个很不舒服的点就是,反代之后比我的小土豆访问还慢但是服务器是 300 M,我的小土豆才 1 M 不应该比我的访问还慢的啊,实际上,反代是通过先去我们原服务器上获取文件之后再通过这个服务器返回的,所以还是限制于我们的小土豆不够快鸭…

于是我想能不能在我们这台反代的服务器上加上静态资源缓存?我一想,咦这不就是和 CDN 实现原理差不多了吗?

搭建实现 CDN 的软件(轮子)应该有很多,比 Nginx 成熟的方案也应该有一大把,不过我对 Nginx 还是用过的,而且我们的服务器一般都是装了 Nginx 的,于是就研究研究 Nginx 怎么简单实现一个 CDN 吧,首先,我这里的只是简单实现,很多优化以及清除缓存等东西都没有考虑到,多 CDN 节点,以及网络选优等功能更是没牵扯到的,还有 CDN 后面的负载均衡等等…

我这里只是对自己折腾的一个小记录叭,如果小伙伴们有专业需求的话我还是建议使用专业的 CDN 服务,或者使用成熟的 CDN 实现方案。

Nginx 反向代理这里我就不多提了,如果有小伙伴感兴趣的话可以给我留言呀,我可以专门写一篇博客介绍的,不过其实网上已经有很多优秀的文章讲了。

首先我们先编辑 nginx.conf ,在其 http 节点添加缓存配置:

http {
    ……

    proxy_temp_path /data/cdn_cache/proxy_temp_dir;
    proxy_cache_path /data/cdn_cache/proxy_cache_dir levels=1:2 keys_zone=cache_one:50m inactive=1d max_size=1g;

    proxy_connect_timeout 5;
    # nginx 服务器与被代理服务连接超时时间,代理超时

    proxy_read_timeout 60;
    # nginx 服务器接收被代理服务器数据超时时间,单位秒,规定时间内 nginx 服务器没收到数据,则超时

    proxy_send_timeout 5;
    # nginx 服务器发送数据给被代理服务器超时时间,单位秒,规定时间内 nginx 服务器没发送数据,则超时

    proxy_buffer_size 16k;
    #设置代理服务器(nginx)保存用户头信息的缓冲区大小

    proxy_buffers 4 64k;
    # proxy_buffers 缓冲区,网页平均在64k以下的话,这样设置

    proxy_busy_buffers_size 128k;
    # 高负荷下缓冲大小(proxy_buffers*2)

    proxy_temp_file_write_size 128k;
    # 设定缓存文件夹大小,大于这个值,将从 upstream 服务器传

    proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_404;
    # 服务器返回了超时或者 500 配置返回规则

    ……
}

说明:

  • proxy_temp_path:Nginx 最初会将注定写入缓存的文件先放入一个临时存储区域, use_temp_path=off 命令指示 Nginx 将在缓存这些文件时将它们写入同一个目录下,我们强烈建议你将参数设置为 off 来避免在文件系统中不必要的数据拷贝。如果没有配置 use_temp_path=off 或者没有配置则按 proxy_temp_path 设置来给定存储目录,如果 proxy_temp_path 也没配置,则直接缓存到 proxy_cache_path 目录下 。
  • proxy_cache_path :用于缓存的本地磁盘目录我这里设置是 /data/cdn_cache/proxy_cache_dir
  • levels:在 /usr/local/nginx/cache/ 设置了一个两级层次结构的目录。将大量的文件放置在单个目录中会导致文件访问缓慢,所以推荐使用两级目录层次结构,如果 levels 参数没有配置,则 Nginx 会将所有的文件放到同一个目录中。
  • keys_zone:设置一个共享内存区,该内存区用于存储缓存键和元数据,有些类似计时器的用途。将键的拷贝放入内存可以使 Nginx 在不检索磁盘的情况下快速决定一个请求是 HIT 还是MISS,这样大大提高了检索速度。一个 1MB 的内存空间可以存储大约 8000 个 key,那么上面配置的 20MB内存空间可以存储差不多 160000 个 key。
  • max_size:设置了缓存的上限(在上面的例子中是 5G),这是一个可选项。如果不指定具体值,那就是允许缓存不断增长,占用所有可用的磁盘空间,当缓存达到这个上线,处理器便调用 cache manager 来移除最近最少被使用的文件,这样把缓存的空间降低至这个限制之下。
  • inactive:指定了项目在不被访问的情况下能够在内存中保持的时间。在上面的例子中,如果一个文件在 1 天之内没有被请求,则缓存管理将会自动将其在内存中删除,不管该文件是否过期。该参数默认值为 10 分钟(10m)。注意,非活动内容有别于过期内容,Nginx 不会自动删除由缓存控制头部(Cache-Control)指定的过期内容,过期内容只有在 inactive 指定时间内没有被访问的情况下才会被删除,如果过期内容被访问了,那么 Nginx 就会将其从原服务器上刷新,并更新对应的 inactive 计时器。

接下来添加一个 upstream 服务 (也就是你的原服务器,可以是你的服务器 ip,你服务器那边记得接收解析域名):

upstream tzmax.com.pool
{
    server bin.zmide.com weight=10 max_fails=3;
}

最后就是配置 server 节点(这里我就不一个一个参数的解释了,其实大部分都是重复的参数配置,就加了几个 header 区分资源来自源服务器还是本服务器…):

server
{
    listen 80;
    server_name tzmax.com *.tzmax.com;
    
    location ~ .*\.(gif|jpg|png|html|htm|css|js|ico|swf|pdf)$
    {
        # Proxy 
        proxy_redirect off;
        proxy_next_upstream http_502 http_504 http_404 error timeout invalid_header;
        proxy_set_header Host $host;
        proxy_set_header X-real-ip $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_pass https://tzmax.com.pool;

        # Use Proxy Cache
        proxy_cache cache_one;
        proxy_cache_key "$host$request_uri";
        add_header Cache "$upstream_cache_status";
        proxy_cache_valid  200 304 301 302 8h;
        proxy_cache_valid 404 1m;
        proxy_cache_valid  any 2d;
    }
    
    location /
    {
        proxy_redirect off;
        proxy_next_upstream http_502 http_504 http_404 error timeout invalid_header;
        proxy_set_header Host $host;
        proxy_set_header X-real-ip $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_pass http://tzmax.com.pool;
        client_max_body_size 40m;
        client_body_buffer_size 128k;
        proxy_connect_timeout 60;
        proxy_send_timeout 60;
        proxy_read_timeout 60;
        proxy_buffer_size 64k;
        proxy_buffers 4 32k;
        proxy_busy_buffers_size 64k;
   }
}

源服务器如何获取用户的真实 IP

使用反代功能后,实际上对于源站来说,访客是代理服务器而不是真实的访客,Nginx 针对这种情况也给了解决方案,在源站 Nginx 配置中添加如下配置:

......
    set_real_ip_from 反代服务器 IP;
    real_ip_recursive on;
......

后面的清除缓存,多服务器架构,智能解析,负载均衡,反向代理…… 我在这里就不多讲了,以后有机会再弄吧