1.Nginx特点
Nginx是一个事件驱动架构,而非传统过程驱动架构。具有内存占用低,当并发连接大时,能够预测内存使用率。Nginx改变了传统的web服务器体系架构,提高了响应速度,起初Nginx开发的目标是实现10倍以上的性能,并能够模块化,事件驱动,异步,单线程web服务器和web服务器代理。
(1)Nginx作为web服务器
Nginx使用更少的资源,支持更多连接,更快响应,能够支持高达50000个并发连接的响应,并选用了epoll and kqueue模型。
(2) Nginx作为负载均衡服务器
不仅可以支持Rails和PHP,也可作为HTTP代理服务器。Nginx是使用C语言开发,这使得CPU占有率和系统资源开销比Perbal出色很多。
(3)Nginx作为邮件代理服务器
Nginx最早是作为一个邮件代理服务器,所以它本身就是一个很好的代理服务器。并且安装和配置简单,,升级简单(热升级),bugs非常少。启动简单,几乎可以做到7*24不间断运行,运行数个月也不需要重新启动。
2.Nginx架构
Nginx采用了操作系统中高级事件机制的不断发展的启发,开发了一个模块化,事件驱动,异步,单线程的非阻塞架构。并使用复用和事件通知,用于分离进程的特定任务。在每个worker进程中,nginx可以处理每秒数千个并发连接和请求。这些架构思想,解决了传统web服务器在内存和CPU消耗方面,低效的特点。
(1)代码结构
nginx包括核心和功能模块,核心是维护某些循环的执行,并在请求处理时,执行模块代码适当部分。模块包括了大部分演示和应用层功能。模块的读取和写入网、存储,转换内容,执行出站过滤,应用服务器端包含操作,并在代理启动时将请求传递给上游服务器。
nginx允许扩展web服务器功能,不用修改nginx其它源码,但不支持动态加载模块。即在构建阶段将模块与其核心一起编译。nginx使用一些事件通知机制和磁盘IO性能增强,如kqueue,epoll和事件端口,并优化了复用和高级I/O操作的不同使用方法。主要目的是使得操作系统的提示能够及时,并且能够快速获得入站和出站流量,磁盘操作,读取和写入套接字等。
(2)工作模式
worker进程接受自共享"listen"套接字的新请求,并高效执行循环,处理数千个连接。注意这个过程是没有仲裁或分配与nginx工作的联系,这个worker是由操作系统内核机制完成。启动后,首先创建一组初始侦听套接字,然后worker不断处理HTTP请求,不断接收,读取和写入套接字。
这个直线循环是很复杂部分,包括内部调用,并在很大程度上依赖异步任务处理,异步操作通过模块化,事件通知,广泛使用回调函数和微调定时器来实现。开发的关键原则是尽可能不要阻塞,但是当磁盘空间不够时,应该要阻塞。
nginx由于谨慎使用内存(不会连接一个线程或线程),同时也节省CPU使用周期(没有持续创建和销毁),当初始化新连接,并将其添加到运行循环中,并异步处理指导完成,此时连接被重新分配并从运行循环中删除。为什么CPU使用率低?一般就是结合优化系统调用流程和支持接口(如pool,slab内存分配器),使得在极端工作负载下实现很低的CPU负载。
如何根据磁盘使用和 CPU 负载模式去配置nginx 工作(worker)的数量?
如果负载大多是大量处理TCP/IP,执行SSL或压缩,则worker的数量与CPU核的数量相匹配。如果负载大多是磁盘 I/O 绑定,存储或重代理服务,worker的数量可能是核心数量的一到两倍。
关于worker模式与嵌入式脚本有限支持有关,一个使用标准的 nginx 分发,只支持嵌入 Perl 脚本。由于脚本有意外退出的可能,就可能导致worker挂起,同时影响数千个连接。所以脚本应该更稳定才行。
(3)Nginx进程
主要由主进程和多个worker进程。所有进程都是单线程,进程间通信主要采用共享内存进行通信。主进程作为root用户运行,worker进程,缓存加载器和管理器(nginx特殊用途)则以无权限用户执行。
主进程工作:
1.读取,验证配置
2.创建,绑定和关闭套接字
3.启动,终止和维护配置的worker进程
4.重新配置,无需中断服务
5.重新打开日志文件
6.编译嵌入式perl脚本
worker进程工作:
(1)处理客户端连接
(2)提供反向代理和过滤功能
缓存加载器工作:
(1)检查磁盘缓存项目,使用nginx实例来处理已经存储在磁盘的特定分配的目录结构中的文件,遍历目录,检查缓存内容元数据,更新共享内存的相关条目,然后在退出时再清理。
缓存管理器工作:
(1)主要清理缓存,正常的nginx操作保持在内存中,并且在失败的情况下由主进程重新启动。
3.Nginx缓存
nginx中的缓存是以文件系统的分层数据存储实现。缓存密钥(可配置)和缓存元数据存储在共享存储器段中,通过高速缓存加载器,缓存管理器和worker进程访问。每个缓存的响应都放在文件系统上的不同文件中,并通过不同nginx配置命令进行控制。当响应写入缓存目录结构时,文件的路径和名称将从代理URL的MD5哈希导出。
将数据放在缓存的过程如下:
(1) nginx从上游服务器读取响应,首先写入缓存目录结构之外的临时文件
(2)nginx完成处理请求,将临时文件移动到缓存目录。如果临时文件位于另外一个文件系统,则文件将被复制,因此建议将临时文件目录和缓存目录保存在同一文件系统。
(3)如果要显式删除缓存目录结构,从文件中删除文件也是很安全。
4.安装Nginx
nginx只是实现了http这一层,pcre是负责正则表达式的,正则表达式,只是用在location.conf文件里面。openssl应用与加密。Zlib应用于压缩。服务器返回客户端的数据,需要压缩的方式。
解压nginx
解压openssl
解压pcre
解压zlib
配置命令:
./configure --prefix=/usr/local/nginx --with-http_realip_module --with-http_addition_module --with-http_gzip_static_module --with-http_secure_link_module --with-http_stub_status_module --with-stream --with-pcre=/home/qaa/share/nginx/pcre-8.41 --with-zlib=/home/qaa/share/nginx/zlib-1.2.11 --with-openssl=/home/qaa/share/nginx/openssl-1.1.0g
出现如下,配置成功:
再make
出现如下,编译成功。
make install 出现如下编译成功:
最终安装在这个目录下
这个就是可以运行的nginx
启动nginx
./sbin/nginx -c conf/nginx.conf
出现如下,表示启动成功。
到浏览器,输入这个地址,就表示nginx能够启动成功。
http://172.16.204.129/
(1)nginx -s signal
信号(signal)的值可能是以下之一:
stop 快速关闭服务
quit - 正常关闭服务
reload - 重新加载配置文件
reopen - 重新打开日志文件
ps -ax | grep nginx
要获取所有运行的 nginx 进程的列表,可以使用 ps 命令,例如,以下列方式:
5.配置nginx做代理
先写个简单的服务器配置文件:
逐个解释下,下面配置文件的意思。
work_process:表示的是work进程的数量
events:表示的是事件
worker_connections 1024:表示服务端与客户端连接的数量
http:表示响应的具体协议
server:表示服务,具体的服务。可以配置多个server
listen:表示自定义监听的端口号,端口建议大于1024
server_name:表示服务的名字,名字可以随便取
client_max_body_size:表示客户端请求数据的大小
location:表示请求的根目录
然后,停止当前正在运行的nginx服务,并重新开启
./sbin/nginx -s stop
./sbin/nginx -c vip_conf/demo.conf
把图片放到/usr/local/nginx下面
6.Nginx 压缩和解压
(1)压缩和解压缩
压缩响应通常会显着减少传输数据的大小。然而,由于压缩在运行时发生,它还可以增加相当大的处理开销,这会对性能产生负面影响 在向客户端发送响应之前,NGINX 会执行压缩,但不会“压缩”已压缩的响应(例如,由代理的服务器)。
(2) 启用压缩
gzip on
默认情况下,NGINX 仅使用 MIME 类型 text/html 压缩响应。要使用其他 MIME 类型压缩响应,请包含 gzip_types 指令并列出其他类型。
gzip_types text/plain application/xml
要指定要压缩的响应的最小长度,默认值为 20 字节(可将此处调整为 1000)。
gzip_min_length 1000
gzip_proxied 指令具有指示 NGINX 在响应中检查 Cache-Control 头字段的参数,如果值为 no-cache, no-store 或 private,则压缩响应。另外,您必须包括 Expires 参数以用来检查 Expires 头域的值。这些参数在以下示例中与 auth 参数一起设置,该参数检查 Authorization 头字段的存在(授权响应特定于最终用户,并且通常不被缓存):
gzip_proxied no-cache no-store private expired auth;
与大多数其他指令一样,配置压缩的指令可以包含在http 上下文中,也可以包含在 server或 location 配置块中。
gzip 压缩的整体配置可能如下所示。
server {
gzip on;
gzip_types text/plain application/xml;
gzip_proxied no-cache no-store private expired auth;
gzip_min_length 1000;
...
}
(3)启用解压缩
由于客户端可能不支持gzip编码的响应,为了服务不接收压缩数据的客户端,Nginx可以执行及时压缩。
要启用运行时解压缩,请使用gunzip指令。
location /storage/
{
gunzip on;
.........
}
gunzip 指令与gzip指令相同上下文的环境中运行。
server {
gzip on;
gzip_min_length 1000;
gunzip on;
。。。
}
该指令最好在单独模块中定义,默认情况可能不包含在NGINX中。
(4) 发送压缩文件
将压缩文件发送大客户端,需要把gzip_static指令设置为on。
location / {
gzip_static on;
}
Nginx会去查找并发送压缩文件,如果客户端不支持gzip,则发送未压缩版本的文件。
需要注意的是,gzip_static指令不启用及时压缩,而是使用压缩工具预先压缩的文件。如果需要及时压缩内容(而不是静态内容),请使用gzip指令。同上,这个模块需要单独定义。
7.Nginx内容缓存
(1)启用响应缓存
要启用缓存,使用proxy_cache_path指令,第一个参数是缓存本地内容的路径,强制keys_zone参数用于存储有关缓存项目的元数据的共享内存区域的名称和大小。
http{
....
proxy_cache_path /data/nginx/cache keys_zone=one:10m;
}
然后在要缓存服务器响应的上下文中包含proxy_cache指令,将keys_zone参数定义的区域名称指定为proxy_cache_path 指令。
http {
...
proxy_cache_path /data/nginx/cache keys_zone=one:10m;
server
{
proxy_cache one;
location / {
proxy_pass http://localhost:8000;
}
}
}
注意:keys_zone 参数定义的大小不会限制缓存的响应数据的总量。如果要限制缓存的响应数据量,请将max_size参数包含到proxy_cache_path指令中。
(2)涉及缓存的 NGINX 进程
有两个额外的Nginx进程涉及到缓存,缓存管理器会周期性检查缓存状态,如果缓存大小超过max_cize_path指令设置的max_size参数,它将删除最近访问的数据,注意,高速缓存管理器激活之间的缓存数据量可以临时超过限制。
当Nginx启动后,缓存加载程序只运行一次。将有关以前缓存的数据加载到共享内存区域。注意,一次加载整个缓存可能在开始几分钟会消耗很多资源,导致减慢Nginx性能。为了避免这种情况,可以使用proxy_cache_path 伪指令来配置缓存的迭代加载。
loader_threshold:迭代持续时间,以毫秒为单位(默认200)
loader_files:在一次迭代期间加载的最大项目数(默认为100)
loader_sleeps:迭代之间延迟,以毫秒为单位(默认为50)
在以下示例中,迭代持续 300 毫秒或直到加载了 200 个项目:
proxy_cache_path /data/nginx/cache keys_zone=one:10m
loader_threshold=300
loader_files=200;
(3)指定要缓存的请求
如果请求具有与缓存响应相同的密钥,则Nginx将缓存的响应发送给客户端。可以用http,server或location上下文中包含各种指令,以控制哪些响应被缓存。
要定义缓存响应之前需要进行相同密钥的请求的最小次数,需要使用proxy_cache_min_uses指令。
如proxy_cache_min_uses 5;
要使用除 GET 和 HEAD 之外的方法来缓存对请求的响应,请将它们与 GET 和 HEAD 一起列为参数。
proxy_cache_methods GET HEAD POST;
(4) 限制或绕过缓存
默认情况下,响应将无限期地保留在缓存中。只有缓存超过最大配置大小,然后按照最后
一次请求的时间长度,它们才被删除。可以在http,server或location上下文中去设置有效时间长度。
限制缓存响应与特定状态代码被认为有效的时间,使用proxy_cache_valid指令,200或302的响应有效时间为10分钟,且404的响应有效1分钟。
定义具有所有状态代码的响应有效时间,指定any作为第一个参数。
proxy_cache_valid any 5m;
如果针对客户端,不设置缓存响应的条件,包括proxy_cache_bypass指令。每个参数定义一个条件并由多个变量组成。则Nginx不会在缓存中查找响应,而是将请求立即转发到后端服务器。
proxy_cache_bypass $cookie_nocache $arg_nocache$arg_comment;
要定义 NGINX 根 本 不 缓 存 响 应 的 条 件 , 请 包 括 proxy_no_cache 指 令 , 以 与
proxy_cache_bypass 伪指令相同的方式定义参数。
proxy_no_cache $http_pragma $http_authorization;
8.缓存中清除内容
(1)使用“PURGE”的标志配置http方法的请求并删除匹配的URL。
http{
...
map $request_method $purge_method{
PURGE 1;
default 0;
}
}
配置高速缓存,包括指定缓存清除请求的条件proxy_cache_purge指令。
server
{
listen 80;
server_name www.example.com;
location / {
proxy_pass http://localhost:8002;
proxy_cache mycache;
proxy_cache_purge $purge_method;
}
}
(3) 发送清除命令
配置proxy_cache_purge 指令后,清除缓存,如curl命令。
curl -X PURGE -D - " http://www.example.com"
HTTP/1.1 204 No Content
Server: nginx/1.5.7
.....
在该例子中,具有公共URL部分的资源将被删除,但是,这些高速缓存条目将不会从缓存中完全删除。因为这些保留在磁盘上,直到他们被删除为非活动状态。
(4) 限制访问清除命令
限制有限数量的IP,发送缓存请求。
geo $purge_allowed
{
default 0;#拒绝所有ip
10.0.0.1 1;#拒绝本地
192.168.0.0/24 1; #允许10.0.0.0/24
}
map $request_method $purge_method {
PURGE $purge_allowed;
default 0;
}
上例中,设置$purge_allowed:"1",允许清除,"0"表示拒绝清除。
(5)在缓存中完全删除文件
将purge参数添加到proxy_cache_path指令中,完全删除与星号相匹配的缓存文件。
proxy_cache_path /data/nginx/cache
levels=1:2
keys_zone=mycache:10m purge=on
(6) 缓存清除配置
http
{
proxy_cache_path /data/nginx/cache
levels=1:2
keys_zone=mycache:10m purger=on;
map $request_method $purge_method
{
PURGE 1;
default 0;
}
server
{
listen 80;
server_name www.example.com;
location /{
proxy_pass http://localhost:8002;
proxy_cache mycache;
proxy_cache_purge $purge_method;
}
}
geo $purge_allowed{
default 0;
10.0.0.1 1;
192.168.0.0/24 1;
}
map $request_method $purge_method {
PURGE $purge_allowed;
default 0;
}
}
(7) 字节缓存
当针对大文件时,使用Nginx进行切片,每个范围请求选择择将覆盖所请求范围的特定切片,如果此范围还没有放入缓存,就将其放入缓存中。使用 slice 指令指定切片的大小。
location /{
slice 1m;
}
切片设计要合理,太小可能会导致内存使用量过大,会大量打开文件描述符。切片太大可能会导致延迟。
将$slice_range 变量包含到缓存键中:
proxy_cache_key$uri$is_args$args$slice_range;
启用206状态码缓存响应:
proxy_cache_valid 200 206 1h;
通过在 Range 头字段中传递$slice_range 变量来将传递范围请求设置为代理服务器:
proxy_set_header Range $slice_range;
字节范围缓存示例:
location / {
slice 1m;
proxy_cache cache;
proxy_cache_key $uri$is_args$args$slice_range;
proxy_set_header Range $slice_range;
proxy_cache_valid 200 206 1h;
proxy_pass http://localhost:8000;
}
值得注意,如果切片缓存打开,则不应更改初始文件。
(8)组合配置
以下配置,组合了上述某些缓存选项
http{
...
proxy_cache_path /data/nginx/cache
keys_zone=one:10m
loader_threshold=300
loader_files=200 max_size=200m;
server {
listen 8080;
proxy_cache one;
location / {
proxy_pass http://backend1;
}
location /some/path {
proxy_pass http://backend2;
proxy_cache_valid any 1m;
proxy_cache_min_uses 3;
proxy_cache_bypass $cookie_nocache $arg_nocache$arg_comment;
}
}
}
由于 backend1 服务器的响应很少更改,因此不包括缓存控制指令。首次请求响应缓存,
并无限期保持有效。相比之下,对 backend2 服务的请求的响应频繁变化,因此它们被认为只有 1 分钟有效,并且在相同请求 3 次之前不被缓存。此外,如果请求符合 proxy_cache_bypass 指令定
义的条件,则 NGINX 会立即将请求传递给 backend2,而不在缓存中查找。
9.Nginx应用场景
Nginx主要应用场景如下:
(1) 反向代理
(2) 负载均衡
(3) HTTP服务器(动静分离)
(4)正向代理
(1)反向代理
反向代理,代理的是服务器,代理服务器和目标服务器在同一个局域网,也有可能是在同一台机器上。此时代理服务器对外就表现为一个反向代理服务器。由于目标服务器不能被外部网络方位,所以就需要一台代理服务器。
下面是一个简单的实现反向代理的代码:
server{
listen 80;
server_name localhost;
client_max_body_size 1024M;
location / {
proxy_pass http://localhost:8080;
proxy_set_header Host $host:$server_port;
}
}
保存配置文件,启动Nginx,当访问localhost,就相当于访问localhost:8080。
(2)负载均衡
负载均衡就是要把任务分摊到各个不同的目标服务器上去执行,如web服务器,FTP服务器等。根据规则随机的将请求分发到指定服务器上处理,负载均衡是在反向代理的基础上进行,通过反向代理跳转到负载均衡。Nginx目前支持自带3种负载均衡策略,还有2种常用的第三方策略。
PR(默认)
每个请求按时间顺序逐一分配到不同的后端服务器,若后端服务器down掉,能自动取消。
upstream test{
server localhost:8080;
server localhost:8081;
}
server{
listen 81;
server_name localhost;
client_max_body_size 1024M;
location / {
proxy_pass http://test;
proxy_set_header Host $host:$server_port;
}
}
负载均衡的核心代码
upstream test {
server localhost:8080;
server localhost:8081;
}
设置了两台不同的服务器,这里只是端口号不一样,访问http://localhost,会默认跳到http://localhost:8080,Nginx会自动判断服务器状态,如果服务器出于不能访问,服务挂了,就不会跳转。由于使用的的是PR策略,所以不需要其他更多设置。
权重
指定轮询概率,即设置权重。如:
upstream test {
server localhost:8080 weight=9;
server localhost:8081 weight=1;
}
那么 10 次一般只会有 1 次会访问到 8081,而有 9 次会访问到 8080。
ip_hash
上述2种方式存在一个问题,就是下一个请求来的时候,可能会分发到另外一个服务器,当程序是无状态的时候,这个时候就有很大的问题,如把登陆信息保存到了session中,那跳转到另外一台服务器的时候需要重新登录,这个时候需要一个客户访问指定的服务器,就需要iphash了。iphash的每个请求按访问ip的hash结果分配,这样每个访客固定访问一个后端服务器,可以解决session的问题。
upstream test {
ip_hash;
server localhost:8080;
server localhost:8081;
}
fair(第三方)
按照目标服务器的响应时间来分配请求,响应时间短的优先分配。
upstream backend {
fair;
server localhost:8080;
server localhost:8081;
}
url_hash(第三方)
按访问 url 的 hash 结果来分配请求,使每个 url 定向到同一个后端服务器,后端服务器为缓存时比较有效。在 upstream 中加入 hash 语句,server 语句中不能写入 weight 等其他的参数,hash_method 是使用的 hash 算法。
upstream backend {
hash $request_uri;
hash_method crc32;
server localhost:8080;
server localhost:8081;
}
以上 5 种负载均衡各自适用不同情况下使用,所以可以根据实际情况选择使用哪种策略模式,不过 fair 和 url_hash 需要安装第三方模块才能使用。
(3) HTTP 服务器
Nginx实现动静分离,用Nginx做静态资源服务器。
server {
listen 80;
server_name localhost;
client_max_body_size 1024M;
location / {
root /usr/local/nginx/html/www;
index index.html;
}
}
动静分离
动静分离是让动态网站里的动态网页根据一定规则把不变的资源和经常变的资源区分开来。动静资源做好了拆分以后,我们就可以根据静态资源的特点将其做缓存操作,这就是网站静态化处理的核心思路。
upstream test
{
server localhost:8080;
server localhost:8081;
}
server{
listen 80;
server_name localhost;
location /{
root root /usr/local/nginx/html/www;
index index.html;
}
}
# 所有静态请求都由 nginx 处理,存放目录为 html
location ~ .(gif|jpg|jpeg|png|bmp|swf|css|js) ${
root /var/www;
}
# 所有动态请求都转发给 tomcat 处理
location ~ .(jsp|do) ${
proxy_pass http://test;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /var/www;
}
}
这样就把静态图片,css,js放到html/www,而tomact只负责处理jsp请求,当我们后缀为 gif 的时候,Nginx 默认会从 html/www 获取到当前请求的动态图文件返回,当然这里的静态文件跟 Nginx 是同一台服务器,我们也可以在另外一台服务器,然后通过反向代理和负载均衡配置过去就好了。
正向代理
代理客户端,客户端是可以感知代理服务器存在,发出的请求,由代理服务器去转发给目标服务器。
resolver 114.114.114.114 8.8.8.8;
server {
resolver_timeout 5s;
listen 81;
access_log /var/www/access.log;
error_log /var/www/error.log;
location / {
proxy_pass http://$host$request_uri;
}
}
resolver 是配置正向代理的 DNS 服务器,listen 是正向代理的端口,配置好了就可以在 ie 上面或者其他代理插件上面使用服务器 ip+端口号进行代理了。
Nginx是支持热启动,当修改配置文件后,不用关闭Nginx,就可以实现让配置生效。Nginx从新读取配置的命令:
nginx -s reload
nginx.exe -s reload