Nginx 与 IO 多路复用面试笔记

Nginx 与 IO 多路复用面试笔记

参考:Nginx 与 F5 对比、select/poll/epoll、Linux 五种 IO 模型、TCP 半连接和全连接队列、Nginx 性能为何这么强悍

1 Nginx 与 F5(硬件负载均衡器)对比

Nginx

  1. 工作在网络的 7 层(应用层)之上,可针对 http 应用做分流策略,比如针对域名、目录结构;
  2. 对网络的依赖比较小;
  3. 安装和配置比较简单,测试起来比较方便;
  4. 可承担高的负载压力且稳定,一般能支撑超过 1 万次的并发;
  5. 可以通过端口检测到服务器内部故障(根据返回的状态码、超时等),并把返回错误的请求重新提交到另一个节点;
  6. 对请求的异步处理可帮助节点服务器减轻负载;
  7. 支持 http 和 Email。

F5(硬件 LB)

基础功能:状态监控、SSL 加速、智能 HTTP 压缩、Cookie 加密、攻击过滤、拒绝服务(DoS)攻击和 SYN Flood 保护、防火墙过滤。

先进功能:应用交换、会话交换、智能网络地址转换、通用持续性、响应错误处理、IPv6 网关、高级路由、智能端口镜像、TCP 优化、第 7 层速率整形、内容缓冲、内容转换、连接加速、高速缓存、选择性内容加密。

F5 优势:硬件设备处理速度快、安全性高(防御 DDoS/SYN Flood)、内置 SSL 加速和负载率高;缺点:价格昂贵、运维成本高。Nginx 是软件方案,成本低、灵活,适合互联网中小型应用。

负载均衡算法

  • hash(ip_hash / consistent):按 ip 或一致性 hash 分发;
  • rr(weighted rr):加权轮询,按权重依次分发;
  • least_conn:分发到当前连接数最少的节点。

2 IO 多路复用

IO 多路复用是指内核一旦发现进程指定的一个或多个 IO 条件准备就绪(可读、可写、异常),就通知该进程。通过一种机制让一个进程同时监视多个描述符(fd),某个描述符就绪时通知程序进行读写。相比多进程/多线程的优势是系统开销小,不必创建和维护进程/线程。

适用场合:

  1. 客户端处理多个描述符(交互式输入 + 网络套接口);
  2. TCP 服务器既要处理监听套接口又要处理已连接套接口;
  3. 服务器既要处理 TCP 又要处理 UDP;
  4. 服务器处理多个服务或多个协议。

注意:select、pselect、poll、epoll 本质上都是同步 IO——它们都只负责”监视就绪”,实际读写过程仍由进程自己阻塞完成;异步 IO 才由内核把数据拷贝到用户空间。

select

监视 writefds、readfds、exceptfds 三类文件描述符,阻塞直到有描述符就绪或超时。本质是通过设置/检查存放 fd 标志位的数据结构来处理。

  • 优点:跨平台,几乎所有平台都支持。
  • 缺点:
    1. 单个进程监视的 fd 数量有最大限制(FD_SETSIZE,Linux 一般 1024,64 位机默认 2048);
    2. 对 socket 是线性轮询,每次返回都遍历全部 n 个 socket,浪费 CPU;
    3. 每次调用返回后没有就绪的位会被归零,下次必须重新设置位。

poll

本质上与 select 没有区别,把用户传入的 pollfd 数组拷贝到内核空间,逐个查询设备状态:

struct pollfd { int fd; // 套接字描述符 short events; // 关心的事件:读、写、异常 short revents; // 内核通过 revents 告诉进程发生的事件 };
  • 优点:没有最大连接数限制(基于变长数组存储);
  • 缺点:
    1. 大量 fd 数组在用户态和内核态之间整体复制,不管有没有意义;
    2. 用户空间和内核空间传递该结构时复制开销大;
    3. 个别描述符就绪也要遍历整体集合,性能随 socket 集合增大线性下降,不适合大并发场景;
    4. 水平触发:报告了 fd 后若未处理,下次 poll 还会再报告。

epoll(Linux 2.6 内核提出)

相对 select/poll 更灵活、无描述符限制。使用一个文件描述符管理多个描述符,将关心的 fd 事件存放到内核的事件表中,用户空间和内核空间的 copy 只需一次。内核 2.6.8 之后用红黑树组织监控的 fds 集合(之前用 hash)。

  • 原理:使用”事件”就绪通知方式,通过 epoll_ctl 注册 fd,一旦 fd 就绪,内核用类似 callback 回调机制激活该 fd,epoll_wait 收到通知;
  • 优点:
    1. 没有最大并发连接限制,1G 内存能监听约 10 万个端口;
    2. 效率不随 FD 数目增加下降,只对活跃可用的 FD 调用 callback,只关心”就绪”的连接;
    3. 利用 mmap() 文件映射内存加速内核空间消息传递、减少复制开销。

触发模式

  • LT(level triggered,默认):epoll_wait 检测到事件并通知,应用可以不立即处理,下次 epoll_wait 还会再通知;同时支持 block 和 no-block socket;
  • ET(edge triggered):检测到事件通知后应用必须立即处理,否则不再通知;只支持 no-block socket,当描述符从”未就绪”变为”就绪”时内核只通知一次,直到再次变为未就绪。ET 大量减少事件重复触发次数,效率高于 LT。

如果没有大量 idle-connection,epoll 效率并不比 select/poll 高多少;遇到大量 idle-connection 时 epoll 效率远高于 select/poll。

3 mmap

把用户空间和内核空间的一块地址同时映射到同一块物理内存(用户空间和内核空间使用虚拟地址,最终经地址映射到物理地址),使该物理内存对内核和用户均可见,减少用户态和内核态之间的数据交换。

4 backlog 参数(全连接队列)

参数 backlog 限制了用于存放挂起状态连接的队列(全连接队列)最大长度,即已连接(三次握手完成)但尚未被 accept 处理的 SOCKET 队列。默认值 -1(FreeBSD/DragonFly/macOS),其他平台默认 511。

  • 当一个连接请求到达且队列已满,客户端会收到连接拒绝(”Connection refused”);
  • 半连接(未完成握手)队列长度由 /proc/sys/net/ipv4/tcp_max_syn_backlog 设置;启用 syncookies 时无逻辑上限。

5 常见面试组合

  • select、poll、epoll 的底层原理(见上文);
  • TCP 三次握手、四次挥手(见《TCP/IP 网络协议面试笔记》);
  • 为什么要引入 TIME_WAIT 和 CLOSE_WAIT。

6 参考资料

阅读 — · 全站 —
🎸 我的歌单 0 首