Nginx介绍与原理浅析
Nginx介绍
Nginx是异步web服务器,可用作反向代理、负载均衡以及缓存服务器
基本功能:
- Web服务器(常用)
- 反向代理服务器(常用)
- 邮件代理服务器(几乎不用)
- 通用TCP / UDP代理服务器(四层调度器)
特性:
- 高性能、高并发
- 模块化开发
- 热部署、热更新
- 内存低消耗
- 配置、维护简单
原理图:
图片摘自网络,侵删
常用命令
- nginx 启动
- nginx -s quit 优雅停止nginx,有连接时会等连接请求完成再杀死worker进程
- nginx -s reload 优雅重启,并重新载入配置文件nginx.conf
- nginx -s reopen 重新打开日志文件,一般用于切割日志
- nginx -v 查看版本
- nginx -t 检查nginx的配置文件语法是否正确
- nginx -h 查看帮助信息
- nginx -V 详细版本信息,包括编译参数
- nginx -c filename 指定配置文件
Nginx核心模块
- main核心模块——官方文档速查
- user(指定运行Nginx worker进程的用户名)
- daemon(指定Nginx是否后台运行)
- worker_processes (定义工作进程数,最佳值取决于许多因素,包括(但不限于)CPU内核数、存储数据的硬盘驱动器数以及加载模式)
- error_log(定义Nginx错误日志的输出位置及错误日志级别)
- include(指定主配置文件中引入的子配置文件位置)
- load_module(指定主配置文件中加载的模块文件位置)
- accept_mutex(on:工作进程轮询接收连接 off:通知所有工作进程新连接的信息)
- Http核心模块——官方文档速查
- keepalive_timeout(保持活动的客户端连接的超时时间)
- sendfile(指定nginx是否调用sendfile函数(zero copy)来输出文件,对于普通应用必须设为on,如果用来进行下载等应用磁盘I/O重负载应用,可设置为OFF)
- autoindex(是否开启目录列表访问,默认关闭)
Nginx配置文件概述
- 主配置文件:/usr/local/nginx/conf/nginx.conf
- 默认启动nginx时,使用的配置文件是:安装路径/conf/nginx.conf文件
- 可以在启动nginx时通过-c选项来指定要读取的配置文件
- nginx.conf配置概述
- main(全局设置):全局配置段。其中main配置段中可能包含event配置段
- event(事件设置):定义event模型工作特性
- http (http协议相关的设置):定义http协议相关的配置
- server(主机设置)
- upstream(上游服务器设置,主要为反向代理、负载均衡相关配置)
- location(URL匹配特定位置后的设置)
Nginx配置文件示例
- main配置段
#master:负责系统管理级别的调度,worker:处理用户请求
#worker进程的用户组
user nginx;
#指定worker进程数,默认auto:跟cpu核数相同
worker_processes auto;
#定义nginx错误日志位置
error_log /var/log/nginx/error.log;
#定义nginx主进程pid文件路径(nginx的启动、停止、重启等信号操作均依赖该文件)
pid /run/nginx.pid;
#将子配置包含进来
include /usr/share/nginx/modules/*.conf;
#用于定义事件驱动相关配置
events {
#定义nginx使用的事件驱动模型
use epoll;
#woker可接受的连接数
worker_connections 1024;
#处理新连接方法 on:由各个worker轮流处理 off:通知所有worker,但只有一个worker获得处理连接的权限,centos7推荐使用off
accept_muetx off;
}
- http配置段
# http协议级别
http {
include mime.types;
default_type application/octet-stream;
keepalive_timeout 65;
gzip on;
#指定nginx是否调用sendfile函数(zero copy)来输出文件,对于普通应用必须设为on,如果用来进行下载等应用磁盘I/O重负载应用,可设置为OFF,以平衡磁盘与网络I/O处理速度,降低系统的uptime
sendfile on;
#是否开启目录列表访问,适合下载服务器,默认关闭
autoindex off;
#负载均衡配置
upstream {
...
}
#http server
#服务器级别,每一个server类似于httpd中的一个<VirtualHost,通俗来说就是一个网站>
server {
listen80;
server_name localhost;
#请求级别,类似与httpd中的<Location>,用于定义URL与本地文件系统的映射关系
location / {
root html;
index index.html index.htm;
}
}
#https server
#服务器级别
server {
listen 443 ssl;
server_name localhost;
ssl_certificate /usr/local/nginx/ssl/nginx.crt;
ssl_certificate_key /usr/local/nginx/ssl/nginx.key;
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 5m;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
location / {
root html;
index index.html;
}
}
}
其中https证书生成步骤如下:
参考博文
- 创建签名证书存放目录并进入目录
mkdir /usr/local/nginx/ssl
cd /usr/local/nginx/ssl
- 创建服务器私钥
openssl genrsa -des3 -out nginx.key 1024
#根据提示输入密钥确认密钥,即在当前目录生成nginx.key文件
- 创建签名请求证书(csr)
[root@localhost ssl]# openssl req -new -key nginx.key -out nginx.csr
Enter pass phrase for nginx.key: ##输入密匙
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [XX]:CN ##国家
State or Province Name (full name) []:HB #省
Locality Name (eg, city) [Default City]:WH ##城市
Organization Name (eg, company) [Default Company Ltd]:www.baibai.com ##公司名称
Organizational Unit Name (eg, section) []:www.baibai.com ##部门
Common Name (eg, your name or your server's hostname) []:www.baibai.com ##主机名
Email Address []:1@2.com ##邮箱
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []: ##可以不用输入
An optional company name []: ##可以不用输入
[root@localhost ssl]# ls
nginx.csr nginx.key
- 生成crt
[root@localhost ssl]# openssl x509 -req -days 365 -in nginx.csr -signkey nginx.key -out nginx.crt
Signature ok
subject=/C=CN/ST=HB/L=WH/O=www.baibai.com/OU=www.baibai.com/CN=www.baibai.com/emailAddress=1@2.com
Getting Private key
Enter pass phrase for nginx.key:
- mail配置段(用得少)
- 准备工作
停用postfix服务
service postfix stop
chkconfig postfix off
安装编译时需要配置的模块:–with-mail
./configure --prefix=/date/Appsfot/nginx` --with-mail
make && make install
- 配置示例
mail {
#mail服务名
server_name mail.example.com;
#提供认证方式,用于POP3/IMAP用户认证使用
auth_http localhost:9000/auth;
#启用或禁用mail代理
proxy on;
#支持ssl的相关配置
#表明SSLv3和TLSv1服务器密码是客户首选
ssl_prefer_server_ciphers on;
#使用的SSL协议
ssl_protocols TLSv1 SSLv3;
#支持密码(OpenSSL格式)
ssl_ciphers HIGH:!ADH:!MD5:@STRENFTH;
#所有的worker进程是否共享指定SSL缓存
ssl_session_cache shared:MAIL:10m;
#PEM编码的SSL证书路径
ssl_certificate /opt/mail.example.com.crt;
#PEM编码的SSL密码密钥
ssl_certificate_key /opt/mail.example.com.key;
#后端服务支持POP3
pop3_capabilities TOP USER;
#后端服务支持IMAP4
imap_capabilities IMAP4rev1 UIDPLUS QUOTA;
#后端服务支持SMTP
smtp_capabilities PIPELINING 8BITMIME DSN;
pop3_auth apop cram-md5;
imap_auth login cram-md5;
smtp_auth login cram-md5;
server {
listen 25;
protocol smtp;
timeout 120000;
}
server {
listen 465;
protocol smtp;
ssl on;
}
server {
listen 587;
protocol smtp;
starttls on;
}
server {
listen 110;
protocol pop3;
starttls on;
}
server {
listen 995;
protocol pop3;
ssl on;
}
server {
listen 143;
protocol imap;
starttls on;
}
server {
listen 993;
protocol imap;
ssl on;
}
}
- stream配置段(用得少)
- 准备工作
安装编译时需要配置的模块:–with-stream - stream配置示例
stream {
upstream backend {
hash $remote_addr consistent;
server backend1.example.com:12345 weight=5;
server 127.0.0.1:12345 max_fails=3 fail_timeout=30s;
server unix:/tmp/backend3;
}
upstream dns {
server 192.168.0.1:53535;
server dns.example.com:53;
}
server {
listen 12345;
proxy_connect_timeout 1s;
proxy_timeout 3s;
proxy_pass backend;
}
server {
listen 127.0.0.1:53 udp reuseport;
proxy_timeout 20s;
proxy_pass dns;
}
server {
listen [::1]:12345;
proxy_pass unix:/tmp/stream.socket;
}
}
注意:每次修改完配置记得检查格式是否正确并重启nginx!!!
配置虚拟主机
虚拟主机的配置每个server就是一个独立的虚拟主机
- 准备文件
- 在/etc/nginx/conf.d/目录创建子配置文件ip.conf, domain.conf, port.conf
- 创建演示目录
mkdir /data/nginx/{ip,domain,port} -pv - 在相应演示目录下创建index.html,并添加区分性内容
- 三种配置方式
- 基于ip地址
#示例
vim /etc/nginx/conf.d/ip.conf
#添加如下内容
server{
listen 192.168.129.26;
root /data/nginx/ip/;
index index.html;
}
#重启
nginx -s reload
#测试访问http://192.168.129.26/,访问内容正确即为成功
- 基于port
vim /etc/nginx/conf.d/port.conf
#添加如下内容
server{
listen 81;
root /data/nginx/port/;
}
#重启nginx后,测试访问http://192.168.129.26:81/,访问内容正确即为成功
- 基于domian(生产环境常用方式)
vim /etc/nginx/conf.d/domain.conf
#添加如下内容
server{
listen 80;
server_name www.a.com;
root /data/nginx/domain/;
}
#如果域名仅仅是测试域名,需在测试本机配置hosts文件
#举例:在hosts文件末尾追加
192.168.129.26 www.a.com
#nginx重启后测试访问www.a.com
#此处小坑:通过域名访问首先会解析到ip地址对应的页面,解析后就不会再去解析域名对应页面,此处做了两个实验发生冲突,导致结果不符预期,通常情况ip和域名的方式不会同时使用,此处暂时注释掉ip配置即可成功访问
Nginx调优及其相关原理(以下为初学汇总,新手过招,欢迎大佬指点)
正向代理与反向代理
-
正向代理
-
反向代理
Linux网络包的接收过程
该图片摘自网络,侵删!!
-
网卡收包过程
从整体上是网线中的高低电平转换到网卡FIFO存储再拷贝到系统主内存(DDR3)的过程,其中涉及到网卡控制器 -
涉及到的主要模块
- 网卡控制器
- CPU
- DMA
- 驱动程序
-
三种网络体系结构对比
图片摘自网络,侵删!!
-
在OSI模型的位置
属于物理层和链路层 -
物理网卡收到数据包的处理流程大致步骤:
- 网卡收到数据包
- 将数据包从网卡硬件缓存转移到服务器内存中
- 通知内核处理
- 经过TCP/IP协议逐层处理
- 应用程序通过read()从socket buffer读取数据
Linux网络IO模型
- 阻塞I/O模型
- 非阻塞I/O模型
- I/O多路复用模型
- select模型(操作方式:遍历 底层实现:数组 bitmap 时间复杂度:o(n))
- poll模型(操作方式:遍历 底层实现:链表 时间复杂度:o(n))
- epoll模型(操作方式:回调 底层实现:哈希表 时间复杂度:o(1))
- 信号驱动式I/O模型
- 异步I/O模型
- 总结
- 阻塞IO、非阻塞IO、多路复用IO、信号驱动IO,在内核数据copy到用户空间时都是阻塞的
- 阻塞IO和非阻塞IO的区别在于发起IO请求是否会被阻塞。如果会则是阻塞IO,不会则是非阻塞IO
- 同步IO和异步IO的区别在于实际的IO读写是否会阻塞请求进程。如果会则是同步IO,如果不阻塞,而是操作系统帮你做完IO操作再将结果返回给你,则是异步IO
TCP三次握手与四次挥手
- TCP标志位说明
- SYN - synchronous建立联机
- ACK - acknowledgement确认
- PSH - push传送
- FIN - finish结束
- RST - reset重置
- URG - urgent紧急
- Sequence number - 序列码
- Acknowledge number - 确认码
- TCP状态说明
- LISTEN - 侦听来自远方TCP端口的连接请求
- SYN-SENT -在发送连接请求后等待匹配的连接请求
- SYN-RECEIVED - 在收到和发送一个连接请求后等待对连接请求的确认
- ESTABLISHED- 代表一个打开的连接,数据可以传送给用户
- FIN-WAIT-1 - 等待远程TCP的连接中断请求,或先前的连接中断请求的确认
- FIN-WAIT-2 - 从远程TCP等待连接中断请求
- CLOSE-WAIT - 等待从本地用户发来的连接中断请求
- CLOSING -等待远程TCP对连接中断的确认
- LAST-ACK - 等待原来发向远程TCP的连接中断请求的确认
- TIME-WAIT -等待足够的时间以确保远程TCP接收到连接中断请求的确认
- CLOSED - 没有任何连接状态
- 三次握手
- 第一次握手:建立连接时,客户端A发送SYN包(SYN=j)到服务器B,并进入SYN_SEND状态,等待服务器B确认
- 第二次握手:服务器B收到SYN包,必须确认客户A的SYN(ACK=j+1),同时自己也发送一个SYN包(SYN=k),即SYN+ACK包,此时服务器B进入SYN_RECV状态
- 第三次握手:客户端A收到服务器B的SYN+ACK包,向服务器B发送确认包ACK(ACK=k+1),此包发送完毕,客户端A和服务器B进入ESTABLISHED状态,完成三次握手
- 其中,确认号数值=发送方的发送序号 +1(即接收方期望接收的下一个序列号)
- 四次挥手
- 客户端A发送一个FIN,用来关闭客户A到服务器B的数据传送
- 服务器B收到这个FIN,它发回一个ACK,确认序号为收到的序号加1。和SYN一样,一个FIN将占用一个序号
- 服务器B关闭与客户端A的连接,发送一个FIN给客户端A
- 客户端A发回ACK报文确认,并将确认序号设置为收到序号加1
- 相关问题
- shutdown()和close()的区别
shutdown()函数可以选择关闭全双工连接的读通道或者写通道,如果两个通道同时关闭,则这个连接不能再继续通信。close()函数会同时关闭全双工连接的读写通道,除了关闭连接外,还会释放套接字占用的文件描述符 - syn队列(半连接)
- backlog队列(全连接)
Nginx优化(优化应针对应用实际,不宜过度盲目优化)
- 配置文件优化项
- worker_processes
nginx 进程数,一般按照cpu核数来定,高并发情况下,为它的倍数 (eg:2个四核的cpu计为8)
- worker_cpu_affinity
一个nginx 进程打开的最多文件描述符数目,理论值应该是最多打开文件数(ulimit -n)与nginx 进程数相除,但是nginx 分配请求并不是那么均匀,所以最好与ulimit -n 的值保持一致
现在在linux 2.6内核下开启文件打开数为65535,worker_rlimit_nofile就相应应该填写65535
- worker_rlimit_nofile 00000001 00000010 00000100 00001000
为每个进程分配cpu,或者将一个进程分配到多个cpu(eg:将4 个进程分配到4 个cpu)
- use epoll
1.标准事件模型
select、poll属于标准事件模型,如果当前系统不存在更有效的方法,nginx会选择select或poll
2.高效事件模型
squeue:适用于 FreeBSD 4.1+, OpenBSD 2.9+, NetBSD 2.0 和 MacOS X, 使用双处理器的MacOS X系统使用kqueue可能会造成内核崩溃
epoll: 适用于Linux内核2.6版本及以后的系统
- worker_connections 65535
每个worker进程允许的最多连接数
理论上每台nginx服务器的最大连接数为worker_processes*worker_connections
- keepalive_timeout 60
keepalive 超时时间
- client_header_buffer_size 4k
客户端请求头部的缓冲区大小,这个可以根据你的系统分页大小来设置,一般一个请求头的大小不会超过1k,不过由于一般系统分页都要大于1k,所以这里设置为分页大小。
分页大小可以用命令getconf PAGESIZE查看
- open_file_cache max=65535 inactive=60s
这个将为打开文件指定缓存,默认是没有启用的,max 指定缓存数量,建议和打开文件数一致,inactive 是指经过多长时间文件没被请求后删除缓存
- open_file_cache_valid 80s
指定指多长时间检查一次缓存的有效信息
- open_file_cache_min_uses 1
指定open_file_cache 指令中的inactive 参数时间内文件的最少使用次数,如果超过限制,文件描述符一直是在缓存中打开的(eg:如果有一个文件在inactive 时间内一次没被使用,它将被移除)
- 系统内核参数的优化
net.ipv4.tcp_max_tw_buckets = 6000
timewait 的数量,默认是180000
net.ipv4.ip_local_port_range = 1024 65000
允许系统打开的端口范围
net.ipv4.tcp_tw_recycle = 1
启用timewait 快速回收
net.ipv4.tcp_tw_reuse = 1
开启重用。允许将TIME-WAIT sockets 重新用于新的TCP 连接
- 防盗链
- 在nginx.conf文件加入一个location配置项
- 配置示例
#正则匹配需要用防盗链的文件,或者设置需要用防盗链的目录
location ~* ^.+\.(gif|jpg|png|swf|flv|rar|zip)$ {
#配置可直接访问的服务
valid_referers none blocked www.-------.com ---------.com;
#不在上述配置中的,均需要跳转防盗链
if ($invalid_referer) {
return 404;
#rewrite ^/ https://www.-------.com/wwww.jpg;(可配置一个友好的提示图片 注意:该图片放在外网)
}
access_log off;
root html/www;
expires 1d;
break;
}