NGINX缓存原理及源码分析(二)

21 篇文章 2 订阅

概述

上篇我们讲述了NGINX缓存的原理以及NGINX的Cache Loader和Cache Manager进程是如何工作的。本篇,我们继续分析NGINX工作原理的剩余的两个部分,那就是NGINX是如何生成和使用缓存的。

引用上篇文章中的图片来描述从高层次来看,NGINX缓存的大体结构。

如上图所示,NGINX在内存中维护一棵红黑树,然后每一个节点上存储这文件的元数据(meta data),并且在磁盘中存放文件的完整内容。

NGINX的缓存功能都是围绕上述数据结构进行的。主要包括以下四个任务:

  1. 维护

保存上图数据的一致性,比如相应缓存文件已经对应的内存数据进行删除。

  1. 加载

在NGINX启动时,如果磁盘中存在缓存文件,则需要生成对应内存中的元数据。

  1. 生成

创建Memory中的元数据以及对应的磁盘中的文件。

  1. 使用

新的请求到来时,如果对应的location匹配有cache,判断cache是否存在已经是否可用,如果可用,则直接返回对应磁盘中的文件。

本篇文章,我们要分析3,4的工作原理和流程。

配置指令

NGINX提供了如下总多的配置选项来控制NGINX缓存的生成和使用。

与buffer工作有关指令


如果不配置proxy_buffering,NGINX是不能生产缓存的,所以我们先来分析buffering的工作原理。

buffer工作原理

首先第一个概念是所有的这些proxy buffer参数是作用到每一个请求的。每一个请求会安按照参数的配置获得自己的buffer。proxy buffer不是global而是per request的。
proxy_buffering 是为了开启response buffering of the proxied server,开启后proxy_buffers和proxy_busy_buffers_size参数才会起作用。
无论proxy_buffering是否开启,proxy_buffer_size都是工作的,proxy_buffer_size所设置的buffer_size的作用是用来存储upstream端response的header。

在proxy_buffering 开启的情况下,NGINX将会尽可能的读取所有的upstream端传输的数据到buffer,直到proxy_buffers设置的所有buffer们被写满或者数据被读取完(EOF)。此时NGINX开始向客户端传输数据,会同时传输这一整串buffer们。同时如果响应的内容很大的话,NGINX会接收并把他们写入到临时文件里去。大小由proxy_max_temp_file_size控制。如果busy的buffer传输完了会从temp_file里面接着读数据,直到传输完毕。

一旦proxy_buffers设置的buffer被写入,直到buffer里面的数据被完整的传输完(传输到客户端),这个buffer将会一直处在busy状态,我们不能对这个buffer进行任何别的操作。所有处在busy状态的buffer size加起来不能超过proxy_busy_buffers_size,所以proxy_busy_buffers_size是用来控制同时传输到客户端的buffer数量的。

相关指令

Syntax:            proxy_buffering on | off;

Default:           proxy_buffering on;

Context:          http, server, location

启用或禁用使用缓冲区来存储代理服务器的响应。默认打开,如果proxy_buffering关闭,则NGINX不会生成缓存文件。启用后,NGINX会尽快从代理服务器收到响应,并将其保存到由指令proxy_buffer_size和proxy_buffers指令设置的缓冲区中 。如果缓冲区不能容纳整个响应,则可以将一部分响应保存到磁盘上的临时文件中。临时文件大小由 proxy_max_temp_file_size和proxy_temp_file_write_size 指令配置。指令proxy_temp_file_write_size定义的是一次访问能写入的临时文件的大小,默认是proxy_buffer_size和proxy_buffers中设置的缓冲区大小的2倍,Linux下一般是8k。指令proxy_max_temp_file_size指定当响应内容大于proxy_buffers指定的缓冲区时, 写入硬盘的临时文件的大小. 如果超过了这个值, NGINX将与Proxy服务器同步的传递内容, 而不再缓冲到硬盘. 设置为0时, 则直接关闭硬盘缓冲。

禁用后,收到响应后到就立即同步传递到客户端。NGINX不会尝试从代理服务器读取整个响应。一次可以从服务器接收的最大数据大小由proxy_buffer_size指令设置。

可以通过在“ X-Accel-Buffering”响应头字段中传递“ yes”或“ no” 来启用或禁用缓冲。也可以使用proxy_ignore_headers指令禁用此功能 。

Syntax:           proxy_buffer_size size;

Default:           proxy_buffer_size 4k|8k;

Context:          http, server, location

设置从代理服务器接收响应头的缓冲区大小。默认情况下,缓冲区大小等于系统一个内存页面大小。根据平台的不同,它可以是4K8K。当然,也可以设置的比4K或者8K小。

Syntax:            proxy_buffers number size;

Default:           proxy_buffers 8 4k|8k;

Context:          http, server, location

设置用于为单个客户连接从代理服务器读取响应的缓冲区的数量和单个缓存的大小。proxy_buffers的缓冲区大小一般会设置的比较大,以应付大网页。 proxy_buffers当中单个缓冲区的大小是由系统的内存页面大小决定的,Linux系统中一般为4k。 proxy_buffers由缓冲区数量和缓冲区大小组成的。总的大小为number*size。

若某些请求的响应过大,则超过_buffers的部分将被缓冲到硬盘(缓冲目录由_temp_path指令指定), 当然这将会使读取响应的速度减慢, 影响用户体验. 可以使用proxy_max_temp_file_size指令关闭磁盘缓冲。

Syntax:            proxy_busy_buffers_size size;

Default:           proxy_busy_buffers_size 8k|16k;

Context:          http, server, location

参数proxy_busy_buffers_size不是独立的空间,它是proxy_buffers和proxy_buffer_size的一部分。NGINX会在没有完全读完后端响应的时候就开始向客户端传送数据,所以它会划出一部分缓冲区来专门向客户端传送数据(这部分的大小是由proxy_busy_buffers_size来配置的,建议为proxy_buffers中单个缓冲区大小的2倍,比如8K),然后它继续从后端取数据,缓冲区满了之后就写到磁盘的临时文件中。

与NGINX缓存生成和使用有关指令

Syntax:            proxy_cache_background_update on | off;

Default:           proxy_cache_background_update off;

Context:          http, server, location

允许在后台发送子请求来更新过期的缓存文件。一般一个请求过来判断一下缓存时间,如果过期了再从后端取

Syntax:            proxy_cache_bypass string ...;

Default:           —

Context:          http, server, location

类似于proxy_no_cache,但是,其控制什么情况不使用缓存的内容,而是直接到后端获取最新的内容。如果命中,则$upstream_cache_status为BYPASS,而且响应内容会再被缓存。可以与proxy_no_cache指令一起使用。

Proxy_cache_bypass $cookie_nocache $arg_nocache$arg_comment;

proxy_cache_bypass $http_pragma    $http_authorization;

Syntax:            proxy_cache_convert_head on | off;

Default:           proxy_cache_convert_head on;

Context:          http, server, location

启用或禁用将“ HEAD”方法转换为“ GET”进行缓存。禁用转换后, 应将缓存键配置为包括$request_method。

Syntax:         proxy_cache_key string;
Default:        proxy_cache_key $scheme$proxy_host$request_uri;
Context:       http, server, location
该指令用来设置生成缓存的Key值,NGINX根据Key值md5哈希存储。一般根据$host(域名)、$request_uri(请求的路径)等变量组合成proxy_cache_key 例如:
proxy_cache_key “$host:$server_port$uri$is_args$args”; 

Syntax:            proxy_cache_lock on | off;

Default:           proxy_cache_lock off;

Context:          http, server, location

当多个客户端同时请求同一份内容时,如果开启proxy_cache_lock(默认off),则只有一个请求被发送至后端。其他请求将等待该请求的返回。当第一个请求返回后,其他相同请求将从缓存中获取内容返回。当第一个请求超过了proxy_cache_lock_timeout超时时间(默认为5s),则其他请求将同时请求到后端来获取响应,且响应不会被缓存(在1.7.8版本之前是被缓存的)。启用proxy_cache_lock可以应对Dog-pile effect(当某个缓存失效时,同时有大量相同的请求没命中缓存,而同时请求到后端,从而导致后端压力太大,此时限制一个请求去拿即可)。

Syntax:            proxy_cache_max_range_offset number;

Default:           —

Context:          http, server, location

指令是在1.11.6版本中引入的。设置字节范围请求的字节偏移量。如果范围超出偏移量,则范围请求将传递到代理服务器,并且不会缓存响应。

Syntax:            proxy_cache_methods GET | HEAD | POST …;

Default:           proxy_cache_methods GET HEAD;

Context:          http, server, location

设置为哪些客户端请求类型进行缓存。默认值是GET和HEAD方法。

Syntax:            proxy_cache_min_uses number;

Default:           proxy_cache_min_uses 1;

Context:          http, server, location

为在缓存响应之前,相同文件请求的最小次数。再达到此数值之前,响应不会被缓存。

Syntax:        proxy_cache_revalidate on | off;
Default:       proxy_cache_revalidate off;
Context:      http, server, location
当缓存过期后,如果开启了proxy_cache_revalidate,则会发出一次if-modified-since或if-none-match条件请求到后端服务器,如果后端返回304,并且使用本地缓存响应客户请求。此时$upstream_cache_status为REVALIDATED,这样可以节省带宽和减少写磁盘的次数。

Syntax:            proxy_cache_use_stale error | timeout | invalid_header | updating | http_500 | http_502 | http_503 | http_504 | http_403 | http_404 | http_429 | off ...;

Default:           proxy_cache_use_stale off;

Context:          http, server, location

当对缓存内容的过期时间不敏感,或者后端服务出问题时,即使缓存的内容不新鲜也总比返回错误给用户强(类似于托底),此时可以配置该参数,如“proxy_cache_use_stale error timeout http_500 http_502 http_503 http_504”,即如果出现超时、后端连接出错、500、502、503等错误时,则即使缓存内容已过期也先返回给用户,此时$upstream_cache_status为STALE。还有一个updating表示缓存已过期但正在被别的NGINX Worker进程更新,但先返回了过期内容,此时$upstream_cache_status为UPDATING。

参数error可以在无法选取有效后端服务处理当前请求的情况下使用过期缓存。参数update允许当前缓存在更新的时候使用过期缓存。这样可以减少在缓存更新时对后端服务器的访问次数。

如果收到的客户端HTTP协议的头部的Cache-Control字段包含某些参数,NGINX也可以使用过期缓存来响应客户端请求。这个条件的优先级低于指令配置的参数。

参数“stale-while-revalidate”: 在缓存更新时可以使用过期缓存。参数“stale-if-error:在出现错误时可以使用缓存。

确定在与代理服务器通信期间可以在哪些情况下使用过时的缓存响应。该指令的参数与 proxy_next_upstream 指令的参数匹配。

如果无法选择代理服务器来处理请求,则 error 参数还允许使用过时的缓存响应。此外,如果当前正在更新,则 updating 参数允许使用过时的缓存响应。这允许在更新缓存数据时最大化减少对代理服务器的访问次数。也可以直接在响应头中指定响应失效多少秒数后直接启用过时的缓存响应(1.11.10)。这比使用指令参数的优先级低。

Cache-Control 头字段的 stale-while-revalidate 扩展允许使用过时的缓存响应(如果当前正在更新)。

Cache-Control 头字段的 stale-if-error 扩展允许在出现错误时使用过时的缓存响应。

要在填充新缓存元素时最大化减少对代理服务器的访问次数,可以使用 proxy_cache_lock 指令。

Syntax:            proxy_cache_lock on | off;

Default:           proxy_cache_lock off;

Context:          http, server, location

当多个客户端同时请求同一份内容时,如果开启proxy_cache_lock(默认off),则只有一个请求被发送至后端。其他请求将等待该请求的返回。当第一个请求返回后,其他相同请求将从缓存中获取内容返回。当第一个请求超过了proxy_cache_lock_timeout超时时间(默认为5s),则其他请求将同时请求到后端来获取响应,且响应不会被缓存(在1.7.8版本之前是被缓存的)。启用proxy_cache_lock可以应对Dog-pile effect(当某个缓存失效时,同时有大量相同的请求没命中缓存,而同时请求到后端,从而导致后端压力太大,此时限制一个请求去拿即可)。

Syntax:            proxy_cache_lock_age time;

Default:           proxy_cache_lock_age 5s;

Context:          http, server, location

指令proxy_cache_lock_age是1.7.8新添加的,如果在proxy_cache_lock_age指定的时间内(默认为5s),最后一个发送到后端进行新缓存构建的请求还没有完成,则下一个请求将被发送到后端来构建缓存(因为1.7.8版本之后,proxy_cache_lock_timeout超时之后返回的内容是不缓存的,需要下一次请求来构建响应缓存)。

Syntax:            proxy_cache_lock_timeout time;

Default:           proxy_cache_lock_timeout 5s;

Context:          http, server, location

设置proxy_cache_lock的过期时间。当timer过期,请求会被发向后端服务器,但是,服务器的响应不会被缓存。在1.7.8版本之前,这种请求的响应也会被缓存。

Syntax:            proxy_cache_valid [code ...] time;

Default:           —

Context:          http, server, location

为不同的响应代码设置缓存时间。例如以下指令

proxy_cache_valid 200 302 10m;

proxy_cache_valid 404      1m;

为代码为 200 和 302 的响应设置 10 分钟的缓存时间,为代码 404 的响应设置 1 分钟的缓存时间。

如果仅指定了缓存时长比如proxy_cache_valid 5m;将只缓存 200、301 和 302 的响应。

此外,可以指定 any 参数来缓存任何响应:

proxy_cache_valid 200 302 10m;

proxy_cache_valid 301      1h;

proxy_cache_valid any      1m;

也可以直接在响应头中设置缓存的参数。这比使用该指令设置缓存时间具有更高的优先级。X-Accel-Expires 头字段设置以秒为单位的响应缓存时间。零值将禁用响应缓存。如果值以 @ 前缀开头,则设置自 Epoch 以来的绝对时间(以秒为单位)内的响应可以被缓存。如果头不包括 X-Accel-Expires 字段,则可以在头字段 Expires 或 Cache-Control 中设置缓存的参数。如果头包含了 Set-Cookie 字段,则不会缓存此类响应。

如果头包含有特殊值 * 的 Vary 字段,则不会缓存此类响应(1.7.7)。如果头包含有另一个值的 Vary 字段,这样的响应则将考虑缓存相应的请求头字段(1.7.7)。

为不同的响应状态码设置缓存时间。如果是proxy_cache_valid5s,则200、301、302响应都将被缓存。

指令proxy_cache_valid不是唯一设置缓存时间的,还可以通过如下方式(优先级从上到下)。

  1.以秒为单位的“X-Accel-Expires”响应头来设置响应缓存时间。

  2.如果没有“X-Accel-Expires”,则可以根据“Cache-Control”、“Expires”来设置响应缓存时间。

  3.否则,使用proxy_cache_valid设置缓存时间。

如果响应头包含Cache-Control:private/no-cache/no-store、Set-Cookie或者只有一个Vary响应头且其值为*,则响应内容将不会被缓存。可以使用proxy_ignore_headers来忽略这些响应头。

如果NGINX无法通过上述途径获得有效期,NGINX将不会为响应生成缓存文件。 

Syntax:            proxy_ignore_headers field ...;

Default:           —

Context:          http, server, location

忽略上游服务器返回的特定的响应头部。这些头部包括:“X-Accel-Redirect”, “X-Accel-Expires”, “X-Accel-Limit-Rate” (1.1.6), “X-Accel-Buffering” (1.1.6), “X-Accel-Charset” (1.1.6), “Expires”, “Cache-Control”, “Set-Cookie” (0.8.44), and “Vary” (1.7.7)。

如果不忽略处理这些头部,他们产生的效果如下:

“X-Accel-Expires”, “Expires”, “Cache-Control”, “Set-Cookie”, and “Vary” 影响缓存有效期。

“X-Accel-Redirect” 内部重定向到某个特定URI。

“X-Accel-Limit-Rate” 设置到客户端的rate limit数值。

“X-Accel-Buffering” 启用或者禁止proxy_buffering。

“X-Accel-Charset” 设置发向客户端的字符集。

Syntax:            proxy_intercept_errors on | off;

Default:           proxy_intercept_errors off;

Context:          http, server, location

对于上游返回的大于300的错误返回码是否需要重新处理再返回客户端。

数据结构

继续引用上篇文章中的数据结构图,这样可以随时查看相关数据结构之间的关系。

 

原理

在生成缓存文件时,NGINX会根据客户端发来的请求以及指令proxy_cache_key中的配置参数使用md5生成一个32位的16进制数值。

比如配置如下的服务器:

    proxy_cache_path  /data/cache levels=2:2 keys_zone=jikuicdn:10m inactive=6000m;

    server {

        listen 80;

        location  / {

            proxy_cache_key $scheme$proxy_host$request_uri;

            proxy_cache jikuicdn;

            add_header X-Cache-Status $upstream_cache_status;

            proxy_pass http://10.145.73.28/;

        }

}

在客户端执行请求curl http://10.145.70.103/index.html。 则NGINX对此请求生成的key值是"http10.145.73.28/index.html"。

计算此key值的md5  hash可以得到:

[jikui@nginx-dev ~]$ echo -n "http10.145.73.28/index.html" | md5sum

85c8a32fc36adfde2824ec3fc06d9304  -

对于此请求后端服务器返回的响应,NGINX会生成一个key值为85c8a32fc36adfde2824ec3fc06d9304的ngx_http_file_cache_node_t的结构并且插入到红黑树节点中。同时还会并且根据proxy_cache_path的配置生成如下名为85c8a32fc36adfde2824ec3fc06d9304的磁盘文件存放到配置的路径下。

[jikui@nginx-dev ~]$ ls -al /data/cache/04/93/

total 8

drwx------ 2 jikui users   46 Jan 16 03:02 .

drwx------ 3 jikui users   16 Jan 16 03:02 ..

-rw------- 1 jikui users 4729 Jan 16 03:02 85c8a32fc36adfde2824ec3fc06d9304

存放在磁盘上的缓存文件内容格式如下所示:

[ngx_http_file_cache_header_t]["\nKEY: "][orig_key]["\n"][header][body]中的[orig_key]["\n"]

第一部分是数据结构ngx_http_file_cache_header_t的内容,第二部分是生成文件名所需要的key值,一般是指令proxy_cache_key定义的参数。第三部分就是发送给客户端的文件内容,包括header和body两部分。

NGINX收到一个请求以后,计算请求对应的key的md5sum值然后使用该hash值作为key去搜索是否存在缓存文件,如果存在并且有效则尝试使用此文件响应客户请求。

缓存生成

在接收到上游响应并准备向下游发送之前,upstream 模块会判断是否需要对响应进行缓存并设置相关信息。这个过程主要在函数 ngx_http_upstream_send_response 中完成,具体流程为:

  1. 调用函数ngx_http_test_predicates判断是否满足生成缓存文件的条件。函数ngx_http_test_predicates会根据proxy_no_cache指令的配置来判断是否需要生成缓存文件。
  2. 如果函数ngx_http_test_predicates返回NGX_ERROR,则通过ngx_http_upstream_finalize_request(r, u, NGX_ERROR)直接返回错误。如果返回NGX_DECLINE则表示不需要生成缓存文件。
  3. 如果返回NGX_OK则表示需要生成缓存文件,同时把结构ngx_http_upstream_t中的cacheable变量设置为1。
  4. 获得缓存文件的有效期。缓存文件的有效期首先是通过上游服务器返回的响应头部中的X-Accel-Expires,Cache-Control,或者Expires头部信息来获得。如果返回没有上述头部信息,则通过函数ngx_http_file_cache_valid获取通过指令proxy_cache_valid设置的有效期。如果无法获得要生成缓存文件的有效期,则NGINX不会生成缓存文件。
  5. 如果需要缓存通过如下步骤生成缓存文件的内存meta信息和磁盘文件:
  • 通过函数ngx_http_file_cache_exists判断系统内存中是否已经存在着缓存文件的红黑树节点,如果存在则重新刷新缓存文件的有效期。如果没有,则生成一个新的ngx_http_file_cache_node_t红黑树节点并且插入到内存红黑树中。至此,缓存文件的meta信息就已经生成完毕。
  • 通过函数ngx_http_file_cache_create通过对请求的keys进行md5 hash生成缓存文件的文件名。
  • 通过函数ngx_http_file_cache_set_header初始化缓存文件的ngx_http_file_cache_header_t头部信息结构已经生成文件名所用的key值。这个结构信息也同时会被写入磁盘缓存文件的头部。[ngx_http_file_cache_header_t]["\nKEY: "][orig_key]["\n"][header][body]
  • 在有buffering的时候,NGINX使用ngx_event_pipe进行数据转发。函数ngx_event_pipe调用ngx_event_pipe_read_upstream读取upstream发送的数据并且通过函数ngx_event_pipe_write_chain_to_temp_file写入临时文件中。
  • 等上游服务器请求接收完毕通过函数ngx_http_file_cache_update把临时文件重命名为正式的缓存文件。

缓存使用

再来分析一下在正常请求处理过程中,一个请求是怎样使用缓存 数据的 (同时,在分析代码过程中还需要注意的是, NGINX 允许 Cache Loader 进程在加载缓存文件信息的同时响应这些对缓存的请求,这个特性用于提高 NGINX本身的可用性)。

所有请求缓存使用的尝试,都是通过 ngx_http_upstream_cache 函数开始的。 这个函数的主要流程是:

  1. 如果还未给当前请求分配缓存相关结构体 (ngx_http_cache_t) ,则调用函数ngx_http_file_cache_new创建此类型字段 (r->cache) 并初始化。
  2. 通过函数ngx_http_proxy_create_key对proxy_cache_key配置的缓存key进行取值。
  3. 通过函数ngx_http_file_cache_create_key身材md5sum(key)和crc32(key)并计算header_start值。
  4. 调用函数ngx_http_test_predicates根据指令proxy_cache_bypass的配置信息,来判断对于本次请求是不是要绕过缓存文件直接通过后端服务器进行获取。
  5. 调用函数ngx_http_file_cache_open查找是否有对应的有效缓存数据。函数ngx_http_file_cache_open我们下面接着分析。
  6. 如果缓存命中,调用 ngx_http_upstream_cache_send 函数发送缓存数据给请求者。如果缓存未命中,继续正常 upstream 请求处理流程。

函数ngx_http_file_cache_open 函数负责缓存文件定位、缓存文件打开和校验等操作,其返回值及对应含义,以及其调用者 ngx_http_upstream_cache 对应的行为总结如下:

  1. NGX_OK

             - 缓存正常命中

             - 设置 `cache_status` 为 `NGX_HTTP_CACHE_HIT`,然后向客户端发送缓存内容

  1. NGX_HTTP_CACHE_STALE

            - 缓存内容过期,当前请求需要向后端请求新的响应数据。

            - 设置 `cache_status` 为 `NGX_HTTP_CACHE_EXPIRED`,并返回 `NGX_DECLINED`

              以继续请求处理 (`r->cached = 0; c->valid_sec = 0`)。

  1. NGX_HTTP_CACHE_UPDATING

            - 缓存内容过期,同时己有同样使用该缓存节点的其它请求正在请求新的响应数据。

            - 如果 proxy_cache_use_stale 启用了 "updating",设置 `cache_status` 为

           `NGX_HTTP_CACHE_UPDATING`,然后向客户端发送过期缓存内容。否则,将返回

           值重设为 `NGX_HTTP_CACHE_STALE`。

  1. NGX_HTTP_CACHE_SCARCE

            - 因缓存节点被查询次数还未达 `min_uses`,对此请求禁用缓存机制

            - 继续请求处理,但是不再缓存其响应数据 (`u->cacheable = 0`)。

  1. NGX_DECLINED

            - 缓存内容因为不存在 (`c->exists == 0`)、缓存内容未通过校验、或者当前请

              求正在更新缓存等原因,暂时无法使用缓存。

            - 继续请求处理,并尝试对其响应数据进行缓存。

  1. NGX_AGAIN

            - 缓存内容过期,并且当前缓存节点正在被其它请求更新,或者 还未能从缓存文

            件中读到足够的数据 (aio 模块下)。

             - 返回 `NGX_BUSY`,NGINX 会再次尝试读取缓存。

  1. NGX_ERROR

             - 内存相关、文件系统等系统错误。

            - 返回 `NGX_ERROR`,NGINX 会调用 `ngx_http_finalize_request` 终止此请求。

  1. NGX_HTTP_SPECIAL_RESPONSE

            - 打开 `proxy_intercept_errors` 配置情况下,直接返回缓存的错误码。

            - 设置 `cache_status` 为 `NGX_HTTP_CACHE_HIT` 并返回错误码。

函数 ngx_http_file_cache_open 的主要逻辑如下:

  1. 第一次根据请求信息生成的 key 查找对应缓存节点时,先注册一下请求内存池级别的清理函数:
  2. 调用 ngx_http_file_cache_exists 函数,使用 ngx_http_file_cache_lookup 函 数以 c->key 为查找条件从缓存中查找缓存节点:
  • 如果找到了对应 c->key 的缓存节点:
  • 如果该请求第一次使用此缓存节点,则增加相关引用和使用次数,继续下面条件判断;
  • 如果 proxy_cache_valid 配置指令对此节点过期时间做了特殊设定,检查节点是否过期。如果过期,重置节点,并返回 NGX_DECLINED; 如果未过期,返 回 NGX_OK;
  • 如果缓存文件存在或者缓存节点被使用次数超过 proxy_cache_min_uses 配置值,置 c->error = fcn->error,并返回 NGX_OK;
  • 条件 2, 3 都不满足时,此次查找失败,返回 NGX_AGAIN。
  • 如果未找到对应 c->key 的缓存节点,创建并创始化新的缓存节点,同时返回 NGX_DECLINED。
  • 调用 ngx_http_file_cache_name 函数生成缓存文件完整文件名。调用 ngx_open_cached_file 函数尝试打开并获取文件缓存信息。
  1. 创建用于存储 缓存文件头的临时缓冲区 c->buf。
  2. 调用 ngx_http_file_cache_read 函数读取缓存文件头并进行有效性验证。
  3. 文件内容通过ngx_http_upstream_cache_send调用ngx_http_cache_send来完成发送。

缓存使用和生成涉及的基本流程大致分析完毕了,其中涉及 cache_lock 等诸多细节因为篇幅原因,暂时不做分析。

总结

缓存是NGINX最重要的功能之一。通过两篇文章,我们大体分析了NGINX缓存工作的原理。就缓存的实现来说,内容很多,细节也很庞杂。所以在进行源码分析时很多细节都没有顾及到。很多细节留给我们自己阅读代码时去体会。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值