Nginx是一个 轻量级/高性能的反向代理Web服务器,实现了高效的反向代理、负载平衡,可以处理4-5万并发连接数。用于HTTP、HTTPS、SMTP、POP3和IMAP协议。
Nginx内置的健康检查功能:如果有一个服务器宕机,会做一个健康检查,再发送的请求就不会发送到宕机的服务器了。重新将请求提交到其他的节点上。
接收用户请求是异步的
缺点: 处理动态页面则很鸡肋,现在一般前端用nginx作为反向代理抗住压力
nginx常用模块
access 访问模块
auth 认证模块
gzip 压缩模块
proxy 代理模块
upstream 负载均衡
rewrite 重写模块
log 日志模块
limit conn现在用户访问并发连接
ssl模块
autoindex 开启目录浏览
为什么Nginx性能高
-
因为他的事件处理机制
Nginx使用反应器模式。主事件循环等待操作系统发出准备事件的信号,这样数据就可以从套接字读取,在该实例中读取到缓冲区并进行处理。单个线程可以提供数万个并发连接。 -
多进程IO模型
首先,对于每个worker进程来说,独立的进程,不需要加锁,所以省掉了锁带来的开销,同时在编程以及问题查找时,也会方便很多。
其次,采用独立的进程,可以让互相之间不会影响,一个进程退出后,其它进程还在工作,服务不会中断,master进程则很快启动新的worker进程。当然,worker进程的异常退出,肯定是程序有bug了,异常退出,会导致当前worker上的所有请求失败,不过不会影响到所有请求,所以降低了风险。
如何设置worker进程的数量呢?
在有多个cpu的情况下,可以设置多个worker,worker进程的数量可以设置到和cpu的核心数一样多,如果在单个cpu上起多个worker进程,那么操作系统会在多个worker之间进行调度,这种情况会降低系统性能,如果只有一个cpu,那么只启动一个worker进程就可以了。
- 单线程异步非阻塞事件处理机制
所有请求都由一个线程处理
nginx是可以同时处理成千上万个请求的。一个worker进程可以同时处理的请求数只受限于内存大小,而且在架构设计上,不同的worker进程之间处理并发请求时几乎没有同步锁的限制,worker进程通常不会进入睡眠状态,因此,当Nginx上的进程数与CPU核心数相等时(最好每一个worker进程都绑定特定的CPU核心),进程间切换的代价是最小的。
nginx是如何实现高并发的
一个主进程,多个工作进程,每个工作进程可以处理多个请求,每进来一个request,会有一个worker进程去处理。
但不是全程的处理,处理到可能发生阻塞的地方,比如向上游(后端)服务器转发request,并等待请求返回。那么,这个处理的worker继续处理其他请求,而一旦上游服务器返回了,就会触发这个事件,worker才会来接手,这个request才会接着往下走。Nginx 的异步非阻塞工作方式正是利用了这点等待的时间。在需要等待的时候,这些进程就空闲出来待命了。 因此表现为少数几个进程就解决了大量的并发问题。这就是为什么说,Nginx 基于事件模型。
由于web server的工作性质决定了每个request的大部份生命都是在网络传输中,实际上花费在server机器上的时间片不多,属于网络io密集型应用,不算是计算密集型。
采用单线程来异步非阻塞处理请求(管理员可以配置Nginx主进程的工作进程的数量),不会为每个请求分配cpu和内存资源,节省了大量资源,同时也减少了大量的CPU的上下文切换,所以才使得Nginx支持更高的并发。
Netty、Redis 基本采用相同思路。
- 运用了epoll模型,提供了一个队列,排队解决
应用场景
- http服务器。Nginx是一个http服务可以独立提供http服务。可以做网页静态服务器。
- 虚拟主机(基于域名/端口/ip)。可以实现在一台服务器虚拟出多个网站,例如个人网站使用的虚拟机。
- 反向代理,负载均衡。当网站的访问量达到一定程度后,单台服务器不能满足用户的请求时,需要用多台服务器集群可以使用nginx做反向代理。并且多台服务器可以平均分担负载,不会应为某台服务器负载高宕机而某台服务器闲置的情况。
- nginz 中也可以配置安全管理、比如可以使用Nginx搭建API接口网关,对每个接口服务进行拦截。
目录结构
[root@localhost ~]# tree /usr/local/nginx
/usr/local/nginx
├── client_body_temp
├── conf # Nginx所有配置文件的目录
│ ├── fastcgi.conf # fastcgi相关参数的配置文件
│ ├── fastcgi.conf.default # fastcgi.conf的原始备份文件
│ ├── fastcgi_params # fastcgi的参数文件
│ ├── fastcgi_params.default
│ ├── koi-utf
│ ├── koi-win
│ ├── mime.types # 媒体类型
│ ├── mime.types.default
│ ├── nginx.conf # Nginx主配置文件
│ ├── nginx.conf.default
│ ├── scgi_params # scgi相关参数文件
│ ├── scgi_params.default
│ ├── uwsgi_params # uwsgi相关参数文件
│ ├── uwsgi_params.default
│ └── win-utf
├── fastcgi_temp # fastcgi临时数据目录
├── html # Nginx默认站点目录
│ ├── 50x.html # 错误页面优雅替代显示文件,例如当出现502错误时会调用此页面
│ └── index.html # 默认的首页文件
├── logs # Nginx日志目录
│ ├── access.log # 访问日志文件
│ ├── error.log # 错误日志文件
│ └── nginx.pid # pid文件,Nginx进程启动后,会把所有进程的ID号写到此文件
├── proxy_temp # 临时目录
├── sbin # Nginx命令目录
│ └── nginx # Nginx的启动命令
├── scgi_temp # 临时目录
└── uwsgi_temp # 临时目录
配置文件nginx.conf
worker_processes 1; # worker进程的数量
events { # 事件区块开始
worker_connections 1024; # 每个worker进程支持的最大连接数
} # 事件区块结束
http { # HTTP区块开始
include mime.types; # Nginx支持的媒体类型库文件
default_type application/octet-stream; # 默认的媒体类型
sendfile on; # 开启高效传输模式
keepalive_timeout 65; # 连接超时
server { # 第一个Server区块开始,表示一个独立的虚拟主机站点
listen 80; # 提供服务的端口,默认80
server_name localhost; # 提供服务的域名主机名
location / { # 第一个location区块开始
root html; # 站点的根目录,相当于Nginx的安装目录
index index.html index.htm; # 默认的首页文件,多个用空格分开
} # 第一个location区块结果
error_page 500502503504 /50x.html; # 出现对应的http状态码时,使用50x.html回应客户
location = /50x.html { # location区块开始,访问50x.html
root html; # 指定对应的站点目录为html
}
}
......
error_log /data/logs/nginx/error.log; # 错误日志打印地址
access_log /data/logs/nginx/access.log; # 进入日志打印地址
log_format main '$remote_addr"$request" ''$status $upstream_addr "$request_time"'; # 进入日志格式
Nginx 日志格式中的 $time_local 表示的是请求开始写入本地的时间
当我们从前到后观察日志中的 $time_local 时间时,因为请求发生时间有前有后,所以会时间顺序前后错乱。
Nginx怎么处理请求的
nginx接收一个请求后,首先由listen和server_name指令匹配server模块,再匹配server模块里的location,location就是实际地址
server { # 第一个Server区块开始,表示一个独立的虚拟主机站点
listen 80; # 提供服务的端口,默认80
server_name localhost; # 提供服务的域名主机名
location / { # 第一个location区块开始
root html; # 站点的根目录,相当于Nginx的安装目录
index index.html index.htm; # 默认的首页文件,多个用空格分开
} # 第一个location区块结果
}
当客户端访问localhost,监听端口号为80,直接跳转到默认的首页文件。
location指令的作用是根据用户请求的URI来执行不同的应用,也就是根据用户请求的网站URL进行匹配,匹配成功即进行相关的操作。可正则匹配。
Location正则案例
#优先级1,精确匹配,根路径
location =/ {
return 400;
}
#优先级2,以某个字符串开头,以av开头的,优先匹配这里,区分大小写
location ^~ /av {
root /data/av/;
}
#优先级3,区分大小写的正则匹配,匹配/media*****路径
location ~ /media {
alias /data/static/;
}
#优先级4 ,不区分大小写的正则匹配,所有的****.jpg|gif|png 都走这里
location ~* .*.(jpg|gif|png|js|css)$ {
root /data/av/;
}
# !~ 优先级5,区分大小写不匹配的正则;
# !~* 优先级6,不区分大小写不匹配的正则
#优先7,通用匹配
location / {
return 403;
}
Nginx怎么判断别IP不可访问
# 如果访问的ip地址为192.168.9.115,则返回403
if ($remote_addr = 192.168.9.115) {
return 403;
}
Nginx怎么限制浏览器访问
# 不允许谷歌浏览器访问 如果是谷歌浏览器返回500
if ($http_user_agent ~ Chrome) {
return 500;
}
Nginx 配置反向代理
需求:输入 www.123.com 便可以跳转到 Tomcat初始界面
server {
listen 80;
server_name www.123.com;
location / {
proxy_pass http://127.0.0.1:8080;
index index.html index.htm index.jsp;
}
}
监听80端口,访问域名为www.123.com,不加端口号时默认为80端口,故访问该域名时会跳转到127.0.0.1:8080路径上。
反向代理服务器可以隐藏源服务器的存在和特征。它充当互联网云和web服务器之间的中间层。这对于安全方面来说是很好的,特别是当您使用web托管服务时。
Nginx 常用命令
启动 nginx
停止 nginx -s stop
或 nginx -s quit
。
重载配置 ./sbin/nginx -s reload
(平滑重启) 或 service nginx reload
。
重载指定配置文件 .nginx -c /usr/local/nginx/conf/nginx.conf
。
查看 nginx 版本nginx -v
。
检查配置文件是否正确 nginx -t
。
显示帮助信息 nginx -h
。
Nginx常见配置优化
安全优化
-
隐藏nginx版本信息优化:修改nginx配置文件实现优化。
server_tokens off;
-
修改nginx进程用户信息:
修改默认进程用户nginx为其他,如www. -
修改nginx服务上传文件限制:
client_max_body_size 设置客户端请求报文主体最大尺寸,用户上传文件 大小。 -
nginx图片及目录防盗链解决方法
根据HTTP referer实现防盗链
用户从哪里跳转过来的(通过域名)referer控制
根据cookie防盗链
nginx站点目录文件及目录权限优化
-
只将用户上传数据目录设置为755用户和组使用nginx
其余目录和文件为755/644,用户和组使用root -
使用普通用户启动nginx
利用nginx -c参数启动nginx多实例,使master进程让普通用户管理。普通用户无法使用1-1024端口。使用iptables转发。 -
控制nginx并发连接数
控制客户端请求nginx的速率
性能优化:
-
调整worker_processes
指nginx要生成的worker数量,一般和cpu的核心数设置一致,高并发可以和cpu核心2倍.
cat /proc/cpuinfo
-
优化nginx服务进程均匀分配到不同cpu进行处理。
利用worker_cpu_affinity进行优化让cpu的每颗核心平均。 -
优化nginx事件处理模型
利用use epoll参数修改事件模型为epoll模型。
事件模型指定配置参数放置在event区块中 -
优化nginx单进程客户端连接数
利用worker_connections连接参数进行调整
用户最大并发连接数=worker进程数*worker连接数 -
优化nginx服务进程打开文件数
利用worker_rlimit_nofile
参数进行调整 -
优化nginx服务数据高效传输模式。
利用sendfile on
开启高速传输模式。
tcp_nopush on
表示将数据积累到一定的量再进行传输。
tcp_nopush on
表示将数据信息进行快速传输 -
优化nginx服务超时信息。
keepalive_timeout
优化客户端访问 nginx服务端超时时间。
http协议特点:连接断开后会给你保留一段时间
Nginx优化怎么做
内核优化
net.ipv4.tcp_max_tw_buckets :选项用来设定timewait的数量,默认是180000,这里设为6000。
net.ipv4.ip_local_port_range:选项用来设定允许系统打开的端口范围。在高并发情况否则端口号会不够用。
net.ipv4.tcp_tw_recycle:选项用于设置启用timewait快速回收.
net.ipv4.tcp_tw_reuse:选项用于设置开启重用,允许将TIME-WAIT sockets重新用于新的TCP连接。
net.ipv4.tcp_syncookies:选项用于设置开启SYN Cookies,当出现SYN等待队列溢出时,启用cookies进行处理。
net.core.somaxconn:选项的默认值是128, 这个参数用于调节系统同时发起的tcp连接数,在高并发的请求中,默认的值可能会导致链接超时或者重传,因此,需要结合并发请求数来调节此值。
net.core.netdev_max_backlog:选项表示当每个网络接口接收数据包的速率比内核处理这些包的速率快时,允许发送到队列的数据包的最大数目。
net.ipv4.tcp_max_orphans:选项用于设定系统中最多有多少个TCP套接字不被关联到任何一个用户文件句柄上。如果超过这个数字,孤立连接将立即被复位并打印出警告信息。这个限制只是为了防止简单的DoS攻击。不能过分依靠这个限制甚至人为减小这个值,更多的情况下应该增加这个值。
net.ipv4.tcp_max_syn_backlog:选项用于记录那些尚未收到客户端确认信息的连接请求的最大值。对于有128MB内存的系统而言,此参数的默认值是1024,对小内存的系统则是128。
net.ipv4.tcp_synack_retries参数的值决定了内核放弃连接之前发送SYN+ACK包的数量。
net.ipv4.tcp_syn_retries选项表示在内核放弃建立连接之前发送SYN包的数量。
net.ipv4.tcp_fin_timeout选项决定了套接字保持在FIN-WAIT-2状态的时间。默认值是60秒。正确设置这个值非常重要,有时即使一个负载很小的Web服务器,也会出现大量的死套接字而产生内存溢出的风险。
net.ipv4.tcp_syn_retries选项表示在内核放弃建立连接之前发送SYN包的数量。
如果发送端要求关闭套接字,net.ipv4.tcp_fin_timeout选项决定了套接字保持在FIN-WAIT-2状态的时间。接收端可以出错并永远不关闭连接,甚至意外宕机。
net.ipv4.tcp_fin_timeout的默认值是60秒。需要注意的是,即使一个负载很小的Web服务器,也会出现因为大量的死套接字而产生内存溢出的风险。FIN-WAIT-2的危险性比FIN-WAIT-1要小,因为它最多只能消耗1.5KB的内存,但是其生存期长些。
net.ipv4.tcp_keepalive_time选项表示当keepalive启用的时候,TCP发送keepalive消息的频度。默认值是2(单位是小时)。
Nginx 配置参数优化
nginx要开启的进程数 一般等于cpu的总核数 其实一般情况下开4个或8个就可以。
每个nginx进程消耗的内存10兆的模样
worker_cpu_affinity
仅适用于linux,使用该选项可以绑定worker进程和CPU(2.4内核的机器用不了)
假如是8 cpu 分配如下:
worker_cpu_affinity 00000001 00000010 00000100 00001000 00010000
00100000 01000000 10000000
worker_rlimit_nofile 102400;
每个nginx进程打开文件描述符最大数目 配置要和系统的单进程打开文件数一致,linux 2.6内核下开启文件打开数为65535,worker_rlimit_nofile就相应应该填写65535 nginx调度时分配请求到进程并不是那么的均衡,假如超过会返回502错误。我这里写的大一点
use epoll
Nginx使用了最新的epoll(Linux 2.6内核)和kqueue(freebsd)网络I/O模型,而Apache则使用的是传统的select模型。
处理大量的连接的读写,Apache所采用的select网络I/O模型非常低效。在高并发服务器中,轮询I/O是最耗时间的操作 目前Linux下能够承受高并发
访问的Squid、Memcached都采用的是epoll网络I/O模型。
worker_connections 65535;
每个工作进程允许最大的同时连接数 (Maxclient = work_processes * worker_connections)
keepalive_timeout 75
keepalive超时时间
client_header_buffer_size 16k
large_client_header_buffers 4 32k
客户请求头缓冲大小
nginx默认会用client_header_buffer_size这个buffer来读取header值,如果header过大,它会使用large_client_header_buffers来读取
如果设置过小HTTP头/Cookie过大 会报400 错误 nginx 400 bad request
求行如果超过buffer,就会报HTTP 414错误(URI Too Long) nginx接受最长的HTTP头部大小必须比其中一个buffer大,否则就会报400的HTTP错误(Bad Request)。
open_file_cache max 102400
使用字段:http, server, location 这个指令指定缓存是否启用,如果启用,将记录文件以下信息: ·打开的文件描述符,大小信息和修改时间. ·存在的目录信息. ·在搜索文件过程中的错误信息 -- 没有这个文件,无法正确读取,参考open_file_cache_errors 指令选项:
·max - 指定缓存的最大数目,如果缓存溢出,最长使用过的文件(LRU)将被移除
例: open_file_cache max=1000 inactive=20s; open_file_cache_valid 30s; open_file_cache_min_uses 2; open_file_cache_errors on;
open_file_cache_errors
语法:open_file_cache_errors on | off 默认值:open_file_cache_errors off 使用字段:http, server, location 这个指令指定是否在搜索一个文件是记录cache错误.
open_file_cache_min_uses
语法:open_file_cache_min_uses number 默认值:open_file_cache_min_uses 1 使用字段:http, server, location 这个指令指定了在open_file_cache指令无效的参数中一定的时间范围内可以使用的最小文件数,如 果使用更大的值,文件描述符在cache中总是打开状态.
open_file_cache_valid
语法:open_file_cache_valid time 默认值:open_file_cache_valid 60 使用字段:http, server, location 这个指令指定了何时需要检查open_file_cache中缓存项目的有效信息.
开启gzip
gzip on;
gzip_min_length 1k;
gzip_buffers 4 16k;
gzip_http_version 1.0;
gzip_comp_level 2;
gzip_types text/plain application/x-JavaScript text/css
application/xml;
gzip_vary on;
缓存静态文件:
location ~* ^.+.(swf|gif|png|jpg|js|css)$ {
root /usr/local/ku6/ktv/show.ku6.com/;
expires 1m;
}
Nginx 如何处理 HTTP 请求
- Nginx 在启动时,会解析配置文件,得到需要监听的端口与 IP 地址,然后在 Nginx 的 Master 进程里面先初始化好这个监控的Socket(创建 Socket,设置 addr、reuse 等选项,绑定到指定的 ip 地址端口),再 listen 监听。
- 然后fork(一个现有进程可以调用 fork 函数创建一个新进程。由 fork 创建的新进程被称为子进程 )出多个子进程出来。
子进程会竞争 accept 新的连接。
此时,客户端就可以向 nginx 发起连接了。 - 当客户端与nginx进行三次握手,与 nginx 建立好一个连接后,某一个子进程会 accept 成功,得到这个建立好的连接的 Socket ,然后创建 nginx 对连接的封装,即 ngx_connection_t 结构体。
- 接着,根据事件调用相应的事件处理模块,如http模块与客户端进行数据的交换。
- 最后,Nginx 或客户端来主动关掉连接,到此,一个连接就完成了。