相比于iptables,使用Nginx作为网关主要有以下几个方面不足:

  1. 工作于TCP层,转发效率不高
  2. 任何新增/删除端口的操作,都需要重新构建nginx.conf配置文件,并执行nginx -s reload重启所有broker

TCP层转发 vs. IP层转发

如下图所示,TCP层代理在转发数据时需要维持两个连接:client->proxy的tcp连接以及proxy->server的连接,当client端有数据到来时,Nginx需要将数据从内核缓冲区中拷贝至预置的buffer中,再将buffer中的数据塞到与server端连接的内核缓冲区中。相比iptables数据转发,Nginx转发会多一次数据拷贝,并使得程序多次在内核态/用户态切换,因此整体效率相比iptables转发要低。 nginx-iptables

我做了一个简单的测试,Client端分别通过iptables的网关以及Nginx的网关向服务发送数据,发送1GB数据的耗时分别为:

  • 使用Nginx作为网关,总耗时为42522ms
  • 使用iptables作为网关,总耗时为30749ms

除数据转发耗时较长以外,由于Nginx创建了两个连接,因此随着连接的增多,承载Nginx的服务器的内存文件描述符资源也会随之增加。其中:

  • 文件描述符资源需要放开ulimit限制
  • 每10000个链接约增加200MB内存消耗

nginx -s reload 带来的问题

ngins -s reload 流程如下:

nginx-reload

虽然spice协议通信大多都是长连接,但是客户使用场景下通常会出现批量启动的情况,此时nginx -s reload命令将在短时间内多次被执行。nginx.conf文件的反复修改/读取,工作线程的创建/销毁/调度都会占用大量CPU资源,由于Nginx本身进行转发也非常依赖CPU在内存缓冲区与用户区之间进行数据拷贝,整个系统在批量启动/重启的过程中可能会导致网络通信不稳定的情况产生。

iptables采用链表的方式组织所有过滤/转发规则,如下图所示。每次添加/删除的时候仅涉及到链表上单个节点的增删,相比于Nginx的全量更改配置文件耗费的CPU资源更少、速度更快,也不会涉及到线程的启动和结束。

iptables-chain

总结

iptables同样是目前Google公司K8S集群网关kube-proxy的实现方案,它通过内核态直接转发ip报文的方式进行工作,相比于Nginx转发数据传输效率更高,延迟更低,耗费的CPU、内存等资源更少。在高并发大数据量环境下优势更加明显。iptables通过链表组织所有的配置规则,规则增/删的开销更小,更加适合于我们大量虚拟机不断启动、停止的环境。