之前我们介绍了LVS和HAProxy两种负载均衡器,今天我们来介绍另外一种负载均衡器Nginx。当然Nginx不只具有负载均衡功能, 还有很多很强大的功能。今天我们就来详细介绍介绍Nginx。
什么是Nginx?
Nginx是一个高性能的HTTP和反向代理服务器,也是一个邮件代理服务器。由俄罗斯的程序设计师Igor Sysoev所开发,官方测试nginx能够支撑5万并发链接,并且cpu、内存等资源消耗却非常低,运行非常稳定。
所以其特点是占有内存少,并发能力强,事实上Nginx的并发能力确实在同类型的网页服务器中表现较好。
在介绍Nginx 服务器的web请求处理机制之前,我们先来介绍一般实现并行处理请求的方式。
1. 一般实现并行处理请求的方式
从设计架构上来说,nginx服务器是与众不同的。不同之处一方面体现在它的模块化设计,另一方面体现在它对客户端请求的处理机制上。
web服务器和客户端是一对多的关系,web服务器必须有能力同时为多个客户端提供服务。一般来说,完成并行处理请求工作有三种方式可供选择:多进程方式、多线程方式和异步方式。
1)多进程方式
多进程方式是指,服务器每当接收到一个客户端请求时,就由服务器主进程生成一个子进程出来和该客户端建立连接进行交互,直到连接断开,该子进程就结束了。
多进程方式的优点在于,设计和实现相对简单,各个子进程之间相互独立,处理客户端请求的过程彼此不受到干扰,并且当一个子进程产生问题时,不容易将影响漫延到其他进程中,这保证了提供服务的稳定性。当子进程退出时,其占用资源会被操作系统回收,在资源和时间上会产生一定的额外开销,因此,如果web服务器接受大量并发请求,就会对系统资源造成压力,导致系统性能下降。
2)多线程方式
多线程方式和多进程方式相似,它是指,服务器每当接受到一个客户端请求时,会由服务器主进程派生一个线程出来和该客户端进行交互。
由于操作系统产生一个线程的开销远远小于产生一个进程的开销,所以多线程方式在很大程度上减轻了web服务器对系统资源的要求。该方式使用线程进行任务调度,开发方面可以遵循一定的标准,这相对来说比较规范和有利于协作。但在线程管理方面,该方式有一定的不足。多个线程位于同一个进程内,可以访问同样的内存空间,彼此之间相互影响;同时,在开发过程中不可避免地要由开发者自己对内存进行管理,其增加了出错的风险。服务器系统需要长时间连续不停地运转,操作的逐渐积累可能最终对整个服务器产生了重大影响。
iis服务器使用了多线程方式对外提供服务,它的稳定性相对来说还是不错的,但对于经验丰富的web服务器管理人员而言,他们通常还是会定期检查和重启服务器,以预防不可预料的故障发生。
3)异步方式
网络通信中的同步机制和异步机制是描述通信模式的概念。同步机制,是指发送方发送请求后,需要等待接收到接收方发回的响应后,才接着发送下一个请求;异步机制,和同步机制正好相反,在异步机制中,发送方发出一个请求后,不等待接收响应这个请求,就继续发送下个请求。在同步机制中,所有的请求在服务器端得到同步,发送方和接收方对请求的处理步调是一致的;在异步机制中,所有来自发送方的请求形成一个队列,接收方处理完成后通知发送方。
阻塞和非阻塞描述的是进程处理调用的方式,在网络通信中,主要指的是网络套接字socket的阻塞和非阻塞方式,socket实质上就是IO操作。
阻塞:调用结果返回之前,当前的线程从运行状态被挂起,一直等到调用结果返回之后,才进入就绪状态,获取CPU继续执行。
非阻塞:调用结果返回之前,线程不会被挂起,而是立即返回执行下一个周期。
所以共有如下四种方式:
同步阻塞方式: 发送方向接收方发送请求后,一直等待响应;接收方处理请求时进行的io操作如果不能马上得到结果,就一直等到返回结果后,才响应发送方,期间不能进行其他工作。比如,在超市排队付账时,客户(发送方)向收款员(接收方)付款(发送请求)后需要等待收款员找零,期间不能做其他的事情;而收款员要等待收款机返回结果(io操作)后才能把零钱取出来交给客户(响应请求),期间也只能等待,不能做其他事情。这种方式实现简单,但是效率不高。
同步非阻塞方式:发送方向接收方发送请求后,一直等待响应;接收方处理请求时进行的io操作如果不能马上得到结果,就立即返回,去做其他事情,但由于没有得到请求处理结果,不响应发送方,发送方一直等待。一直到io操作完成后,接收方获得结果响应发送方后,接收方才进入下一次请求过程。在实际中不使用这种方式。
异步阻塞方式:发送方向接收方发送请求后,不用等待响应,可以接着进行其他工作;接收方处理请求时进行的io操作如果不能马上得到结果,就一直等待返回结果后,才响应发送方,期间不能进行其他工作。这种方式在实际中也不使用。
异步非阻塞方式:发送方向接收方发送请求后,不用等待响应,可以继续其他工作;接收方处理请求时进行的io操作如果不能马上得到结果,也不等待,而是马上返回去做其他事情。当io操作完成以后,将完成状态和结果通知接收方,接收方再响应发送方。继续使用在超市排队付账的例子。客户(发送方)向收款员(接收方)付款(发送请求)后在等待收款员找零的过程中,还可以做其他事情,比如打电话、聊天等;而收款员在等待收款机处理交易(io操作)的过程中可以帮助客户将商品打包,当收款机产生结果后,收款员给客户结账(响应请求)。在四种方式中,这种方式是发送方和接收方通信效率最高的一种。
2. Nginx服务器如何处理请求/Nginx实现高并发原理?
nginx服务器的一个显著优势是能够同时处理大量并发请求。它结合多进程机制和异步机制对外提供服务。异步机制使用的是异步非阻塞方式。
nginx服务器启动后,会产生一个主进程(master process)和多个工作进程(worker process),可以在配置文件中指定产生的工作进程数量。nginx服务器的所有工作进程都用于接收和处理客户端的请求。这就类似于Apache使用的改进的多进程机制,预先生成多个工作进程,等待处理客户端请求。
每个工作进程使用了异步非阻塞方式,可以处理多个客户端请求。当某个工作进程接收到客户端的请求以后,调用io进行处理,如果不能立即得到结果,就去处理其他的请求而非阻塞;而客户端在此期间也无需等待响应,可以去处理其他的事情;当io调用返回结果时,就会通知此工作进程;该进程得到通知,暂时挂起当前处理的事物,去响应客户端请求。
客户端请求数量增长、网络负载繁重时,nginx服务器使用多进程机制能保证不增长对系统资源的压力;同时使用异步非阻塞方式减小了工作进程在io调用上的阻塞延迟,保证了不降低对请求的处理能力。
3. 多进程的工作模式:
原理图:
master进程主要用来管理worker进程,具体包括如下4个主要功能:
1)接收来自外界的信号。
2)向各worker进程发送信号。
3)监控woker进程的运行状态。
4)当woker进程退出后(异常情况下),会自动重新启动新的woker进程。
woker进程主要用来处理基本的网络事件:
1)多个worker进程之间是对等且相互独立的,他们同等竞争来自客户端的请求。
2)一个请求,只可能在一个worker进程中处理,一个worker进程,不可能处理其它进程的请求。
3)worker进程的个数是可以设置的,一般我们会设置与机器cpu核数一致。同时,nginx为了更好的利用多核特性,具有cpu绑定选项,我们可以将某一个进程绑定在某一个核上,这样就不会因为进程的切换带来cache的失效。
1.Nginx安装
#安装依赖
yum -y install gcc zlib zlib-devel pcre-devel openssl openssl-devel
yum install nginx
#检查是否安装成功
nginx -v
#启动 / 停止 /重新加载nginx
systemctl start nginx
systemctl stop nginx
systemctl reload nginx
#编辑配置文件
/etc/nginx/nginx.conf
2. 配置文件介绍
配置文件名:/etc/nginx/nginx.conf , 该文件也会加载/etc/nginx/conf.d/*.conf 的配置。
nginx.conf 结构图可以这样概括
main # 全局配置,对全局生效
├── events # 配置影响 Nginx 服务器或与用户的网络连接
├── http # 配置代理,缓存,日志定义等绝大多数功能和第三方模块的配置
│ ├── upstream # 配置后端服务器具体地址,负载均衡配置不可或缺的部分
│ ├── server # 配置虚拟主机的相关参数,一个 http 块中可以有多个 server 块
│ ├── server
│ │ ├── location # server 块可以包含多个 location 块,location 指令用于匹配 uri
│ │ ├── location
│ │ └── ...
│ └── ...
└── ...
Nginx 配置文件由三部分组成:
第一部分:全局块
主要会设置一些影响Nginx 服务器整体运行的配置指令
第二部分:Events块
worker_connections 1024;表示每个 worker process 支持的最大连接数
第三部分:Http块
这是Nginx服务配置中最频繁的部分,代理、缓存和日志定义等绝不多数功能和第三方模块的配置都在这里。需要注意的是:http 块也可以包括http全局块、server块。server 块又包含全局server块和localtion块。
默认配置如下:
下面我们介绍Nginx的常用功能及相应配置。
今天我们介绍Nginx四种最常见的功能:
1)正向代理
2)反向代理
3)负载均衡
4)HTTP服务器
1.正向代理
简单来说就是Nginx代理客户端来访问互联网。典型代表:翻墙。
最大特点是:客户端非常明确要访问的服务器地址;服务器只清楚请求来自哪个代理服务器,而不清楚来自哪个具体的客户端;正向代理模式隐藏了真实客户端信息。
正向代理的配置:
[root@nginx-master ~]# vim /etc/nginx/nginx.conf #在配置文件中的http块中添加server块
server {
resolver 114.114.114.114; #指定DNS服务器IP地址
listen ;
location / {
proxy_pass http://localhost:80; #设定代理服务器的协议和地址
proxy_set_header HOST $host;
proxy_buffers k;
proxy_max_temp_file_size 0k;
proxy_connect_timeout ;
proxy_send_timeout ;
proxy_read_timeout ;
proxy_next_upstream error timeout invalid_header http_502;
}
}
server {
resolver 114.114.114.114; #指定DNS服务器IP地址
listen ;
location / {
proxy_pass https://localhost:443; #设定代理服务器的协议和地址
proxy_buffers k;
proxy_max_temp_file_size 0k;
proxy_connect_timeout ;
proxy_send_timeout ;
proxy_read_timeout ;
proxy_next_upstream error timeout invalid_header http_502;
}
}
Linux客户端访问测试:
配置htp_proxy和https_proxy变量如下:IP为Nginx proxy server IP
想要永久生效请配置到/etc/profile文件
2. 反向代理
简单来说就是Nginx作为反向代理服务器接收来自客户端的请求,并将请求转发给后端的真实服务器集群中的一台。典型代表:负载均衡
最大特点:主要用于服务器进群分布式部署的情况下,隐藏了服务器的真实信息!
反向代理配置:
配置关键: 1) server_name: 代表客户端向服务器发起请求时输入的域名
2)proxy_pass: 代表源服务器的访问地址, 即真正处理请求的服务器地址(服务器+端口号)
示例一:客户端访问 http://www.yuki.com:80, 实际访问的是http://www.yuki.com:8081,也就是http://192.168.93.101:8081,只是做了一个端口的转换。
server {
#监听端口
listen ;
#服务器名称,也就是客户端访问的域名地址
server_name www.yuki.com;
#nginx日志输出文件
access_log logs/nginx.access.log main;
#nginx错误日志输出文件
error_log logs/nginx.error.log;
root html;
index index.html index.htm index.php;
location / {
#被代理服务器的地址
proxy_pass http://localhost:8081; #localhost IP 为192.168.93.101
#对发送给客户端的URL进行修改的操作
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
proxy_max_temp_file_size ;
}
}
3. Nginx通过反向代理实现负载均衡
注意:upstream{}配置在http块中的全局块中
首先我们介绍下Nginx实现负载均衡的几种方式:
1)轮询
默认模式,每个请求按照顺序逐一分配到不同的后端服务器。
优点:配置简单,只需要将服务器列表加入到upstream模块中即可。
#负载中有三台服务器,当请求到达时,nginx按照时间顺序将请求分配给这三台服务器
upstream serverList {
server 1.2.3.4;
server 1.2.3.5;
server 1.2.3.6;
}
2)加权轮询
每个请求按照5:3:2的权重分配到后端服务器。
#当请求到达时,nginx按照时间顺序和权重把请求分配给三台服务器处理。例如10个请求,30%的4处理,30%的3处理,20%的2处理
upstream serverList {
server 1.2.3.4 weight=;
server 1.2.3.5 weight=;
server 1.2.3.6 weight=;
}
3)ip_hash
每个请求按照IP的hash结果分配,同一个IP客户端访问一个固定的后端服务器。
优点:可以保证来自同一个IP的请求,被打到固定的机器上,可以解决session的问题。
#负载中有三台服务器,当请求到达时,nginx会优先按照ip_hash的结果进行分配,其他则按照时间顺序把请求分配给三台服务器处理。
upstream serverList {
ip_hash
server 1.2.3.4;
server 1.2.3.5;
server 1.2.3.6;
}
4)url_hash
按访问url的hash结果来分配请求,相同url固定转发到同一个后端服务器进行处理。
upstream serverList {
server 1.2.3.4;
server 1.2.3.5;
server 1.2.3.6;
hash $request_uri;
hash_method crc32;
}
5)fair
按后端服务器的响应时间来分配请求,响应时间短的优先分配。
upstream serverList {
server 1.2.3.4;
server 1.2.3.5;
server 1.2.3.6;
fair;
}
备注:
如:
# 负载中三台服务器,服务器4的失败超时时间 60s,服务器5暂不参与负载,服务器6只是作为备份机。
# upstream:是负载的配置模块,serverList是名称,随便起
upstream serverList {
server 1.2.3.4 fail_timeout=60s;
server 1.2.3.5 down;
server 1.2.3.6 backup;
}
Nginx实现负载均衡的常用的几种方式我们先介绍到这里, 下面我们来看实现负载均衡的配置:
负载均衡示例(关键配置)
# upstream:是负载的配置模块,serverList是名称,随便起
upstream serverList {
server 192.168.93.110; #web server1,后端真实服务器
server 192.168.93.111; #web server2,后端真实服务器 }
server {
listen 80;
server_name www.xxx.com; # server_name:是客户端请求的域名地址
root html;
index index.html index.htm index.php;
location / {
proxy_pass http://serverList; # 指向负载的列表的模块,如serverList
proxy_redirect off;
proxy_set_header Host $host;
}
}
测试:
访问网页http://www.yuki.com:80,可以看到请求轮询定向到web server1 和web server2. 负载均衡功能验证成功。
4. nginx作为静态网页服务器
配置:
server {
listen ;
server_name www.xxx.com; #静态网站访问的域名地址;
client_max_body_size 1024M;
location / {
root /var/www/static; #直接静态项目绝对路径的根目录;
index index.html;
}
}
网页配置:
测试:
可以访问到该静态网页,测试成功。
好了, 我们今天就先介绍到这里,以后还会继续介绍Nginx的内容以及LVS+Nginx实现四七层负载, 可以持续关注!