南琴浪博客

本博客 Nginx 配置(系列二) 性能篇

10/29/2017

在之前的文章 本博客 Nginx 配置(系列一) 安全篇 中,我介绍了本博客的 Nginx 配置中与安全相关的项目。这篇帖子会继续介绍与站点性能相关的条目。

TCP 优化

http {
    sendfile    on;
    tcp_nopush  on;
    tcp_nodelay on;
    keepalive_timeout 60;
}

server {
    listen 443 fastopen=3 reuseport;
}

sendfile 可以提高 Nginx 静态资源管理效率,它是一个系统调用,直接在内核空间完成文件发送,不需要先 read 再 write,没有上下文切换开销。

tcp_nopush 是 FreeBSD 的一个 socket 选项,对应于 Linux 的 tcp_cork,Nginx 中统一用 tcp_nopush 控制,且只有在启用了 sendfile 后才会生效。启用它后,数据包会累计到一定大小后才会发送,减小额外开销,提高网络效率。

tcp_nodelay 也是一个 socket 选项,启用后会禁用 Nagle 算法,尽快发送数据。Nginx 只会针对处于 keep-alive 状态的 TCP 连接启用 tcp_nodelay。

然后你会发现,一个要等数据包累积到一定大小才发送,另一个要尽快发送,这不是矛盾的吗?事实是,这俩是可以叠加的,最终结果是:先填满包,然后尽快发送。

keepalive_timeout 用于指定服务端每个 TCP 连接的最大保持连接时间。Nginx 默认是 75 秒,而有的浏览器最多只保持 60 秒,所以我设置为 60。

fastopen=3 用于指定开启 Tcp Fast Open。设置这项的值为 3,表示只允许 3 个未经三次握手的 TCP 连接进行排队。超过这个限制,服务端会退化到采用普通的 TCP 握手流程。这是为了减少资源耗尽攻击:Tcp Fast Open 可以在第一次 SYN 的时候发送 HTTP 请求,而服务端会校验 Fast Open Cookie(FOC),如果通过就开始处理请求。如果不加限制,恶意客户端可以利用合法的 FOC 发送大量请求耗光服务端资源。关于 Tcp Fast Open 的更多信息,可以参看 RFC7413

reuseport Nginx 在 1.9.1 版本中加入了 reuseport 功能,表示 Nginx 开始支持 TCP 的 so_reuseport 选项。关于这部分,可参看 官方文档

Gzip 压缩

http {
    gzip           on;
    gzip_vary  on;
    gzip_min_length 1000;
    gzip_buffers        16 10k;
    gzip_comp_level 3;
    gzip_proxied   any;
    gzip_types      text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript application/javascript;
    gzip_disable  "msie6";
    gzip_http_version 1.0;
}

关于 gzip 压缩的更多说明,可以看我的 这篇帖子

缓存

缓存是很常见的优化手段,缓存手段也很多,本文列举出本博客使用的几种方案:

proxy_cache

用于对 proxy_pass 的缓存

http {
    proxy_cache_path  /home/nginx/proxy_cache/cache levels=1:2 keys_zone=proxycache:60m max_size=120m inactive=2h use_temp_path=on;
    proxy_temp_path   /home/nginx/proxy_cache/temp;
    proxy_cache_key   $host$uri;
}

server {
    ...
    location / {
        proxy_cache          proxycache;
        proxy_cache_valid 304 2h;
        proxy_cache_valid 404 2h;
        proxy_cache_lock  on;
        proxy_cache_lock_timeout 5s;
        proxy_cache_use_stale updating error timeout invalid_header http_500 http_502;
    }
}

首先在全局配置 http 块内配置 proxy_cache 的路径(path)、空间名(keys_zone)、缓存上限、生成 key 规则,然后在站点配置中需要使用 proxy_cache 进行剩下的配置。上面我以 location / 作为示例。关于 proxy_cache 的更多说明,可以看我的 这篇文章

open_file_cache

缓存被频繁访问的文件相关的信息

open_file_cache                      max=2048 inactive=1d;
open_file_cache_valid             1d;
open_file_cache_min_uses    5;
open_file_cache_errors          off;

其中:

  • max 缓存中的最大文件描述符数量
  • inactive 存活时间,经过多长时间文件没被请求后清理缓存
  • min_uses在 inactive 时间段内,日志文件使用次数小于该值后,清理缓存
  • valid 缓存的有效信息的检查频率

HTTP 强缓存

有一种缓存机制是,服务端通过响应头告诉浏览器,在哪个时间点之前(Expires),或在多长时间之内(Cache-Control: Max-age=…),不要再请求服务器了。这个机制通常称之为 HTTP 强缓存

一旦资源被判强缓存规则后,再次访问资源会完全没有 HTTP 请求(Chrome 开发者工具的 Network 面板依然会显示请求,但会注明 from cache;Firefox 的 Firebug 也类似,会注明 BFCache),这能够大幅提升性能。所以我们一般会对 CSS、JS、IMG 等资源使用强缓存。

开启强缓存,需要配置如下:

location ~ ^/static/ {
    root       /home/site/static;
    etag      on;
    expires 2h;
}

HTTPS 优化

ssl_session_tickets       on;
ssl_session_ticket_key  ~/ssl_session_ticket.key;
ssl_session_cache       shared:SSL:10m;
ssl_session_timeout     10m;

ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate   ~/ocsp.cer;
resolver 208.67.222.222 valid=300s;
resolver_timeout 5s;

这部分配置包含两部分内容:TLS 会话恢复OCSP Stapling

关于 OCSP Stapling,可以参看 我的这篇文章

TLS 会话恢复的目的是简化 TLS 握手,它包含两种方案:Session CacheSession Ticket,这俩都是将之前握手的 Session 存起来,供后续连接使用。

所不同的是,Session Cache 将缓存丢在服务端,占用服务端资源;而 Session Ticket 丢在客户端,不占用服务端资源,而是对客户端提出缓存要求,这对客户端浏览器的兼容性提出了要求。目前主流浏览器普遍支持 Session Cache,而 Session Ticket 的支持度较一般。

在以上配置中,出现了一个 ssl_session_ticket.key,这个文件是用于让多台机器使用相同的 key 文件,否则 Nginx 会使用随机生成的 key 文件,无法复用 Session Ticket,降低性能。对于单服务器站点,此文件无需配置。可执行以下指令生成该文件:

openssl rand 48 > ssl_session_ticket.key

至此,本博客 Nginx 配置(系列二)之优化篇,就告一段落了。当然本文中还有些地方没有点的很细的,会在之后的完整篇中进行注释。