目录
[1、部署 Nginx 负载均衡器](#1、部署 Nginx 负载均衡器)
[2、部署 2 台 Tomcat 应用服务器](#2、部署 2 台 Tomcat 应用服务器)
一、Nginx与Tomcat概述
1、Nginx应用
Nginx 是一款非常优秀的 HTTP 服务器软件,广泛应用于大型网站的后端。
它支持高达 50,000 个并发连接,并拥有强大的静态资源处理能力。
Nginx 的运行非常稳定,系统资源(如内存和 CPU)的消耗也非常低。因此,许多大型网站选择 Nginx 作为反向代理服务器和负载均衡器,以提升整个站点的负载并发能力。
2、正向代理和反向代理
2.1、正向代理
**正向代理:**是指代理服务器替客户端访问目标服务器,以加快访问速度或突破访问限制。客户端可以访问代理服务器,而代理服务器再去访问目标服务器,并将返回数据传递给客户端。目标服务器只知道请求来自代理服务器,但不清楚实际客户端的地址,因此正向代理可以隐藏客户端的信息。
正向代理的工作原理类似于"跳板":当用户无法直接访问某个网站时,用户可以先连接到能够访问该网站的代理服务器,由代理服务器代为获取网站内容,再将内容返回给用户。目标网站只能记录代理服务器的访问,而不一定知道是用户的请求,这取决于代理服务器是否向网站透露用户信息。
作用:
-
突破访问限制:当客户端因网络限制无法直接访问某个目标服务器时,正向代理可以帮助客户端绕过这些限制,通过代理服务器访问目标服务器。常见的应用场景包括访问地理限制的网站或绕过公司内网的访问限制。
-
加速访问:通过正向代理,客户端可以选择更接近目标服务器的代理,从而缩短请求的传输距离,提升访问速度。
-
隐藏客户端信息:正向代理可以隐藏客户端的 IP 地址和其他信息,使目标服务器无法识别请求的真实来源。对于需要保护隐私的用户或希望隐藏真实位置的应用场景,正向代理非常有用。
-
缓存功能:正向代理服务器通常会缓存访问过的数据。当客户端请求相同的内容时,代理服务器可以直接返回缓存数据,从而减少访问延迟和带宽消耗。
-
访问控制和日志管理:正向代理可以用来对客户端的访问行为进行监控和控制,例如限制某些用户访问特定网站或记录用户的访问日志。
2.2、反向代理
**反向代理:**则是代理服务器替服务器端处理客户端请求,通常用于负载均衡。反向代理屏蔽了后端服务器的信息,常用于多台服务器的分布式部署。对于访问量大的网站,反向代理服务器可以根据一定规则将客户端的请求分发到不同的后端服务器,客户端无需知道具体是哪台服务器处理了请求。
作用:
-
负载均衡:反向代理可以根据一定的算法(如轮询、最小连接数、加权轮询等)将客户端的请求分发到多个后端服务器,以平衡各服务器的负载,避免单一服务器过载,提升系统的整体性能和稳定性。
-
隐藏服务器信息:反向代理可以屏蔽后端服务器的真实 IP 地址和其他信息,所有请求都先经过反向代理,这样客户端只看到代理服务器,而不知道真正提供服务的后端服务器。这种机制有助于增强系统的安全性,减少攻击者直接攻击后端服务器的机会。
-
SSL 卸载:反向代理服务器可以承担 SSL/TLS 加密的处理任务,从而减轻后端服务器的负担。反向代理接收到客户端的加密请求后,可以在代理服务器处解密,并将解密后的请求传递给后端服务器。对于需要大量处理加密请求的应用场景,这种方式可以显著提高系统效率。
-
缓存功能:反向代理可以缓存后端服务器的响应数据。当多个客户端请求相同的内容时,代理服务器可以直接返回缓存的数据,而不需要每次都向后端服务器请求,减少后端服务器的负担,提高响应速度。
-
安全防护:反向代理可以作为第一道防线,阻止恶意请求直接到达后端服务器。例如,可以通过设置访问控制规则、过滤恶意流量、检测并阻止 DDoS 攻击等手段来保护后端服务器的安全。
-
内容分发和加速:反向代理常用于内容分发网络(CDN),将内容分发到更接近用户的服务器节点上,从而加快内容的交付速度。此外,反向代理可以将不同类型的请求分发到专门的服务器上处理(如静态内容和动态内容分离),进一步提升效率。
Nginx 常用于反向代理,借助它可以有效提升网站的处理能力,确保高并发情况下的稳定运行。
3、负载均衡模式
①、轮询
**轮询算法:**是 Nginx 的默认分流算法。它按顺序将请求依次分配给每一台后端服务器,直到最后一台服务器,然后重新从第一台服务器开始。这种方法简单且均匀地分配了流量。
- 数据流向:每个请求依次被分配到下一个服务器。假设有三台服务器(Server A、Server B、Server C),第一个请求被分配到 Server A,第二个请求分配到 Server B,第三个请求分配到 Server C,第四个请求又回到 Server A,依此类推。
- 特点:请求均匀分布,无视服务器的当前负载和响应时间。
配置示例:
cpp
upstream backend {
server backend1.example.com;
server backend2.example.com;
server backend3.example.com;
}
②、最少连接数
**最少连接数算法:**将请求分配给当前活动连接数最少的服务器。这种算法适用于请求处理时间不均匀的情况,可以有效平衡服务器的负载。
- 数据流向:每个请求被分配到当前连接数最少的服务器。例如,Server A 有 2 个连接,Server B 有 5 个连接,新的请求会被分配到 Server A。
- 特点:动态均衡负载,适用于请求处理时间不一的场景。
配置示例:
cpp
upstream backend {
least_conn;
server backend1.example.com;
server backend2.example.com;
server backend3.example.com;
}
③、IP 哈希
**IP 哈希算法:**通过计算客户端 IP 地址的哈希值,将请求始终分配给同一台服务器。适用于需要将特定客户端的请求固定在同一台服务器上的场景。
- 数据流向:每个客户端的 IP 地址被哈希计算,然后根据哈希值将请求固定分配到某一台服务器。假设客户端 X 的哈希值指向 Server A,客户端 Y 的哈希值指向 Server B,则无论多少次请求,X 的请求总是流向 Server A,Y 的请求总是流向 Server B。
- 特点:同一个客户端总是被分配到同一台服务器,有助于会话保持。
配置示例:
cpp
upstream backend {
ip_hash;
server backend1.example.com;
server backend2.example.com;
server backend3.example.com;
}
④、加权轮询
**加权轮询算法:**允许为每台服务器设置权重,权重越大的服务器将会获得更多的请求。适用于服务器性能不均衡的情况。
- 数据流向:根据服务器设置的权重值分配请求。假设 Server A 权重为 3,Server B 权重为 1,则 4 个请求中,3 个会被分配到 Server A,1 个会被分配到 Server B。
- 特点:高权重服务器接收更多的请求,适用于服务器性能差异较大的场景。
配置示例:
cpp
upstream backend {
server backend1.example.com weight=3;
server backend2.example.com weight=1;
server backend3.example.com weight=2;
}
⑤、最少时间算法
**最少时间算法:**基于请求的响应时间,将请求分配给响应时间最短的服务器。这种算法适用于需要最大化响应速度的场景,在 Nginx 1.15.3 及以后版本中可用。
- 数据流向:每个请求分配到响应时间最短或平均连接时间最短的服务器。假设 Server A 的响应时间较快,Server B 较慢,则新的请求更可能流向 Server A。
- 特点:进一步优化了最少连接算法,适用于高负载环境下的动态负载均衡。
配置示例:
cpp
upstream backend {
least_time header;
server backend1.example.com;
server backend2.example.com;
server backend3.example.com;
}
⑥、一致性哈希
**一致性哈希算法:**可以保证当集群中某台服务器故障时,只有部分请求会重新分配到其他服务器,而不是全部重新分配。这在缓存等场景中非常有用。
- 数据流向:根据请求的某个特定参数(如 URL、Cookie 或其他 Header),进行哈希计算,将请求分配到哈希值对应的服务器。假设 Server A 和 Server B,参数 "foo" 的哈希值指向 Server A,参数 "bar" 的哈希值指向 Server B,则 "foo" 请求总是流向 Server A,"bar" 请求总是流向 Server B。
- 特点:适应服务器节点变动,减少请求的重新分配,适合缓存敏感的场景。
配置示例 (需要第三方模块如 ngx_http_upstream_hash_module
):
cpp
upstream backend {
hash $request_uri consistent;
server backend1.example.com;
server backend2.example.com;
server backend3.example.com;
}
二、规划部署负载均衡和反向代理
1、部署 Nginx 负载均衡器
关闭防火墙和临时防护:
cpp
systemctl stop firewalld
setenforce 0
安装所需的依赖包:
cpp
yum -y install pcre-devel zlib-devel openssl-devel gcc gcc-c++ make
创建 Nginx 用户:
cpp
useradd -M -s /sbin/nologin nginx
下载并解压 Nginx 源码:
cpp
cd /opt
tar zxvf nginx-1.20.2.tar.gz -C /opt/
编译并安装 Nginx:
cpp
cd nginx-1.20.2/
./configure --prefix=/usr/local/nginx \
--user=nginx \
--group=nginx \
--with-file-aio \
--with-http_stub_status_module \
--with-http_gzip_static_module \
--with-http_flv_module \
--with-http_ssl_module \
--with-stream
make && make install
创建软链接:
cpp
ln -s /usr/local/nginx/sbin/nginx /usr/local/sbin/
创建 Nginx 服务文件:
cpp
vim /lib/systemd/system/nginx.service
[Unit]
Description=nginx
After=network.target
[Service]
Type=forking
PIDFile=/usr/local/nginx/logs/nginx.pid
ExecStart=/usr/local/nginx/sbin/nginx
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/bin/kill -s QUIT $MAINPID
PrivateTmp=true
[Install]
WantedBy=multi-user.target
设置权限并启动 Nginx:
cpp
chmod 777 /lib/systemd/system/nginx.service
systemctl start nginx.service
systemctl enable nginx.service
2、部署 2 台 Tomcat 应用服务器
停止防火墙并禁用 SELinux:
cpp
systemctl stop firewalld
setenforce 0
安装 JDK:
cpp
tar zxvf jdk-8u91-linux-x64.tar.gz -C /usr/local/
配置环境变量;
cpp
vim /etc/profile
export JAVA_HOME=/usr/local/jdk1.8.0_91
export JRE_HOME=${JAVA_HOME}/jre
export CLASSPATH=.:${JAVA_HOME}/lib:${JRE_HOME}/lib
export PATH=${JAVA_HOME}/bin:$PATH
加载环境变量:
cpp
source /etc/profile
安装并启动 Tomcat:
cpp
tar zxvf apache-tomcat-8.5.16.tar.gz
mv /opt/apache-tomcat-8.5.16/ /usr/local/tomcat
/usr/local/tomcat/bin/shutdown.sh
/usr/local/tomcat/bin/startup.sh
检查端口占用:
cpp
netstat -ntap | grep 8080
3、动静分离配置
①、Tomcat1 服务器配置
cpp
mkdir /usr/local/tomcat/webapps/test
vim /usr/local/tomcat/webapps/test/index.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<html>
<head>
<title>JSP test1 page</title>
</head>
<body>
<% out.println("动态页面 1,http://www.test1.com");%>
</body>
</html>
修改 server.xml:
cpp
vim /usr/local/tomcat/conf/server.xml
<Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true" xmlValidation="false" xmlNamespaceAware="false">
<Context docBase="/usr/local/tomcat/webapps/test" path="" reloadable="true" />
</Host>
重启 Tomcat:
cpp
/usr/local/tomcat/bin/shutdown.sh
/usr/local/tomcat/bin/startup.sh
②、Tomcat2 服务器配置
创建 JSP 页面:
cpp
mkdir /usr/local/tomcat/tomcat1/webapps/test
vim /usr/local/tomcat/tomcat1/webapps/test/index.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<html>
<head>
<title>JSP test2 page</title>
</head>
<body>
<% out.println("动态页面 2,http://www.test2.com");%>
</body>
</html>
修改 server.xml:
cpp
vim /usr/local/tomcat/tomcat1/conf/server.xml
<Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true" xmlValidation="false" xmlNamespaceAware="false">
<Context docBase="/usr/local/tomcat/tomcat1/webapps/test" path="" reloadable="true" />
</Host>
重启 Tomcat
cpp
/usr/local/tomcat/tomcat1/bin/shutdown.sh
/usr/local/tomcat/tomcat1/bin/startup.sh
③、Nginx 服务器配置
准备静态页面和静态图片:
cpp
echo '<html><body><h1>这是静态页面</h1></body></html>' > /usr/local/nginx/html/index.html
mkdir /usr/local/nginx/html/img
cp /root/game.jpg /usr/local/nginx/html/img
修改 Nginx 配置文件:
cpp
vim /usr/local/nginx/conf/nginx.conf
http {
...
upstream tomcat_server {
server 172.16.88.22:8080 weight=1;
server 172.16.88.33:8080 weight=1;
server 172.16.88.44:8080 weight=1;
}
server {
listen 80;
server_name www.kgc.com;
charset utf-8;
location ~ .*\.jsp$ {
proxy_pass http://tomcat_server;
proxy_set_header HOST $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location ~ .*\.(gif|jpg|jpeg|png|bmp|swf|css)$ {
root /usr/local/nginx/html/img;
expires 10d;
}
location / {
root html;
index index.html index.htm;
}
}
...
}
④、测试
测试静态页面效果:
- 浏览器访问:http://172.16.88.11
- 浏览器访问:http://172.16.88.11/game.jpg
测试负载均衡效果:
- 浏览器访问:http://172.16.88.11/index.jsp (不断刷新浏览器)