文章目录
- 一、 负载均衡分类及特点
- 1.1 负载均衡分类
- 1.2 各层负载均衡的对比
- 二、 负载均衡的实现 - Nginx
- 2.1 Nginx 简介
- 2.2 Nginx 架构与底层原理
- 2.3 Nginx 配置文件
- 2.4 Nginx 负载均衡算法与配置
- 三、 负载均衡的实现 - DNS
负载均衡是一种计算机网络技术,建立在现有网络结构之上,用来在多个计算机(计算机集群)、网络连接、CPU、磁碟驱动器或其它资源中分配负载,以达到最佳化资源使用、最大化吞吐率、最小化响应时间、同时避免过载的目的。
一、 负载均衡分类及特点
1.1 负载均衡分类
根据计算机网络的OSI模型,负载均衡可以分为以下几类:
① 数据链路层负载均衡 Layer 2:
负载均衡服务器对外提供一个Virtual IP(虚拟IP),集群中不同的机器采用相同IP地址,但机器的MAC地址不一样。当负载均衡服务器接受到请求之后,通过改写报文的目标MAC地址的方式将请求转发到目标机器实现负载均衡。
② 网络层负载均衡 Layer 3:
负载均衡服务器对外依然提供一个Virtual IP(虚拟IP),集群中不同的机器采用不同的IP地址。当负载均衡服务器接受到请求之后,根据不同的负载均衡算法,通过IP将请求转发至不同的真实服务器。
③ 传输层IP+Port负载均衡 Layer 4:
由于在传输层,只有TCP/UDP协议,这两种协议中除了包含源IP、目标IP以外,还包含源端口号及目的端口号。负载均衡服务器在接受到客户端请求后,通过修改数据包的地址信息(IP+端口号)将流量转发到应用服务器,并记录下这个TCP或者UDP的流量是由哪台服务器处理的,后续这个连接的所有流量都同样转发到同一台服务器处理。常用的传输层负载均衡为LVS (Linux Virtual Server)
。
④ 应用层负载均衡 Layer 7:
由于应用层应用层协议较多,常用http、DNS等,因此应用层负载均衡根据不同的应用层协议可以有多种不同的负载均衡方式。常用的传输层负载均衡为Nginx
,Haproxy
等。
1.2 各层负载均衡的对比
在各层负载均衡中,Layer 2,Layer 3属性硬件负载均衡,Layer 4,Layer 7属于软件负载均衡。
Q1. Layer 4 和 Layer 7 负载均衡的区别 ?
① 四层负载均衡是基于TCP协议报文,通过TCP/UDP协议中的目的IP和Port,通过负载均衡算法对目的IP和Port进行请求的转发,仅处理消息的传递,但不考虑消息的内容。
② 七层负载均衡是基于HTTP协议/DNS协议的。在四层负载均衡的基础上,可以处理每个消息的实际内容,可以根据消息内容(如URL或cookie)做出负载均衡决策。
二、 负载均衡的实现 - Nginx
2.1 Nginx 简介
Nginx 是一个高性能的 HTTP 服务器和反向代理,以及 IMAP / POP3 代理服务器。
Q1. 代理与反向代理 ?
● 代理服务器是位于客户端和目标服务器的一台中间服务器,为了获取到目标服务器中的内容,客户端向代理服务器发送一个请求并带上目标服务器,代理服务器在接收到请求后就会将请求转发给目标服务器,并将从原始服务器上获取到的数据返回给客户端,代理服务器是代理的客户端,所以客户端是知道代理服务器的存在的。
● 反向代理服务器是位于目标服务器端的服务器,反向代理服务器接收来自互联网的请求,然后将这些请求发送给内网的服务器,并将从内网的服务器获取结果返回给互联网上的客户端,反向代理服务器是代理的服务端,所以客户端是不知道反向代理服务器的存在的,服务端是知道反向代理服务器的。
Q2. Nginx的作用 ?
Nginx主要有三个作用:
●
反向代理
:将内网集群中的多个服务器代理成一台服务器
●
负载均衡
:将多个请求均匀的分配到多台服务器上,减轻每台服务器的压力,提高服务的吞吐量
●
动静分离
:Nginx可以将静态文件缓存到Nginx服务器中,当访问静态文件时无需再请求内部服务器,提高访问速度
2.2 Nginx 架构与底层原理
▍ 2.2.1 Nginx 架构
Nginx在架构上采用模块化的方式构成,除了核心代码,其余均是通过模块的方式组成,如下图所示:
Nginx从功能上分为主进程(master
)、工作进程(worker
)、后端服务器和缓存等部分,如下图所示:
▍ 2.2.2 Nginx 的核心模块与进程模型
1. Nginx 进程模型
Nginx的核心模块是其高性能处理Web请求的基础。Nginx在启动后,会有一个master
进程和多个worker
进程。
● master
进程:master
进程是管理进程,主要用来管理work
进程,不处理网络事件和业务的执行,通过管理worker
进程来实现重启服务、平滑升级、更换日志文件、配置文件实时生效等功能。
● worker
进程:工作进程,处理网络事件和业务的执行。多个worker
进程之间是对等的,他们同等竞争来自客户端的请求,各进程互相之间是独立的。一个请求,只可能在一个worker
进程中处理,一个worker
进程,不可能处理其它进程的请求。worker
进程的个数是可以设置的,一般我们会设置与机器cpu
核数一致。
2. Nginx 事件处理机制
Nginx通过多进程的方式工作,采用异步非阻塞的方式对网络事件进行处理,具体过程如下所示:
① worker
进程创建:在master
进程建立好listen
的socket
(listenfd
套接字)后,通过fork()
创建多个worker
进程(此时worker
进程与master
进程”内容”相同,监听同一个IP和Port)。
② worker
进程接收请求:当client
连接到来时,所有accept
状态的worker
进程的listenfd
变为可读,且都会收到master
信号,但只有一个进程可以accept
成功。Nginx提供一个共享锁accept_mutex
,保证只有一个worker进程建立client连接。所有worker
进程在注册listenfd
读事件前抢占accept_mutex
锁(避免了epoll的惊群问题),抢到锁的进程在epoll
事件集中注册listenfd
读事件,在读事件中调用accept()
建立client
连接。
② worker
进程处理请求:当一个worker
进程accept
客户端连接后,开发读取、解析、处理请求,得到数据后返回给客户端,并断开连接。
Q1. Nginx是如何实现高并发的 ?
① Nginx采用独立进程,相互之间独立,不需要加锁。一个进程退出后,其它进程还在工作,服务不会中断,master
进程则很快重新启动新的worker
进程。
② worker进程个数与CPU核心数相同,避免了worker进程竞争CPU资源,减少了上下文的切换。同时Nginx可以将某一个进程绑定在某一个CPU核上,这样就不会因为进程的切换带来cache的失效。
③ 虽然每个worker进程内只有一个主线程,但Nginx通过epoll实现了请求的异步非阻塞,从而提高了Nginx的高并发。
2.3 Nginx 配置文件
▍ 2.3.1 Nginx 配置文件层次结构
Nginx是通过配置文件来对各个模块进行设置的。Nginx的配置文件nginx.conf
位于其安装目录的conf
目录下。nginx.conf
的文件结构如下图所示:
# Nginx main模块 - 全局配置
user nobody; # user是个主模块指令,指定Nginx Worker进程运行用户以及用户组,默认由nobody账号运行
worker_processes 1; # 指定Nginx运行的进程数,一般与CPU内核数量一致
error_log logs/error.log notice; # 定义全局错误日志文件,日志输出级别由高到低为debug、info、notice、warn、error、crit
access_log logs/access_log notice; # 定义全局请求日志文件
pid logs/nginx.pid; # 指定Nginx进程pid的存储文件位置
worker_rlimit_nofile 65535; # 用于绑定worker进程与CPU
# Nginx events模块 - 设置Nginx的工作模式
events {
use epoll; # Nginx支持的工作模式有select、poll、kqueue、epoll、rtsig和/dev/poll,首选epoll
worker_connections 1024; # 设置每个worker进程的最大连接数,默认为1024。
# 最大客户端连接数 Max_clients = worker_processes × worker_connections,
# 在作为反向代理时 Max_clients = worker_processes × worker_connections / 4
}
# Nginx Http模块 - Http服务器相关配置
http {
include mime.types; # include实现对配置文件所包含的文件的设定,减少主配置文件的复杂度
default_type application/octet-stream; # 设定默认类型为二进制流,没有配置PHP环境时,Nginx不会对PHP文件进行解析
# HttpLog 模块
log_format main ’…’ # 指定Nginx Http的日志输出格式,main为输出日志名称
access_log logs/access.log main; # 对access_log请求日志,使用名称为main的日志输出格式
sendfile on; #设置高效文件传输模式,on - 开启,off - 关闭
tcp_nopush on; # 防止网络阻塞
tcp_nodelay on;
keepalive_timeout 65; # 设置与客户端连接保持活动的超时时间,超过时间则断开连接
client_header_timeout 10; # 设置客户端请求Head读取超时时间,如果超过时间没有发送任何数据,Nginx将返回408错误;
client_body_timeout 10; # 设置客户端请求Body读取超时时间,如果超过时间没有发送任何数据,Nginx将返回408错误;
send_timeout 10; # 响应客户端的时间
client_max_body_size 20m; # 允许客户端请求的单个最大文件;
client_header_buffer_size 32K; # 指定来自客户端请求Head的headerbuffer大小
# HttpGzip 模块 - 支持在线实时压缩输出数据流
gzip on; # 开启或关闭gzip模块
gzip_min_length 1k; # 允许压缩的页面最小字节数,>1K的页面才会被压缩
gzip_buffers 4 16k; # 压缩结果缓存空间 4 × 16K
gzip_http_version 1.1; # Http 协议版本
gzip_comp_level 2; # Gzip 压缩比,1压缩比最小,压缩速度最快,9压缩比最大,传输速度最快
gzip_types text/plain application/x-javascript text/css application/xml; # 指定压缩类型
# Http Upstream - 负载均衡配置
upstream test.com{ # test.com 为负载均衡器名称
ip_hash; # 负载均衡调度算法,每个请求根据IP进行Hash分配,同一个IP会访问到同一个后端服务器
server 192.168.8.11:80;
server 192.168.8.12:80 down;
server 192.168.8.13:8009 max_fails=3 fail_timeout=20s;
server 192.168.8.146:8080;
}
# server虚拟主机配置 - 通常将该配置写在另外一个文件,然后通过include包含进来
server {
listen 80; # 指定虚拟主机的服务端口
server_name localhost; # 指定虚拟主机IP或域名,多个域名之间通过空格分隔
index index.html index.htm index.php; # 设定默认访问的首页地址
root /wwwroot/www.test.com # 指定虚拟主机资源文件的根目录,即在nginx所在文件夹下的wwwroot文件夹
charset gb2312; # 设置网页的默认编码方式
access_log logs/host.access.log main; # 设置虚拟主机的请求日志路径和格式
# URL 匹配设置 - 可以实现对动,静态网页的过滤、实现反向代理、PHP动态解析、负载均衡
# location块 正则匹配说明:
# 匹配优先级:= > (^~) > 正则匹配 > 字符串(长 > 短)
# 1. = 精确匹配;
# 2. ^~ 提高前缀字符串的匹配优先级;
# 3. ~ 区分大小写的正则表达式匹配;
# 4. ~* 不区分大小写的正则表达式匹配;
# 5. / 通用匹配(所有的地址都以 / 开头,这条规则将匹配到所有请求),如果没有其它匹配,任何请求都会匹配到。
# 如果有多个location块被请求到,Nginx选择最长前缀的块
location / { # 通用规则,所有未匹配到的请求都会进入该location
root html;
index index.html index.htm;
}
location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$ { # 将图片静态文件交由Nginx处理,不用访问后端服务器
root /wwwroot/www.test.com; # 静态文件目录
expires 30d; # 设置过期时间为30天
}
location ~ \*.php$ { # 对虚拟主机下的动态网页进行过滤
root html;
fastcgi_pass 127.0.0.1:9000; # 请求交由后端服务器9000端口处理
fastcgi_index index.php;
include fastcgi_params;
}
}
}
▍ 2.3.2 Nginx Location 匹配规则
1. 正则表达式语法
Nginx Location块通过正则表达式进行匹配,其包含5种正则表达式: 【 = 精确匹配】【^~ 提高前缀字符串的匹配优先级】【~ 区分大小写的正则表达式匹配】【~* 不区分大小写的正则表达式匹配】【 / 通用匹配,所有的地址都以 / 开头,如果没有其它匹配,任何请求都会匹配到该规则】
2. 正则表达式匹配规则
正则表达式的匹配优先级为:= > (^~) > 正则匹配 > 字符串(长 > 短)
server{
listen 80;
server_name test.com;
# 1. = 精准匹配,对于路径/test/a/b/c,会精准匹配到第三条结果
location ~ /test/* {
echo '/equal/*';
}
location /test/a/b {
echo '/equal/a/b';
}
location = /test/a/b/c {
echo '/equal/a/b/c';
}
# 2. 普通匹配测试,对于路径/test/a/b/c,会匹配到第三条结果,因为第三条匹配路径最长
location /match/a/b {
return 200 "/match/a/b";
}
location /match/a/b/c {
return 200 "/match/a/b/c";
}
location /match/a/b/c/d {
return 200 "/match/a/b/c/d";
}
# 3. 正则匹配覆盖普通匹配,访问/test/a.htm,会被后面的正则覆盖,即匹配第二条
location /test/a.htm {
echo 'match /re/a.htm';
}
location ~ /test/(.*)\.(htm|js|css)$ {
echo "cover /re/$1.$2";
}
# 4. 正则匹配成功一条后,便不再走其它正则,访问/test/a/b/c.htm,匹配第一条
location ~ /test/.*\.(htm|js|css)$ {
echo "match first";
}
location ~ /test/a/(.*)\.(htm|js|css)$ {
echo "match second";
}
location ~ /test/a/b/(.*)\.(htm|js|css)$ {
echo "match third";
}
}
▍ 2.3.3 Nginx 常用配置
① 普通静态页面HTTP服务器与动静分离
在Web开发过程中,动态资源是指后台服务器的资源,静态资源是指HTML,CSS,img等资源文件。通常都需要将动态资源与静态资源分离,将静态资源部署在Nginx中,当一个请求来的时候,如果是静态资源的请求,就直接到nginx配置的静态资源目录下面获取资源,如果是动态资源的请求,nginx利用反向代理的原理,把请求转发给后台应用去处理,实现动静分离。动静分离可以提升静态资源的访问速度。
server {
listen 80; # 指定虚拟主机的服务端口
server_name localhost; # 指定虚拟主机IP或域名,多个域名之间通过空格分隔
charset gb2312; # 设置网页的默认编码方式
access_log logs/host.access.log main; # 设置虚拟主机的请求日志路径和格式
location / {
root html; //所有的请求都由root处理,返回index.html静态页面
index index.html;
}
# 所有静态请求都由nginx处理,存放目录为wwwroot
location ~ .(gif|jpg|jpeg|png|bmp|swf|css|js)$ {
root wwwroot;
}
# 动态请求转发到后端的服务器,动静分离减轻后端服务器的压力
location ~ \*.php$ { # 对虚拟主机下的动态网页进行过滤
root html;
fastcgi_pass 127.0.0.1:9000; # 请求交由后端服务器9000端口处理
fastcgi_index index.php;
include fastcgi_params;
}
}
② 反向代理 - 将请求转发给第三方处理
反向代理主要用于转发客户机请求,防止外网对内网服务器的恶性攻击、缓存数据以减少服务器的压力,访问安全控制。同时还可以进行负载均衡,将用户请求分配给多个服务器。转发的路径必须是同一个web容器下的url,不能转向到其他的web路径。客户端对服务器的转发是无感知的,其浏览器URL仍然是请求访问的路径。在转发行为下,浏览器只做了一次访问请求。
server {
listen 80;
server_name localhost;
client_max_body_size 1024M;
location / {
proxy_pass http://localhost:8080; //通过proxy_pass转发请求
proxy_set_header Host $host:$server_port; //思路:通过/,将所有的请求,转发给第3方处理
}
}
③ 重定向
重定向通常是访问某个网址时,将该网址导向到另一个网址的过程,使用rewrite
重定向会是浏览器链接发生变化,客户端会根据首次请求返回的location
地址,再次发送一次Http请求。如果location
中有多个重写规则,那么它们会根据flag
选择是否被执行。如果在location
中执行rewrite
产生了新的URI,则说明当前location
确定了一个新的URI,这样rewrite
最多可以执行10次,超过以后nginx将返回500错误。
server {
listen 80;
server_name test.location.com;
location /a.html {
echo 'test a.html';
}
location /b.html {
echo 'test b.html';
}
# 请求路径为:http://test.location.com/aa.html
# break:URL根据rewrite重写后,直接使用重写URL对应的资源,不再执行余下的语句,完成本次请求,地址栏url不变
location /aa.html { # 内部重定向
rewrite ^/ /a.html break; # 重写URL /a.html,并使用location /a.html{...}中对应的资源
rewrite ^/ /b.html break;
root /etc/nginx/html/;
}
# 请求路径为:http://test.location.com/ab.html
# last:URL根据rewrite重写后会马上发送请求,根据重写的URL再次进行location匹配,若超过10次匹配不到报500错误,地址栏URL不变
location /ab.html { # 内部重定向
rewrite ^/ /a.html last; # 重写URL /a.html,并根据重写URL在server中进行匹配Location
rewrite ^/ /b.html last;
rewrite ^/ /c.html;
root /etc/nginx/html/;
}
# 请求路径为:http://test.location.com/ba
location /ba {
rewrite ^/ /b.html permanent; # permanent:返回301永久重定向,地址栏显示重定向后的url,爬虫更新url
root /etc/nginx/html/;
}
# 请求路径为:http://test.location.com/bb
location /bb {
rewrite ^/ /b.html redirect; # redirect:返回302临时重定向,地址栏显示重定向后的url,爬虫不会更新url
set $aa 12;
root /etc/nginx/html/;
}
#此路径请求:http://test.location.com/cc.html
location /cc.html {
rewrite ^/ /c.html; # 指令不停,继续往下
rewrite ^/ /b.html;
rewrite ^/ /a.html; # 最后一条,生效的是这条
root /etc/nginx/html/;
}
}
④ 防盗链
浏览器对资源的获取过程就是对该资源的URL发起一个数据请求的过程,通过html语法指定的格式排列获取到各类资源,最终呈现一个完整的页面。当浏览器获取资源时,拉取非本站(跨站访问)的资源,这就称“盗链”。盗链会使被盗链的服务器资源请求变大,服务器的性能降低。根据HTTP协议,浏览器在加载非本站的资源时,会增加一个头域,头域名字固定为:Referer
。Referer
的作用是指示一个请求是从哪里链接过来,如果当一个请求并不是由链接触发产生的,那么就不需要指定这个请求的链接来源,即Referer
为空。根据Referer
标签,在浏览器(客户端)请求服务端资源时,可以知道本次资源请求的引用者(请求者)是谁,从而根据引用者(请求者)判断是否返回资源。这个过程称为防盗链。
# 过滤出.jpg资源的请求
location ~* \.(jpg)$ {
root html;
# 通过请求的referer字段和valid_referers后面的referer列表进行匹配,
# 如果匹配到了就invalid_referer字段值为0 否则设置该值为1
# 如果没有referer字段,即匹配到none,会访问该资源
valid_referers none blocked 192.168.10.15; # referer列表,匹配到该列表的,可以访问资源。不在列表的请求被转发
if ($invalid_referer){ # 当Referer匹配到时,invalid_referer=0,不会转发到error,否则会转发显示error。
rewrite ^/ http://192.168.10.15/images/error.png;
}
}
⑤ 禁止访问某个目录
在Nginx的Web目录中,可能存在某些配置文件,为了防止用户访问,下载这个关键信息的文件,需要禁止访问某些目录。
location ~* \.(txt|doc)${
root /data/www/wwwroot/test; #所有用户都禁止访问这个目录
deny all;
}
location ~ ^/(uploads|images)/.*\.(php|php5|jsp)$ { # 对于/upload目录的上传文件,如果是.php或.jsp文件,返回403
return 403;
}
2.4 Nginx 负载均衡算法与配置
负载均衡(Load Balance)就是一个任务分摊到多个操作单元上进行执行,从而共同完成工作任务。Nginx支持5种负载均衡算法:
① 轮询: 默认情况下Nginx服务器通过轮询实现负载均衡,轮询策略按照顺序选择组内服务器处理请求。如果一个服务器在处理请求的过程中出现错误,请求会被顺次交给组内的下一个服务器进行处理,以此类推,直到返回正常的响应为止。但如果所有的服务器都出错,则返回最后一个服务器的处理结果。
upstream webserver {
server 192.168.10.1:8080; //后端服务器列表
server 192.168.10.2:8080;
}
② 加权轮询: 为组内服务器设置权重,权重值高的服务器被优先用于处理请求。weight
和访问比率成正比,用于后端服务器性能不均的情况。
upstream webserver {
server 192.168.10.1:8080 weight=2; //后端服务器列表
server 192.168.10.2:8080 weight=1;
}
③ ip_hash: 每个请求按访问IP的哈希结果分配,使来自同一个IP的访客固定访问一台后端服务器,并且可以有效解决动态网页存在的session共享问题。ip_hash
用于实现会话保持功能,保证客户端与服务器之间建立稳定的会话。使用ip_hash
后不能使用weight
。
upstream webserver {
ip_hash;
server 192.168.10.1:8080; //后端服务器列表
server 192.168.10.2:8080;
}
④ fair: fair
算法可以根据页面大小和加载时间长短智能地进行负载均衡,也就是根据后端服务器的响应时间 来分配请求,响应时间短的优先分配。Nginx本身不支持fair
,如果需要这种调度算法,则必须安装upstream_fair
模块。
upstream webserver {
fair;
server 192.168.10.1:8080; //后端服务器列表
server 192.168.10.2:8080;
}
⑤ url_hash: 按访问的URL
的哈希结果来分配请求,使每个URL
定向到一台后端服务器,可以进一步提高后端缓存服务器的效率。Nginx本身不支持url_hash
,需要第三方模块的支持ngx_http_upstream_hash_module
。注意:使用url_hash
后不能使用weight
。
upstream webserver {
hash $request_uri;
hash_method crc32;
server 192.168.10.1:8080; //后端服务器列表
server 192.168.10.2:8080;
}
三、 负载均衡的实现 - DNS
DNS负载均衡技术是在DNS服务器中为同一个主机名配置多个IP地址,在应答DNS查询时,DNS服务器对每个查询将以DNS文件中主机记录的IP地址按顺序返回不同的解析结果,将客户端的访问引导到不同的机器上去,使得不同的客户端访问不同的服务器,从而达到负载均衡的目的。在当前大型网站中,通常利用DNS作为第一级负载均衡手段,即DNS得到的一组服务器并不是实际提供服务的物理服务器,而是同样提供负载均衡服务器的Nginx服务器,这组Nginx负载均衡服务器再进行负载均衡,请请求发到真实的服务器上,最终完成请求。
Q1.DNS负载均衡的优点和缺点 ?
● 优点:
① 使用成本低,简单易行,对于部署在服务器上的应用来说不需要进行任何的代码修改即可实现不同机器上的应用访问。
② DNS支持基于地理位置的域名解析,即会将域名解析成距离用户地理最近的一个服务器地址,可以加速用户访问,改善性能。
● 缺点:
① DNS是多级解析的,每一级DNS都包含缓存A的记录,当某台服务器下线之后,即使修改了A记录,要使其生效也需要较长的时间,这段时间,DNS仍然会将域名解析到已下线的服务器上,最终导致用户访问失败。
② DNS不能按服务器的处理能力来分配负载,仅能简单的轮询算法,其的负载均衡效果并不是太好。