基于 Nginx 的 CDN 基础实现

概览

本文是对基于Nginx的CDN网络的学习笔记,阅读的代码为:https://github.com/leandromoreira/cdn-up-and-running

其中,先确定CDN中的一些基础概念:

  • Balancer:负载均衡,即请求数据的流量最开始打到Balancer,由负载均衡算法确定流量导到后续Edge节点,即缓存边缘节点
  • Edge:边缘节点,即具有数据缓存,能够更快响应数据给回客户端的节点,在负载均衡和后端服务之间
  • Backend:后端节点,即实际存储数据的节点

本文阅读学习的仓库,通过Nginx构建所有节点,用到了以下属性

  • vhost_traffic_status:记录并存储每个节点的网络情况,包括处理状态码、处理时间
  • proxy_cache:缓存交互处理,包括缓存路径、过期时间、中断处理、缓存键值存储区域(共享内存)
  • nginx:使用nginx的基础功能,包括 server、location、proxy_pass、upstream 等
  • openresty:配合lua引擎使用的nginx扩展,包括脚本增强、set_by_lua、access_by_lua、balancer_by_lua、content_by_lua 等能力

另外,还是用到 prometheus 作为监控各节点的工具,使用 grafana 作为时间序列数据的可视化工具

实现

Balancer
bash 复制代码
# vi:syntax=nginx
events {
  worker_connections 1024;
}

error_log stderr;

http {
  resolver 127.0.0.11 ipv6=off;
  include generic_conf/setup_logging.conf;

  include generic_conf/lua_path_setup.conf;

  # 本节点的统计信息,请求时长、status状态等
  include generic_conf/basic_vts_setup.conf;
  # 缓存相关设置
  include generic_conf/setup_cache.conf;

  init_by_lua_block {
    loadbalancer = require "loadbalancer"
    loadbalancer.setup_server_list()
  }

  upstream backend {
    server 0.0.0.1;

    # 进行流量负载均衡,选定 edge 节点
    balancer_by_lua_block {
      loadbalancer.set_proper_server()
    }
    keepalive 60;
  }

  server {
    listen 8080;

    location / {

      # access 阶段解析dns,并获取 edge 列表,后续在本文件的 backend 进行负载均衡
      access_by_lua_block {
        loadbalancer.resolve_name_for_upstream()
      }

      # 代理到本文件的backend,进行负载均衡到 edge 节点
      proxy_pass http://backend;
      add_header X-Edge LoadBalancer;
    }

    # 可通过 /status 接口获取本节点的统计信息
    include generic_conf/basic_vts_location.conf;
  }
}

generic_conf/setup_cache.conf 缓存设置如下:

bash 复制代码
# /cache/ 指定缓存文件存储目录,levels定义缓存目录结构,key_zone 定义存储缓存的键的共享内存区域
# max_size 为缓存最大大小,inactive表示缓存被视为非活的时间,use_temp_path表示不使用临时路径,用缓存目录
# 最终实现:zone_1 共享内存中,存储缓存的键key与数据对应的路径(/cache/中),数据则实际缓存到本机 /cache/ 中
proxy_cache_path /cache/ levels=2:2 keys_zone=zone_1:10m max_size=10m inactive=10m use_temp_path=off;
# 多个请求尝试缓存同一资源,在 lock_timeout 时间窗口内只请求backend一次,其余请求等待资源
proxy_cache_lock_timeout 2s;
# 缓存数据过期或backend失效,允许使用过期的缓存数据
proxy_cache_use_stale error timeout updating;
# 请求backend的超时时间,超过则关闭nginx连接
proxy_read_timeout 2s;
# nginx 向客户端发送数据的超时时间,超过则关闭连接
proxy_send_timeout 2s;
# 如果客户端中止连接,nginx 将继续与后端完成数据获取与缓存本地
proxy_ignore_client_abort on;
Edge实现
bash 复制代码
# vi:syntax=nginx
events {
  worker_connections 1024;
}

error_log stderr;

http {
  resolver 127.0.0.11 ipv6=off;
  include generic_conf/setup_logging.conf;

  include generic_conf/lua_path_setup.conf;

  # 本节点的统计信息,请求时长、status状态等
  include generic_conf/basic_vts_setup.conf;
  # 设置缓存交互策略
  include generic_conf/setup_cache.conf;

  # 数据后端,即从哪获取数据缓存到 edge 节点
  upstream backend {
    server backend:8080;
    server backend1:8080;
    keepalive 10;  # connection pool
  }

  server {
    listen 8080;

    location / {

      # 将参数 cache_key 设置为 uri
      set_by_lua_block $cache_key {
        return ngx.var.uri
      }

      # access 阶段模拟 edge 节点延时
      access_by_lua_block {
        local edge = require "edge"
        edge.simulate_load()
      }

      # 获取实际数据的后端 backend 服务器
      proxy_pass http://backend;
      # edge 节点缓存处理策略,根据 cache_key 参数获取缓存
      include generic_conf/define_cache.conf;
      add_header X-Edge Server;
    }

    # 获取当前节点统计信息的接口
    include generic_conf/basic_vts_location.conf;
  }
}

edge节点具体实现了缓存策略,根据请求uri作为缓存key,划定某个文件路径存储实际数据value,使用共享内存记录key和缓存路径的映射,利用nginx实现缓存功能

generic_conf/define_cache.conf 缓存处理策略实现:

bash 复制代码
# 启用名为 zone_1 的共享缓存区域,来存储和检索缓存键key和实际数据的路径映射
proxy_cache zone_1;
# 设置缓存的键为 cache_key 变量
proxy_cache_key $cache_key;
# 启用缓存锁定。当多个请求同时尝试获取同一资源时,只有一个请求会去后端服务器获取数据,其他请求将等待该请求完成
proxy_cache_lock on;
# 设置与后端服务器的 HTTP 协议版本为 1.1,这通常用于启用持久连接
proxy_http_version 1.1;
# 清空 Connection 头
proxy_set_header Connection "";
# 启用代理缓冲。这意味着 Nginx 会在发送响应给客户端之前,先将后端服务器的响应全部接收并缓冲
proxy_buffering on;
# 设置用于缓冲响应的缓冲区数量和大小
proxy_buffers 16 16k;
# 添加一个参数到Header,表示是否命中缓存、正在更新
add_header X-Cache-Status $upstream_cache_status;
Backend
bash 复制代码
# vi:syntax=nginx
events {
  worker_connections 1024;
}

error_log stderr;

http {
  include generic_conf/setup_logging.conf;
  include generic_conf/lua_path_setup.conf;

  # 本节点的统计信息,请求时长、status状态等
  include generic_conf/basic_vts_setup.conf;

  server {
    listen 8080;

    location / {

      # 获取数据,模拟延时并返回数据、过期时间、数据键key
      content_by_lua_block {
        local backend = require "backend"
        backend.generate_content()
      }
    }

    # 可通过 /status 接口获取本节点的统计信息
    include generic_conf/basic_vts_location.conf;
  }
}

backend.generate_content() 后端节点的具体实现:

lua 复制代码
local simulations = require "simulations"
local backend = {}

backend.generate_content = function()
  -- 模拟 backend 节点延时
   simulations.for_work_longtail(simulations.profiles.backend)

  -- 返回数据头,根据 max_age 参数设置过期时间
  ngx.header['Content-Type'] = 'application/json'
  ngx.header['Cache-Control'] = 'public, max-age=' .. (ngx.var.arg_max_age or 10)

  -- 返回数据,记录了 key,即请求 uri
  ngx.say('{"service": "api", "value": 42, "request": "' .. ngx.var.uri .. '"}')
end

return backend

总结

利用Nginx特性实现简易CDN模型,简明概要了CND各个重要模块的主要功能

相关推荐
小卓笔记19 小时前
第1章 Web服务-nginx
前端·网络·nginx
Ting-yu21 小时前
Nginx快速入门
java·服务器·前端·nginx
麦兜*1 天前
Spring Boot集群 集成Nginx配置:负载均衡+静态资源分离实战
java·spring boot·后端·nginx·spring·缓存·负载均衡
Lynnxiaowen1 天前
今天我们开始学习nginx缓存功能,CORS以及nginx防盗链
linux·运维·学习·nginx·云计算·bash
哦你看看1 天前
nginx缓存、跨域 CORS与防盗链设置(2)
运维·nginx·缓存
工会代表1 天前
前端项目自动化部署改造方案
前端·nginx
路上阡陌2 天前
nginx 介绍及作用
运维·nginx
花开富贵贼富贵2 天前
Nginx 反向代理与缓存功能
运维·nginx·缓存
一条懒鱼6662 天前
Nginx反向代理与缓存功能
运维·nginx
云游2 天前
Zabbix7.4.8(二):通过http监控Nginx相关指标
服务器·nginx·http