Nginx 负载均衡

《Nginx 负载均衡》

负载均衡是我们大流量网站要做的一个东西,下面我来给大家介绍在Nginx服务器上进行负载均衡配置方法,希望对有需要的同学有所帮助哦。

先来简单了解一下什么是负载均衡,单从字面上的意思来理解就可以解释N台服务器平均分担负载,不会因为某台服务器负载高宕机而某台服务器闲置的情况。那么负载均衡的前提就是要有多台服务器才能实现,也就是两台以上即可。

测试环境

由于没有服务器,所以本次测试直接host指定域名,然后在VMware里安装了三台CentOS。

测试域名  :a.com

A服务器IP :192.168.5.149 (主)

B服务器IP :192.168.5.27

C服务器IP :192.168.5.126

部署思路
A服务器做为主服务器,域名直接解析到A服务器(192.168.5.149)上,

由A服务器负载均衡到B服务器(192.168.5.27)与C服务器(192.168.5.126)上。

nginx 的 upstream目前支持 4 种方式的分配

0)、轮询(默认)
      每个请求按时间顺序逐一分配到不同的后端服务器,如果后端服务器down掉,能自动剔除。
1)、weight
      指定轮询几率,weight和访问比率成正比,用于后端服务器性能不均的情况。
2)、ip_hash
      每个请求按访问ip的hash结果分配,这样每个访客固定访问一个后端服务器,可以解决session的问题。 
3)、fair(第三方)
      按后端服务器的响应时间来分配请求,响应时间短的优先分配。 
4)、url_hash(第三方)

以追加的方式添加fair模块

//下载地址:
https://github.com/gnosek/nginx-upstream-fair
//目录不存在就自己新建 (将下载的所有文件放入这个目录中)
/usr/local/tengine-2.3.3/modules/ngx_http_upstream_fair_module

//查看已安装的模块:
#cd /usr/local/tengine/sbin
./nginx -V
Tengine version: Tengine/2.3.3
nginx version: nginx/1.18.0
built by gcc 8.5.0 20210514 (Red Hat 8.5.0-4) (GCC) 
built with OpenSSL 1.1.1k  FIPS 25 Mar 2021
TLS SNI support enabled
configure arguments: --prefix=/usr/local/tengine --with-http_v2_module --with-http_ssl_module --with-http_realip_module --with-http_stub_status_module --with-ipv6 --with-http_lua_module --with-luajit-inc=/usr/local/luajit/include/luajit-2.0 --with-luajit-lib=/usr/local/luajit/lib

1.备份原来的nginx 
mv /usr/local/tengine/sbin/nginx /usr/local/tengine/sbin/nginx_back
2.用上边复制过的配置参数,加上--add-module=/xxx/ngx_http_upstream_fair_module,生成Makefile
3.执行make开始编译,但不要执行make install
注意事项:已安装Nginx,配置第三方模块时,只需要--add-module=/第三方模块目录,然后make编译一下就可以,不要 make install 安装。编译后复制objs下面的Nginx到指定目录下。


#cd /usr/local/tengine-2.3.3

./configure  --prefix=/usr/local/tengine --with-http_v2_module --with-http_ssl_module --with-http_realip_module --with-http_stub_status_module --with-ipv6 --with-http_lua_module --with-luajit-inc=/usr/local/luajit/include/luajit-2.0 --with-luajit-lib=/usr/local/luajit/lib --add-module=/usr/local/tengine-2.3.3/modules/ngx_http_upstream_fair_module
//红色部分对应上面新建的目录

#make (不要执行 make install)

//编译完成后,复制/usr/local/tengine-2.3.3/objs/nginx 到/usr/local/tengine/sbin 下
upstream indexhandel(指定的域名){
  server 127.0.0.1:9090 down; 
  server 127.0.0.1:8080 weight=2; 
  server 127.0.0.1:6060; 
  server 127.0.0.1:7070 backup; 
}

[down]表示单前的server暂时不参与负载 
[weight=2]默认为1.weight越大,负载的权重就越大。 
[max_fails=2]允许请求失败的次数默认为1.当超过最大次数时,返回proxy_next_upstream 模块定义的错误 
[fail_timeout=2s] 次失败后,暂停的时间。 
[backup]备用服务器其它非backup机器或down或者忙的时候,才会请求backup机器。所以这台机器压力会最轻。
[ip_hash] 此技术能够将某个ip的请求定向到同一台后端,这样一来这个ip下的某个客户端和某个后端就能建立起稳固的session,ip_hash是在upstream配置中定义的:
upstream indexhandel{
ip_hash;
  server 127.0.0.1:8080 max_fails=3 fail_timeout=20s;
  server 127.0.0.1:9090 ;
}

ip_hash是容易理解的,但是因为仅仅能用ip这个因子来分配后端,因此ip_hash是有缺陷的,不能在一些情况下使用:
1.nginx不是最前端的服务器。ip_hash要求nginx一定是最前端的服务器,否则nginx得不到正确ip,就不能根据ip作hash。譬如使用 的是squid为最前端,那么nginx取ip时只能得到squid的服务器ip地址,用这个地址来作分流是肯定错乱的。
2.nginx的后端还有其它方式的负载均衡。假如nginx后端又有其它负载均衡,将请求又通过另外的方式分流了,那么某个客户端的请求肯定不能定位到同一 台session应用服务器上。这么算起来,nginx后端只能直接指向应用服务器,或者再搭一个squid,然后指向应用服务器。最好的办法是用 location作一次分流,将需要session的部分请求通过ip_hash分流,剩下的走其它后端去。

A服务器nginx.conf设置

在http段加入以下代码
upstream indexhandel{ 
  ip_hash;
  server  192.168.5.126:80;  //转发到C服务器
  server  192.168.5.27:80;   //转发到B服务器
  server  127.0.0.1:8080;    //交由自己处理  8080    
} 
server{
    listen 80; 
    server_name a.com; 
    location / {
        proxy_pass      http://indexhandel;  #代理回本机最好用http
        proxy_set_header   Host       $host; 
        proxy_set_header   X-Real-IP     $remote_addr; 
        proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for; 
    }
}

server{  #本机对本机的转发处理
        listen 8080; 
	server_name  127.0.0.1; 
	root   /usr/share/nginx/html;
	location / {
		set $args "";
		proxy_pass http://chickencdn.info;
		proxy_set_header Host chickencdn.info; 
		proxy_http_version 1.1;
	}
}

保存重启nginx

B、C服务器nginx.conf设置

打开nginx.conf,在http段加入以下代码
upstream indexhandle{
	ip_hash;
	server 127.0.0.1:8081;
	server 127.0.0.1:8082 max_fails=3 fail_timeout=20s;
} 

#图片服务器... 响应
server {
	listen 80;
	listen 443 ssl;
	ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
	ssl_certificate /etc/letsencrypt/live/xx.net/fullchain.pem;
	ssl_certificate_key /etc/letsencrypt/live/xx.net/privkey.pem;
	server_name media.xx.net;

	include conf.d/set.ban.conf;
	#root  /usr/share/nginx/html;
	#index  index.php index.html index.htm;

	location / {
		expires 720d;
		include conf.d/set.proxy.conf;#基本代理设置
		proxy_pass http://indexhandle; #代理回本机最好用http
		#proxy_pass https://xx.xx.net:209; #8443
		include conf.d/set.proxy_cache.conf;#开启x-cache设置 缓存命中率·MISS 未命中
	}
}

server {
	listen       8081;
	server_name  127.0.0.1; 
	root         /usr/share/nginx/html;
	location / {
		include conf.d/set.proxy.conf;#基本代理设置
		proxy_pass https://xmedia.xxx.net:2096;
	}
}
server {
	listen       8082;
	server_name  127.0.0.1; 
	root         /usr/share/nginx/html;
	location / {
		include conf.d/set.proxy.conf;#基本代理设置
		proxy_pass https://xmedia.xxx.net:8443;
	}
}
保存重启nginx


测试:
当访问a.com的时候,为了区分是转向哪台服务器处理我分别在B、C服务器下写一个不同内容的index.html文件,以作区分。
打开浏览器访问a.com结果,刷新会发现所有的请求均分别被主服务器(192.168.5.149)分配到B服务器(192.168.5.27)与C服务器(192.168.5.126)上,实现了负载均衡效果。

一、负载均衡不是nginx独有,著名鼎鼎的apache也有,但性能可能不如nginx。

二、多台服务器提供服务,但域名只解析到主服务器,而真正的服务器IP不会被ping下即可获得,增加一定安全性。

三、upstream里的IP不一定是内网,外网IP也可以。不过经典的案例是,局域网中某台IP暴露在外网下,域名直接解析到此IP。然后又这台主服务器转发到内网服务器IP中。

四、某台服务器宕机、不会影响网站正常运行,Nginx不会把请求转发到已宕机的IP上

一、Session问题

当我们确定一系列负载的服务器后,那我们的WEB站点会分布到这些服务器上。这个时候如果采用Test2 每一次请求随机访问任何一台服务器上,这样导致你访问A服务器后,下一次请求又突然转到B服务器上。这个时候与A服务器建立的Session,传到B站点 服务器肯定是无法正常响应的。我们看一下常用的解决方案:

  • Session或凭据缓存到独立的服务器
  • Session或凭据保存数据库中
  • nginx ip_hash 保持同一IP的请求都是指定到固定的一台服务器

第一种缓存的方式比较理想,缓存的效率也比较高。但是每一台请求服务器都去访问Session会话服务器,那不是加载重了这台Session服务器的负担吗?

第二种保存到数据库中,除了要控制Session的有效期,同时加重了数据库的负担,所以最终的转变为SQL Server 负载均衡,涉及读,写,过期,同步。

第三种通过nginx ip_hash负载保持对同一服务器的会话,这种看起来最方便,最轻量。

正常情况下架构简单的话, ip_hash可以解决Session问题,但是我们来看看下面这种情况

《Nginx 负载均衡》
点赞

发表评论

邮箱地址不会被公开。 必填项已用*标注