Nginx与七层负载均衡

时间:2021-08-26 17:50:03
上一篇博客中介绍了DNS和四层上的负载均衡,其主要思想分别是通过将域名解析到不同IP上以及将VIP上的流量分流到多个IP上来达到负载均衡的目的。既然已经通过这些手段进行了分流了,为什么还需要七层负载均衡呢?主要是出于下面的场景:在同一个域名下访问多种资源,例如CSS, JS, IMAGE等静态数据以及JSON/XML/TEXT等动态数据。这两种资源的响应方式差异很大,例如静态资源可以通过缓存进行加速,而动态数据则可以进行文本压缩传输。而在域名层次和IP层次无法很好的将这些请求区分开来,因此才需要在七层上进行分流处理(常见的做法是通过不同的业务采用不同的uri前缀来进行业务池的区分)。
我们知道四层负载均衡主要采用更改IP数据包的地址的方式来进行分流,响应结果通常由后端机器直接返回给客户端(例如LVS的DR模式)。而七层负载均衡主要应用于HTTP协议,所使用的技术和四层不一样。具体过程是客户端发送HTTP请求到七层负载均衡服务器,七层服务器则将请求发送给后端服务器,后端服务器处理完请求后将结果发送回七层服务器,然后由七层服务器将响应结果返回给客户端。在这个过程中所有的请求响应流量都要经过七层负载均衡设备,仅从这点就可以看出来七层负载均衡的效率上要比四层差(另外一点是七层比四层要多做几层协议的解析封装工作)。
虽然七层设备达不到4层设备动辄几十万每秒的QPS,但是由于不用处理后端业务逻辑,仅仅是转发请求获取响应,相对来说也可以达到比较高的并发处理速度(一般来说只要后端服务器足够多,业务处理足够快,七层设备不太容易会成为瓶颈)。在传统的同步阻塞IO模型下,七层服务器每次向后端服务器发送请求需要等待响应结果,这样CPU大部分时间都在等待IO完成,效率非常低。为了解决这个问题可以采用非阻塞的方式,七层服务器开多个工作线程,每个工作线程通过轮询的方式去检查IO事件是否完成,如果没有完成则让出CPU让其他工作线程处理。这种方式比同步阻塞的方式要好,但是只有在工作线程很多的情况下效率才比较高,而工作线程一多带来的内存开销以及线程切换的开销也非常大,阻碍了进一步提升并发处理能力。这时可以采用异步非阻塞IO模型,也就是说不再开很多个工作线程,而是由一个工作线程注册很多个IO事件,如果有IO事件准备完毕,则可以直接处理。如果没有准备完毕,则阻塞一个固定超时时间,在这个时间之内如果有多个IO事件都准备完毕了,则可以依次处理这些IO事件。从整体上来看节省了上下文切换的开销,提升了CPU的利用率,因此也提升了并发处理能力。这也是当前select/poll/epoll/kqueue这些机制的基本原理。
一般常用的七层负载均衡设备有Nginx和Varnish,两者都可以进行负载均衡处理,但是应用方式和场景略有不同。Varnish配置简单并且具有比较强大的缓存加速功能,因此通常用在静态资源请求的分流上。而Nginx主要的特点是高效,可以编写各种各样的第三方模块提供定制化的功能。例如可以在Nginx上做认证,灰度流量切换以及文本压缩等等功能。在处理过程中我们知道Nginx服务器通过upstream模块选择后端服务器转发请求,通过实现特定的后端服务器选择算法就可以做到灰度流量切换的功能。另外在获取后端服务的结果之后,还可以通过Nginx的filter模块对结果进行各种处理,包括文本压缩增加Footer等功能。从这个角度来说,Nginx比Varnish使用要灵活许多。