后浪笔记一零二四

1 如何减轻缓存失效时上游服务的压力?

  1. 合并回源请求——减轻峰值流量下的压力
Syntax:  proxy_cache_lock on|off;
Default: proxy_cache_lock off;
Context: http,server,location
当值为on时:同一时间,仅第1个请求发向上游,其他请求等待第1个响应返回或者超时后,
使用缓存响应客户端

Syntax:   proxy_cache_lock_timeout time;
Default:  proxy_cache_lock_timeout 5s;
Context:  http,server,location
# 等待第1个请求返回响应的最大时间,到达后其他请求直接向上游发送请求,但不缓存响应

Syntax:   proxy_cache_lock_age time;
Default:  proxy_cache_lock_age 5s;
Context:  http,server,location
# 上一个请求返回响应的超时时间,到达后再放行一个请求发向上游
  1. 减少回源请求——使用stale陈旧的缓存
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
* updating: 
    * 当缓存内容过期,有一个请求正在访问上游试图更新缓存时,其他请求直接使用过期内容返回客户端
    * 上游还可以使用Cache-Control响应头来控制updating的行为:
        * stale-while-revalidate
             * 缓存内容过期后,定义一段时间,在这段时间内updating设置有效,否则请求仍然访问上游服务
             * 例如:Cache-Control:max-age=600,stale-while-revalidate=30
        * stale-if-error
             * 缓存内容过期后,定义一段时间,在这段时间内上游服务出错后就继续使用缓存,否则请求仍然访问
               上游服务。stale-while-revalidate包括stale-if-error场景
             * 例如:Cache-Control:max-age=600,stale-if-error=1200
* error
    * 当与上游建立连接、发送请求、读取响应头部等情况出错时,使用缓存
* timeout
    * 当与上游建立连接、发送请求、读取响应头部等情况出现定时器超时,使用缓存
* http_(500|502|503|504|403|404|429)
    * 缓存以上错误响应码的内容


Syntax:  proxy_cache_background_update on|off;
Default: proxy_cache_background_update off;
Context: http,server,location
当使用proxy_cache_use_stale允许使用过期响应时,将同步生成一个子请求,通过访问上游服务更新过期的缓存

Syntax:  proxy_cache_revalidate on|off;
Default: proxy_cache_revalidate off;
Context: http,server,location
更新缓存时,使用If-Modified-Since和If-None-Match作为请求头部,预期内容未发生变更时通过304来减少传输的内容

2 及时清除缓存

模块:https://github.com/FRiCKLE/ngx_cache_purge

功能:接收到指定HTTP请求后立刻清除缓存

Syntax:  proxy_cache_purge on|off|<method> [ from all|<ip> [...<ip>] ]
Default: none
Context: http,server,location

Syntax:  proxy_cache_purge zone_name key
Default: none
Context: location

案例:

proxy_cache_path /data/nginx/tmpcache levels=2:2 keys_zone=two:10m loader_threshold=300
                     loader_files=200 max_size=200m inactive=1m;
server {
  location ~ /purge(/.*) {
    proxy_cache_purge two $scheme$1;
  }
  location / {
    proxy_cache two;
    proxy_cache_valid 200 1m;
    add_header X-Cache-Status $upstream_cache_status;

    proxy_cache_key $scheme$uri;
    proxy_pass http://localhost:8012;
  }
}

验证:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#生成缓存
$ curl cache.taohui.tech/index.html -I
HTTP/1.1 200 OK
Server: openresty/1.13.6.2
Date: Sun, 23 Dec 2018 03:17:21 GMT
Content-Type: text/html
Content-Length: 612
Connection: keep-alive
Last-Modified: Thu, 08 Nov 2018 03:12:07 GMT
ETag: "5be3a987-264"
X-Cache-Status: HIT
Accept-Ranges: bytes

#清除缓存
$ curl cache.taohui.tech/purge/index.html -I
HTTP/1.1 200 OK
Server: openresty/1.13.6.2
Date: Sun, 23 Dec 2018 03:17:29 GMT
Content-Type: text/html
Content-Length: 281
Connection: keep-alive

#再次访问发现缓存MISS了
$ curl cache.taohui.tech/index.html -I
HTTP/1.1 200 OK
Server: openresty/1.13.6.2
Date: Sun, 23 Dec 2018 03:17:21 GMT
Content-Type: text/html
Content-Length: 612
Connection: keep-alive
Last-Modified: Thu, 08 Nov 2018 03:12:07 GMT
ETag: "5be3a987-264"
X-Cache-Status: MISS
Accept-Ranges: bytes

3 使用分片提升缓存效率

slice模块:

  1. 默认没有编译进nginx,需要通过--with-http_slice_module启用
  2. 功能:通过range协议将大文件分解为多个小文件,更好的用缓存为客户端的range协议服务。 当上游返回的文件特别大的时候,可以使用分片的方式。
  3. 指令
Syntax:  slice size;
Default: slice 0;
Context: http,server,location

配置案例:

proxy_cache_path /data/nginx/tmpcache levels=2:2 keys_zone=three:10m loader_threshold=300
                     loader_files=200 max_size=200m inactive=1m;
server {
  location ~ /purge(/.*) {
    proxy_cache_purge three $1$is_args$args$slice_range;
  }
  location / {
    proxy_cache three;
    # 1. 设置每个slice的大小
    slice            1m;
    # 2. 设置缓存key
    proxy_cache_key  $uri$is_args$args$slice_range;
    # 3. 设置发给上游的请求的Range请求头
    proxy_set_header Range $slice_range;

    proxy_cache_valid 200 206 1m;
    add_header X-Cache-Status $upstream_cache_status;

    proxy_pass http://localhost:8012;
  }
}

工作的流程:

                                                        2.Nginx retrieves enclosing
1.Client requests 100 bytes,                              segments
 starting at offset 150        +-----------------------+     \
              \                |                       |--GET range=100-199-->+---------+
[clients]---GET Range=150-249->| Nginx                 |<---------------------|         |
[       ]<---------------------|     Cache slice:100   |--GET range=200-299-->|上游服务  |
                  /            |                       |<---------------------+---------+
  4.Nginx assembles response   +-----------------------+
    from the cached segments           |   |3.Each segment is cached
                                       |   | separately 
                                       V   V 
                                   [  ]/cache/XYZ (slice for 100-199)
                                   [  ]/cache/ABC (slice for 200-299)

4 open file cache提升系统性能

Syntax:  open_file_cache off
         open_file_cache max=N [inactive=time];
Default: open_file_cache off;
Context: http,server,location

* max=N : 最多缓存多少个文件,在内存中,而不是共享内存中。
          如果超过了max=N的数量以后,我们就采用LRU链表进行淘汰。
* inactive=time : 如果一个文件在inactive=time时间内没有被访问过,就把它移出缓存


Syntax:  open_file_cache_errors on|off;
Default: open_file_cache_errors off;
Context: http,server,location
功能:对访问文件错误的信息,是否进行缓存

Syntax:  open_file_cache_min_uses number;
Default: open_file_cache_min_uses 1;
Context: http,server,location
功能:最少访问多少次,该文件的信息才被缓存在缓存中。

Syntax:  open_file_cache_valid time;
Default: open_file_cache_valid 60s;
Context: http,server,location
功能:多少秒后,去确认下缓存是否发生了更新。

缓存哪些元信息?

typedef struct {
    ngx_fd_t                 fd;------------------->文件句柄
    ngx_file_uniq_t          uniq;
    time_t                   mtime;----------------->文件修改时间
    off_t                    size;------------------->文件大小
    off_t                    fs_size;
    off_t                    directio;
    size_t                   read_ahead;

    ngx_err_t                err;-------------------->文件查询时的错误信息
    char                    *failed;

    time_t                   valid;

    ngx_uint_t               min_uses;

#if (NGX_HAVE_OPENAT)
    size_t                   disable_symlinks_from;
    unsigned                 disable_symlinks:2;
#endif

    unsigned                 test_dir:1;
    unsigned                 test_only:1;
    unsigned                 log:1;
    unsigned                 errors:1;
    unsigned                 events:1;

    unsigned                 is_dir:1;------------------->目录是否存在
    unsigned                 is_file:1;
    unsigned                 is_link:1;
    unsigned                 is_exec:1;
    unsigned                 is_directio:1;
} ? end {anonngx_open_file_info_t} ? ngx_open_file_info;

验证:

  1. nginx服务的配置
server {
  listen 8092;
  root html;
  location / {
    open_file_cache max=10 inactive=60s;
    open_file_cache_min_uses 1;
    open_file_cache_valid 60s;
    open_file_cache_errors on;
  }
}
  1. 使用strace来跟踪系统调用
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#1. 查看worker进程的进程ID
$ ps -ef | grep nginx
root   16715    1  0  Dec22 ?    00:00:00 nginx: master process ../sbin/ngin
root   4669 16715  0  14:59 ?    00:00:00 nginx: worker process

#2. 使用strace来跟踪系统调用
$ strace -p 4669

#3. 访问
$ curl localhost:8092

#第2步的输出如下:
strace: Process 4669 attached
epoll_wait(18, [{EPOLLIN, {u32=1692460464, u64=139897367225776}}], 512, -1) = 1
accept4(12, {sa_family=AF_INET, sin_port=htons(56644), sin_addr=inet_addr("127.0.0.1")}, [16], SOCK_NONBLOCK)=3
epoll_ctl(18, EPOLL_CTL_ADD, 3, {EPOLLIN|EPOLLRDHUP|EPOLLET, {u32=1692461664, u64=139897367226976}}) = 0
epool_wait(18, [{EPOLLIN, {u32=1692461664, u64=139897367226976}}], 512, 60000) = 1
recvfrom(3, "GET / HTTP/1.1\r\nUser-Agent: curl"..., 1024, 0, NULL, NULL) = 78
open("/usr/local/nginx/html/index.html", O_RDONLY|O_NONBLOCK) = 4
fstat(16, {st_mode=S_IFREG|0755, st_size=612, ...}) = 0
writev(3, [{"HTTP/1.1 200 OK\r\nServer: nginx/1"..., 238}], 1) = 238
sendfile(3, 4, [0] => [612], 612)      = 612
write(17, "127.0.0.1 - - [23/Dec/2018:15:02"..., 86) = 86
setsockopt(3, SOL_TCP, TCP_NODELAY, [1], 4) = 0
epoll_wait(18, [{EPOLLIN|EPOLLRDHUP, {u32=1692461664, u64=139897367226976}}], 512, 65000) = 1
recvfrom(3, "", 1024, 0, NULL, NULL)   = 0
close(3)                               = 0
epoll_wait(18,


[{EPOLLIN, [u32=1692460464, u64=139897367225776]}, 512, -1] = 1
accept4(12, {sa_family=AF_INET, sin_port=htons(56646), sin_addr=inet_addr("127.0.0.1")}, [16], SOCK_NONBLOCK) = 3
epoll_ctl(18, EPOLL_CTL_ADD, 3, {EPOLLIN|EPOLLRDHUP|EPOLLET, {u32=1692461665, u64=139897367226977}}) = 0
epool_wait(18, [{EPOLLIN, {u32=1692461665, u64=139897367226977}}], 512, 60000) = 1
recvfrom(3, "GET / HTTP/1.1\r\nUser-Agent: curl"..., 1024, 0, NULL, NULL) = 78
writev(3, [{"HTTP/1.1 200 OK\r\nServer: nginx/1"..., 238}], 1) = 238
sendfile(3, 4, [0] => [612], 612)      = 612
write(17, "127.0.0.1 - - [23/Dec/2018:15:02"..., 86) = 86
setsockopt(3, SOL_TCP, TCP_NODELAY, [1], 4) = 0
epoll_wait(18, [{EPOLLIN|EPOLLRDHUP, {u32=1692461665, u64=139897367226977}}], 512, 65000) = 1
recvfrom(3, "", 1024, 0, NULL, NULL)  = 0
close(3)                              = 0
epoll_wait(18,

本文发表于 0001-01-01,最后修改于 0001-01-01。

本站永久域名「 jiavvc.top 」,也可搜索「 后浪笔记一零二四 」找到我。


上一篇 « 下一篇 »

赞赏支持

请我吃鸡腿 =^_^=

i ysf

云闪付

i wechat

微信

推荐阅读

Big Image