首页 后端开发 php教程 nginx的cache系统设计原理

nginx的cache系统设计原理

Aug 08, 2016 am 09:20 AM
cache nbsp nginx proxy store

这里我们nginx的cache系统为线索,来探讨一个缓存服务器的设计和相关细节,我尽量站在设计和框架的角度来分析,限于篇幅这里不再去撸代码了,相关的细节,欢迎大家一起参与讨论。

    一个cache服务器中从后端取得文件之后,要么直接发送给客户端(学名叫透传),要么缓存在本地,后续相同的请求访问到cache服务器时,就可以直接拿本地的拷贝来用了,如果可以用的话。如果本地缓存的文件被后续的请求访问到,在cache中叫做命中(即Hit)。如果本地还没有文件的缓存拷贝,那么cache服务器需要根据配置或者做解析域名,去后端获取文件,这时称为缓存miss,即未命中。关于cache服务器更多的知识,我们在分析nginx的缓存系统时再深入讨论。

    nginx的存储系统分两类,一类是通过proxy_store开启的,存储方式是按照url中的文件路径,存储在本地。比如/file/2013/0001/en/test.html,那么nginx就会在指定的存储目录下依次建立各个目录和文件。另一类是通过proxy_cache开启,这种方式存储的文件不是按照url路径来组织的,而是使用一些特殊方式来管理的(这里称为自定义方式),自定义方式就是我们要重点分析的。那么这两种方式各有什么优势呢?

    按url路径存储文件的方式,程序处理起来比较简单,但是性能不行。首先有的url巨长,我们要在本地文件系统上建立如此深的目录,那么文件的打开和查找都很会很慢(回想kernel中通过路径名查找inode的过程吧)。如果使用自定义方式来处理模式,尽管也离不开文件和路径,但是它不会因url长度而产生复杂性增加和性能的降低。从某种意义上说这是一种用户态文件系统,最典型的应该算是squid中的CFS。nginx使用的方式相对简单,主要依靠url的md5值来管理,后面我们会分析。

    缓存离不开从后端取内容,然后发送给客户端。具体的处理方式大家很容易就会想到,肯定是一边接收一边发送,其他的方式都太低效了,如读完再发等等。这里提一下nginx边收边发,使用的结构是ngx_event_pipe_t,它是沟通后端和客户端的媒介。由于该结构是一个通用组件,所以需要一些特殊的标记来处理涉及存储的相关功能,那么成员cacheable就担当了这份重任。

p->cacheable = u->cacheable || u->store;

即cacheable为1,则需要存储,否则不存储。那么u->cacheable跟u->store代表什么?他们分别代表前面说的两种方式,即proxy_cache和proxy_store。 

(补充一些知识,nginx在取后端数据时,它的行为受proxy_buffering控制,作用是为后端的服务器启用应答缓冲。如果启用缓冲,nginx假设被代理服务器能够非常快的传递应答,并将其放入缓冲区,可以使用proxy_buffer_size和proxy_buffers设置相关参数。如果响应无法全部放入内存,则将其写入硬盘。如果禁用缓冲,从后端传来的应答将立即被传送到客户端。)


    这里都是一些擦边球,我们还没有接触nginx cache功能的核心。从实现上看,在nginx upstream结构中有个成员叫cache,它的类型是ngx_shm_zone_t。如果我们开启cache功能,cache成员用来管理共享内存(为什么用到了共享内存?),而其他方式的存储该成员都为NULL。另外有一点需要说明一下,在cache系统中一个文件通常被称为store object,即缓存对象,所以进行cache之前必然需要先创建一个store object。一个重要的问题就是如何选择创建的时机,这点大家有什么看法?首先我们需要检查一个文件是否是需要缓存,很明显GET方法请求的文件一般需要缓存,所以我们在请求处理的前期,看到了GET方法,就可以先创建一个对象。但是很多时候,即使是一个GET方法请求的文件也不能缓存,那么你过早的创建对象,不仅浪费时间也浪费了空间,到头来还要将它销毁。那么什么会影响GET请求的存储呢?那就是响应头中的Cache-control字段,这个字段就告诉代理或者浏览器,该文件能否被缓存。一般的cache服务器面对响应头中没有Cache-control字段的请求,默认都是要缓存的。

    基于这一点的考虑,我们开发的cache服务器就是在响应头解析完成,拿到可缓存的足够证据之后,才会创建缓存对象。遗憾的是,nginx没有这么去做。

nginx在ngx_http_upstream_init_request函数中完成缓存对象的创建,这个函数处在http处理的什么阶段呢?在跟后端建立连接之前。这个地方,我个人认为不太合适。。。大家认为呢?

    关于创建过程,大家可以去读函数ngx_http_upstream_cache。这里我拿我们的cache跟nginx对比来分析吧。我们的request中使用一个名叫store的成员,来跟缓存对象建立联系。nginx也差不多,它的request结构体中有个cache成员来做同样的事情。区别在于我们的store成员对应的空间在共享内存中,而nginx则是在r->pool里申请的(我们为什么这么做?)。

    下一步,nginx需要根据配置来生成缓存对象的key,此处一般都是用md5来算的。这个key作为一个缓存对象在系统中的唯一标识,很多人可能担心md5碰撞的问题。这个我认为要求如果不是特别苛刻,这里完全可以接受的,而且处理也相对简单。

后面要处理的是,文件到底应该已怎样的形式存储在磁盘?

    我们拿前面用过的一个例子:/file/2013/0001/en/test.html,它对应的md5值是8ef9229f02c5672c747dc7a324d658d0,实际上nginx就用它当做文件名。这样就可以了?如果我们找一个目录来存放文件,里面都是一堆这样的文件,那么会怎样?我们知道,大多数文件系统下,都对单个目录下的文件数量有限制,所以这样简单粗暴的处理是不行的。那怎么办?nginx通过配置可以让你使用多级目录,来解决这个问题。简单来说,nginx通过levels这个指令指定目录层数(冒号分隔)和每个目录名字的字符个数,在我们的例子中,假设配置levels=1:2,意思是说使用两级目录,第一级目录名是一个字符,第二级用两个字符。但是nginx最大支持3级目录,即levels=xxx:xxx:xxx。

    那么构成目录名字的字符哪来的呢?假设我们的存储目录为/cache,levels=1:2,那么对于上面的文件 就是这样存储的:

  /cache/0/8d/8ef9229f02c5672c747dc7a324d658d0

    看到0和8d这两个目录名怎么来的了吧,不用解释了。

    对象创建完成之后,就需要缓存对象管理结构中去了,这个ngx_http_file_cache_exists去处理的。

    如果在创建这个文件时,当前目录及文件已经存在,那如何处理?大家可以去翻翻代码,看nginx怎么处理的。

    讨论先告一个段落,其实现在都是一些准备工作,下次讨论后端内容到来的处理。

    扩展阅读:

    http://www.pagefault.info/?p=123

    http://www.pagefault.info/?p=375

以上就介绍了nginx的cache系统设计原理,包括了方面的内容,希望对PHP教程有兴趣的朋友有所帮助。

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
3 周前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
3 周前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您听不到任何人,如何修复音频
3 周前 By 尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解锁Myrise中的所有内容
4 周前 By 尊渡假赌尊渡假赌尊渡假赌

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

tomcat服务器怎么让外网访问 tomcat服务器怎么让外网访问 Apr 21, 2024 am 07:22 AM

要让 Tomcat 服务器对外网访问,需要:修改 Tomcat 配置文件,允许外部连接。添加防火墙规则,允许访问 Tomcat 服务器端口。创建 DNS 记录,将域名指向 Tomcat 服务器公有 IP。可选:使用反向代理提升安全性和性能。可选:设置 HTTPS 以提高安全性。

thinkphp怎么运行 thinkphp怎么运行 Apr 09, 2024 pm 05:39 PM

ThinkPHP Framework 的本地运行步骤:下载并解压 ThinkPHP Framework 到本地目录。创建虚拟主机(可选),指向 ThinkPHP 根目录。配置数据库连接参数。启动 Web 服务器。初始化 ThinkPHP 应用程序。访问 ThinkPHP 应用程序 URL 运行。

Welcome to nginx!怎么解决? Welcome to nginx!怎么解决? Apr 17, 2024 am 05:12 AM

要解决 "Welcome to nginx!" 错误,需要检查虚拟主机配置,启用虚拟主机,重新加载 Nginx,如果无法找到虚拟主机配置文件,则创建默认页面并重新加载 Nginx,这样错误消息将消失,网站将正常显示。

html文件怎么生成网址 html文件怎么生成网址 Apr 21, 2024 pm 12:57 PM

要将 HTML 文件转换为网址,需要使用网络服务器,包括以下步骤:获取网络服务器。设置网络服务器。上传 HTML 文件。创建域名。路由请求。

nodejs项目怎么部署到服务器 nodejs项目怎么部署到服务器 Apr 21, 2024 am 04:40 AM

Node.js 项目的服务器部署步骤:准备部署环境:获取服务器访问权限、安装 Node.js、设置 Git 存储库。构建应用程序:使用 npm run build 生成可部署代码和依赖项。上传代码到服务器:通过 Git 或文件传输协议。安装依赖项:SSH 登录服务器并使用 npm install 安装应用程序依赖项。启动应用程序:使用 node index.js 等命令启动应用程序,或使用 pm2 等进程管理器。配置反向代理(可选):使用 Nginx 或 Apache 等反向代理路由流量到应用程

dockerfile中最常见的指令是什么 dockerfile中最常见的指令是什么 Apr 07, 2024 pm 07:21 PM

Dockerfile 中最常用的指令有:FROM:创建新镜像或派生新镜像RUN:执行命令(安装软件、配置系统)COPY:复制本地文件到镜像ADD:类似 COPY,可自动解压缩 tar 存档或获取 URL 文件CMD:指定容器启动时的命令EXPOSE:声明容器监听端口(但不公开)ENV:设置环境变量VOLUME:挂载主机目录或匿名卷WORKDIR:设置容器中的工作目录ENTRYPOINT:指定容器启动时要执行的可执行文件(类似 CMD,但不可覆盖)

nodejs可以外网访问么 nodejs可以外网访问么 Apr 21, 2024 am 04:43 AM

是的,Node.js 可以外网访问。您可以使用以下方法:使用 Cloud Functions 部署函数并公开访问。使用 Express 框架创建路由并定义端点。使用 Nginx 反向代理请求到 Node.js 应用程序。使用 Docker 容器运行 Node.js 应用程序并通过端口映射公开。

如何使用 PHP 部署和维护网站 如何使用 PHP 部署和维护网站 May 03, 2024 am 08:54 AM

要成功部署和维护PHP网站,需要执行以下步骤:选择Web服务器(如Apache或Nginx)安装PHP创建数据库并连接PHP上传代码到服务器设置域名和DNS监控网站维护步骤包括更新PHP和Web服务器、备份网站、监控错误日志和更新内容。

See all articles