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

基于Nginx的软件负载均衡解读

时间:2023-03-16 15:28:50 科技观察

负载均衡是服务端开发中的一个重要特性。因为Nginx不仅仅是作为一个常规的web服务器,它还会被大规模的用作反向代理前端,因为Nginx的异步框架可以处理大的并发请求,并且在hold住这些并发请求之后,可以分发到后台服务器(backendservers,也叫服务池,以下简称backend)做复杂的计算、处理和响应。增加时,后台服务器可以轻松扩展。负载均衡可以分为硬件负载均衡和软件负载均衡。前者一般是专用软件和硬件的组合。设备商会提供完整成熟的解决方案,但通常价格较高。软件的复杂平衡以Nginx为主,本文根据其手册进行相应的学习和研究。一、基本介绍负载均衡涉及以下基本知识。(1)负载均衡算法a.RoundRobin:是最简单的向所有后端轮训发送请求的方式,也是默认的分发方式;b.LeastConnections(least_conn):跟踪后端当前活跃连接数,连接数最少表示后端负载最轻,请求会分配给他。此方法将考虑分配给配置中每个上游的权重信息;C。LeastTime(least_time):请求将被分配到响应最快且活跃连接数最少的后端;d.IPHash(ip_hash):为请求源的IP地址计算哈希值,IPv4会考虑前3个八位字节,IPv6会考虑所有地址位,然后根据得到的哈希值通过一定的映射分配给后端;e.GenericHash(hash):计算用户自定义资源(如URL)形式的哈希值,完成分发。可选的consistent关键字支持一致性哈希特性;(2)会话一致性 用户(浏览器)在与服务器进行交互时,通常会在本地保存一些信息,整个过程称为一个会话(Session),由唯一的SessionID标识。session的概念不仅仅用在购物车这种常见的情况下,因为HTTP协议是无状态的,所以任何需要逻辑上下文的情况都必须使用session机制。另外,HTTP客户端也会在本地缓存一些数据,这样你就可以通过更少的请求提高性能。如果负载均衡器可能会将本次会话的请求分配给不同的后台服务器,这肯定是不合适的。数据必须通过多个后端共享,效率肯定会很低。最简单的情况就是保证session的一致性——每次对同一个session的请求都会分配到同一个backend。  (3)后台服务器动态配置有问题的后台要及时发现并从分发组中移除,后台数量可以随着业务增长灵活增加。此外,对于目前流行的ElasticCompute云计算服务,服务提供商也应该根据当前的负载自动增减后端主机。(4)基于DNS的负载均衡通常,现代Web服务器的一个域名与多个主机相关联。在执行DNS查询时,默认情况下,DNS服务器将以不同的顺序以循环格式返回IP地址列表。因此,客户端请求自然会分配给不同的主机。但是这种方式有先天的缺陷:DNS不会检查主机和IP地址的可访问性,因此不能保证分配给客户端的IP可用(Google404);DNS解析结果会在客户端,多个中间的DNS服务器不断缓存,所以后端的配置不会那么理想。2.Nginx中的负载均衡 Nginx中的负载均衡配置在手册中有详细的介绍,这里就不赘述了。对于常用的HTTP负载均衡,首先定义一个upstream作为后端组,然后通过proxy_pass/fastcgi_pass进行转发操作,其中fastcgi_pass几乎是Nginx+PHP站点的标准配置。2.1会话一致性 Nginx中的会话一致性是通过sticky实现的。会话一致性和之前的负载均衡算法没有冲突。只是在第一次分配之后,会话的所有请求都必须分配到同一个后端。目前支持三种session一致性模式: (1)CookieInsertion会在后端第一次响应后在其header中添加一个sessioncookie,即负载均衡器植入一个cookie给client,然后client该端下一次请求会携带这个cookie值,Nginx可以根据这个cookie判断需要转发到哪个后端。(2)StickyRoutes 也是在后端第一次响应后生成一条路由信息,路由信息通常是从cookie/URI信息中提取出来的。这样Nginx会依次查找routecookie和route_uri参数,选择第一个非空参数作为路由。如果所有参数都为空,它会使用上面默认的负载均衡算法来决定将请求分发到哪个后端。 (3)Learn 是比较复杂和智能的。Nginx会自动监听request和response中的session信息,通常需要和response保持一致的request和response都会有session信息。这与第一种方式相同,是动态学习现有会话而不是添加cookie。 该方法需要使用zone结构。在Nginx中,Zone都是共享内存,可以用来在多个worker进程中共享数据。(但是,为什么其他sessionconsistency不使用共享内存区?)2.2SessionDraining主要是因为维护或者升级需要关闭一些backend。这些关键服务都被优雅地处理了:新的请求不会发送到这个后端,分配给这个后端的session的后续请求会继续发送给他,直到session最终完成。让一个后端进入draining状态,可以直接修改配置文件,然后按照之前的方式向masterprocess发送信号重新加载配置,也可以使用Nginx的on-the-fly配置方式。2.3后端健康监控后端错误会涉及到两个参数,max_fails=1fail_timeout=10s;意思是只要Nginx向后端发送请求失败或者没有收到响应,在接下来的10s状态下就认为后端不可用。 通过定期向后端发送特殊请求并期望收到特殊响应,可用于确认后端是否健康可用。可以通过health_check进行此配置。使用health_check功能时,一般需要在backendgroup中创建一个zone。在共享后端组配置的同时,所有后端状态可以在所有工作进程之间共享,否则每个工作进程独立保存自己的状态检查计数和结果,这两种情况会有很大不同。2.4通过DNS设置HTTP负载均衡。Nginx后端组中的主机可以配置为域名。如果在域名后面加上resolve参数,Nginx会定时解析域名。当域名解析结果发生变化时,会自动生效,无需重启。2.5TCP/UDP流量的负载均衡通常,HTTP和HTTPS的负载均衡称为七层负载均衡,TCP和UDP协议的负载均衡称为四层负载均衡。因为七层负载均衡通常是基于HTTP和HTTPS协议,所以这种负载均衡相当于四层负载均衡的一种特化。平衡器可以使用HTTP/HTTPS协议头(User-Agent、Language等)甚至对响应内容做额外的规则以满足特定条件和目的的后端转发要求。除了Nginx擅长的HTTP负载均衡,Nginx还支持TCP和UDP流量的负载均衡,适用于LDAP/MySQL/RTMP、DNS/syslog/RADIUS等各种应用场景。本例中负载均衡是使用stream配置的,Nginx在编译时需要支持--with-stream选项。查看手册,配置原理和参数与HTTP负载均衡类似。因为TCP和UDP的负载均衡是针对通用程序的,不能使用之前HTTP协议支持的匹配条件(status,header,body)。TCP和UDP程序可以根据特定程序使用send和expect方法进行动态健康检查。2.6其他特性slow_start=30s:为了防止新添加/恢复的主机被突然增加的请求压垮,通过这个参数可以让主机的权重从0慢慢增加到设定值,使其负载可以慢慢增加的过程。 max_conns=30:可以设置最大后端连接数。当超过这个数量时,它将被放入队列中。同时还可以设置队列的大小和超时参数。当队列中的请求数大于设定值,或者超时但后端无法处理请求时,客户端会收到错误返回。一般来说,这是一个比较重要的参数,因为当Nginx作为反向代理时,通常是用来抵抗并发的。如果过多的并发请求交给后端,很可能会占用后端过多的资源(比如线程和进程不是事件驱动的),最终会影响后端的处理能力。