一、负载均衡

就是当数据量过大的时候,代理服务器充分当作一个调度者的身份,来将这些请求合理的分配到后端各个服务器上,保证服务器的性能能够充分发挥。在Nginx有常用的几种实现负载均衡的方式,下面就给大家介绍下。

二、Nginx路径匹配规则

在介绍负载均衡之前,先给大家介绍Nginx常用的几种路径匹配规则。

=

=/aaa/1.jpg

路径严格匹配,路径必须一模一样才会匹配到

^~

^~/aaa

只要是指定路径开头的路径都可以匹配

~

~.png$

区分大小写按正则匹配路径

~*

~*.png$

不区分大小写按正则匹配路径

/

/

通用匹配,所有路径都可以匹配到

优先级:

  1. 首先匹配 =
  2. 其次匹配 ^~
  3. 其次是按文件中顺序正则匹配
  4. 最后是交给 / 通用匹配
  5. 当有匹配成功时候,停止匹配,按当前匹配规则处理请求

总的规律是,精度越高优先级越高

案例:

upstream ccc{
		server localhost:8081;
		server localhost:8082;
		server localhost:8083;
	}

	server {
		listen 80;
		server_name www.cccmall.com;
		location /{
			proxy_pass http://ccc;
		}
	}
listen               表示监听的端口号
server_name   表示访问的主机名
location            表示处理的请求地址,一个server中可以配置多个location
server               表示虚拟服务器,一个http中可以配置多个server
upstream          用于配置一组服务器地址供后续使用

三、轮询方式

轮询方式是Nginx默认处理负载方式,它的工作原理,就如其名称,根据请求顺序轮流的分配到后端服务器上,举个例子,假设后端有3台服务器,此时有5个连接发送过来,如果使用轮询,它是这样工作的,A->1,B->2,C->3,A->4,B->5。轮流处理请求。

实现:

upstream ccc{
		server localhost:8081;
		server localhost:8082;
		server localhost:8083;
	}

	server {
		listen 80;
		server_name www.cccmall.com;
		location /{
			proxy_pass http://ccc;
		}
	}
  1. upstream,表明有几台服务器。
  2. 在location中,通过proxy_pass  引用upstream

如果不指定负载均衡方式,那么默认就是轮询的方式。

但是,这种方式有一点问题,大家有没有想过,假设有这样一个场景,A服务器处理了张三的登录请求,并将张三的信息保存在Session域中,重所周知,Session域中的内容是保存在服务器中的。此时,张三点击了一下购买商品,此时是B服务器处理的购买请求,B服务器中没有张三的个人信息,所以服务器要求张三去登录。但是,第二次登录的请求是又被A服务器处理了,A服务器中有张三的信息,显示您已经登录,请不要重复登录。然后,张三在点击购买,此时又被B服务器处理,张三又被要求去登录。此时,张三肯定会崩溃的。所以,轮询的方式也是有一点问题的。 

三、hash方式

由于,不同服务器之间不能共享数据,所以Nginx提供了一种基于Hash的方式,用以提供负载均衡。

处理公式:abs(客户端ip.hash())%服务器数量

因为客户端的ip地址是唯一不变的,所以,通过hash算法计算出ip地址对应的哈希码值,通过哈希码值对服务器的数量进行一个求模运算。这样就可以保证每个客户端访问的服务器都是保持不变的,因为hash算法的散列特点,也可以近似的当作平均分配。

实现:

upstream czf{
		ip_hash;
		server localhost:8081;
		server localhost:8082;
		server localhost:8083;
	}

	server {
		listen 80;
		server_name www.cccmall.com;
		location /{
			proxy_pass http://czf;
		}
	}

通过ip_hash;就可以实现基于Hash的负载均衡的方式。

但是,正如hash算法的散列特点,因为它的不确定性,可能会造成某个A服务器处理请求的数量是100,B服务器处理请求的数量是50,C服务器处理请求的数量是0,如果,在来一条请求,那么按照我们所想的,最好是可以分配到C服务器上。所以,Nginx又为我们提供了另外一种方式,用来解决以上问题,这个方式就是基于最小连接数的负载均衡方式。

四、最小连接方式

基于最小连接的负载均衡方式,Nginx会将请求发送给当前处理请求数量最少的服务器上。可以分担各个服务器之间的压力。

实现:

upstream czf{
		least_conn;
		server localhost:8081;
		server localhost:8082;
		server localhost:8083;
	}

	server {
		listen 80;
		server_name www.cccmall.com;
		location /{
			proxy_pass http://czf;
		}
	}

通过least_conn;就可以实现基于最小连接数的负载均衡方式。

但是,大家有没有想过这样一个情况。在公司里,有三台服务器,A服务器采购于2000年,最高处理并发数100,B服务器采购于2010年。最高处理并发数500,C服务器采购于2018年,最高处理并发数1000。如果,此时A服务器处理请求数为99,B服务器处理请求数为300,C服务器请求数为500,如果是你,进行分配资源的话,我想更倾向于C服务器吧,C虽然处理了很多请求,但是任然没有到达它的处理瓶颈。但是,根据最小连接数的规则,这条请求应该是A服务器处理,但很有可能就是压死骆驼的最后一根稻草。所以,给大家在介绍一种处理规则,基于权重的负载均衡方式。

五、权重方式

基于权重的负载均衡方式,Nginx会根据服务器设置的权重,进行合理分配请求连接数。

实现:

upstream czf{
		server localhost:8081 weight=5;
		server localhost:8082 weight=3;
		server localhost:8083 down;
	}

	server {
		listen 80;
		server_name www.cccmall.com;
		location /{
			proxy_pass http://czf;
		}
	}

通过设置weight的比重,来进行资源分配。

补充两个关键字:

  • down,表示当前服务器不参与负载均衡。
  • backup,预留的备份服务器。当其他所有的非backup机器出现故障或者忙的时候,才会请求backup机器,因此这台机器的压力最轻。

六、选择方式

通过以上的介绍,我想大家都应该对不同的负载均衡方式应该有所取舍。如果大家担心因为共享资源的问题,而去选择基于Hash的均衡方式,其实不然,这种方式,真正开发使用的次数其实也不是很多。现在市面上,也有许多解决共享资源的问题。像redis+sso就可以处理该问题。