周报@2023-04-18

TypeScript 如何拓展第三方类型声明,nginx 负载均衡,nginx upstream keepalive 设置

TypeScript 如何拓展第三方类型声明

全面拥抱 ESM 的时代,@jest/global 的 expect 方法,如何拓展 @testing-library/jest-dom/matchers?
可以随便声明一个 d.ts 文件,内容如下:

ts
1import type { Matchers as _M } from 'expect';
2import type { expect } from '@jest/globals';
3import type { TestingLibraryMatchers } from '@testing-library/jest-dom/matchers';
4
5declare module 'expect' {
6  interface Matchers<R extends void | Promise<void>, T = unknown>
7    extends _M<R, T>,
8      TestingLibraryMatchers<typeof expect.stringContaining, R> {}
9}

Nginx 负载均衡

  1. Round Robin(轮询调度):这是 Nginx 默认的负载均衡方法。在此方法中,Nginx 按顺序将请求分发到后端服务器,确保每个服务器都得到相等的请求。要使用轮询调度,只需省略 upstream 块中的负载均衡指令即可。
nginx
1http {
2    upstream backend {
3        server backend1.example.com;
4        server backend2.example.com;
5    }
6
7    server {
8        location / {
9            proxy_pass http://backend;
10        }
11    }
12}
  1. Weighted Round Robin(加权轮询调度):与轮询调度类似,但可以为每个后端服务器分配一个权重。权重较高的服务器将接收更多的请求,使您可以根据服务器性能和容量调整负载分配。要使用加权轮询调度,请在 upstream 块中为每个服务器指定 weight 参数。
nginx
1http {
2    upstream backend {
3        server backend1.example.com weight=3;
4        server backend2.example.com weight=2;
5    }
6
7    server {
8        location / {
9            proxy_pass http://backend;
10        }
11    }
12}
  1. Least Connections(最小连接数):此方法将请求发送到当前活动连接数最少的服务器。这种方法有助于确保即使某些服务器处理速度较慢,负载仍能平衡地分配给所有服务器。要使用最小连接数负载均衡,请在 upstream 块中添加 least_conn 指令。
nginx
1http {
2    upstream backend {
3        least_conn;
4        server backend1.example.com;
5        server backend2.example.com;
6    }
7
8    server {
9        location / {
10            proxy_pass http://backend;
11        }
12    }
13}
  1. IP Hash(基于 IP 的哈希负载均衡):在此方法中,Nginx 根据客户端 IP 地址计算哈希值,并将请求分发给相应的后端服务器。这种方法有助于确保来自同一客户端的请求始终路由到相同的后端服务器,从而实现会话持久性(session persistence)。要使用 IP 哈希负载均衡,请在 upstream 块中添加 ip_hash 指令。
nginx
1http {
2    upstream backend {
3        ip_hash;
4        server backend1.example.com;
5        server backend2.example.com;
6    }
7
8    server {
9        location / {
10            proxy_pass http://backend;
11        }
12    }
13}
  1. Generic Hash(通用哈希负载均衡):这是一种基于任意键的哈希负载均衡方法。您可以根据诸如 URL、请求头或其他数据进行哈希。要使用通用哈希负载均衡,请在 upstream 块中添加 hash 指令,并指定用于计算哈希值的键。
nginx
1http {
2    upstream backend {
3        hash $request_uri consistent;
4        server backend1.example.com;
5        server backend2.example.com;
6    }
7
8    server {
9        location / {
10            proxy_pass http://backend;
11        }
12    }
13}

nginx upstream keepalive

upstream 模块中的 keepalive 指令用于控制 Nginx 与后端服务器之间的长连接。长连接允许 Nginx 在多个请求之间重用与后端服务器的连接,而不是为每个请求创建新连接。这有助于减少连接建立和关闭的开销,从而提高性能和响应时间。

keepalive 指令需要一个参数,即允许保持活跃的最大连接数。当这个限制被达到时,Nginx 将开始关闭最旧的连接。这个值可以根据您的服务器性能和负载进行调整。

以下是一个使用 keepalive 的示例配置:

nginx
1http {
2    upstream backend {
3        server backend1.example.com;
4        server backend2.example.com;
5        keepalive 32;
6    }
7
8    server {
9        location / {
10            proxy_pass http://backend;
11            proxy_http_version 1.1;
12            proxy_set_header Connection "";
13        }
14    }
15}

注意,在这个示例中,我们还设置了 proxy_http_version 为 1.1,并清除了 Connection 请求头。这两个设置都是为了确保 Nginx 使用 HTTP/1.1 连接到后端服务器,因为长连接需要 HTTP/1.1 或更高版本。

keepalive 大小选择

keepalive 值的选择取决于多个因素,包括服务器性能、网络状况、应用程序需求和负载。没有一个固定的值适用于所有情况,但以下是一些建议,可以帮助您选择一个合适的值:

  1. 服务器性能:确保您的服务器具有足够的资源来处理保持活跃的连接。较高的 keepalive 值可能会导致更多的空闲连接,从而占用内存和文件描述符。根据您的服务器性能,可以选择一个合适的值。
  2. 网络状况:如果您的网络状况较好且延迟较低,那么较低的 keepalive 值可能就足够了。但是,如果您的网络状况较差,那么较高的 keepalive 值可能有助于减少连接建立和关闭的开销。
  3. 应用程序需求:不同的应用程序可能对长连接的需求不同。高并发且短时的请求可能会受益于较高的 keepalive 值,而较低的并发和长时间的请求可能不需要那么高的值。

一般来说,可以从一个较低的值(如 8 或 16)开始,然后根据应用程序和服务器的表现逐步调整。您可以通过监控服务器性能指标(如内存使用、文件描述符使用和响应时间)来评估 keepalive 值的影响,并根据需要进行调整。

proxy_http_version 1.1; 的必要性

在 Nginx 中,proxy_http_version 指令的默认值为 1.0。这意味着默认情况下,Nginx 会使用 HTTP/1.0 协议与后端服务器通信。

如果您希望 Nginx 与后端服务器使用 HTTP/1.1 协议(例如,在使用 keepalive 时),需要显式设置 proxy_http_version

nginx
1proxy_http_version 1.1;

proxy_http_version 设置为 1.1 会启用一些 HTTP/1.1 的特性,如长连接和分块传输编码等。这可以提高与后端服务器通信的性能。

proxy_set_header Connection ""; 的必要性

proxy_set_header Connection ""; 这行配置在 Nginx 的负载均衡配置中用于清除 Connection 请求头。这是在使用 keepalive 与后端服务器保持长连接时的一个重要设置。

默认情况下,当 Nginx 作为反向代理服务器时,它会将客户端发来的请求头传递给后端服务器。如果客户端发来的请求中包含 Connection 请求头,那么它也会被传递到后端服务器。然而,在使用 keepalive 时,我们希望 Nginx 与后端服务器之间的连接保持活跃,并且遵循 HTTP/1.1 协议的长连接规范。

通过设置 proxy_set_header Connection "";,我们实际上是在告诉 Nginx 清除或忽略客户端请求中的 Connection 请求头,从而使 Nginx 与后端服务器之间的连接遵循 HTTP/1.1 长连接规范。这有助于确保 Nginx 与后端服务器之间的连接保持活跃,提高性能。

因此,当使用 keepalive 时,建议在 Nginx 配置中添加 proxy_set_header Connection ""; 以确保正确地使用长连接。

Nginx 相关属性解读

worker_processes auto;

调整 worker 进程数:将 Nginx 的 worker 进程数设置为与服务器 CPU 核心数相同,这样可以最大限度地利用多核 CPU。在 nginx.conf 文件中,设置 worker_processes 参数。

nginx
1worker_processes auto;

这里设置为 auto,Nginx 会自动检测并使用服务器上的 CPU 核心数。

sendfile on;

启用 sendfile:sendfile 功能可让 Nginx 在发送静态文件时直接从磁盘到网络,避免不必要的内存复制操作。在 nginx.conf 文件中启用 sendfile:

keepalive_timeout 65;

配置 keepalive:启用 HTTP keepalive 功能可减少 TCP 握手次数,从而降低 CPU 负载。在 nginx.conf 文件中配置 keepalive_timeout 参数:

gzip

开启 gzip 压缩:启用 gzip 压缩可以减少传输的数据量,从而降低网络带宽和 CPU 负载。在 nginx.conf 文件中启用并配置 gzip 相关参数:

gzip on; gzip_comp_level 2; gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
  • gzip_disable "msie6";:禁用针对 Internet Explorer 6 的 gzip 压缩,因为这个较旧的浏览器可能会出现兼容性问题。

  • gzip_vary on;:设置 Vary: Accept-Encoding 响应头,以便告诉代理服务器和 CDN 正确处理压缩内容。

  • gzip_proxied any;:对所有经过代理服务器的请求启用 gzip 压缩。

  • gzip_comp_level 6;:设置 gzip 压缩级别为 6。这是一个折中的选择,可以在压缩效果和 CPU 资源消耗之间取得较好的平衡。

  • gzip_buffers 16 8k;:设置用于处理 gzip 压缩的缓冲区数量和大小。这里设置为 16 个 8KB 的缓冲区。

  • gzip_http_version 1.1;:设置支持 gzip 压缩的最低 HTTP 版本为 1.1。

  • gzip_min_length 256;:设置最小文件大小为 256 字节,只有大于这个大小的文件才会被压缩。这可以避免对过小的文件进行压缩,从而节省 CPU 资源。

  • gzip_types ...;:设置需要进行 gzip 压缩的 MIME 类型。这里包括了常见的文本、脚本、字体和图像文件类型。

ssl

优化 SSL/TLS:如果你的网站使用了 SSL/TLS,可以优化相关设置以降低 CPU 负载。在 nginx.conf 文件中设置 SSL 会话缓存:

ssl_session_cache shared:SSL:10m; ssl_session_timeout 10m;
  1. ssl_session_cache 参数用于设置 SSL/TLS 会话缓存。在给定的示例中,参数被设置为:
nginxCopy code ssl_session_cache shared:SSL:10m;

这里,shared:SSL:10m 表示使用一个名为 SSL 的共享内存区域,大小为 10MB,来存储 SSL/TLS 会话。共享内存区域可以跨多个工作进程使用,这有助于提高 SSL/TLS 会话重用的效率。

  1. ssl_session_timeout 参数用于设置 SSL/TLS 会话在缓存中的超时时间。在给定的示例中,参数被设置为:
nginxCopy code ssl_session_timeout 10m;

这意味着 SSL/TLS 会话在缓存中的最长存活时间为 10 分钟。在这个时间内,客户端可以重用之前的 SSL/TLS 会话,从而避免重新进行握手过程,减少了连接建立的延迟和服务器资源消耗。

proxy cache

  1. httpserver 配置块中,设置代理缓存路径和缓存大小。使用 proxy_cache_path 指令来定义缓存存储的路径,以及指定缓存的最大大小、内存使用等相关参数。例如:
nginx
1http {
2    ...
3    proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=my_cache:10m max_size=1g inactive=60m use_temp_path=off;
4    ...
5}

这里,/var/cache/nginx 是缓存文件存储的路径,levels=1:2 设置了目录层级结构,keys_zone=my_cache:10m 定义了一个名为 my_cache 的共享内存区域,用于存储缓存键和相关元数据,大小为 10MB。max_size=1g 设置了缓存的最大磁盘空间,inactive=60m 表示超过 60 分钟未访问的缓存内容将被清理,use_temp_path=off 禁用了使用临时路径存储缓存。

  1. 在需要使用代理缓存的 location 配置块中,使用 proxy_cache 指令启用代理缓存,并指定在第 1 步中定义的缓存名称。例如:
nginx
1location / {
2    proxy_pass http://your-backend-server;
3    proxy_cache my_cache;
4    proxy_cache_valid 200 302 60m;
5    proxy_cache_valid 404 1m;
6    proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
7    proxy_cache_lock on;
8    add_header X-Proxy-Cache $upstream_cache_status;
9}

在这个示例中,proxy_cache my_cache; 启用了名为 my_cache 的代理缓存。proxy_cache_valid 指令定义了不同 HTTP 状态码的缓存有效期,例如 200 和 302 状态码的响应将被缓存 60 分钟,而 404 响应将被缓存 1 分钟。proxy_cache_use_stale 指令配置了在后端服务器出现错误或超时的情况下,使用过期缓存来响应请求。proxy_cache_lock 防止“缓存雪崩”现象,即同一时间多个请求尝试更新同一个缓存项。add_header X-Proxy-Cache $upstream_cache_status; 添加一个自定义响应头,用于显示缓存状态(HIT、MISS 或者 BYPASS 等)。

后端数据过期

当使用 Nginx 的 proxy_cache 进行反向代理缓存时,可能会遇到缓存数据过期但未更新的问题。为了解决这个问题,可以采取以下措施:

  1. 设置缓存时间:使用 proxy_cache_valid 参数来设置不同 HTTP 响应状态码的缓存时间。例如,将成功响应(200、301、302 等)的缓存时间设置为 1 小时:

    nginx
    1proxy_cache_valid 200 301 302 1h;

    这将使 Nginx 在缓存数据过期后向后端请求新的数据。

  2. 使用 Cache-Control 头:确保后端服务器在响应中发送正确的 Cache-Control 头,以便 Nginx 遵循后端服务器的缓存策略。例如,如果后端服务器发送了 Cache-Control: max-age=3600,则 Nginx 将缓存该响应 1 小时。

  3. 清除或绕过缓存:在更新后端数据后,可以使用 proxy_cache_purge 参数(需要安装 Nginx Plus 或使用开源的 ngx_cache_purge 模块)手动清除特定 URL 的缓存。另外,也可以根据需要在请求中添加特定的 HTTP 头(例如,Cache-Control: no-cache),以便 Nginx 跳过缓存并向后端请求新数据。

  4. 使用缓存键:使用 proxy_cache_key 参数自定义缓存键,以便更细粒度地控制缓存。例如,可以根据请求的 URL 和查询参数创建缓存键:

    nginx
    1proxy_cache_key "$scheme$request_method$host$request_uri$args";

    这将使具有不同查询参数的请求被视为不同的缓存项。

通过调整这些配置参数,您可以更好地控制 Nginx 的缓存行为,确保后端数据更新时缓存内容得到刷新。在应用任何配置更改之前,请确保进行充分的测试,以找到最适合实际需求的设置。

proxy_cache_lock

proxy_cache_lock 是一个 Nginx 配置参数,用于控制在更新缓存时如何处理并发请求。当启用 proxy_cache_lock 时,如果多个请求尝试获取相同的资源(即相同的缓存键),Nginx 会将其中一个请求发送到后端服务器获取新数据,而其他请求将等待直至第一个请求完成并将数据写入缓存。

以下是一个示例配置,启用 proxy_cache_lock

nginx
1location / {
2    proxy_pass http://backend;
3    proxy_cache my_cache;
4    proxy_cache_lock on;
5    proxy_cache_lock_timeout 5s;
6}

在这个配置中,proxy_cache_lock 被设置为 on,表示启用此功能。同时,还设置了 proxy_cache_lock_timeout 参数,表示在请求等待缓存更新时的最大等待时间。在此示例中,最大等待时间为 5 秒。如果在 5 秒内缓存未更新,等待的请求将继续发送到后端服务器。

启用 proxy_cache_lock 的主要优势是减轻了对后端服务器的负担,尤其是在处理耗时较长的请求时。这可以避免多个并发请求同时触发后端服务器的资源更新,从而导致不必要的资源消耗。

请注意,在应用任何配置更改之前,请确保进行充分的测试,以找到最适合实际需求的设置。

proxy_cache 是内存缓存?

proxy_cache 不是纯粹的内存缓存。在 Nginx 中,proxy_cache 是一个配置指令,用于设置 HTTP 反向代理的缓存行为。当启用 proxy_cache 时,Nginx 会将代理请求的响应内容缓存在磁盘上。然后,当收到相同请求时,Nginx 会直接从缓存中提供响应,而不是再次向后端服务器发送请求。这有助于提高性能并减轻后端服务器的负担。

尽管缓存主要存储在磁盘上,但 Nginx 会利用操作系统的文件缓存机制,将磁盘上的缓存内容缓存在内存中。这意味着,对于频繁访问的内容,操作系统可能会将其缓存在内存中以提高访问速度。然而,这取决于操作系统的缓存策略和可用内存。

如果您想要实现纯内存缓存,可以考虑使用 proxy_cache_path 配置指令将缓存目录设置为一个内存文件系统(如 tmpfs)。这将使 Nginx 将缓存内容直接存储在内存中。但是,请注意,这种方法可能会占用大量内存,因此在使用前请确保有足够的内存资源。

worker_connections

events 配置块是 Nginx 配置文件中的一个重要部分,用于设置与连接处理相关的参数。在给定的配置示例中:

nginx
1events {
2    worker_connections 768;
3}

worker_connections 参数设置了每个 Nginx 工作进程(worker process)允许的最大并发连接数。这里,值被设置为 768,意味着每个工作进程最多可以处理 768 个并发连接。

需要注意的是,Nginx 的总并发连接数受到工作进程数量(worker_processes 参数)和每个工作进程的最大连接数(worker_connections 参数)的限制。例如,如果有 4 个工作进程,每个工作进程的最大连接数为 768,则 Nginx 服务器的总并发连接数为 4 * 768 = 3072。

在调整 worker_connections 参数时,请确保操作系统的文件描述符限制足够高,以支持所需的并发连接数。这通常可以通过操作系统的 ulimit 命令或相关配置文件进行设置。在应用任何配置更改之前,请确保进行充分的测试,以找到最适合实际需求的设置。

在 Nginx 中,worker_connections 参数的默认值通常为 512。这意味着,在默认配置下,每个 Nginx 工作进程(worker process)可以处理最多 512 个并发连接。

然而,这个默认值可能不适用于所有场景,特别是在高并发环境下。因此,在设置 Nginx 时,需要根据实际需求、服务器资源和操作系统限制来调整 worker_connections 参数。在调整参数之前,请确保进行充分的测试,以找到最适合实际需求的设置。