什么是nginx
2012年成长为世界第二大web服务器
业内高性能web服务器代名词
竞争对手
1 Apache2 Lighttped(受欧美界青睐的,与nginx有的一拼的)3 Tomcat("java语言web服务器 先天就是重量级性能跟nginx没法比")4 Jetty("java语言web服务器 先天就是重量级性能跟nginx没法比")5 IIS(window系统)
基于REST架构风格,以统一资源定位符(URI)货统一资源描述符(URL)作为沟通依据
基于事件驱动
高度模块化的设计----->第三方模块众多
可运行在众多平台
可以使用当前操作系统的高效API来提高自己的性能 支持linux上的epoll,epoll是大并网络连接的利器
为什么是nginx
1.因为很吊,体现在如下几个方面
非要用一句话总结,那就是能够支持高并发请求的同时保持高效的服务
更快
单次请求得到更快的响应高扩展性
nginx设计极具扩展性,完全是由多个不同层次/不同功能/不同类型且耦合度极低的模块组成
并且Nginx的模块都是嵌入到二进制文件中执行的
-- --比如HTTP模块中,还设计了HTTP过滤模块,一个正常的HTTP模块处理完请求后,会有一连串的HTTP过滤模块再对其进行过滤。 -- --我们开发一个新的HTTP模块时,可以使用HTTP核心模块 events模块 log模块等 还可以自由的复用各种过滤器模块
高可靠性
低内存消耗
一般情况下,10000个非活跃的HTTP Keep-Alive连接在Nginx中仅消耗2.5M内存
单机支持10万以上的并发连接
理论上,Nginx的并发连接数仅取决于内存,10万远未封顶,当然与业务特点也紧密相连
热部署
由于master管理进程与worker工作进程的分离设计 使得nginx可以不停止服务就能升级可执行文件/更新配置项目/更换日志文件等
nginx的架构设计很高明
先天的事件驱动型设计 全异步的网络I/O处理机制 极少的进程间切换
强大的开源社区
数以万计的码畜们为nginx添砖加瓦
2.为什么这么吊
这里我们着重讲解一下nginx使用的事件驱动架构,简单来说如下所示
graph LRA[事件发生源]--产生事件-->B[事件收集器收集]B--分发事件-->C[时件处理器注册自己感兴趣的事件并消费之]
事件源: 一般由网卡和磁盘产生
事件收集器: nginx的事件模块,如ngx_epoll_module
消费者: 所有其它模块
消费者首先向事件模块注册自己感兴趣的事件类型,当该类型事件产生时,事件模块就会把事件分发到相应消费者模块
nginx采用完全的事件驱动架构来处理业务,那它与传统的web服务器有哪些不同呢?
传统web服务器(比如Apache)
一个连接建立以后到关闭之前,所有的操作不再是事件操作,退化成了按序执行每个操作
整个请求在连接期间始终占用cpu 内存资源,及时没有作任何有意义的事
把一个进程或线程作为事件消费者
,当一个请求产生事件被该进程处理时,直到请求处理结束时进程资源都将被这一个请求占用
Apache采用的所谓事件驱动仅仅是体现在TCP连接的建立和关闭事件上
nginx服务器
不会使用进程或者线程作为事件消费者
,所谓的事件消费者只能是某个模块(在这里没有进程的概念)只有事件收集和分发器才有资格占用进程资源
重要差别
前者是每个事件消费者独占一个进程资源,后者的事件消费者只是被事件分发者进程短期调用而已
nginx这种设计的一个弊端
即每个事件消费者都不能有阻塞行为,否则会长时间占用事件分发者进程而导致其它事件得不到及时响应,
尤其是每个消费者不可以让进程转为休眠或等待状态
,这都增加了码畜们的开发难度
手摸手教你使用nginx
准备工作
安装nginx开发所需的最基本的库
以下是完成web服务器功能所需要的基本包
使用uname -a 查看linuxe内核是否时2.6及以上版本
因为只有linux2.6及以上版本才支持epoll,能够更大限度发挥nginx的威力
GCC编译器 使用yum install -y gcc安装
GCC(GNU Compile Collection)可以用来编译C语言程序,因为有时候nginx不会直接提供二进制可执行程序,需要自己编译
PCRE库
Perl正则兼容表达式包,pcre-devel时PCRE做二次开发时所需要的开发库,也是nginx开发所必需的
zlib库 yum install -y gzip gzip-devel
nginx.conf中配置了gzip on对Http 包的内容作gzip格式压缩,需要用
zlip-devel是二次开发所需要的库OpenSSL库 yum install -y openssl openssl-devel
如果想使用更安全的SSL 协议传输HTTP,就需要该包,如果要使用MD5或者SHA1包,也需要Openssl包
需要了解的几个目录
nginx源码存放目录,随便放,没人管你,看个人癖好
Nginx编译阶段产生的中间目录
该目录用于存放configure和make命令执行后,生成的中间目录,默认情况下,生产objs目录存放在源码目录中
部署目录默认
/usr/local/nginx
存放nginx运行期间所需的二进制文件,配置文件等。
日志文件存放目录
如果你要研究nginx的底层架构,那么打开debug级别日志后,会产生大量日志,所以最好弄一个大点的磁盘
源码编译安装
官方下载nginx源码并解压后,cd到源码目录 ./configure && make && make install
下面我们来看看这几个命令做了哪些见不得人的勾当
1 大部分工作其实都是configure命令做了,使用config --help来查看都是有哪些命令 我们一般只关心以下几个2 --prefix=PATH 安装目录,默认是/usr/local/nginx --sbin-path=PATH可执行文件防止路径,默认是?<prefix>/sbin/nginx --conf-path=PATH配置文件路径,默认是<prefix>/conf/nginx.conf --error-log-path=PATH错误日志文件,默认<prefix>/logs/error.log 后面会在nginx.conf中详细介绍把不同请求的错误日志打到不同的log文件中 --pid-path=PATH pid文件存放目录,默认<prefix>/logs/nginx.pid 这个文件以ascii码存放着nginx master的进程id 更多的请自行搜索~~~~
必须知道的命令
/usr/local/nginx/sbin/nginx命令
默认加载/usr/local/nginx/conf/nginx.conf
/usr/local/nginx/sbin/nginx -c <配置文件目录> 来启动非默认的配置 /usr/local/nginx/sbin/nginx -p <目录> 来指定nginx的安装目录 /usr/local/nginx/sbin/nginx -g 来临时指定一些全局配置项 /usr/local/nginx/sbin/nginx -g "pid /var/nginx/test.pid;" 意味着把pid写到另一个文件中,-g指定的不能与默认冲突,另外以-g启动的ngix在停止事也需要加上-g /usr/local/nginx/sbin/nginx -g "pid /var/nginx/test.pid;" -s stop. 如果不加-g 就找不到pid文件了
/usr/local/nginx/sbin/nginx -t
不启动nginx情况下,测试配置文件将是否有误
/usr/local/nginx/sbin/nginx -V
显示版本信息
/usr/local/nginx/sbin/nginx -s stop
快速停止服务处理完当前正在处理的请求后,关闭服务
/usr/local/nginx/sbin/nginx -s reload
运行中的nginx重新加载nginix.conf 等效于kill -s SIGHUP <nginx master pid>
/usr/local/nginx/sbin/nginx -s reopen
等效于kill -s SIGUSR1 <nginx master pid>
可以重新打开配置文件,这样我们就可以把当前的日志文件改名或者移动,使其不会太大
平滑升级nginx
1.kill -s SIGUSR2 <nginx master pid> 会将nginx.pid重命名为nginx.pid.oldbin
2.使用命令启动nginx
3.使用kill -s SIGQUIT <旧版本的master pid> 关闭旧版本服务
nginx配置
1 生产环境一般都是一个master进程管理多个worker进程,worker进程与cpu核心数相等,每个worker都能繁忙的提供服务处理。 2 master进程只负责worker的管理。worker进程之间通过共享内存,原子操作等进程间通信机制实现负载均衡等功能 3 nginx是支持单进程 (只有一个master)提供服务的。使用master+worker的优势如下 1master只提供纯管理工作,只提供命令行服务。 2多worker进程可以提高服务的健壮型,可以充分利用多核cpu
为什么需要把nginx的worker 进程数量设置的根cpu核心数一致呢
在apache上每个进程每一时刻只能处理一个请求,因此要想并发处理更多的并发请求数就要设置很多个进程,而大量的进程间切换很消耗内存资源
而nginx的一个worker进程处理的请求数只受限于内存大小,并且worker进程之间处理并发请求时几乎没有同步锁的限制,worker进程也不会进入睡眠状态,因此当nginx进程与cpu核数一致时(最好每一个worker绑定一个内核),进程切换的代价是最小的
将进程与cpu绑定,这样不会出现多个进程抢占一个cpu的问题,就不会出现同步问题,这样在内核的调度上就实现了完全的并发
nginx.conf文件说明
nginx的配置文件采用块配置项的组织方式,如下所示
全局配置 块配置项名1 { 配置项名 配置项值1 配置项值1; } 块配置项名2 参数 { 配置项名 配置项值1 配置项值1; } 基本的块配置项有:events http server location upstreams 快配置项可以嵌套 配置项名必须是nginx的某一个配置模块中想要处理的,否则会出错 如果配置项值中包括语法符号,比如空格,需要用引号括注配置项值
配置项的单位,如果是空间大小是 k或者m
有些模块允许配置项值中使用变量,变量前加上$
一个具体的nginx.conf配置说明如下
可能包括以下几部分,这里我尽可能多的写几个哈~方便自己以后回头查阅
全局配置
上面两个配置将worder进程与cpu实现绑定
将其它配置文件嵌入到nginx.conf中,它的目录可以是绝对的,也可以是相对的,相对nginx.conf所在目录
当进程意外终止时,nginx会把进程执行时的内存内容转储到一个core文件中,方便我们查看寄存器堆栈来定位问题,上面两个配置设定这个文件的大小和目录
可以是/dev/null,这样就不会有任何日志了,这也是关闭error日志的唯一手段了
如果日志级别写成debug,那么在最初configure时需要加上--with-debug配置项
用于当master进程启动后,fork出的worker进程运行在哪个用户和用户组下
需要在configure时使用参数 --user=username --group=groupname
user username [groupname];
daemo on|off; 是否以守护进程方式运行服务,默认on
master_process on|off; 是否以master/worker方式工作 默认on
error_log /path/file level; 错误日志 默认logs/error.log error
woker_rlimit_nofile limit; 一个worker进程可以打开的最大句柄描述符个数
worker_rlimit_core size;
worker_directory path;
env VAR|VAR=VALUE 这个配置项可以让用户直接操作系统变量
include /path/file
worker_process 4;
worder_cpu_affinity 1000 0100 0010 0001
worker_priority nice nginx 的进程优先级配置s
事件类配置
events {
debug_connection IP; 只对该ip的请求才输出debug级别的日志,可以通过该方法定位bug accept_mutex [on|off]; 负载均衡锁,默认打开,如果关闭建立TCP链接的耗时更短,但每个worker的负载会非常不均衡 lock_file path/file; accept锁需要这个文件,如果由于程序的编译和操作系统的架构等因素导致nginx不支持原子锁, 就会用文件锁来实现accept锁。如果支持原子锁,这个文件就没意义了 accept_mutex_delay Nms; 使用文件锁后,同一时间只有一个worker能获得到这个锁,这个锁不是阻塞所,worker获取不到,会立即返回,然后间隔这个时间之后再去获取。 multi_accept on|off;默认关闭,当事件模型通知有新连接时,尽可能的对本次调度中客户端发起的所有的TCP请求都去建立连接use [poll| select | epoll| kqueue]; Nginx 默认会选择最合适的事件模型 woker_connections number; 每个worker进程可以同时处理的最大连接数
}
http模块
静态web服务器主要由nginx中的ngx_http_core_module实现
http模块是一个最小静态web服务器的基本配置http {
gzip on; server { listen address:port; address可以是ip或者hostname 在port后可以加上一些参数 如下所示 listen 443 default_server ssl deferred; deault_server当一个请求无法匹配所有的域名后,使用这个作为默认处理域名 ssl 在当前端口的连接必须是基于SSL协议 deferred用户发起建立连接请求,完成TCP三次握手之后,内核也不会调度worker进程来处理这次链接, 只有用户真的发了数据(网卡收到请求数据包)内核才会唤醒worker进程去处理, server_name name ;后面可以跟多个主机名称,用顿号隔开 'nginx 收到请求后,会先取出Header头中的host,根server中去比较,如果匹配了多个server,会根据匹配优先级来选择用哪个server, 如果都找不到,就用server_name 为空的server块' server_name_in_redirect on|off 默认为on '如果为开启,那么首先查找server_name,如果没有找到,查找请求头的HOST字段,如果没有,则以当前服务器的IP进行拼接 location [=|~|~*|^~|@] /uri/ {} uri参数里可以用正则 location = / {} 用户请求是/时匹配 ~ URI大小写敏感 ~* 匹配URI时忽略大小写 ^~前半部分大小写敏感匹配,如 location ^~ /images/ {}以/images/ 开始的请求都会匹配 @表示nginx内部请求之间的重定向,不直接处理用户请求 root path 文件路径,默认是root html root配置还可以位于http模块下或者location下,如果位于location下含义如下 location /download/ { root /opt/web/html/; } 如果用户的请求是/download/test.html,web服务器将会返回服务器上的/opt/web/html/download/test.html文件中内容 location /conf { location下配置说明 alias /usr/local/nginx/conf/ 如果用户请求是/conf/nginx.conf,用户实际想访问/usr/local/nginx/conf/nginx.conf,就可以使用alias配置 alias只能放在location中 root path; index 首页文件; } error_page code uri|@named_location 也可以在location块中配置 可以作如下配置 error_code 404 /404.html error_code 501 502 504 /50x.html error_code 403 http://example.com/forbidden.html error_code 404 = @fetch 也可以改变错误码 error_page 404 =200 /empty.gif 或者不指定错误码 ,由重定向后的实际处理决定 error_page 404 /empty.gif 如果不想修改uri,只是想定向到另一个location中处理,可以如下配置 location / { error_code 404 @fallback } location @fallback { proxy_pass http://backend; } try_files path1 path2 uri 尝试访问每一个path找到了就结束请求 ,都找不到久落到了uri上,所以uri必须存在 type { MIME类型设置,可以位于server location块中 type说白了就是不同的文件类型用不同的应用程序打开。 } } "http中还有贼多的配置 比如tcp网络链接 内存资源管理 对客户端请求的限制 文件操作的优化等等,等
作者:washCutBlow
链接:https://www.jianshu.com/p/7bc180650829
共同学习,写下你的评论
评论加载中...
作者其他优质文章