基于 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
# 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 缓存设置如下:

# /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实现
# 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 设置为 uriset_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 缓存处理策略实现:

# 启用名为 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
# 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 / {# 获取数据,模拟延时并返回数据、过期时间、数据键keycontent_by_lua_block {local backend = require "backend"backend.generate_content()}}# 可通过 /status 接口获取本节点的统计信息include generic_conf/basic_vts_location.conf;}
}

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

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,即请求 uringx.say('{"service": "api", "value": 42, "request": "' .. ngx.var.uri .. '"}')
endreturn backend

总结

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/69525.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Coze(扣子)+ Deepseek:多Agents智能体协作开发新范式

前言 在当今数字化浪潮中,人工智能(AI)技术的迅猛发展正深刻改变着我们的生活和工作方式。从智能语音助手到自动化流程机器人,AI 的应用无处不在,为我们提供了更加便捷、高效的服务。然而,对于非专业人士来…

user、assistant、system三大角色在大语言模型中的作用(通俗解释)

1 概述 在大语言模型中,通常涉及到三种角色:用户(user)、助手(assistant)和系统(system)。简单来说,和大模型对话其实是三个人的电影。 2 角色定义 2.1 系统&#xf…

【文献讲解】《Non-local Neural Networks》

一、引言 传统的深度学习方法(如卷积神经网络CNN和循环神经网络RNN)在捕捉长距离依赖关系时存在局限性。CNN主要关注局部邻域的特征,而RNN则依赖于序列的递归计算,无法直接捕捉全局信息。为了解决这一问题,本文提出了一种非局部神经网络(Non-local Neural Networks),通…

BiGRU双向门控循环单元多变量多步预测,光伏功率预测(Matlab完整源码和数据)

代码地址:BiGRU双向门控循环单元多变量多步预测,光伏功率预测(Matlab完整源码和数据) BiGRU双向门控循环单元多变量多步预测,光伏功率预测 一、引言 1.1、研究背景和意义 随着全球对可再生能源需求的不断增长,光伏…

经典题型:求数组中逆序对的数量

经典题型:求数组中逆序对的数量 题目思路代码 题目 链接 思路 步骤一:两个指针指向两个有序区间,进行合并操作。 步骤二:1与前面的区间,构成逆序对,个数就是前面区间的个数。 步骤三:前面数组…

安卓逆向(Xposed-Hook)

关于参数问题 📌 如果方法是这样 public int addNumbers(int a, int b) {return a b; }📌 Hook 代码 XposedHelpers.findAndHookMethod("com.example.app.Calculator",lpparam.classLoader,"addNumbers",int.class, int.class, …

nacos报错9848端口解决方法

近日在部署nacos时一直出现长报错,显示9848端口被占用无法访问,但是通过netstat -ano | findstr 9848查看端口状态却没有输出,表明没有运行在此端口上的程序,同时重新下载不同版本的nacos均出现此问题,排除是nacos的问…

ASP.NET Core 如何使用 C# 向端点发出 POST 请求

使用 C#,将 JSON POST 到 REST API 端点;如何从 REST API 接收 JSON 数据。 本文需要 ASP .NET Core,并兼容 .NET Core 3.1、.NET 6和.NET 8。 要从端点获取数据,请参阅本文。 使用 . 将 JSON 数据发布到端点非常容易HttpClien…

【React】页面刷新后状态丢失的原因与解决方案

在 React 应用中,页面刷新后状态丢失是一个常见的问题。这主要是因为 React 的状态(state)是存储在内存中的,而页面刷新会导致内存被清空,从而导致状态丢失。以下是常见的原因及对应的解决方案。 一、状态丢失的原因 1. React 的状态存储在内存中 React 的状态(通过 us…

kafka消费端之分区分配策略

文章目录 概述分区分配策略RangeAssignor分配策略RoundRobinAssignor分配策略StickyAssignor自定义分区分配策略 总结 概述 我们知道kafka的topic可以被分成多个分区,消费者在集群模式下消费时一个消费组内的每个消费者实例只能消费到一个分区的消息,那…

Flink CDC YAML:面向数据集成的 API 设计

摘要:本文整理自阿里云智能集团 、Flink PMC Member & Committer 徐榜江(雪尽)老师在 Flink Forward Asia 2024 数据集成(一)专场中的分享。主要分为以下四个方面: Flink CDC YAML API Transform A…

【截图】selenium自动通过浏览器截取指定元素div的图片

【截图】selenium自动通过浏览器截取指定元素div的图片 思路 截取完整网页截图 通过元素的坐标 截图到指定位置的图片 前提是已经获取到 driver 了 # 定位目标divtarget_div driver.find_element(By.CLASS_NAME, headlines-right)# 获取div的位置和大小location target_div…

gradio教程

Gradio 是一个开源的 Python 库,专为快速创建和共享机器学习模型和数据科学应用的交互式界面而设计。它简化了将复杂的机器学习模型转换为易于使用的 Web 应用程序的过程,使开发者能够轻松地与他人分享他们的工作成果。 主要特点: 简单易用&…

清理软件——软媒清理大师

随着电脑使用时间的增加,系统垃圾文件也会不断累积,导致C盘空间逐渐变得紧张。今天,我为大家推荐一款专业的清理软件——软媒清理大师,它能够高效地清理电脑中的无用垃圾文件,为您的电脑“减负”。 清理软件——软媒清…

【C++八股】 前置 ++i vs. 后置 i++ 的区别

在 C 中&#xff0c; 运算符有前置 i 和后置 i 两种方式&#xff0c;它们都能让变量自增 1&#xff0c;但在执行顺序、性能、应用场景上有所不同。 1. i vs. i 对比表 2. 代码示例 #include <iostream> int main() {int a 5, b 5;std::cout << "a "…

手动配置IP

手动配置IP&#xff0c;需要考虑四个配置项&#xff1a; 四个配置项 IP地址、子网掩码、默认网关、DNS服务器 IP地址&#xff1a;格式表现为点分十进制&#xff0c;如192.168.254.1 子网掩码&#xff1a;用于区分网络位和主机位 【子网掩码的二进制表达式一定是连续的&#…

PyTorch快速入门

Anaconda Anaconda 是一款面向科学计算的开源 Python 发行版本&#xff0c;它集成了众多科学计算所需的库、工具和环境管理系统&#xff0c;旨在简化包管理和部署&#xff0c;提升开发与研究效率。 核心组件&#xff1a; Conda&#xff1a;这是 Anaconda 自带的包和环境管理…

DeepSeek部署的一些问题

问题1&#xff1a;为什么不直接使用网页版的deepseek&#xff1f; 如果我们的需求是绝对的隐私保护和个性化的知识库的构建&#xff0c;就需要本地部署。试想一下&#xff0c;如果我们希望通过大模型能根据我们自己独有的文档来回答问题&#xff0c;那我们就需要把文件或附件上…

解决 Sentinel 控制台无法显示 OpenFeign 资源的问题

前言 在使用 Spring Cloud Alibaba Sentinel 进行微服务治理时&#xff0c;可能会遇到 Sentinel 控制台无法显示 OpenFeign 资源的问题。本文将详细分析问题的原因&#xff0c;并提供解决方案。 一、问题描述 在 Sentinel 控制台 1.8.8 版本中&#xff0c;簇点链路&#xff…

(done) openMP学习 (Day14: 总结)

url: https://dazuozcy.github.io/posts/introdution-to-openmp-intel/#23-%E5%8F%AF%E6%80%95%E7%9A%84%E4%B8%9C%E8%A5%BF%E5%86%85%E5%AD%98%E6%A8%A1%E5%9E%8Batomicsflushpairwise%E5%90%8C%E6%AD%A5%20 新手并行程序员与专家并行程序员之间的区别是专家have a collection…