优化Web性能:Varnish中精准识别并缓存移动与桌面请求

embedded/2024/9/20 11:29:41/ 标签: 缓存, Varnish

引言

在现代Web开发中,为了提升用户体验,针对不同类型的设备提供定制化的内容是一项重要的策略。Varnish作为HTTP加速器和缓存代理服务器,能够帮助我们实现这一目标。本文将详细介绍如何利用Varnish来实现基于设备类型(PC端与移动端)的同路由内容差异化显示,并探讨如何优化缓存管理。

一、Varnish 简介

Varnish 是一种高性能的 Web 应用加速器,它主要通过缓存 HTTP 响应来减轻服务器负载,从而提升网站的访问速度。Varnish 的主要特点包括:

  • 高速缓存Varnish 能够快速存储和检索静态内容,显著降低延迟。
  • 负载均衡:它可以作为负载均衡器,分发请求到多个后端服务器。
  • 安全性:通过过滤恶意请求,增强网站的安全性。
  • 灵活性:支持通过 Varnish 编程语言 (VCL) 自定义复杂的缓存和路由逻辑。

二、Varnish 中区分设备类型的方法

2.1 为什么需要区分设备?

在现代 Web 开发中,网站通常需要适应多种设备和屏幕尺寸。例如,移动端用户可能希望看到简化版的页面,而桌面用户则可能更喜欢功能齐全的版本。为了提供最佳用户体验,网站需要能够智能地检测用户设备,并据此调整页面布局和功能。

2.2 使用 User-Agent 字符串

Varnish 中,最常用的方法之一是通过分析请求中的 User-Agent 字符串来判断设备类型。虽然这种方法并非绝对准确(因为 User-Agent 可以被伪造),但在大多数情况下,它仍然是一种有效的方法。

2.3 VCL配置及实现

2.3.1  实现步骤

  • 识别设备类型:通过分析User-Agent字符串来确定请求来源设备类型。
  • 配置VCL文件:编写规则来区分设备类型,并根据设备类型选择不同的后端服务或返回不同的内容。

2.3.2 示例代码

下面是一个详细的示例,展示了如何根据User-Agent字符串来区分PC和移动设备,并设置相应的缓存策略:

# 配置桌面设备的后端服务器地址及端口
backend backend_desktop {   # 定义一个名为 backend_desktop 的后端.host = "desktop-backend.example.com";   # 设置后端主机地址.port = "80";                            # 设置后端服务监听的端口
}# 配置移动设备的后端服务器地址及端口
backend backend_mobile {   # 定义一个名为 backend_mobile 的后端.host = "mobile-backend.example.com";    # 设置后端主机地址.port = "80";                            # 设置后端服务监听的端口
}# 当请求到达时触发的子程序
sub vcl_recv {# 根据User-Agent判断设备类型并设置X-Device-Type头if (req.http.User-Agent ~ "mobile|android|iphone|ipad|ipod|blackberry|iemobile|opera mini|mobilesafari|silk|dolfin|skyfire|midp|wap|phone") {set req.http.X-Device-Type = "mobile";   # 如果User-Agent包含上述字符串之一,则设置X-Device-Type为"mobile"} else {set req.http.X-Device-Type = "desktop";  # 否则设置X-Device-Type为"desktop"}# 检查已设置的 X-Device-Type 请求头if (req.http.X-Device-Type == "desktop") {# 如果是桌面设备,则设置后端为 desktop 后端set req.backend = backend_desktop;       # 设置请求后端为 desktop 后端} else if (req.http.X-Device-Type == "mobile") {# 如果是移动设备,则设置后端为 mobile 后端set req.backend = backend_mobile;        # 设置请求后端为 mobile 后端}
}# 根据设备类型缓存
sub vcl_hash {// 基于请求URL计算哈希hash_data(req.url);                         # 用请求的URL作为哈希数据的一部分// 检查设备类型,并将之加入哈希计算if (req.http.User-Agent ~ "(?i)(mobile|tablet)"){  # 使用正则表达式检查User-Agent是否包含 "mobile" 或 "tablet"(不区分大小写)// 设备类型为移动设备(手机或平板)set req.http.X-Device-Type = "mobile";           # 如果条件满足,则设置X-Device-Type为"mobile"} else {// 设备类型为桌面设备set req.http.X-Device-Type = "desktop";          # 否则设置X-Device-Type为"desktop"}// 将设备类型信息加入哈希计算hash_data(req.http.X-Device-Type);                  # 将设备类型添加到哈希数据中,以便根据设备类型进行缓存
}

解释

  1. vcl_recv 子程序:这里我们检查请求的 User-Agent 字符串是否包含某些关键词,如果包含,则认为这是一个来自移动设备的请求,并设置一个特殊的请求头 X-Device-Typemobile。否则,假设这是来自 PC 的请求,并设置 X-Device-Typedesktop

  2. vcl_hash 子程序:这里我们将 X-Device-Type 请求头的内容加入到哈希运算中。这意味着来自不同类型的设备即使请求相同的 URL,也会被缓存为不同的副本。

三、缓存管理

3.1 为什么需要刷新缓存

在动态网站中,内容经常发生变化,特别是在新闻站点、电商平台等需要实时更新信息的地方。为了确保用户看到的是最新内容,需要定期或按需刷新缓存

3.2 Varnish缓存刷新机制

Varnish 提供了几种方法来刷新缓存

3.2.1 使用 PURGE 方法

通过发送一个特殊的 HTTP 请求来清除特定的缓存项。这个请求通常使用 HTTP 方法 PURGE 发送到 Varnish

curl -X PURGE http://<varnish-ip>:<port>/<path-to-purge>

该请求需要配置 VCL 文件:

# 在vcl_recv中处理自定义的PURGE请求  
sub vcl_recv {  # 检查请求方法是否为PURGE  if (req.method == "PURGE") {# 检查请求是否来自可信的 IP 地址if (client.ip == "192.0.2.1" || client.ip == "2001:db8::1") {# 如果来自可信 IP,则继续处理请求return (pipe);} else {# 如果不是来自可信 IP,则返回 405 Method Not Allowederror 405 "Method Not Allowed for PURGE requests from this IP.";}# 执行清除缓存的操作purge(req.url);# 发送一个200 OK响应作为PURGE成功的初步确认  # 注意:在实际应用中,你可能希望根据PURGE操作的结果来发送不同的响应  # 但由于VCL中直接处理PURGE的逻辑可能较为复杂,这里只是发送一个静态响应  return (synth(200, "Purged"));  }  
}

注意:

  • -X PURGE:指定使用 PURGE HTTP 方法。
  • <varnish-ip>:运行 Varnish 的服务器 IP 地址。
  • <port>:Varnish 监听的端口号,默认通常是 80 或者 443 (对于 HTTPS),但也可以是其他端口,如 6081。
  • <path-to-purge>:要清除缓存的 URL 路径。

3.2.2 使用varnishadm发送ban请求

首先,你需要通过varnishadm连接到Varnish实例,然后发送一个ban命令。这里有一个简单的命令示例,用于清除所有URL中包含/news/缓存

varnishadm -T localhost:6082 ban req.url ~ "/news/"

注意:

  • -T 参数后面跟的是Varnish的管理地址和端口。
  • ban 命令后面跟的是匹配条件,这里使用的是req.url ~ "/news/",表示匹配所有URL中包含/news/的请求。

3.2.3 设置过期时间(TTL)

在 VCL 中设置缓存条目的过期时间,使其在一定时间后自动失效。

sub vcl_backend_response {  # 检查请求的URL是否以/news开头  if (bereq.url ~ "^/news") {  # 设置缓存时间为3600秒(1小时)  set beresp.ttl = 3600s;  # 如果你还想设置优雅期(grace period),可以这样做:  # set beresp.grace = 60s;  } else {  # 对于其他路径,使用默认的缓存策略  # 这里没有显式设置,因为Varnish会使用varnish.params中配置的默认TTL  }  # 其他可能的逻辑...  
}

注意:

  • 我们在vcl_backend_response子程序中设置缓存时间,因为这个子程序在Varnish从后端服务器接收到响应后立即执行,此时可以修改响应的TTL。
  • bereq.url包含了后端请求的URL,这是从客户端请求中解析出来的,并且已经过Varnish的任何重写规则的处理。
  • beresp.ttl用于设置缓存对象的TTL。设置为0s表示不缓存该对象。
  • beresp.grace(如果设置了)定义了当缓存对象过期后,但在被新响应替换之前,该对象仍然可以被提供的“优雅期”。

结论

通过利用Varnish缓存系统的强大功能和灵活性,结合精细化的设备类型识别策略和智能的缓存策略优化,我们可以实现基于设备类型的智能内容差异化展示。这不仅提升了用户体验,还提高了网站的性能和可维护性。然而,实施此功能时需要注意性能、安全性和可维护性等方面的挑战,并持续关注和优化这些方面以确保最佳效果。


http://www.ppmy.cn/embedded/114144.html

相关文章

【C语言】(指针系列3)数组指针+函数指针+typedef+函数数组指针+转移表

前言&#xff1a;前言&#xff1a;开始之前先感谢一位大佬&#xff0c;清风~徐~来-CSDN博客&#xff0c;由于是时间久远&#xff0c;博主指针的系列忘的差不多了&#xff0c;所以有顺序部分借鉴了该播主的&#xff0c;同时也加入了博主自己的理解&#xff0c;有些地方如果解释的…

Qt学习之旅 I

构建一个跨平台的应用(Create A Cross-Platform Application) 目录 构建一个跨平台的应用(Create A Cross-Platform Application) 设计模式 开始构建 Qt是跨平台的C框架&#xff0c;这里&#xff0c;我们将会构建一个简单的C跨平台项目来熟悉QT是如何实现简单的跨平台的。 …

上传富文本插入文件时报错:JSON parse error: Unexpected character解决办法

方式一&#xff08;加密解密&#xff09;&#xff1a; 1.前端 &#xff08;1&#xff09;安装 crypto-js npm install crypto-js&#xff08;2&#xff09;util下引入asc.js asc.js import CryptoJS from crypto-js// 需要和后端一致 const KEY CryptoJS.enc.Utf8.parse(…

前端开发规范

前端开发规范 编写背景&#xff1a;当前项目前端开发过程中&#xff0c;每个人有不同的编码风格&#xff0c;这就导致同一个模块不同人开发时可能产生阅读不方便的情况&#xff0c;这对于项目的长久开发是不利的&#xff0c;所以编写这套前端开发规范。 编写目的&#xff1a;避…

google map小叉号不显示

背景需求 需要在uniapp中接入google地图,研究了一番,都没有找到合适的,现在说一下教程。 效果图 前期工作 这两点缺一不可,否则你啥也看不到。 1、电脑安装L-O-U梯 用于访问G-OO-G-LE的API或者创建google map key。 2、手机安装L-O-U梯 用于显示google地图。我就是手…

C++ ——string的模拟实现

目录 前言 浅记 1. 构造函数 2. 拷贝构造函数 2.1 拷贝构造传统写法 2.2 拷贝构造现代写法 3. swap 4. 赋值重载 4.1 赋值重载的传统写法 4.2 赋值重载的现代写法1 4.3 赋值重载的现代写法2 5. 析构函数 6. reserve&#xff08;扩容&#xff09; 7. push_back&am…

Windows10安装cuda11.3.0+cudnn8.5.0,以及创建conda虚拟环境(pytorch)

1、检查电脑驱动版本为561.09&#xff0c;选择cuda版本&#xff0c;下图可知cuda版本<12.6。 nvidia-smi #查看驱动版本&#xff0c;以及最大可以安装的cuda版本 2、Anaconda3-2024.06-1-Windows-x86_64.exe下载&#xff1a; 官网&#xff1a;https://www.baidu.com/link?…

Unity教程(十五)敌人战斗状态的实现

Unity开发2D类银河恶魔城游戏学习笔记 Unity教程&#xff08;零&#xff09;Unity和VS的使用相关内容 Unity教程&#xff08;一&#xff09;开始学习状态机 Unity教程&#xff08;二&#xff09;角色移动的实现 Unity教程&#xff08;三&#xff09;角色跳跃的实现 Unity教程&…

如何利用 Visual Studio 和 AI 工具实现高效编程

哪个编程工具让你的工作效率翻倍? 在现代软件开发的世界中,编程效率的提升对开发者来说至关重要。高效编程不仅仅是编写更多的代码,还包括如何减少重复劳动、提高代码质量、加快调试和测试流程等。而 Visual Studio 作为一个功能强大的开发环境(IDE),配合各种 AI 工具,…

Java入门:09.Java中三大特性(封装、继承、多态)02

2 继承 需要两个类才能实现继承的效果。 比如&#xff1a;类A 继承 类B A类 称为 子类 &#xff0c; 衍生类&#xff0c;派生类 B类 称为 父类&#xff0c;基类&#xff0c;超类 继承的作用 子类自动的拥有父类的所有属性和方法 &#xff08;父类编写&#xff0c;子类不需要…

基于vue框架的宠物领养管理系统88v55(程序+源码+数据库+调试部署+开发环境)系统界面在最后面。

系统程序文件列表 项目功能&#xff1a;用户,宠物分类,宠物信息,领养信息,宠物动态,捐赠物资,领养进度,友情链接 开题报告内容 基于Vue框架的宠物领养管理系统开题报告 一、项目背景与意义 随着社会的进步和人们生活水平的提高&#xff0c;宠物已成为许多家庭不可或缺的一部…

node+express部署多套vue3项目,总404页面由node控制,子404页面由子vue控制,node路由重定向

const express require(express) const history require(connect-history-api-fallback) const { createProxyMiddleware } require(http-proxy-middleware) const cors require(cors)let app express()app.use(cors()) app.use(history())// //匹配api开头的请求&#xf…

利用Leaflet.js和turf.js创建交互式地图:航道路线绘制

引言 在现代Web应用中&#xff0c;地图的交互性是提供丰富用户体验的关键。Leaflet.js是一个轻量级的开源JavaScript库&#xff0c;它提供了简单易用的API来构建交云的地图。与此同时&#xff0c;turf.js作为一个强大的地理空间分析库&#xff0c;能够处理复杂的地理数据操作。…

【前端基础篇】JavaScript之DOM介绍

文章目录 前言WebAPI背景知识什么是WebAPI什么是APIAPI参考文档 DOM基本概念什么是DOMDOM树查找HTML元素方法概览1. document.getElementById(id)2.document.getElementsByTagName(name)3. document.getElementsByClassName(name)4. document.querySelector(CSS选择器)5. docum…

C++ std::find函数 容器元素查找

简介 std::find函数是C标准库内非常实用的一个函数&#xff0c;主要用于在给定范围内查找某个元素&#xff0c;如果找到该元素&#xff0c;则返回指向该元素的迭代器&#xff1b;如果没有找到&#xff0c;则返回指向范围末尾的迭代器&#xff08;即 end() &#xff09;。 fin…

解锁定位服务:Flutter应用中的高德地图定位

前言 在现代移动应用开发中&#xff0c;定位服务已成为一项基本功能&#xff0c;它使得应用能够获取用户的地理位置信息&#xff0c;为用户提供更加个性化的服务。 Flutter 作为跨平台的移动应用开发框架&#xff0c;支持集成多种服务&#xff0c;包括定位服务。 本文将介绍如…

Golang | Leetcode Golang题解之第405题数字转换为十六进制数

题目&#xff1a; 题解&#xff1a; func toHex(num int) string {if num 0 {return "0"}sb : &strings.Builder{}for i : 7; i > 0; i-- {val : num >> (4 * i) & 0xfif val > 0 || sb.Len() > 0 {var digit byteif val < 10 {digit 0…

Bio-Linux-shell详解-1-从0开始

21世纪是数据的世纪&#xff0c;蓬勃发展的生物学积累了大量的数据&#xff0c;急需计算生物学、生物信息学及系统生物学等交叉学科大放异彩&#xff0c;而windows作为我们最熟悉的操作平台&#xff0c;并不能承担如此巨大的工作量&#xff0c;课题组的服务器因此承担了这个责任…

前端开发之原型模式

介绍 原型模式本质就是借用一个已有的实例做原型&#xff0c;在这原型基础上快速复制出一个和原型一样的一个对象。 class CloneDemo {name clone democlone(): CloneDemo {return new CloneDemo()} } 原型原型链 函数&#xff08;class&#xff09;都有显示原型 prototyp…

【算法篇】栈与队列类(笔记)

目录 一、用栈实现队列 二、用队列实现栈 三、有效的括号 四、删除字符串中的所有相邻重复项 五、逆波兰表达式求值 六、滑动窗口最大值 七、前 K 个高频元素 一、用栈实现队列 232. 用栈实现队列 - 力扣&#xff08;LeetCode&#xff09;https://leetcode.cn/proble…