点赞
评论
收藏
分享
举报
《NGINX 完全指南》章节精选 | 流量管理和可编程性
发表于2023-12-05 15:50

浏览 1.4k

原文链接:《NGINX 完全指南》章节精选 | 流量管理和可编程性
转载来源:NGINX 开源社区

NGINX 唯一中文官方社区 ,尽在 nginx.org.cn




编者按——由 O'Reilly 出版的《NGINX 完全指南》中文版(2022 年最新版)现已正式上线,现可点击此处免费下载电子版全本。

这本 180 多页易于理解的配置指南将为您讲述从如何安装 NGINX 到如何进行配置,再到如何调试和排除应用性能故障。不仅如此,本书还提供了将 NGINX 用于负载均衡、云部署、自动化、容器和微服务、服务网格、安全防护等场景的相关配置示例。

本文中,本书的中文校译熊平为大家节选了本书的第三章《流量管理》和第五章《可编程性和自动化》中的精彩段落:A/B 测试、限制速率、使用通用编程语言扩展 NGINX。

     

A/B 测试

问题

在文件或应用的两个或多个版本之间分割客户端流量,以测试接受度或参与度。

解决方案

使用 split_clients 模块将一定比例的客户端流量定向到一个不同的上游 (upstream) 池:

 

split_clients "${remote_addr}AAA" $variant {
       20.0% "backendv2";
       *     "backendv1";
}

   

split_clients 指令对作为第一个参数提供的字符串进行哈希处理,并用该哈希值除以提供的百分比,以映射作为第二个参数提供的变量的值。在第一个参数中添加“AAA”是为了证明这是一个可以包含多个变量的串联字符串,如通用哈希负载均衡算法中所述。


第三个参数是一个包含键值 (key-value) 对的对象,其中键是百分比权重,值是要分配的值。键可以是百分比或星号。星号表示取完所有百分比后的剩余部分。对于 $variant 变量的值,backendv2 为客户端 IP 地址流量的 20% ,backendv1 为其余 80%。


在此示例中,backendv1 和 backendv2 表示上游服务器池,可以与 proxy_pass 指令一起使用,如下所示:

   

location / {
       proxy_pass http://$variant
}

   

使用变量 $variant 时,我们的流量将会分配给两个不同的应用服务器池。


为了理解 split_clients 的广泛用途,我们通过一个例子来看看两个静态站点版本之间的流量分割:

       

http {
       split_clients "${remote_addr}" $site_root_folder {
              33.3% "/var/www/sitev2/";
              * "/var/www/sitev1/";
       }
       server {
              listen 80 _;
              root $site_root_folder; location / {
                     index index.html;
              }
       }
}

         

详解

在测试电子商务网站上不同类型的营销和前端功能的转化率时,这种类型的 A/B 测试非常有用。应用通常通过“灰度发布”进行部署。在这种类型的部署中,用户可以逐步增加路由到新版本的用户百分比,进而将流量慢慢切换到新版本。在推出新版本的代码时,在不同的应用版本之间分割客户端流量非常实用,这可以降低发生错误后带来的影响。


更常见的部署模式是蓝绿部署,也就说在将用户切换到新版本的同时,仍然保持旧版本在验证部署期间的可用性。无论出于何种原因在两组不同的应用之间分割客户端流量,NGINX 的 split_client 模块都可以帮您轻松搞定。

             

限制速率

问题

通过预定义的键(例如客户端的 IP 地址)来限制请求的速率。

解决方案

利用限速模块限制请求速率:

   

http {
       limit_req_zone $binary_remote_addr zone=limitbyaddr:10m rate=3r/s;
       limit_req_status 429;
       # ...
       server {
              # ...
              limit_req zone=limitbyaddr;
              # ...
       }
}

   

此示例配置创建了一个名为 limitbyaddr 的共享内存区。使用的预定义键是二进制形式的客户端 IP 地址。共享内存区的大小设置为 10 MB。该区域使用关键字参数设置速率。limit_req 指令使用了一个必不可少的关键字参数:zone。


zone 指示了要使用哪个共享内存请求限制区的指令。根据 limit_req_status 指令的定义,超过明示速率的请求将返回 429 HTTP 代码。建议设置一个 400 级范围的状态码,因为默认值是 503,这代表服务器有问题,而实际问题是出在客户端方面。


使用 limit_req 指令的可选关键字参数来启用两级速率限制:


server {
       location / {
              limit_req zone=limitbyaddr burst=12 delay=9;
       }
}

   

在某些情况下,客户端需要同时发出许多请求,此后先在一段时间内降低速率,然后再发出更多请求。您可以使用关键字参数 burst 允许客户端超过其速率限制但不拒绝其请求。超出速率的请求将延迟处理,以将速率限制匹配到配置的值。


有一组关键字参数可以改变这种行为,即 delay 和 nodelay。nodelay 参数不带值,只允许客户端一次性消耗所有流量突发值;但是必须要先等待足够的时间,直到满足速率限制要求为止,否则所有请求都会被拒绝。


在此示例中,如果我们使用 nodelay,客户端可以在第一秒消耗 12 个请求,但是必须要在初始请求之后等待 4 秒才能发出另一个请求。delay 关键字参数定义了在不限流的情况下可以预先发出多少请求。在这种情况下,客户端可以毫无延迟地预先发出 9 个请求,接下来的 3 个将受到限制,此后 4 秒内的任何请求都将被拒绝。

   

详解

限速模块非常强大,可以防止滥用快速请求,同时仍然为每个人提供优质服务。限制请求速率的原因有很多,安全性就是其中之一。您可以通过严格限制登录页面的速率来防御暴力破解攻击。您可以对所有请求设置合理的限制,从而防止恶意用户试图对您的应用拒绝服务或浪费资源的不轨行为。


限速模块的配置很像连接限制模块,并且存在许多相同的问题。您可以按照每秒限速,也可以按照每分钟限速。当达到速率限制时,日志就会记录事件。


此外,还有一条指令没有在示例中给出:limit_req_log_level,它的默认值为 error,您也可以把它设置为 info、notice 或 warn。在 NGINX Plus 中,速率限制目前具有集群感知能力。


测试限制可能是个很棘手的问题,测试方案通常很难在替代环境中模拟实时流量。在这种情况下,您可以将 limit_req_dry_run 指令设置为 on,然后使用访问日志中的变量 $limit_req_status。$limit_req_status 变量将计算为 PASSED、REJECTED 或 REJECTED_DRY_RUN。


启用 dry run 后,您将能够分析实时流量日志,并在真正实施限制前根据需要调整限制,从而确保您的限制配置正确。

             

使用通用编程语言扩展 NGINX

问题

您需要 NGINX 使用通用编程语言执行一些自定义扩展。

解决方案

在用 C 语言编写自定义 NGINX 模块之前,请先评估您的用例是否适合使用其他编程语言模块。C 编程语言是一种非常强大且高效的语言,但是也有许多其他语言模块能够支持所需的自定义。


NGINX 引入了 NGINX JavaScript (NJS),只需启用一个模块就可以将 JavaScript 的强大功能暴露到 NGINX 配置中。您也可以使用 Lua 和 Perl 模块。


使用这些语言模块时,您要么需要导入一个包含代码的文件,要么直接在配置中定义代码块。


要使用 Lua,请安装 Lua 模块和以下 NGINX 配置,以定义一个内联的 Lua 脚本:


load_module modules/ndk_http_module.so;
load_module modules/ngx_http_lua_module.so;
events {}
http {
    server {
           listen 8080;
           location / {
                  default_type text/html;
                  content_by_lua_block {
                         ngx.say("hello, world")
              }
           }
      }
}


Lua 模块通过 ngx 模块定义的对象提供自己的 NGINX API。与 NJS 中的 request 对象一样,ngx 对象也有描述请求和操作响应的属性和方法。


安装了 Perl 模块后,此示例将使用 Perl 从运行时环境设置 NGINX 变量:


load_module modules/ngx_http_perl_module.so;
events {}
    http {
      perl_set $app_endpoint 'sub { return $ENV{"APP_DNS_ENDPOINT"}; }';
      server {
             listen 8080;
             location / {
                    proxy_pass http://$app_endpoint
             }
         }
     }
}

 

上述示例表明,这些语言模块不仅仅是返回响应,而且还会暴露更多功能。perl_set 指令将一个 NGINX 变量设置为从 Perl 脚本返回的数据。这个示例比较有限,只是返回了用作请求代理端点的系统环境变量。

           

详解

NGINX 具备出色的可扩展性,这为启用更多功能开创了更多可能。NGINX 可通过使用 C 语言模块自定义代码来扩展,您可以从一开始构建时就把这些模块编译到 NGINX 中,也可以在配置中动态加载。


目前还有一些模块可以暴露 JavaScript (njs)、Lua 和 Perl 的功能与语法。在多数情况下这些预先存在的模块是够用的 —— 除非将 NGINX 的自定义功能分配出去。现在开源社区中有很多为这些模块构建的脚本。


该解决方案演示了 NGINX 和 NGINX Plus 中可用的 Lua 和 Perl 脚本语言的基本用法。无论是寻求响应、设置变量、发送子请求还是定义复杂的重写,这些 NGINX 模块都能提供相应的支持。

 

立即下载

   

《NGINX 完全指南》

英文纸质版原价为 $49.99 美元(含税价约为 350 元人民币),现可点击此处前往 NGINX 中文官网免费下载电子版全本。  

点击此处立即下载>>

   

《API 策略:面向平台工程团队的最佳实践》

您也可以免费下载全新中文电子书,了解如何扩展 NGINX 以管理 API 流量,并学习如何保护 API 网关。

点击此处立即下载>>

   


 

NGINX 唯一中文官方社区 ,尽在 nginx.org.cn

更多 NGINX 相关的技术干货、互动问答、系列课程、活动资源: 开源社区官网 | 微信公众号

已修改于2023-12-05 15:50
本作品系原创
创作不易,留下一份鼓励
NGINX官方账号

暂无个人介绍

关注



写下您的评论
发表评论
全部评论(0)

按点赞数排序

按时间排序

关于作者
NGINX官方账号
这家伙很懒还未留下介绍~
218
文章
21
问答
197
粉丝
相关文章