详解雷池WAF支撑超大流量的秘密(1):雷池对 Nginx 的使用

Web 应用防火墙(Web Application Firewall,简称WAF)是针对 HTTP/HTTPS 流量进行安全防护的一种产品,简单来说,它可以对 HTTP/HTTPS 流量进行恶意特征识别、阻断攻击流量,并将过滤后的安全流量放行给上游业务服务器。WAF 通常支持多种部署模式,而在这些部署模式中,反向代理模式一直是一种比较受欢迎的模式,其部署方式如下:
详解雷池WAF支撑超大流量的秘密(1):雷池对 Nginx 的使用_第1张图片
可以看到,在反向代理模式下,WAF 接收来自 Internet 上的 HTTP 请求,在完成流量检测之后再将请求转发给上游的业务服务器。此时 WAF 对外的表现就是一个 Web 服务器,客户端不感知后端真实业务服务器的存在。由于所有 HTTP 流量都首先到达 WAF 进行处理,这就对 WAF 的 HTTP 流量处理性能有非常高的要求。

雷池的反向代理模式、透明代理模式都是通过 Nginx 来实现 HTTP 流量的代理转发。本文将对 Nginx 以及雷池对 Nginx 的使用进行简单介绍。

1. Nginx 是什么

在 Nginx 官网 上是这样介绍 Nginx 的:

nginx [engine x] is an HTTP and reverse proxy server, a mail proxy server, and a generic TCP/UDP proxy server.

可以看出,Nginx 提供了 HTTP 服务器/HTTP 反向代理、邮件代理、通用的 TCP/UDP 代理等功能。Nginx 最开始是由 Igor Sysoev 开发,目前已经被 F5 收购并推出了 Nginx 商业版本。虽然有了 Nginx 商业版本,但其开源版本仍保持活跃状态。根据 Netcraft 公司的最新报告,Nginx 在 Web 服务器领域仍然占据最大份额:
详解雷池WAF支撑超大流量的秘密(1):雷池对 Nginx 的使用_第2张图片
Nginx 作为一款优秀的、高性能的 Web 服务器,其在代码架构上有许多优秀的设计,接下来对这些设计进行简单介绍。

2. Nginx 高性能的秘密

2.1 master/worker 进程分离

Nginx 采用多进程模型,具体为 「单 master + 多 worker」 。master 进程和 worker 进程的具体分工如下:

  • master 进程不需要处理网络事件,也不负责具体业务的执行。只能通过管理 worker 等子进程实现重启服务、平滑升级、更换日志文件、配置文件实时生效等功能。master 进程通过信号来实现对 worker 进程的控制
  • worker 进程才真正地处理业务请求,每个 worker 进程都是单线程的进程,可以自定义 worker 进程的个数。生产环境下一般会配置和 CPU 核数相等的 worker 进程个数,并且配置 CPU 绑核,从而最大限度地利用多核 CPU,并减少进程间切换开销

在网络领域,通常会有 「控制面」「数据面」 的概念。从上面对 Nginx 进程模型的介绍可以看出,master 进程相当于 Nginx 的 「控制面」,不处理具体的业务请求,只专注于对 worker 的管理。当 worker 进程异常退出时,master 进程会立即创建新的 worker 进程,从而尽量减少对业务的影响。

而 worker 进程则相当于 Nginx 的 「数据面」 ,负责处理真实的业务请求。每个 worker 进程只有一个主线程,这样就避免了进程内多线程同步的开销。同时,一个 HTTP 请求在其生命周期内只会被一个 worker 进程处理,这样也避免了不同 worker 进程之间通信、数据同步的开销。

可以看到,Nginx 的 「master/worker」 进程模型是其高可靠、高性能的基石。

2.2 事件驱动架构

一款高性能的网络服务器,通常要处理网络、磁盘、定时器等事件,而这些事件中,最重要的就是网络 I/O 事件。在传统的网络编程领域,一些服务器会采用 「每连接一线程」「每连接一进程」 网络 I/O 模型,在这些模型中,进程或线程是网络事件的消费者。而 Nginx 采用完全的事件驱动架构来处理业务,具体来说,具有以下特点:

  • Nginx 的事件驱动框架负责网络、定时器等事件的收集、分发
  • 具体的业务模块作为事件消费者,需要提前注册自己感兴趣的事件
  • 当某类事件发生(例如最典型的是网络连接上的可读/可写事件)时,事件驱动框架会调用对应的事件消费者,此时业务模块才有机会得到执行
  • Nginx 的事件驱动框架会根据不同的操作系统选择最优的多路复用接口,例如在 Linux 中,默认使用 epoll

Nginx 的事件驱动架构使得网络性能/吞吐量得到大幅提升,但这也对业务模块提出很高的要求,因为在它们的执行过程中,不能有阻塞行为,否则会导致导致其他事件得不到及时响应,最终降低整个 worker 进程的吞吐量。

2.3 优秀的模块化设计

在 Nginx 中,几乎一切都是模块。Nginx 为 「模块」 定义了高度抽象的接口,即所有模块都遵循 「ngx_module_t」 接口设计规范。同时,所有模块又是分层次、分类别的。如下对 Nginx 的模块设计进行简单介绍:

  • Nginx 框架直接定义了 「核心模块」 和 「配置模块」「配置模块」 实现了 Nginx 最基本的配置项解析功能,而 「核心模块」 则是 Nginx 框架的基础,Nginx 框架代码只与 「核心模块」 打交道,其他模块不会直接与 Nginx 框架交互
  • 「ngx_http_module」 模块就是 Nginx 实现 HTTP 相关功能的 「核心模块」 。它定义了一类新的模块类型,即 HTTP 模块类型。所有 「HTTP 模块」 都要遵循 「ngx_http_module_t」 接口规范
  • 而在所有 「HTTP 模块」 中,「ngx_http_core_module」 又是一个比较特殊的模块,负责实现 HTTP 功能中最基础的逻辑

Nginx 优秀的模块化设计保证了即使 Nginx 功能如此复杂,仍然能够保持清晰的代码结构,同时也允许开发者根据模块接口开发自己的 Nginx 模块,从而对 Nginx 进行扩展。

2.4 其他优秀设计

作为高性能服务器的典范,Nginx 还有非常多的优秀设计,这里简单列举一些:

  • Nginx 采用 C 语言开发,由于 C 标准库没有提供通用的数据结构,Nginx 自己实现了双端队列、红黑树、哈希表等数据结构
  • Nginx 实现了内存池,实现对内存资源的高效管理,同时降低了开发者管理内存的心智负担
  • Nginx 提供了 「ngx_buf_t」 数据结构,用于对缓冲区进行高效操作
  • Nginx 提供了多种 balancer 算法来在一组上游业务服务器之间分发请求,例如轮询算法、哈希算法等等
    ……

3. 雷池 t1k 模块

由于 Nginx 本身就是一款优秀的反向代理服务器,因此雷池使用 Nginx 作为 WAF 的流量转发引擎,实现 HTTP 流量的反向代理功能。但是 WAF 不仅仅需要对流量进行转发,其核心功能还是对流量进行检测。雷池在 Nginx 中自研了一个 HTTP 模块:t1k 模块,用于在 Nginx 中将接收到的流量发送给雷池的检测引擎,并根据检测引擎的返回结果来决定是直接返回 403 拦截,还是继续转发请求。
详解雷池WAF支撑超大流量的秘密(1):雷池对 Nginx 的使用_第3张图片

得益于 Nginx 的可定制化开发能力,在 Nginx 中实现上述功能并不复杂。雷池 t1k 的主要工作原理如下:

  • 在 Nginx HTTP 请求处理流程的 access 阶段,实现请求检测功能。它会产生一个 subrequest,该 subrequest 会重定向到一个特殊的、内部 location,通常命名为 「@safeline」
  • 该特殊 location 的 handler 在处理子请求时,会使用 Nginx 的 upstream 机制来和雷池检测引擎建立连接,并将待检测的内容发送给检测引擎
  • 解析检测引擎返回的检测结果,子请求处理结束
  • 原始请求恢复执行流程,t1k 根据检测结果来决定是返回 403 拦截页面,还是将该请求放行到下一阶段处理
  • 响应检测则是借助 Nginx 的 HTTP body 过滤机制来实现

而正是得益于 Nginx 的高度可定制能力、动态模块加载能力,t1k 模块也可以嵌入到已有的 Nginx/OpenResty 服务器(包括以 OpenResty 为底座的 Kong、APISIX 等 API 网关产品中)中运行,这也是我们的 「嵌入式部署模式」

彩蛋:关于 t1k 这个名字,经过多方打听,终于从大佬处得知,原来它是 「终结者」
详解雷池WAF支撑超大流量的秘密(1):雷池对 Nginx 的使用_第4张图片

你可能感兴趣的:(nginx,运维)