当前位置: 首页 > 科技观察

你管这叫负载均衡吗?

时间:2023-03-14 21:47:50 科技观察

相信大家都听过这样一个经典的面试题:“请告诉我从淘宝输入关键词到最终显示网页的整个过程,越详细越好。”题目比较难,涉及到HTTP、TCP、网关、LVS等一系列相关概念以及很多协议的工作机制。如果你能掌握其中的每一个知识点,都会大大点亮你的技能树。您还将了解网络的工作原理。即使你不能完全掌握,但了解流量的流向对你排查和定位问题会有很大的帮助。我之前用这些知识定位过很多问题。为了了解整个过程,查阅了很多资料,相信这个问题应该清楚了,但是发现写的篇幅太长了,所以分两部分分别介绍。这部分先介绍一下流量在后端的整体结构图,下一篇会深入分析各种细节,比如LVS和NAT的工作细节等,其中会涉及交换机的工作机制等知识点和路由器。流量,所以他只部署了一台tomcat服务器,让客户端直接向这台服务器发送请求。一开始这个部署是没有问题的,因为业务量不是很大,单机就可以搞定,但是后来李大牛的业务踩上了风,业务发展很快,所以性能单机逐渐遇到了瓶颈,因为只部署了一台机器,这台机器的业务会降为零。这是不可能的,所以为了避免单机性能瓶颈,解决单点故障隐患,李大牛决定多部署几台机器(假设是三台),让客户端随机调用一台的机器,这样即使其中一台机器宕机,其他机器仍然存在。就让client调用其他没有down的机器。现在的问题是,客户端应该调用三台机器中的哪一台?让client选择肯定是不合适的,因为如果client选择具体的服务器,那么它肯定知道有哪些服务器,然后通过轮询等方式随机连接其中一台机器,但是如果其中一台服务器挂了,客户端无法提前感知到,那么很可能客户端连接到服务器就挂了,所以最好在服务器上选择连接哪台机器。具体怎么做,架构设计有一个经典的共识:没有什么是加一层解决不了的。如果有,再增加一层,所以我们在server端再增加一层,命名为LB(LoadBalance,负载均衡),LB统一接收cli。ent请求,然后让它决定与哪个服务器通信。一般业界普遍使用Nginx作为LB。采用这样的架构设计,终于支撑了业务的高速增长,但是不久之后李大牛就发现这个架构存在一个问题:所有的流量都可以发到服务器上,这显然是有问题的,也不是很安全。我们可以在流量到达服务器之前进行另一层身份验证吗?认证通过后,我们就可以让它命中服务器了。我们称这一层为网关(为了避免单点故障,网关也应该以集群的形式存在)。这样所有的流量都必须经过网关层才能到达服务器,流量会被转发给服务器,否则会返回错误信息给客户端。网关除了认证之外,还起到风控(防止羊毛党)、协议转换(比如HTTP转Dubbo)、流量控制等功能,最大程度保证转发。到服务器的流量安全可控。这种设计一直持续了很长时间,但是后来李大牛发现这种设计还是有问题的,不管是动态请求还是静态资源(比如js,css文件)请求。打tomcat,流量大的时候会对tomcat造成很大的压力。其实tomcat在处理静态资源方面不如Nginx。Tomcat每次都要从磁盘加载文件,影响性能,而Nginx有代理缓存等功能。大大提高静态资源的处理能力。画外音:所谓代理缓存,就是nginx从静态资源服务器获取资源后,将资源缓存在本地内存+磁盘中。如果下一次请求命中了缓存,则直接从Nginx的本地Cache中返回。于是李大牛做了如下优化:如果是动态请求,会通过网关发送给tomcat;如果是Nginx,则会发送到静态资源服务器擅长动态请求,而静态资源由于使用了Nginx的代理缓存等功能,后端处理能力上了一个新的台阶。另外需要注意的是,并不是所有的动态请求都需要经过网关。比如我们运营中心的后台是给内部员工使用的,所以它的认证和网关的API认证是不一样的,所以我们直接部署了两台运营中心的服务器,直接让Nginx把运营中心的请求发送到这两个服务器,绕过网关。当然,为了避免单点故障,Nginx也需要至少部署两台机器,所以我们的架构就变成了下面这样。Nginx部署两台机器,以主备形式存在。备Nginx会通过keepalived机制(发送心跳包)及时感知主Nginx的存活,发现宕机,就充当主Nginx的角色。看起来这个架构确实不错,但是需要注意的是Nginx是一个七层(即应用层)的负载均衡器,也就是说如果要转发流量,首先要和客户端建立TCP连接,而当转发,还必须和被转发的上游服务器建立TCP连接,而我们知道建立TCP连接其实是需要消耗内存的(TCPSocket、接收/发送缓冲区等需要占用内存),客户端和上游服务器需要先将数据发送给Nginx,再通过另一端的TCP连接发送给对方。因此,Nginx的负载能力受到机器I/O、CPU内存等一系列配置的限制,一旦连接数多了(比如达到百万),Nginx的抗负载能力就会急剧下降。经过分析可以看出,Nginx的负载能力差主要是因为七层负载均衡器必须在上下游分别建立两个TCP。那么是否可以设计一个只加载转发数据包而不建立连接的路由器呢?至于负载均衡器,由于不需要建立连接,它只负责转发数据包,不需要维护额外的TCP连接。它的负载能力必须大大提高,所以四层负载均衡器LVS诞生了。简单比较两者的区别可以看出,LVS只是简单的转发数据包,并没有与上下游建立连接。与Nginx相比,抗负载能力强,性能高(可达F5硬件的60%)。cpu资源消耗比较低,那么四层负载均衡器是如何工作的呢?当负载均衡设备收到客户端的第一个SYN请求时,通过负载均衡算法选择一个最优的服务器,并与报文中的目标服务器进行比较。修改IP地址(改成后台服务器的IP),直接转发给服务器。TCP连接的建立,即客户端和服务器之间直接建立三次握手,负载均衡设备只做类似路由器的转发动作。在一些部署情况下,为了保证服务器返回的报文能够正确返回到负载均衡设备,在转发报文的同时可能会修改报文的原始源地址。综上所述,我们在Nginx之上加了一层LVS,让它来承担我们所有的流量。当然,为了保证LVS的可用性,我们也采用主备方式部署LVS。另外,如果Nginx使用这种架构的话,容量不够的话,我们可以很方便的进行水平扩展,所以我们的架构改进如下:当然,如果只有一个LVS的话,那么大流量是无法应付的。怎么办,多加几个,用DNS负载均衡,DNS服务器解析域名的时候,随便打一个LVS就够了。通过这种方式,流量终于可以稳定流通了。有一点可能有些朋友会有疑惑。让我们来看看吧。既然可以部署LVS避免多台形式的单点故障,也可以使用Nginx,而且Nginx在1.9之后也开始支持四层负载均衡,所以好像不需要LVS了?如果不使用LVS,架构图是这样的。Nginx的方式在流量不是那么大的时候确实可行,但是LVS是Linux内核模块,工作在内核态,而Nginx是工作在用户态,比较重,所以Nginx在性能上不如Nginx的性能和稳定性。LVS,所以我们才采用LVS+Nginx的部署方式。另外,相信大家也注意到了,如果流量大的话,应该在CDN上部署静态资源,CDN会自动选择离用户最近的节点返回给用户,所以我们最后的架构改进为下面总结一下架构一定要结合业务的实际情况来设计,没有业务光谈架构其实就是耍流氓。大家可以看到,以上每一个架构的演进都与我们的业务发展息息相关。对于流量较少的中小型公司,使用Nginx作为负载均衡器就足够了。增长之后,考虑使用lvs+nginx。当然,像美团这样的大流量(几十Gbps的流量,千万并发连接数),lvs就不行了(实测虽然用了lvs,还是有很多丢包的现象)所以他们开发了自己的一套四层负载均衡器MGW。看完这篇文章,相信大家应该对分层的概念有了更透彻的认识。没有什么是分层解决不了的。如果有,那就再加一层,分层让每个模块各司其职,功能解耦,便于扩展。熟悉的TCP/IP就是一个很好的例子。每一层只负责自己的事务。至于下层的实现是什么?上层不关心。以上就是本文的全部内容。希望大家看完后有所收获^^。下一篇我们会继续深入探讨一个请求的往返链路,将深入分析LVS、交换机、路由器等,工作原理敬请期待^^本文转载自微信公众号“码海”,可通过以下二维码关注。转载本文请联系码海公众号。