Nginx负载均衡配置简易实现



什么是动静分离? 
其实就是七层调度,把动态文件的请求和静态文件的请求分别调到不同的后台服务器


什么是网站数据切分?
其实也是七层调度
比如我要把新浪新闻,新浪体育给分开


方法1:
用dns
www.baidu.com
news.baidu.com
tieba.baidu.com
这几个域名得到的ip不同,所以其实是不同的站点



方法2:
前端使用代理
通过代理软件七层调度来分离

以location来分
sports.sina.com.cn/nba/
sports.sina.com.cn/cba/

以文件名后缀来分
sports.sina.com.cn/xxx/xxxx/xxx/xxx.png
sports.sina.com.cn/xxx/xxxx/xxx/xxx.php




================================================================================================

1,四台机器,192.168.100.0/24为kvm的virbr1网络(模拟外网),172.16.25.0/24为桥接网络(模拟内网)
2,web1我这里用的是本来搭建好的lnmp(参考历史文章),为了后面方便测试(但这里直接把lnmp的web家目录改成discuz的家目录/usr/share/nginx/html/discuz)
3,web2这里简单的安装并启动rpm版的apache,并做一个简单主页就好
4,nginx这台需要按下面的第一步过程进行安装,这次只安装nginx就好,不用安装php,mysql等(因为是主要做代理)
5,客户端最好有图形界面,并安装firefox浏览器



nginx 反向代理


			 client(宿主机)  192.168.100.1


					192.168.100.4	eth0   default
			nginx(虚拟机1)	
					172.16.25.4	eth1   桥接



       		web1(虚拟机2)		web2(虚拟机3)
	   	172.16.25.2		172.16.25.3
		 (lnmp)


安装nginx
# yum install nginx




======================================================================================



例一:使用前端nginx代理后面一台web


			 client(宿主机)  192.168.100.1
			      |	
			      |	
			      |		192.168.100.4
			nginx(虚拟机1)	
					172.16.25.4
			      |	
			      |	
			      |	
       			 web1(虚拟机2)    172.16.25.2
	   		




# cat /etc/nginx/nginx.conf |grep -v '#'

user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;

include /usr/share/nginx/modules/*.conf;

events {
    worker_connections 1024;
}

http {
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile            on;
    tcp_nopush          on;
    tcp_nodelay         on;
    keepalive_timeout   65;
    types_hash_max_size 2048;

    include             /etc/nginx/mime.types;
    default_type        application/octet-stream;

    include /etc/nginx/conf.d/*.conf;

    server {
        listen       80 default_server;
        listen       [::]:80 default_server;
        server_name  192.168.100.4;		--改成模拟nginx的外网ip
        root         /usr/share/nginx/html;
	index	     index.php index.html;

        include /etc/nginx/default.d/*.conf;

        location / {
		proxy_pass http://172.16.25.2/;
		proxy_set_header Host $host;
		proxy_set_header X-Forwarded-For $remote_addr;	
        }				       --这个例子主要讨论这一段,五行

        error_page 404 /404.html;
            location = /40x.html {
        }

        error_page 500 502 503 504 /50x.html;
            location = /50x.html {
        }
    }


}


--说明:下面这两句是做外网转内网双网段架构必需要加的
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;



客户端使用firefox验证	
访问 http://192.168.100.4/	--得到后台web上安装的lnmp

验证:
把后面的web关闭,客户端也访问不了,说明nginx默认没有缓存功能



例二:locate网站数据切分


			 client(宿主机)  192.168.100.1


					192.168.100.4
			nginx(虚拟机1)	
					172.16.25.4



       		web1(虚拟机2)		web2(虚拟机3)
	   	172.16.25.2		172.16.25.3



把例一nginx配置文件里的那五行改成下面两段(加在server { }配置段中 ):

        location /nba/ {
		proxy_pass http://172.16.25.2/;
		proxy_set_header Host $host;
		proxy_set_header X-Forwarded-For $remote_addr;		
        }	
        location /cba/ {
		proxy_pass http://172.16.25.3/;
		proxy_set_header Host $host;
		proxy_set_header X-Forwarded-For $remote_addr;		
        }	


# systemctl restart nginx

客户端验证
http://192.168.100.4/nba/
http://192.168.100.4/cba/



例三:网站动静分离

			 client(宿主机)  192.168.100.1


					192.168.100.4
			nginx(虚拟机1)	
					172.16.25.4



       		web1(虚拟机2)		web2(虚拟机3)
	   	172.16.25.2		172.16.25.3

把例二的配置再改成如下(加在server { }配置段中 ):

        location ~ \.(html|htm|gif|jpeg|jpg|css|js|png|swf)$ {
		proxy_pass http://172.16.25.2;
		proxy_set_header Host $host;
		proxy_set_header X-Forwarded-For $remote_addr;			
        }
        location ~ \.(php|cgi)$ {
		proxy_pass http://172.16.25.3;
		proxy_set_header Host $host;
		proxy_set_header X-Forwarded-For $remote_addr;
        }



# systemctl restart nginx

客户端测试(过程省略)



例四:代理后端时使用负载均衡(load balance)


			 client(宿主机)  192.168.100.1


					192.168.100.4
			nginx(虚拟机1)	
					172.16.25.4




       		web1(虚拟机2)		web2(虚拟机3)
	   	172.16.25.2		172.16.25.3



下面一段加到http 和 server 之间
upstream backendweb {
	server 172.16.25.2 weight=1 max_fails=2 fail_timeout=1s;
	server 172.16.25.3 weight=1 max_fails=2 fail_timeout=1s;
        }


--weight代表权重,max_fails=2 fail_timeout=1s代表健康检查(检查后台web是否ok,访问超时1秒,并两次超时,则认为不健康)


把例三的配置再改成如下(加在server { }配置段中 ):
        location ~ \.(txt|html)$ {
		proxy_pass http://backendweb;		--backendweb是一个名称,对应上面upstream的配置
		proxy_set_header Host $host;
		proxy_set_header X-Forwarded-For $remote_addr;
		}

# systemctl restart nginx


客户端验证
访问http://192.168.100.4/1.txt

--验证时,会发现客户端针对同一个URL的访问也会一次web1一次web2,这再次验证说明了nginx默认并没有squid或varnish那样的缓存功能


负载均衡(lb  load banlance)一般要注意四个方面:
1,算法  round-robin
2,健康检查 
3,会话保持  
4,数据一致	rsync   drbd    共享存储	  分布式存储



			   client request


				LB(loaded balanced)
				

			web1		web2
	


例五:使用ip_hash,实现同一IP客户端一旦调到一台,就一直调那一台

			 client(宿主机)  192.168.100.1


					192.168.100.4
			nginx(虚拟机1)	
					172.16.25.4



       		web1(虚拟机2)		web2(虚拟机3)
	   	172.16.25.2		172.16.25.3


upstream backendweb {
	ip_hash;			--在上个例子的基础上只加这一句;
	server 172.16.25.2 weight=1 max_fails=2 fail_timeout=1s;
	server 172.16.25.3 weight=1 max_fails=2 fail_timeout=1s;
        }


# systemctl restart nginx


客户端验证
访问http://192.168.100.4/1.txt

--nginx的ip_hash的意思是,如果一个客户端的访问被调度到其中一台后台服务器,那么同一个IP来的访问都只会被调到这个后台服务器;这里测试时,如果都用同一个网段的内网IP来做客户端测试,可能会都只转到一个后台(因为nginx的hash算法是按网段来算的,如果是公网不同网段的客户端IP就不一样了)




对于nginx的upstrem算法总结:
1,round-robin	轮循(平均分配)
2,weight	权重(人为地分配权重,用于后台服务器性能不均的情况)
3,fair		响应时间(按后台的响应时间来分配,需要第三模块,但如果后台服务器都在内网,就没太大必要使用这种算法了)
4,url_hash	按访问url的hash结果来分配请求,使每个url定向到同一个后端服务器,后端服务器为多台缓存时比较有效,提高缓存命中率
5,ip_hash	在负载均衡的基础上加上会话保持(优点是配置方便,缺点是不能完全的负载均衡)





=======================================================================


			client	  192.168.100.1		
			  |
			  |	     192.168.100.4(模拟网站公网ip,整个架构的域名假设为web.cluster.com )
		      nginx 反向代理   		
			  |	     172.16.25.4
			  |
		   -----------
		  |		    |	 命中  hit 直接返回	
动态程序文件.php	  |		    | 
		  |               squid(web加速,缓存静态文件或图片) 
直接找web	  |		    |			
		   ----	    |    没命中 miss 找后端web去取
			 |	    |	 172.16.25.3
			lnmp  <---- |	 
						     
		      172.16.25.2
			

实验前准备:
1,所有机器配置主机名并在/etc/hosts里互相绑定主机
2,关闭firewalld,selinux
3,关闭NetworkManager,并配置静态ip
4,配置本地yum,epel源,163源
5,时间同步


第一大步:在上图中的lnmp上安装并配置后面的网站




第二大步:在上图中的nginx服务器上安装并配置nginx

1,安装nginx

# yum install nginx  

2,配置文件如下
# cat /etc/nginx/nginx.conf |grep -v '#'

user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;

include /usr/share/nginx/modules/*.conf;

events {
    worker_connections 1024;
}

http {
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile            on;
    tcp_nopush          on;
    tcp_nodelay         on;
    keepalive_timeout   65;
    types_hash_max_size 2048;

    include             /etc/nginx/mime.types;
    default_type        application/octet-stream;

    include /etc/nginx/conf.d/*.conf;


upstream squid {
    server 172.16.25.3 weight=1 max_fails=2 fail_timeout=3s;
}
upstream web {
    server 172.16.25.2 weight=1 max_fails=2 fail_timeout=3s;
}


    server {
        listen       80 default_server;
        listen       [::]:80 default_server;
        server_name  192.168.100.4;
        root         /usr/share/nginx/html;

        include /etc/nginx/default.d/*.conf;


       location ~ .*\.php$ {
            proxy_pass   http://web;
            proxy_set_header Host $host;
            proxy_set_header X-Forwarded-For $remote_addr;
        }
        location ~ .*\.(html|htm|gif|jpeg|jpg|css|js|png|swf)$ {
            proxy_pass   http://squid;
            proxy_set_header Host $host;
            proxy_set_header X-Forwarded-For $remote_addr;
        }
        location / {
            proxy_pass   http://web;
            proxy_set_header Host $host;
            proxy_set_header X-Forwarded-For $remote_addr;
        }


        error_page 404 /404.html;
            location = /40x.html {
        }

        error_page 500 502 503 504 /50x.html;
            location = /50x.html {
        }
    }


}


# systemctl restart nginx





第三大步:在上图中的squid服务器上安装并配置squid

1,安装squid
# yum install squid -y


2,配置squid主配置文件
# vim /etc/squid/squid.conf

http_access allow all		--把这一行前面的全删除,再把这行修改成允许所有
http_port 80 accel vhost vport  --修改成支持反向代理模式,端口也为80与nginx的配置对应
cache_dir ufs /var/spool/squid 256 16 256	--打开缓存目录的定义这一句


cache_peer 172.16.25.2 parent 80 0 no-query originserver name=web
cache_peer_domain web web.cluster.com	--web.cluster.com就是我现在模拟的整个网站架构的域名
cache_peer_domain web 192.168.100.4	--加上这三句,表示代理后台的lnmp的80端口;web.cluster.com为网站的域名,192.168.100.4为我这个架构最前端的nginx的IP


3,启动squid
# systemctl restart squid



第四大步:验证


在客户端机器192.168.100.129上首先绑定静态DNS 
--用于模拟DNS,如果不绑定,也可以直接使用公网IP192.168.100.4来访问,因为在squid里配置了(cache_peer_domain web web.cluster.com	和 cache_peer_domain web 192.168.100.4 两句)

cat /etc/hosts
192.168.100.4  web.cluster.com    --IP要为前端nginx的IP,名字为这个网站的域名要和squid里的cache_peer_domain web web.cluster.com要对应



1,在客户端用firefox访问http://web.cluster.com/或http://192.168.100.4/是可以正常看到我的lnmp安装的discuz论坛



2,在客户端使用下面的命令验证discuz论坛的一个logo,可以看到在squid上命中的信息
# curl -I http://web.cluster.com/static/image/common/logo.png

HTTP/1.1 200 OK
Server: nginx/1.8.0
Date: Mon, 23 Nov 2015 08:10:09 GMT
Content-Type: image/png
Content-Length: 4425
Connection: keep-alive
Last-Modified: Tue, 09 Jun 2015 02:21:12 GMT
ETag: "55764d98-1149"
Accept-Ranges: bytes
Age: 3227
X-Cache: HIT from squid.cluster.com
X-Cache-Lookup: HIT from squid.cluster.com:3128
Via: 1.0 squid.cluster.com (squid/3.1.10)


3,关闭squid,在客户端用firefox访问,会发现整个网站都没有图片(静态的元素)
用curl -I  http://web.cluster.com/static/image/common/logo.png来验证也会报错

因为我的架构里只有一台squid,再次启动squid后,一切又恢复正常




4,关于squid手动清缓存


# vim /etc/squid/squid.conf	

acl purge_admin src 127.0.0.1
acl purge method PURGE
http_access allow purge_admin purge
http_access deny all purge


# systemctl restart squid


最基本的清除一条缓存的操作,必须要在squid本机执行
# squidclient -m PURGE -h 127.0.0.1 -p 80 http://192.168.100.4/static/image/common/logo.png

-- -h参数后只能接127.0.0.1;-p 80是squid的监听端口;最后的路径就是客户端访问的路径


如果要批量清除squid,可以使用下面的脚本(你需要修改成自己对应的路径)

# vim /tmp/purge_squid.sh

#!/bin/bash
squidcache_path="/var/spool/squid/"
squidclient_path="/usr/bin/squidclient"
grep -a -r $1 $squidcache_path/* | strings | grep "http" | while read url
do
$squidclient_path -h 127.0.0.1 -m PURGE -p 80 $url > /dev/null 2>&1
echo "$url被清除"
done


--注意:脚本的squidcache_path修改成你对应的缓存目录,squidclient_path修改成squidclient命令的路径;-h 127.0.0.1是因为我做了acl限制的,所以只能在squid本机上清除



批量清除的方法:
sh /tmp/purge_squid.sh .txt  --表示清除所有的.txt结尾的缓存
sh /tmp/purge_squid.sh .     --表示清除所有缓存
sh /tmp/purge_squid.sh /aaa/  --表示url里有/aaa/路径就清掉缓存



===============================================================================

	
在上面的架构基础上多加一台squid2(我这里IP为172.16.25.5)



				client 192.168.100.1
				  |
				  |	192.168.100.4
				 nginx	
				  |	172.16.25.4
				  |
			    |------------|		
			    |    	 |
			    |	   squid1  	squid2
			    |	   172.16.25.3	172.16.25.5	 
			    |------------|
				  |
				  |	
				 lnmp
			       172.16.25.2



做法,在nginx配置要修改的为下面一段
upstream squid {
    server 172.16.25.3 weight=1 max_fails=2 fail_timeout=3s;
    server 172.16.25.5 weight=1 max_fails=2 fail_timeout=3s;
}

# systemctl restart nginx


在客户端用curl -I去测试多个不同的文件请求,看缓存情况,如:
curl -I http://web.cluster.com/static/image/common/logo.png
curl -I http://web.cluster.com/static/image/feed/task_b.png
curl -I http://web.cluster.com/static/image/feed/album_b.png
curl -I http://web.cluster.com/static/image/feed/portal_b.png
curl -I http://web.cluster.com/static/image/feed/wall_b.png

测试结果为:第一次squid1,第二次squid2,第三次squid1...以此类推(round-robin)


但这个做法的缺点为:比如同一个url的请求,连续访问,它也会RR轮循给squid1和squid2,这样会造成两个squid重复缓存。

改进的做法为:使用nginx的url_hash的算法,把同一个url的请求只给同一个后台squid,以提高缓存命中率。如果要做这个改进的话,只需要把nginx的配置再修改成如下:

upstream squid {
    hash $request_uri;
    server 172.16.25.3 weight=1 max_fails=2 fail_timeout=3s;
    server 172.16.25.5 weight=1 max_fails=2 fail_timeout=3s;
}

# systemctl restart nginx

再次测试:
结果为:新的请求仍然会RR轮循调给squid1和squid2,但已经请求过的地址再次被请求,会调给第一次调的squid,提高缓存命中率。


=================================================================================




你可能感兴趣的:(架构)