搭建负载均衡服务的需求
搭建负载均衡服务的需求如下:
1)把单台计算机无法承受的大规模并发访问或数据流量分担到多台节点设备上分别进行处理,减少用户等待响应的时间,提升用户体验;
2)单个重负载的运算分担到多台节点设备上做并行处理,每个节点设备处理结束后将结果汇总,返回给用户,系统处理能力得到大幅度提高。
3)7×24小时的服务保证,任意一个或多个有限后面节点设备宕机,不会影响业务。
在负载均衡集群中,同组集群所有计算机节点都应该提供相同服务。集群负载均衡器会截获所有对该服务的入站请求。然后将这些请求尽可能平均地分配在所有集群节点上。
Nginx负载均衡集群介绍
1.反向代理与负载均衡概念简介
LVS等的负载均衡是转发用户请求的数据包,而Nginx反向代理是接收用户的请求然后重新发起请求去请求其后面的节点。
2.实现Nginx负载均衡的组件说明
实现Nginx负载均衡的组件模块主要有两个,见下表
(1)硬件准备
准备4台VM虚拟机,两台做负载均衡,两台做RS
(2)软件准备
系统:Centos7.6 x86_64。软件:nginx-1.16.0.tar.gz(http://nginx.org/download/nginx-1.16.0.tar.gz)。
1)安装依赖软件包命令集合:
yum install openssl openssl-devel pcre pcre-devel -y
rpm -qa openssl openssl-devel pcre pcre-devel
2)安装Nginx软件包命令集合:
#1.下载nginx。
mkdir -p /server/tools
cd /server/tools
wget http://nginx.org/download/nginx-1.16.0.tar.gz
ls -l nginx-1.16.0.tar.gz
#2. 解压安装Nginx。
useradd nginx -u 1111-s /sbin/nologin -M
tar xf nginx-1.16.0.tar.gz
cd nginx-1.16.0
./configure --user=nginx --group=nginx --prefix=/application/nginx-1.16.0
--with-http_stub_status_module --with-http_ssl_module
make
make install
ln -s /application/nginx-1.16.0 /application/nginx
#3.设置环境变量。
echo 'PATH="/application/nginx/sbin:$PATH"' >>/etc/bashrc
. /etc/bashrc
echo $PATH
Nginx的负载均衡功能依赖于ngx_http_upstream_module模块,所支持的代理方式包括proxy_pass、fastcgi_pass、memcached_pass等,新版Nginx软件支持的方式有所增加。这里使用proxy_pass。
upstream模块语法,通过upstream配置案例学习
案例1:
upstream www_pools { #<== upstream关键字必须要有,www_pools为一个upstream群组名字,可以自己起名。
server 10.0.0.17:80 weight=5;
server 10.0.0.18:80 weight=10;
server 10.0.0.19:82 weight=15;
#<==server关键字是固定的,后面可以接域名(门户会用)或IP。如果不指定端口,默认是80端口。
weight代表权重,数值越大被分配的请求越多,注意结尾有分号。
}
案例2:
upstream blog_pools {
server 10.0.0.7; #<==这一行标签和下一行是等价的。
server 10.0.0.8:80 weight=1 max_fails=1 fail_timeout=10s;
#<==这一行标签和上一行是等价的,此行多余的部分就是默认配置,不写也可以。
server 10.0.0.9:80 weight=1 max_fails=2 fail_timeout=20s backup;
server 10.0.0.10:80 weight=1 max_fails=2 fail_timeout=20s backup;
案例3:使用域名及socket的upstream配置案例
upstream backend {
server backend1.example.com weight=5;
server backend2.example.com:8080; #<==域名加端口。转发到后端的指定端口上。
server unix:/tmp/backend3; #<==指定socket文件。
#提示:server后面如果接域名,需要内网有DNS服务器或者在负载均衡器的hosts文件做域名解析。
server backup1.example.com:8080 backup;
#<==结尾backup表示备份服务器,其他指定服务器都不可访问时启用,backup的用法和Haproxy中用法一样。
server backup2.example.com:8080 backup;
}
提示:如果是两台Web服务器做高可用,常规方案就需要Keepalived配合,那么这里使用Nginx的backup参数通过负载均衡功能就可以实现Web服务器集群了,对于企业应用来说,能做集群就不做高可用。
upstream模块的内容应放于nginx.conf配置的http{}标签内,其默认调度节点算法是wrr(权重轮询,weighted round-robin)
调度算法一般分为以下两类:第一类为静态调度算法即负载均衡器根据自身设定的规则进行分配,不需要考虑后端节点服务器情况。例如:rr、wrr、ip_hash都属于静态调度算法。
第二类为动态调度算法,即负载均衡器会根据后端节点的当前状态来决定是否分发请求。例如:连接数少的优先获得请求,响应时间短的优先获得请求,least_conn、fair等都属于动态调度算法。
这里只说明一部分,
(1)rr轮询(默认调度算法,静态调度算法)按客户端请求顺序把客户端的请求逐一分配到不同的后端节点服务器,这相当于LVS中的rr算法,如果后端节点服务器宕机(默认情况下Nginx只检测80端口),宕机的服务器会被自动从节点服务器池中剔除,以使客户端的用户访问不受影响。新的请求会分配给正常的服务器。
(2)wrr(权重轮询,静态调度算法)在rr轮询算法的基础上加上权重,即为权重轮询算法,当使用该算法时,权重和用户访问成正比,权重值越大,被转发的请求也就越多。可以根据服务器的配置和性能指定权重值大小,从而有效解决新旧服务器性能不均带来的请求分配问题。
(3)ip_hash(静态调度算法)每个请求按客户端IP的hash结果分配,当新的请求到达时,先将其客户端IP通过哈希算法哈希出一个值,在随后的客户端请求中,客户IP的哈希值只要相同,就会被分配至同一台服务器,该调度算法可以解决动态网页的session共享问题,但有时会导致请求分配不均,即无法保证1∶1的负载均衡,因为在用户大多数都是NAT上网模式,多个客户端会对应一个外部IP,所以,这些客户端都会被分配到同一节点服务器,从而导致请求分配不均。LVS负载均衡的-p参数、Keepalived配置里的persistence_timeout 50参数都类似这个Nginx里的ip_hash参数,其功能均为解决动态网页的session共享问题。
示例:
upstream oldboy_lb {
ip_hash;
server 192.168.1.2:80;
server 192.168.1.3:8080;
}
upstream backend {
ip_hash;
server backend1.example.com;
server backend2.example.com;
server backend3.example.com down;
server backend4.example.com;
}
- proxy_pass指令介绍proxy_pass指令属于ngx_http_proxy_module模块,此模块可以将请求转发到另一台服务器,在实际的反向代理工作中,会通过location功能匹配指定的URI,然后把接收到的符合匹配URI的请求通过proxy_pass抛给定义好的upstream节点池。该指令官方地址见http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_pass。
- proxy_pass的使用案例。
1)将匹配URI为name的请求抛给http://127.0.0.1/remote/。
location /name/ {
proxy_passhttp://127.0.0.1/remote/;
}
2)将匹配URI为some/path的请求抛给http://127.0.0.1。
location /some/path/ {
proxy_passhttp://127.0.0.1;
}
3)将匹配URI为name的请求应用指定的rewrite规则,然后抛给http://127.0.0.1。
location /name/ {
rewrite /name/([^/]+) /users? name=$1 break;
proxy_passhttp://127.0.0.1;
}
http_proxy_module相关参数:Nginx反向代理功能主要是通过http proxy模块来实现的。默认在安装Nginx时已经安装了http proxy模块,因此可直接使用。
Nginx负载均衡反向代理相关实践
1.实现为WWW服务代理
Nginx的实际配置如下:
[root@lb01 conf]# cat nginx.conf
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
upstream www_pools {
server 10.0.0.7:80 weight=1;
server 10.0.0.8:80 weight=1;
}
server {
listen 80;
server_name www.etiantian.org;
location / {
proxy_pass http://www_pools;
}
}
}
现在配置hosts解析到代理的IP或VIP上,然后重新加载服务,访问测试:
[root@lb01 nginx]$ cat conf/nginx.conf
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
upstream www_pools {
server 192.168.3.101:80 weight=1;
server 192.168.3.99:80 weight=1;
}
server {
listen 80;
server_name bbs.yeye.com;
location / {
proxy_pass http://www_pools;
}
}
}
测试结果如下:
这里有个问题,访问bbs显示的是www的内容。下面再说明
反向代理多虚拟主机节点服务器企业案例
对于上述问题原因是,用户访问域名时确实携带了bbs.yeye.com主机头请求Nginx反向代理服务器,但是反向代理向下面节点重新发起请求时,默认并没有在请求头里告诉节点服务器要找哪台虚拟主机,所以,Web节点服务器接收到请求后发现没有主机头信息,因此,就把节点服务器的第一个虚拟主机发给了反向代理(而节点上的第一个虚拟主机放置的是www)。解决这个问题的办法,就是当反向代理向后重新发起请求时要携带主机头信息,以明确告诉节点服务器要找哪个虚拟主机。具体的配置很简单,就是在Nginx代理WWW服务虚拟主机配置里增加如下一行配置:
proxy_set_header Host $host;
在代理向后端服务器发送的HTTP请求头中加入host字段信息后,若后端服务器配置有多个虚拟主机,它就可以识别代理的是哪个虚拟主机。这是节点服务器多虚拟主机时的关键配置。整个Nginx代理配置如下:
[root@lb01 nginx]$ cat conf/nginx.conf
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
upstream www_pools {
server 192.168.3.101:80 weight=1;
server 192.168.3.99:80 weight=1;
}
server {
listen 80;
server_name bbs.yeye.com;
location / {
proxy_pass http://www_pools;
proxy_set_header Host $host;
#<==在代理向后端服务器发送的HTTP请求头中加入host字段信息,用于当后端服务器配置 有多个虚拟主机时识别代理的是哪个虚拟主机。这是节点服务器多虚拟主机时的关键配置。
}
}
}
此时,再重新加载Nginx服务,并用进行测试检查,如下:
经过反向代理后的节点服务器记录用户IP的企业案例
如果需要在虚拟主机的访问日志的第一个字段记录的客户端的IP,而是反向代理服务器本身的IP,最后一个字段也是一个“-”,只需增加如下一行参数即可:
proxy_set_header X-Forwarded-For $remote_addr;
#<==这是反向代理时,节点服务器获取用户真实IP的必要功能配置。
在反向代理请求后端节点服务器的请求头中增加获取的客户端IP的字段信息,然后节点后端可以通过程序或者相关的配置接收X-Forwarded-For传过来的真实用户的IP信息。
解决上述问题的整个Nginx代理配置如下:
[root@lb01 nginx]$ cat conf/nginx.conf
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
upstream www_pools {
server 192.168.3.101:80 weight=1;
server 192.168.3.99:80 weight=1;
}
server {
listen 80;
server_name bbs.yeye.com;
location / {
proxy_pass http://www_pools;
proxy_set_header Host $host; #<==在代理向后端服务器发送的HTTP请求头中加入host字段信息,用于当后端服务器配置 有多个虚拟主机时识别代理的是哪个虚拟主机。这是节点服务器多虚拟主机时的关键配置。
proxy_set_header X-Forwarded-For $remote_addr; #<==在代理向后端服务器发送的HTTP请求头中加入X-Forwarded-For字段信息,用于后端服务器程序、日志等接收记录真实用户的IP,而不是代理服务器的IP。
}
}
}
重新加载Nginx反向代理服务,但是特别注意,虽然反向代理已经配置好了,但是节点服务器需要的访问日志如果要记录用户的真实IP,还必须进行日志格式配置,这样才能把代理传过来的X-Forwarded-For头信息记录下来,具体配置如下:
[root@web02 nginx]# cat conf/nginx.conf
worker_processes 1;
error_log logs/error.log;
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"'; #<==就是这里的"$http_x_forwarded_for"’参数,如果希望在第一行显示,可以替换掉第一行的
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
include extra/01_www.conf;
include extra/02_bbs.conf;
include extra/03_status.conf;
include extra/04_blog.conf;
}
测试结果如下:
关于X-Forwarded-For的详细说明,可见http://en.wikipedia.org/wiki/X-Forwarded-For。下表是Nginx反向代理相关重要基础参数的总结,供参考。
如果参数众多,最好把这些参数放到同一个配置文件里,然后用include方式包含到虚拟主机配置里,效果如下:
[root@lb01 nginx]$ cat conf/nginx.conf
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
upstream www_pools {
server 192.168.3.101:80 weight=1;
server 192.168.3.99:80 weight=1;
}
server {
listen 80;
server_name bbs.yeye.com;
location / {
proxy_pass http://www_pools;
include proxy.conf; #<==这就是包含的配置。
}
}
}
proxy.conf文件的路径是/application/nginx/conf/
[root@lb01 conf]# cat proxy.conf #<==把参数写成一个文件,使用include包含,看起来更简洁、规范。
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_connect_timeout 60;
proxy_send_timeout 60;
proxy_read_timeout 60;
proxy_buffer_size 4k;
proxy_buffers 4 32k;
proxy_busy_buffers_size 64k;
proxy_temp_file_write_size 64k;
更多Nginx反向代理参数说明参见http://nginx.org/en/docs/http/ngx_http_proxy_module.html。
各类型代理转发实现示例
图11-10为企业常见的动静分离集群架构图,此架构图适合网站前端只使用同一个域名提供服务的场景。例如,用户访问的域名是www.etiantian.org,当用户请求www.etiantian.org/upload/xx地址的时候,代理会分配请求到上传服务器池(upload_pools)处理数据;当用户请求www.etiantian.org/static/xx地址的时候,代理会分配请求到静态服务器池(static_pools)请求数据;当用户请求www.etiantian.org/x地址的时候,即不包含上述指定的目录地址路径时,代理会分配请求到默认的动态服务器池请求数据(注意:上面的x表示任意路径)。
2.准备:案例配置实战先进行企业案例需求梳理:❑ 当用户请求www.etiantian.org/upload/x地址时,实现由上传服务器池(upload_pools)处理请求。❑ 当用户请求www.etiantian.org/static/x地址时,实现由静态服务器池(static_pools)处理请求。❑ 除此以外,对于其他访问请求全部由默认的动态服务器池(default_pools)处理请求。了解了需求后,就可以进行upstream模块服务器池的配置了。static_pools为静态服务器池,有一个服务器,地址为10.0.0.7,端口为80。
upstream static_pools {
server 10.0.0.7:80 weight=1;
}
upload_pools为上传服务器池,有一个服务器,地址为10.0.0.8,端口为80。
upstream upload_pools {
server 10.0.0.8:80 weight=1;
}
default_pools为默认的服务器池,即动态服务器池,有一个服务器,地址为10.0.0.9,端口为80。
upstream default_pools {
server 10.0.0.9:80 weight=1;
}
下面利用location或if语句把不同的URI(路径)请求分给不同的服务器池处理,具体配置如下。方案1:以location方案实现。将符合static的请求交给静态服务器池static_pools,配置如下:
location /static/ {
proxy_pass http://static_pools;
include proxy.conf;
}
将符合upload的请求交给上传服务器池upload_pools,配置如下:
location /upload/ {
proxy_pass http://upload_pools;
include proxy.conf;
}
不符合上述规则的请求,默认全部交给动态服务器池default_pools,配置如下:
location / {
proxy_pass http://default_pools;
include proxy.conf;
}
方案2:以if语句实现。
if ($request_uri ~* "^/static/(.*)$")
{
proxy_pass http://static_pools/$1;
}
if ($request_uri ~* "^/upload/(.*)$")
{
proxy_pass http://upload_pools/$1;
}
location / {
proxy_pass http://default_pools;
include proxy.conf;
}
下面以方案1为例进行讲解,Nginx反向代理的实际配置如下:
[root@lb01 conf]# cat nginx.conf
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
upstream static_pools {
server 10.0.0.7:80 weight=1;
}
upstream upload_pools {
server 10.0.0.8:80 weight=1;
}
upstream default_pools {
server 10.0.0.9:80 weight=1;
}
server {
listen 80;
server_name www.etiantian.org;
location / {
proxy_pass http://default_pools;
include proxy.conf;
}
location /static/ {
proxy_pass http://static_pools;
include proxy.conf;
}location /upload/ {
proxy_pass http://upload_pools;
include proxy.conf;
}
}
}
重新加载使配置生效,不要立刻测试成果,为了实现上述代理的测试,还需要在Web节点上做的测试配置,才能更好地展示测试效果。
提示:测试的上传地址为http://www.etiantian.org/upload/index.html,注意,是带upload路径的地址。
以Web03作为动态服务节点,地址端口为10.0.0.9:80,同样需事先配置一个默认的地址页面,并测试访问,确定它会返回正确结果。操作步骤如下:
[root@lb01 conf]# nginx -t
nginx: the configuration file /application/nginx-1.16.0/conf/nginx.conf
syntax is ok
nginx: configuration file /application/nginx-1.16.0/conf/nginx.conf test is
successful
[root@lb01 conf]# nginx -s reload
以上准备了3台Web节点服务器,分别加入到了upstream定义的不同服务器池,代表3组不同的业务集群组,从本机通过hosts解析各自的域名和IP,然后测试访问,其地址和实际访问的内容输出请对照表11-7。表11-7 测试节点信息及访问效果
测试结果: