Nginx 是一个高性能的 HTTP 和反向代理服务器,同时也能作为邮件代理服务器。虽然 Nginx 常被用于处理 HTTP 请求,但它同样支持四层负载均衡。下面是对 Nginx 四层负载均衡的一些关键点的详细阐述:
什么是四层负载均衡?
四层负载均衡(L4 Load Balancing)是在传输层(TCP/UDP)进行的负载均衡,它主要通过网络协议的 IP 地址和端口号来分发请求。与传统的七层负载均衡(L7)不同,后者针对的是应用层的 HTTP 或 HTTPS 请求。
Nginx 四层负载均衡的工作原理
-
TCP/UDP 处理:Nginx 能够通过
stream
模块处理 TCP 和 UDP 协议的数据包。在四层代理模式下,Nginx 只关注数据包的源/目的地址和端口,而不解析内容。 -
转发请求:当 Nginx 接收到请求时,会根据配置的负载均衡策略(如轮询、最少连接等)选择后端服务器,将请求转发到相应的服务器上。
-
状态检查:可以设置健康检查以确保仅将请求转发到可用的后端服务器。
配置示例
下面是一个简单的 Nginx 四层负载均衡的配置示例:
stream {
upstream backend {
server 192.168.1.100:9000;
server 192.168.1.101:9000;
server 192.168.1.102:9000;
}
server {
listen 9000; # Nginx 监听的端口号
proxy_pass backend; # 转发请求到 upstream
}
}
配置选项
-
负载均衡策略:
least_conn
:将新连接分配给当前连接最少的服务器。ip_hash
:根据客户端 IP 地址分配请求,确保同一 IP 的请求总是转发到同一后端服务器。
-
连接限制:
- 可以设置每个后端服务器的最大连接数,以避免某个服务器超载。
-
健康检查:
- 可以利用其他工具(如 Consul、Keepalived)与 Nginx 配合实现。
优点与缺点
优点:
- 性能高:直接在传输层处理请求,开启了高效的连接处理机制,能够处理大量并发请求。
- 简单性:不需要解析请求内容,减少了 CPU 和内存开销。
缺点:
- 灵活性差:无法进行复杂的请求处理和重写。
- 缺失的功能:无法支持基于内容的负载均衡(如 URL 路径、请求头等)。
总结
Nginx 的四层负载均衡用于处理 TCP/UDP 请求,适合需要高性能且简单的负载均衡需求。掌握 Nginx 的四层负载均衡配置可以帮助在流量激增时有效地分配资源并提升可用性。
案例一:端口转发
案例目标:通过访问四层负载均衡服务器,不同的端口,转发到规定的端口,例如转发到22端口实现登录。
步骤一: 安装负载均衡服务器,安装nginx。
步骤二: 配置nginx,由于四层负载均衡是在传输层通过TCP/IP去传输,所以该配置文件不应该和七层负载均衡一样放在http层。
....
events {
worker_connections 1024;
}
include /etc/nginx/conf.c/*.conf;
http {
include
.....
如上述代码第6行所示,四层负载均衡的配置应当在http层外。
stream {
upstream lb {
server 10.0.0.4:22;
}
server {
listen 2222; # Nginx 监听的端口号
proxy_pass lb; # 转发请求到 upstream
}
upstream web01{
server 172.16.1.7:22;
}
server {
listen 3333;
proxy_pass web01;
}
}
如上述代码所示,四层负载的配置基础配置,以实现通过服务器10.0.0.4监听不同的端口实现跳转到22端口进行登录。
其中Nginx起到的是类似路由器的作用,
-
网络拓扑:
- Nginx 实际上是处于外网和内网之间的一个网关。它能够接收来自外网的请求,并向内网服务器转发这些请求。
- 因为 Nginx 在内网可直接访问
172.16.1.7
,所以它可以向这个内网地址发送 SSH 请求。
-
SSH 请求:经过 Nginx 的处理,SSH 请求会被转发到内网服务器,内网服务器的响应通过 Nginx 返回给外部客户端。
-
端口映射:Windows 客户端并不是直接连接到
172.16.1.7
,而是通过 Nginx 连接到外网的nginx服务器IP:3333
。Nginx 会处理这个请求并与内网的 SSH 服务器进行通信。 -
Nginx 反向代理:Nginx 在此充当反向代理,它接收外部请求,并把它们转发到内网的 SSH 服务器,然后将服务器的响应返回给外部客户端,这样用户就可以通过外网访问内网服务
案例二:业务转发
stream {
upstream lb {
server 172.16.1.5:80;
server 172.16.1.5:80;
}
server {
listen 80;
proxy_connect_timeout 3s;
proxy_timeout 3s;
proxy_pass lb;
}
}
通过监听80端口,将请求转发到内网后端服务器上的web服务。
案例三:单台实现动静分离
步骤一: 部署Java
yum -y install java
步骤二: 部署tomcat
wget https://dlcdn.apache.org/tomcat/tomcat-10/v10.1.28/bin/apache-tomcat-10.1.28.tar.gz
步骤三: 配置nginx代理tomcat服务
tomcat的默认端口是8080
server{
listen 80;
server_name www.tomcat.com;
location / {
proxy_pass http://127.0.0.1:8080;
}
}
步骤四: 静态文件拆分
将tomcat默认页面中的图片文件拆分出来
server{
listen 80;
server_name www.tomcat.com;
location / {
proxy_pass http://127.0.0.1:8080;
}
locatin ~ \.(jpg|png|svg) {
root /code/images;
}
}
当客户端访问tomcat
时其中的图片静态资源将被重新定向到/code/images
下,但是要考虑一个问题就是,当静态资源的图片被移动到/code/images
目录下,由于nginx
是用www
用户运行的,当客户端想要访问静态资源时,该目录及以下的权限要和nginx
的运行用户一致。
案例四:动静分离实战
步骤一:环境准备
系统 | 作用 | 服务 | 地址 |
---|---|---|---|
麒麟 | 负载均衡 | nginx proxy | 10.0.0.5 |
麒麟 | 动态资源 | tomcat server | 10.0.0.7 |
麒麟 | 静态资源 | nginx static | 10.0.0.8 |
步骤二:动态资源准备
yum -y install java
wget https://dlcdn.apache.org/tomcat/tomcat-10/v10.1.28/bin/apache-tomcat-10.1.28.tar.gz
ln -s apache-tomcat-10.1.28/ tomcat
cat /usr/local/tomcat/webapps/ROOT/java.jsp
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<HTML>
<HEAD>
<TITLE>oldboy JSP Page</TITLE>
</HEAD>
<BODY>
<%
Random rand = new Random();
out.println("<h1>oldboy随机数:<h1>");
out.println(rand.nextInt(99)+100);
%>
</BODY>
</HTML>
启动tomcat
步骤三:静态资源准备
server {
listen 80;
server_name pic.lzy.com;
root /code;
index index.html;
location ~* .*\.(jpg|png|gif)$ {
root /code/images;
}
}
步骤四:负载均衡实现调度
upstream static {
server 172.16.1.7:80;
}
upstream java {
server 172.16.1.8:8080;
}
server {
listen 80;
server_name pic.lzy.com;
location ~* \.(jpg|png|gif)$ {
proxy_pass http://static;
proxy_set_header Host $http_host;
}
location ~ \.jsp {
proxy_pass http://java;
proxy_set_header Host $http_host;
}
}
步骤五:将动态页面和静态页面集成到负载均衡的index.html的首页
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>测试ajax和跨域访问</title>
<script src="http://libs.baidu.com/jquery/2.1.4/jquery.min.js"></script>
</head>
<script type="text/javascript">
$(document).ready(function(){
$.ajax({
type: "GET",
url: "http://pic.lzy.com/java.jsp",
success: function(data){
$("#get_data").html(data)
},
error: function() {
alert("哎呦喂,失败了,回去检查你服务去~");
}
});
});
</script>
<body>
<h1>测试动静分离</h1>
<img src="http://pic.lzy.com/4.png">
<div id="get_data"></div>
</body>
</html>
步骤六:设置默认访问页面
upstream static {
server 172.16.1.7:80;
}
upstream java {
server 172.16.1.8:8080;
}
server {
listen 80;
server_name pic.lzy.com;
root /code
index index.html
location ~* \.(jpg|png|gif)$ {
proxy_pass http://static;
proxy_set_header Host $http_host;
}
location ~ \.jsp {
proxy_pass http://java;
proxy_set_header Host $http_host;
}
}
案例五 按照客户端转发到不同业务
案例目标:简单的实现按照不同的客户端转发不同的业务。
步骤一:环境准备
系统版本 | 主机角色 | 外网IP | 内网IP | 提供端口 |
---|---|---|---|---|
麒麟 | 负载均衡 | 10.0.0.5 | 172.16.1.5 | 80 |
麒麟 | 提供Android页面 | 172.16.1.7 | 9090 | |
麒麟 | 提供Iphone页面 | 172.16.1.7 | 9091 | |
麒麟 | 提供pc页面 | 172.16.1.7 | 9092 |
步骤二:在web01上通过多端口实现不同的业务
server {
listen 9090;
server_name _;
location / {
root /code/m/android;
index index.html;
}
}
server {
listen 9091;
server_name _;
location / {
root /code/m/iphone;
index index.html;
}
}
server {
listen 9092;
server_name _;
location / {
root /code/m/pc;
index index.html;
}
}
mkdir -p /code/m/{android,iphone,pc}
echo android.... > /code/m/android
echo pc... > /code/m/pc
echo iphone... > /code/m/iphone
步骤三:Nginx根据客户端UA的信息来决定转发到具体的业务
什么是UA,当我们在看/etc/nginx/nginx.conf
中的http模块中的访问日志格式,如下所示的配置中log_fomat
中的$http_user_agent
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
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;
keepalive_timeout 65;
#gzip on;
include /etc/nginx/conf.d/*.conf;
charset utf-8,gbk;
}
利用负载均衡服务器根据内置变量的UA进行转发
upstream android {
server 172.16.1.7:9090;
}
upstream iphone {
server 172.16.1.7:9091;
}
upstream pc {
server 172.16.1.7:9092;
}
server {
listen 80;
server_name sj.lzy.com;
charset 'utf-8';
location / {
#如果客户端来源是Android则跳转到Android的资源;
if ($http_user_agent ~* "Android") {
proxy_pass http://android;
}
#如果客户端来源是Iphone则跳转到Iphone的资源;
if ($http_user_agent ~* "Iphone") {
proxy_pass http://iphone;
}
#如果客户端是IE浏览器则返回403错误;
if ($http_user_agent ~* "MSIE") {
return 403;
}
#默认跳转pc资源;
proxy_pass http://pc;
}
}