基于 Nginx 的七层负载均衡实现初步
0x01 此次演示环境1
2
3
4NginxHttp ip: 192.168.3.49 作为负载均衡器,测试域名为 `lb.org`,生产环境中,最好自己新建个虚拟ip来做负载均衡,方便后续迁徙
OldLamp ip: 192.168.3.45 后端真实处理请求的web服务器 httpd-2.2.34
OldLnmp ip: 192.168.3.42 后端真实处理请求的web服务器 nginx-1.12.2
NewLnmp ip: 192.168.3.43 作为访问客户端,测试各种负载均衡算法是否工作
先改下当前nginx负载均衡器的host解析,即NginxHttp
机器,因为等会儿要直接用机器名去访问后端的web节点1
2
3# vi /etc/hosts
192.168.3.42 test.bwapp.org bwapp.org
192.168.3.45 bwapp.cc www.bwapp.cc
再来改下Newlnmp机器
的host解析,添加如下内容,因为等会儿要用它来进行测试访问1
2# vi /etc/hosts
192.168.3.49 lb.org
0x02 以下是一些常用的负载均衡调度算法1
2
3
4
5
6rr [ 正常轮询 ] 即按照事先给定的后端节点顺序挨个轮询,适合性能相近,业务相同的场景
wrr [ 权重轮询 ] 即按照事先设置好的后端节点轮询比例,进行轮询,适合机器性能差距较大,业务相同的场景
ip_hash [ ip hash ] 也就是说只要客户端ip不变,在一段时间内就只访问固定的后端节点,`常用于会话保持`,如session,cookie,不过这样保持,负载就不均衡了
fair [ 动态算法 ] 属于第三方算法,即根据节点的响应时间来分配请求,响应快的节点优先分配
url_hash [ 节点取模 ] 也属于第三方节点,根据url来分配后端节点,命中率比较低,不过非常适合做web缓存
一致性 hash ...
0x03 在 nginx 中可用来实现负载均衡的主要模块1
2upstream 模块 定义好后端节点及所使用调度算法,大致工作过程是这样的,它会先读取upstream中的配置,然后通过server标签中的proxy_pass来进行实际的调用
http_proxy 模块 主要负责实际的转发行为
0x04 先在用来做负载均衡的机器上安装好 nginx 1.12.21
2
3
4
5
6
7
8
9
10
11
12
13# yum install pcre pcre-devel openssl openssl-devel -y
# useradd -s /sbin/nologin -M nginx
# wget http://nginx.org/download/nginx-1.12.2.tar.gz
# tar xf nginx-1.12.2.tar.gz
# cd nginx-1.12.2
# ./configure --prefix=/usr/local/nginx-1.12.2 --user=nginx --group=nginx \
--with-http_ssl_module \
--with-http_stub_status_module \
--with-http_gzip_static_module \
--with-mail_ssl_module
# make && make install
# ln -s /usr/local/nginx-1.12.2/ /usr/local/nginx
0x05 关于上述两个模块的简单使用样例1
upstream 模块,主要用来定义后端的真实web服务器节点和要使用的调度算法,配置详情如下
1 | upstream backend { # 先定义好后端web节点 |
1 | http_proxy 模块,主要负责请求转发,但转发的方式有很多种,不过用nginx做反向代理通常会使用 `proxy_pass` |
1 | server { # 此时再到指定的server标签段中去引用刚刚的定义,即可实现简单的负载均衡效果 |
0x06 接下来,开始真正在nginx上配置负载均衡及反向代理1
2
3
4
5# mkdir /usr/local/nginx/conf/extra/
# cd /usr/local/nginx/conf/
# mv nginx.conf nginx.conf.bak
# egrep -v "^$|#" nginx.conf.bak > nginx.conf
# vi /usr/local/nginx/conf/nginx.conf
先在nginx.conf
文件中定义好如下配置,这里先以正常轮询为例进行演示1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23# vi /usr/local/nginx/conf/nginx.conf
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
log_format main '$remote_addr - $remote_user [$time_local] '
' "$request" $status $body_bytes_sent '
' "$http_referer" "$http_user_agent" "$http_x_forwarded_for" ';
include extra/lb.conf;
upstream server_pools{ # 设置后端web节点,可同时规定好要使用的轮询算法
server test.bwapp.org:80;
server www.bwapp.cc:80;
}
}
然后再到 lb.conf
文件中去定义好要进行负载均衡的域名,即[server标签段]
,引用上面nginx.conf文件中upstream定义好的后端web节点1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16# vi /usr/local/nginx/conf/extra/lb.conf
server{
listen 80;
server_name lb.org;
location / {
# 下面的语句就表示把请求转发到指定的后端web节点上
proxy_pass http://server_pools;
# 在往后端抛的时候务必要带上主机头,因为后端的web节点是根据这个主机头来确定,是哪个虚拟机主机
proxy_set_header Host $host;
# 另外,记得要把原始客户端ip也带上,不然后端web节点日志中的就只能记录到负载均衡器的ip,而没有客户端的真实ip
proxy_set_header X-Forwarded-For $remote_addr;
}
}
0x07 nginx 负载均衡基本工作流程简述1
2
3
4当客户端访问 `lb.org` 域名时请求会最先到达负载均衡器,负载均衡器就会去读取自己server标签段中的配置
到location里面一看,原来这是一个要往后端web节点抛的请求
而后,nginx通过 `server_pools` 在自己的主配置文件找到了事先定义好的后端web节点
最后,按照事先设置好的轮询算法,把请求带上主机头和客户端原始ip一起抛给后端准备好的web服务器
0x08 所配置完成之后,我们回到NewLnmp机器上进行轮询测试,看访问是否正常1
2# /usr/local/nginx/sbin/nginx -t
# /usr/local/nginx/sbin/nginx
在你没指定负载均衡算法的情况下,默认是按照事先定义好的后端web节点顺序逐个轮询的,如下1
# for i in `seq 10`; do curl lb.org;sleep 1 ;done
接下来,我们让它权重轮询看看,定义方法很简单,只需要把前面http标签段的内容修改为下面这个样子即可1
2
3
4
5
6
7
8http {
...
upstream server_pools{
server test.bwapp.org:80 weight=3; # 设置权重比例
server www.bwapp.cc:80;
}
...
}
最后,再去看看基于ip hash的轮询算法是个什么样子1
2
3
4
5
6
7
8
9http {
...
upstream server_pools{
ip_hash; # 基于ip hash的轮询算法
server test.bwapp.org:80;
server www.bwapp.cc:80;
}
...
}
0x09 最后,再回到OldLamp和OldLnmp 机器上看看日志有没有被正确记录到1
# tail -f /usr/local/httpd/logs/bwapp-access_20171204.log
1 | # tail -f /usr/local/nginx/logs/access_bwapp.log |
小结:
这里提到的只是一部分,更详细具体的用法,请直接参考nginx官方文档,另外,nginx负载均衡较适合用于日pv 2000W以下的站点