01 . Nginx简介及部署
Nginx简介
Nginx(发音同engine x)是一个异步框架的 Web 服务器,也可以用作反向代理,负载平衡器 和 HTTP 缓存。该软件由 Igor Sysoev 创建,并于2004年首次公开发布。同名公司成立于2011年,以提供支持。Nginx 是一款免费的开源软件,根据类 BSD 许可证的条款发布。一大部分Web服务器使用 Nginx ,通常作为负载均衡器。
Nginx 的特点
- 更快:
- 单次请求会得到更快的响应。
- 在高并发环境下,Nginx 比其他 WEB 服务器有更快的响应。
- 高扩展性:
- Nginx 是基于模块化设计,由多个耦合度极低的模块组成,因此具有很高的扩展性。许多高流量的网站都倾向于开发符合自己业务特性的定制模块。
- 高可靠性:
- Nginx 的可靠性来自于其核心框架代码的优秀设计,模块设计的简单性。另外,官方提供的常用模块都非常稳定,每个 worker 进程相对独立,master 进程在一个 worker 进程出错时可以快速拉起新的 worker 子进程提供服务。
- 低内存消耗:
- 一般情况下,10000个非活跃的
HTTP Keep-Alive
连接在 Nginx 中仅消耗2.5MB
的内存,这是 Nginx 支持高并发连接的基础。 - 单机支持10万以上的并发连接:理论上,Nginx 支持的并发连接上限取决于内存,10万远未封顶。
- 一般情况下,10000个非活跃的
- 热部署:
- master 进程与 worker 进程的分离设计,使得 Nginx 能够提供热部署功能,即在 7x24 小时不间断服务的前提下,升级 Nginx 的可执行文件。当然,它也支持不停止服务就更新配置项,更换日志文件等功能。
- 最自由的 BSD 许可协议:
- 这是 Nginx 可以快速发展的强大动力。BSD 许可协议不只是允许用户免费使用 Nginx ,它还允许用户在自己的项目中直接使用或修改 Nginx 源码,然后发布。
# 上面是官方对Nginx的特点介绍,下面是我个人加的,大致差不多:
# 1. apache 的功能 nginx 都具有,且配置简单,但其稳定性没有 apache 好
# 2. 高性能的反向代理服务器(负载均衡器),代理 Web 服务器(用的最多)
# 3. 轻量级、高性能的 HTTP Server:对 CPU 等硬件资源消耗小(在早期官网上测试:10000 个非活跃的 HTTP KEEPALIVE 连接仅占用 2.5M 内存);taobao 和阿里曾对 nginx 做过测试,最多支持 5 万个并发连接,可以解决 C10k 的问题(apache 的并发量为 200,到达 2000 就变得很慢,通过集群,并发量可以达到 2 万左右))
# 4. 基于模块化设计
# 5. 基于 EPOLL 事件驱动模型,所以是高性能
# 6. 重新加载配置及在线升级时,不需要中断正在处理的请求(nginx 热部署),可以做到平滑升级
# 7. URL 重写(rewrite)模块
# 8. 支持验证 HTTP referer,实现反盗链机制。所谓反盗链就是网站上的某一个页面只允许在该网站上点击此超链接跳转,不允许别人仿照写的页面跳转到我们的超链接
# 9. 支持 sendfile,将数据在内核中直接封装响应客户端,不需要将数据复制到进程地址空间。sendfile 是 Linux 进程内核里面的一种机制,这个机制也是为了加快网站服务器的访问速度。
# 10. 支持缓存功能
# 上面有一些概念,下面有解释,大佬可跳过
Nginx为什么会出现
/*
互联网的数据量快速增长
互联网的快速普及
全球化
物联网
摩尔定律
性能提升
低效的Apache
一个连接对应一个进程
*/
C10K 概念
谈到C10K,可以讲一下他的由来:
最早的1990-2000年web1.0,互联网大部分使用场景是下载一个html页面,用户在浏览器中查看网页上信息。这个时期不存在C10K问题。
2000-2010 年,web2.0 时代到来之后就不同了,一方面是普及率大大提高了,用户群体几何倍数增长,另一方面不再是单纯的浏览万维网网页,逐渐开始交互,而且应用程序的逻辑也变的更复杂,从简单的表单提交,到即时通信和在线实时互动。
C10K 的问题就出来了。每一个用户都必须与服务器保持 TCP 连接才能进行实时的数据交互。Facebook 这样的网站同一时间的并发 TCP 连接可能会过亿。
腾讯 QQ 当时也有 C10K 的问题,只不过他们用了 UDP 这种原始的包交换协议来实现的,绕开了这个难题。如果当时有 Epel 技术,他们肯定会 TCP,后来手机 QQ,微信都采用 TCP 技术。
问题来了,最初的服务器都是基于进程/线程模型的,新到来一个 TCP 连接,就需要分配一个进程(或者线程),而进程又是操作系统最昂贵的资源,一台机器无法创建很多进程。如果是 C10K 就要创建一万个进程,那么操作系统是无法承受的。
即使采用分布式系统,维持一亿用户在线就需要十万台服务器,成本巨大,也只有 Facebook,Google,雅虎才有财力购买如此多的服务器。这就是 C10K 的本质。
Facebooke: (脸书) 美国的一个社交网络服务网站,创办者是哈佛大学的学生
截止在2013年每天上传 3.5 亿照片。也是世界领先的照片分享站点。
截止 2012 年 5 月,Facebook 约有 9 亿用户,2018 年 9 月,遭受过一次黑客攻击,涉及 5000 万用户,因为泄露,将面临欧盟 16.3 亿美元的罚款。但是在 09 年一直被中国屏蔽。
2018 年世界品牌 500 强,Facebook 排在 11 位。
C10K解决方案
从网络编程技术角度来说,主要思路
1. 每个进程/线程处理一个连接
# 这一思路最为直接。但是由于申请进程/线程会占用相当可观的系统资源,同时对于多线程/进程的管理会给系统造成压力,可扩展性差
# 在服务器资源还没有富裕到足够程度的时候,是不可行的:即使资源足够富裕,效率也不够高。
2. 每个进程/线程同时处理多个连接(IO多路复用)
1>传统思路
# 最简单方法是循环挨个挨个处理各个连接,每个连接对应一个socket,当所有socket都有数据的时候,这种方法是可行的。
# 但是当应用读取某个socket的文件数据没准备好时候,整个应用就会阻塞在这里等待文件句柄,即使别的文件句柄OK了,也无法往下处理。
# 思路:直接循环处理多个连接
# 问题: 任一文件句柄的不成功会阻塞整个应用
2>select
# 要解决上面阻塞的问题,思路很简单,如果我在读取文件句柄之前,先查看他的状态,准备好了就处理,不准备好就不处理,
# 于是有了select方案。用一个fd_set结构体来告诉内核同时监控多个文件句柄,当其中有文件句柄的状态发生指定变化(例如某句柄由不可用变为可用)或超时,则调用返回。之后应用可以使用FD_ISSET来逐个查看是哪个文件句柄的状态发生了变化。
# 这样做,小规模连接问题不大,但当连接数很多(文件句柄个数很多)的时候,逐个检查状态就很慢了,因此,select往往存在管理的句柄上限(FD——SETSIZE).同时,在使用上,因为只有一个字段记录和发生事件,每次调用之前要重新初始化fd_sed结构体。
# 思路:有连接请求抵达了再检查处理
# 问题:句柄上限+重复初始化+逐个排查所有文件句柄状态效率不高。
3>poll
# poll主要解决select的前两个问题:通过一个pollfd数组向内核传递需要关注的时间 消除文件句柄上限,同时使用不同字段分别标注关注时间和发生事件,来避免重复初始化
# 思路:设计新的数据结构提供使用效率
# 问题:逐个排查所有文件句柄效率不高。
4>epoll
# 既然逐个排查所有文件句柄状态效率不高,很自然的,如果调用返回的时候只给应用提供发生了状态变化(很可能是数据ready)的文件句柄,进行排查的效率不久高多了么。
# epoll采用了这种设计,使用与大规模的应用场景
# 试验表明:当文件句柄数目超过10以后,epoll性能将优于select 和poll:
# 当文件句柄数目达到10K的时候,epoll已经超过select和poll两个数量级。
# 思路:只返回状态变化的文件句柄
# 问题:依赖特定平台(Linux).
# 因为 Linux 是互联网企业中使用率最高的操作系统,Epoll 就成为 C10K killer,高并发,高性能,异步非阻塞这些技术的代名词了。FreeBSD 推出了 kqueue,linux 推出了 epoll,windows 推出了 IOCP,Solaris 推出了/dev/poll.
# 这些操作系统提供的功能就是为了解决 C10K 的问题。epoll 技术的编程模型就是异步非阻塞回调,也可以叫做 Reactor,事件驱动,事件轮询。
# Nginx,libenent,Node.js 这些就是 epoll 时代的产物。
事件驱动模型
在说事件驱动模型之前先了解以下几个概念: 同步和异步,阻塞和非阻塞**
同步机制和异步机制
用于描述网络中主机通信的模式:
同步机制
发送方发送请求后,需要等待接 收方回应,才会继续发送下一个请求,效率不高
异步机制
发送发发送请求后,不等待接收方回应,
阻塞和非阻塞
用于描述进程处理 IO 调用的方式(和磁盘打一次交道就是一次 IO)
阻塞机制
调用结果返回前,进程会从运行状态切换到挂起状态,待调用结果返回后,进程再次进入就绪状态,获取 CPU 后继续执行:
非阻塞机制
调用结果如果不能及时返回,进程也 不会进入挂起状态,而是开始处理下一个请求,待调用结果返回时,进程暂停运行该任务,开始继续处理上一个任务
Nginx上面的某一个进程收到客户端的一个访问请求,无论客户端访问的是哪个页面,进程都要去本地的磁盘找到网页文件,找到之后给客户端响应,但是nginx进程没有权限操纵硬件寻找网页,所以进程要先将请求转交给内核,由kernel去磁盘中搜索这个文件,找到文件将文件返回给进程,再由进程返回给客户端,
所谓阻塞指的是:
进程将请求转交给内核之后进程会一直等待内核返回给它结果才会接收其他的访问请求,而这段期间进程就处于sleeping的状态;
而非阻塞指的是:
进程不会等待内核,而是可以继续接收下一个请求,当内核将第一个请求的结果返回给进程之后,进程会暂停当前正在接收的请求,来响应内核返回给它的结果。
#### Nginx 常用架构
# 1. client nginx PHP # nginx 和 PHP 结合解析静态页面和 PHP 页面
# 2. client 访问静态页面,由 nginx 解析: 动态页面,nginx 代理到后端的 Web 上解析
# 3. nginx 本身不负责任何页面的相应,client 无论访问静态还是动态都代理到后端的服务器上:
# Nginx 对操作系统本身的性能消耗非常小的,故由 nginx 来接收客户端连接,可以增加客户端访问速度.另 nginx 支持缓存功能,也可以加快客户端的访问速度(没有缓存会增加 nginx 代理和 Web 的交互)。
# 大多数加快网站的访问速度的方法都是缓存,当然缓存不仅仅可以使用 nginx 服务器,还可以专门搭建一个缓存服务器
HTTP 的请求报文和响应报文
HTTP 请求报文语法
<method><request-URL><version>
<headers>
<entity-body>
method: # 客户端请求网站资源的方法:GET、PUT、POST、Delete、HEAD
request-URL: # 请求的地址,就是网址(F12--->Network--->Header)
version: # 请求 http 的版本
headers: # 报文头
entity-body: # 请求的实体
HTTP 响应报文语法
<version><status><reason-phrase>
<headers>
<entity-body>
响应报文示例
HTTP/1.1 200 OK
X-Powerd=By: PHP/5.2.17 # 页面的结果是 PHP 应用程序返回来的
Vary: Accept-Encoding,Cookie,User-Agent
Cache-Control: max-age=3,must-revalidate # 缓存
Content-Encoding: gzip # 内容的编码采用压缩
Content-Length: 6931 # 内容的长度
Nginx优势
除了上面所提到的Nginx事件驱动模型,Nginx还有以下优势:
轻量级
/* 1.功能模块少
2.代码模块少
3.高可靠,热部署,可扩展.
4.BSD许可证.
是一个给于使用者很大自由的协议,BSD 代码鼓励代码共享,但需要尊重代码作者的著作权。
BSD由于允许使用者修改和重新发布代码,也允许使用或在BSD代码上开发商业软件发布和销售,
因此是对商业集成很友好的协议。而很多的公司企业在选用开源产品的时候都首选BSD协议,
因为可以完全控制这些第三方的代码,在必要的时候可以修改或者二次开发。
5.CPU亲和
CPU亲和是一种把CPU核心跟nginx工作进程绑定在一起,把每个worker进程固定在一个CPU上执行,减少切换CPU的cache miss,获得更好的性能。
*/
可以高并发
# 官方测试Nginx能够支撑5万并发连接,实际生产环境中只能抗住2-4万的并发
# 采用最新的epoll和kqueue网络I/O模型,而传统的Apache 使用的select模型,消耗CPU比较高。
内存消耗少
稳定性高
Nginx基本功能
# 1.处理静态文件
# 2.反向代理加速
# 3.通过fastcgi,简单的负载均衡和容错。
# 4.SSL 支持
# 5.模块化
Nginx应用场景
// 1.静态请求
// 2.反向代理
// 3.负载均衡
// 4.资源缓存
// 5.安全防护
// 6.访问限制IP
// 7.访问认证
/*
核心主要是以下三个应用:
静态资源服务: 通过本地文件系统提供服务
反向代理服务: Nginx的强大性能,缓存,负载均衡
API: OpenResty
*/
同类型产品
Tengine
简介
/*
Tengine是由淘宝网发起的Web服务器项目,他在Nginx的基础上,针对大量访问网站的需求,
增加了很多高级功能和特性,Tengine的性能和稳定性已经在大型网站如淘宝网,天猫商城得到了很好的检验,
他的目标就是打造一个高效,稳定,安全易用的平台.
*/
OpenResty
/*
这个开源Web平台主要由章亦春维护,2011年之前由淘宝赞助,后来12-16由美国的CloudFlare公司提供支持,
目前由OpenResty软件基金会和OpenRest lnc公司提供支持.
因为大部分Nginx模块都是由软件包的维护者开发,所以可以确保这些模块及其他组件可以很好的一起工作.
因为Nginx模块开发非常难,而他把nginx的事件驱动,非以lua语言开发然后提供给开发者,兼具高性能开发效率提升特点.
*/
Nginx结构解析
线程操作
nginx在启动后,在unix系统中会以daemon(服务)的方式在后台运行,后台进程包含一个master进程和多个worker进程。
我们只需要与master进程通信就行了。master进程会接收来自外界发来的信号,再根据信号做不同的事情。所以我们要控制nginx,只需要通过 kill 向 master 进程发送信号就行了。
比如kill -HUP pid,则是告诉nginx,从容地重启nginx,我们一般用这个信号来重启nginx,或重新加载配置,因为是从容地重启,因此服务是不中断的。
master进程在接收到HUP信号后是怎么做的呢?首先master进程在接到信号后,会先重新加载配置文件,然后再启动新的worker进程,并向所有老的worker进程发送信号,告诉他们可以光荣退休了。
新的worker在启动后,就开始接收新的请求,而老的worker在收到来自master的信号后,就不再接收新的请求,并且在当前进程中的所有未处理完的请求处理完成后,再退出。
事件模型
现在,我们知道了当我们在操作nginx的时候,nginx内部做了些什么事情,那么,worker进程又是如何处理请求的呢?我们前面有提到,worker进程之间是平等的,每个进程,处理请求的机会也是一样的。当我们提供80端口的http服务时,连接请求过来,每个进程都有可能处理这个连接,怎么做到的呢?
首先,每个worker进程都是从master进程fork过来,在master进程里面,先建立好需要listen的 socket(listenfd之后,然后再fork出多个worker 进程。
所有worker进程的listenfd会在新连接到来时变得可读,为保证只有一个进程处理该连接,所有worker进程在注册listenfd读事件前抢accept_mutex,抢到互斥锁的那个进程注册listenfd读事件,在读事件里调用accept接受该连接。
当一个worker进程在accept这个连接之后,就开始读取请求,解析请求,处理请求,产生数据后,再返回给客户端。
最后才断开连接,这样一个完整的请求就是这样的了。我们可以看到一个请求完全由worker进程来处理,而且只在一个worker进程中处理。
事件处理
nginx用的是异步非阻塞
首先,请求过来,要建立连接,然后再接收数据,接收数据后,再发送数据。具体到系统底层,就是读写事件,而当读写事件没有准备好时,必然不可操作,如果不用非阻塞的方式来调用,那就得阻塞调用了,事件没有准备好,那就只能等了,等事件准备好了,你再继续吧。
非阻塞就是,事件没有准备好,马上返回EAGAIN,告诉你,事件还没准备好呢,慌什么,过会再来吧。好吧,你过一会,再来检查一下事件,直到事件准备好了为止,在这期间,你就可以先去做其它事情,然后再来看看事件好了没。虽然不阻塞了,但你得不时地过来检查一下事件的状态,你可以做更多的事情了,但带来的开销也是不小的。
所以,才会有了异步非阻塞的事件处理机制,具体到系统调用就是 select/poll/epoll/kqueue 这样的系统调用。它们提供了一种机制,让你可以同时监控多个事件,调用他们是阻塞的,但可以设置超时时间,在超时时间之内,如果有事件准备好了,就返回。
这种机制正好解决了我们上面的两个问题,拿 epoll 为例(在后面的例子中,我们多以 epoll 为例子,以代表这一类函数),当事件没准备好时,放到epoll 里面,事件准备好了,我们就去读写,当读写返回 EAGAIN 时,我们将它再次加入到 epoll 里面。这样,只要有事件准备好了,我们就去处理它,只有当所有事件都没准备好时,才在 epoll 里面等着。
这样,我们就可以并发处理大量的并发了,当然,这里的并发请求,是指未处理完的请求,线程只有一个,所以同时能处理的请求当然只有一个了,只是在请求间进行不断地切换而已,切换也是因为异步事件未准备好,而主动让出的。这里的切换是没有任何代价,你可以理解为循环处理多个准备好的事件,事实上就是这样的。
与多线程相比,这种事件处理方式是有很大的优势的,不需要创建线程,每个请求占用的内存也很少,没有上下文切换,事件处理非常的轻量级。并发数再多也不会导致无谓的资源浪费(上下文切换)。更多的并发数,只是会占用更多的内存而已。
一个是基于轮询的,一个是基于事件的。apache 想知道5个孩子饿不饿,需要一个个去问,问到谁饿了就知道了。nginx 想知道5个孩子饿不饿,注册一个回调,谁饿了就自己报道一声,调用一下事件。可以这么理解。
Nginx启动顺序
post-read # 1读取请求内容阶段,nginx读取并解析完请求头之后就立即开始运行;
server-rewrite # 2.server请求地址重写阶段;
find-config # 3.配置查找阶段,用来完成当前请求与location配重块之间的配对工作;
rewrite # 4.location请求地址重写阶段,当ngx_rewrite指令用于location中,就是再这个阶段运行的;
post-rewrite # 5.请求地址重写提交阶段,当nginx完成rewrite阶段所要求的内部跳转动作,如果rewrite阶段有这个要求的话;
preaccess # 6.访问权限检查准备阶段,ngx_limit_req和ngx_limit_zone在这个阶段运行,ngx_limit_req可以控制请求的访问频率,ngx_limit_zone可以控制访问的并发度;
access # 7.权限检查阶段,ngx_access在这个阶段运行,配置指令多是执行访问控制相关的任务,如检查用户的访问权限,检查用户的来源IP是否合法;
post-access # 8.访问权限检查提交阶段;
try-files # 9.配置项try_files处理阶段;
content # 10.内容产生阶段,是所有请求处理阶段中最为重要的阶段,因为这个阶段的指令通常是用来生成HTTP响应内容的;
log # 11.日志模块处理阶段;
# 每一个阶段上能够注冊handler。处理请求就是执行每一个阶段上注冊的handler。
# Nginx模块提供的配置指令仅仅会一般仅仅会注冊并执行在当中的某一个处理阶段。
# 比方,set指令属于rewrite模块的,执行在rewrite阶段,deny和allow执行在access阶段。
子请求
Nginx中从客户端访问的叫主请求,他被nginx这个程序来逐步处理。还有一种内部的请求,叫子请求。
比如下面这个,将请求交给foo和bar的区块去处理。
location /main {
echo_location /foo; #echo_location发送子请求到指定的location
echo_location /bar;
}
location /foo {
echo foo;
}
location /bar {
echo bar;
}
#curl http://127.0.0.1/main
#返回 foo
# bar
Nginx如何工作的
// Nginx使用了一个可预见式(predictable)的进程模型,调度可用的硬件资源:
/*
1. 主进程执行特权操作,如读取配置和绑定端口,还负责创建子进程(下面三种类型).
2. 缓存加载进程(cache loader process)在启动时运行,把基于磁盘的缓存(disk-basedcache)加载到内存中,
然后退出,对他的调度很谨慎,所以其资源需求很低.
3. 缓存管理进程(cache manager process)周期性运行,并削减磁盘缓存(prunes entries from the disk caches),
以保证保持在其配置范围内.
4. 工作进程(worker processes)才是执行所有实际任务的进程; 处理网络连接,读取和写入内容到磁盘,与上游服务器通信等.
多数情况下,NGINX建议每1个CPU核心都运行1个工作进程,使硬件资源得到最有效的利用。你可以在配置中设置如下指令: worker_processes auto,
当NGINX服务器在运行时,只有工作进程在忙碌。每个工作进程都以非阻塞的方式处理多个连接,以削减上下文切换的开销。
每个工作进程都是单线程且独立运行的,抓取并处理新的连接。进程间通过共享内存的方式,来共享缓存数据、会话持久性数据(session persistence data)和其他共享资源。
*/
Nginx 软件下载:
Nginx 版本类型
Mainline version: #主线版,即开发版
Stable version: # 最新稳定版,生产环境上建议使用的版本
Legacy versions: # 遗留的老版本的稳定版
yum 部署 Nginx
cat > /etc/yum.repos.d/nginx.repo <<EOF
[nginx-stable]
name=nginx stable repo
baseurl=http://nginx.org/packages/centos/\$releasever/\$basearch/
gpgcheck=1
enabled=1
gpgkey=https://nginx.org/keys/nginx_signing.key
module_hotfixes=true
[nginx-mainline]
name=nginx mainline repo
baseurl=http://nginx.org/packages/mainline/centos/\$releasever/\$basearch/
gpgcheck=1
enabled=0
gpgkey=https://nginx.org/keys/nginx_signing.key
module_hotfixes=true
EOF
yum -y install nginx
systemctl start nginx && systemctl enable nginx
# 查看nginx软件版本
nginx -v
# nginx version: nginx/1.16.1
# -V显示nginx编译参数
# nginx -V
# nginx version: nginx/1.16.1
# built by gcc 4.8.5 20150623 (Red Hat 4.8.5-36) (GCC)
# built with OpenSSL 1.0.2k-fips 26 Jan 2017
# TLS SNI support enabled
# configure arguments: --prefix=/etc/nginx --sbin-path=/usr/sbin/nginx --modules-path=/usr/lib64/nginx/modules --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --pid-path=/var/run/nginx.pid --lock-path=/var/run/nginx.lock --http-client-body-temp-path=/var/cache/nginx/client_temp --http-proxy-temp-path=/var/cache/nginx/proxy_temp --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp --http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp --http-scgi-temp-path=/var/cache/nginx/scgi_temp --user=nginx --group=nginx --with-compat --with-file-aio --with-threads --with-http_addition_module --with-http_auth_request_module --with-http_dav_module --with-http_flv_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_mp4_module --with-http_random_index_module --with-http_realip_module --with-http_secure_link_module --with-http_slice_module --with-http_ssl_module --with-http_stub_status_module --with-http_sub_module --with-http_v2_module --with-mail --with-mail_ssl_module --with-stream --with-stream_realip_module --with-stream_ssl_module --with-stream_ssl_preread_module --with-cc-opt='-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -m64 -mtune=generic -fPIC' --with-ld-opt='-Wl,-z,relro -Wl,-z,now -pie'
# 检测配置文件语法(-c 可以指定非默认配置文件)
# nginx -t # 测试默认配置文件
# nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
# nginx: configuration file /etc/nginx/nginx.conf test is successful
# nginx -s stop # 停止nginx
# nginx -s reload # 重新加载配置文件
源码部署 Nginx
#!/usr/bin/env bash
# Author: ZhouJian
# Mail: 18621048481@163.com
# Time: 2019-9-3
# Describe: CentOS 7 Install Nginx Source Code Script
version="nginx-1.14.2.tar.gz"
user="nginx"
nginx=${version%.tar*}
path=/usr/local/src/$nginx
echo $path
if ! ping -c2 www.baidu.com &>/dev/null
then
echo "网络不通,无法安装"
exit
fi
yum install -y gcc gcc-c++ openssl-devel pcre-devel make zlib-devel wget psmisc
if [ ! -e $version ];then
wget http://nginx.org/download/$version
fi
if ! id $user &>/dev/null
then
useradd $user -M -s /sbin/nologin
fi
if [ ! -d /var/tmp/nginx ];then
mkdir -p /var/tmp/nginx/{client,proxy,fastcgi,uwsgi,scgi}
fi
tar xf $version -C /usr/local/src
cd $path
./configure \
--prefix=/usr/local/nginx \
--user=nginx \
--group=nginx \
--with-http_ssl_module \
--with-http_flv_module \
--with-http_stub_status_module \
--with-http_sub_module \
--with-http_gzip_static_module \
--with-http_auth_request_module \
--with-http_random_index_module \
--with-http_realip_module \
--http-client-body-temp-path=/var/tmp/nginx/client \
--http-proxy-temp-path=/var/tmp/nginx/proxy \
--http-fastcgi-temp-path=/var/tmp/nginx/fastcgi \
--http-uwsgi-temp-path=/var/tmp/nginx/uwsgi \
--http-scgi-temp-path=/var/tmp/nginx/scgi \
--with-pcre \
--with-file-aio \
--with-http_secure_link_module && make && make install
if [ $? -ne 0 ];then
echo "nginx未安装成功"
exit
fi
killall nginx
/usr/local/nginx/sbin/nginx
#echo "/usr/local/nginx/sbin/nginx" >> /etc/rc.local
#chmod +x /etc/rc.local
#systemctl start rc-local
#systemctl enable rc-local
ss -antp |grep nginx
Nginx目录介绍
[root@JD ~]# ll nginx-1.14.2
total 732
drwxr-xr-x 6 1001 1001 326 Sep 9 21:04 auto
-rw-r--r-- 1 1001 1001 288742 Dec 4 2018 CHANGES
-rw-r--r-- 1 1001 1001 440121 Dec 4 2018 CHANGES.ru
drwxr-xr-x 2 1001 1001 168 Sep 9 21:04 conf
-rwxr-xr-x 1 1001 1001 2502 Dec 4 2018 configure
drwxr-xr-x 4 1001 1001 72 Sep 9 21:04 contrib
drwxr-xr-x 2 1001 1001 40 Sep 9 21:04 html
-rw-r--r-- 1 1001 1001 1397 Dec 4 2018 LICENSE
-rw-r--r-- 1 root root 392 Sep 9 21:54 Makefile
drwxr-xr-x 2 1001 1001 21 Sep 9 21:04 man
drwxr-xr-x 3 root root 174 Sep 9 21:57 objs
-rw-r--r-- 1 1001 1001 49 Dec 4 2018 README
drwxr-xr-x 9 1001 1001 91 Sep 9 21:04 src
auto
[root@JD nginx-1.14.2]# ll auto/
total 188
drwxr-xr-x 2 1001 1001 133 Sep 9 21:04 cc
# cc用于编译,其他文件都是为了configure执行去判定nginx有哪些模块和特性供nginx使用.
-rw-r--r-- 1 1001 1001 141 Dec 4 2018 define
-rw-r--r-- 1 1001 1001 889 Dec 4 2018 endianness
-rw-r--r-- 1 1001 1001 2812 Dec 4 2018 feature
-rw-r--r-- 1 1001 1001 136 Dec 4 2018 have
-rw-r--r-- 1 1001 1001 137 Dec 4 2018 have_headers
-rw-r--r-- 1 1001 1001 411 Dec 4 2018 headers
-rw-r--r-- 1 1001 1001 1020 Dec 4 2018 include
-rw-r--r-- 1 1001 1001 745 Dec 4 2018 init
-rw-r--r-- 1 1001 1001 4836 Dec 4 2018 install
drwxr-xr-x 11 1001 1001 163 Sep 9 21:04 lib
-rw-r--r-- 1 1001 1001 18253 Dec 4 2018 make
-rw-r--r-- 1 1001 1001 3183 Dec 4 2018 module
-rw-r--r-- 1 1001 1001 37857 Dec 4 2018 modules
-rw-r--r-- 1 1001 1001 136 Dec 4 2018 nohave
-rw-r--r-- 1 1001 1001 24767 Dec 4 2018 options
drwxr-xr-x 2 1001 1001 88 Sep 9 21:04 os
-rw-r--r-- 1 1001 1001 8654 Dec 4 2018 sources
-rw-r--r-- 1 1001 1001 120 Dec 4 2018 stubs
-rw-r--r-- 1 1001 1001 2014 Dec 4 2018 summary
-rw-r--r-- 1 1001 1001 394 Dec 4 2018 threads
drwxr-xr-x 2 1001 1001 65 Sep 9 21:04 types
-rw-r--r-- 1 1001 1001 26859 Dec 4 2018 unix
CHANGES
# 为了看出每个版本nginx有哪些特性.
# 加上ru是俄罗斯版本的,作者是俄罗斯人
conf
# 实例文件,nginx安装好后通过conf目录里面配置管理nginx
configure
# 用来生成中间文件,编译前必须用它
contrib
# 让nginx文件打开有nginx语法色彩显示
html
# 提供两个页面,一个nginx欢迎界面,一个500错误界面
src
# 源代码
objs
# 编译后生成的目录,存放中间文件
# 他生成的ngx_module.c会决定哪些模块会被编译进来.
编译参数介绍
configure
# configure --help可以查看支持哪些参数
./configure --prefix=/usr/local/nginx
--with-http_ssl_module \ ---# 支持 https 加密传输
--with-http_flv_module \ ---# 支持流媒体功能,视频等
--with-http_stub_status_module \ ---# 支持子状态模块,显示 nginx 的状态
--with-http_sub_module \ ---# nginx 替换网站响应内容
--with-http_gzip_static_module \ ---# 支持压缩功能,将数据压缩之后给客户端响应,客户端收到数据,浏览器调用相应的程序自动解压,主要为了节省中间的宽度
--with-http_auth_request_module \ ---# 认证模块
--with-http_random_index_module \ ---# 随机显示首页模块
--with-http_realip_module \ ---# Nginx 获取真实 IP 模块
--http-client-body-temp-path=/var/tmp/nginx/client \ ---# 存取客户端临时数据
--http-proxy-temp-path=/var/tmp/nginx/proxy \ ---# 存取代理临时数据
--http-fastcgi-temp-path=/var/tmp/nginx/fastcgi \ ---# 让 nginx 以 fastcgi 的机制和后端的应用程序通讯
--http-uwsgi-temp-path=/var/tmp/nginx/uwsgi \ ---# 和 python 相关的文件
--http-scgi-temp-path=/var/tmp/nginx/scgi \ ---# 安全的后端通讯方式
--with-pcre \ ---# 支持 pcre 正则表达式
--with-file-aio \ ---# 支持文件的异步 IO,就是异步非阻塞
--with-http_secure_link_module && make && make install ---# secure_link_module 支持安全链接
Nginx基本配置
大的层面分成三个模块
CoreModule # 全局配置 核心模块
EventsModule # 事件驱动模块
HttpCoreModule # http内核模块(作为网站服务器的模块)
Nginx配置文件
yum安装nginx通过rpm -ql nginx查看
源码安装nginx去到安装目录conf/目录下即可看到
/etc/logrotate.d/nginx
/etc/nginx
/etc/nginx/conf.d
/etc/nginx/conf.d/default.conf
/etc/nginx/fastcgi_params #fastcgi的参数
/etc/nginx/koi-utf
/etc/nginx/koi-win
/etc/nginx/mime.types #存放非文本传输所支持的格式
/etc/nginx/modules #模块已经被编译到了nginx程序中了
/etc/nginx/nginx.conf
/etc/nginx/scgi_params
/etc/nginx/uwsgi_params #和python做结合用的配置文件
/etc/nginx/win-utf
/etc/nginx/fastcgi.conf: # nginx通过fastcgi的机制调用后端的应用程序解析动态页面
#CGI:能提供和开发程序通信的接口,是一个交流程序,调用开发的程序可以在网页上面是内容
/etc/sysconfig/nginx
/etc/sysconfig/nginx-debug
/usr/lib/systemd/system/nginx-debug.service #调试模式
/usr/lib/systemd/system/nginx.service #systemd的启动脚本
/usr/lib64/nginx
/usr/lib64/nginx/modules
/usr/libexec/initscripts/legacy-actions/nginx
/usr/libexec/initscripts/legacy-actions/nginx/check-reload
/usr/libexec/initscripts/legacy-actions/nginx/upgrade
/usr/sbin/nginx
/usr/sbin/nginx-debug
/usr/share/doc/nginx-1.12.1
/usr/share/doc/nginx-1.12.1/COPYRIGHT
/usr/share/man/man8/nginx.8.gz
/usr/share/nginx
/usr/share/nginx/html
/usr/share/nginx/html/50x.html
/usr/share/nginx/html/index.html
/var/cache/nginx #nginx的各种临时缓存信息
/var/log/nginx
Nginx配置语法
/*
1. 配置文件由指令与指令块构成
2. 每条指令以;分号结尾,指令与参数间以空格符号分隔
3. 指令块以{}大括号将多条指令组织在一起
4. include语句允许组合多个配置文件以提升可维护性
5. 使用# 符号添加注释,提高可读性
6. 使用$符号可以使用变量
7. 部分指令参数支持正则表达式
*/
Nginx工作原理
Nginx作为WEB服务器?
Nginx是基于http协议实现的web服务器,通过epoll技术实现I/O多路复用,采用异步非阻塞实现高并发请求,高度的模块化设计;
异步非阻塞: 1个master 2个work进程
每进来一个request,会有一个work进程去处理,但不是全程处理,处理到可能发生堵塞的地方,比如后端服务器转发request,并等待请求返回,那么,这个处理的work不会这么一直这么等着,发送请求后,注册一个事件“如果upstream返回了,告诉我一声,我再接着干”,于是他就休息去了,这就是异步,如果再有request进来,他就可以很快按照这种方式处理
Nginx作为代理服务器?
代理服务器来接受Internet上的连接请求,然后将请求转发给内部网络上的服务器,并将从服务器上得到的结果返回给Internet上连接的客户端,此时代理服务器对外就表现为一个反向代理服务器;
Nginx作为内容服务器的负载均衡器?
当客户机向站点提出请求时候,请求转向负载均衡服务器,然后,负载均衡服务器通过防火墙特定通路,将客户机的请求按照一定规则发送到后端内容服务器,后端内容服务器再通过该通道将结果回传给负载均衡器,负载均衡服务器将检索的信息发给客户机,好像负载均衡器就是实际的内容服务器;
nginx.conf配置文件解读
cat /etc/nginx/nginx.conf
user nginx; # 定义Nginx运行的用户或用户组
worker_processes 1; # 启动的worker进程数量,如果是CPU密集型,如做加密网站或启用压缩功能,worker数量.
# 如果是CPU密集型,如做加密网站或启用压缩功能,worker数量与CPU个数一致
# 如果是IO密集型,如响应大量客户端,worker进程个数为CPU个数的两倍,或者直接设置为auto即可
error_log /var/log/nginx/error.log warn; # 全局错误日志定义类型,[debug |info |notice |warn |error |crit]
pid /var/run/nginx.pid; # 进程文件
worker_rlimit_nofile 65535; # 一个nginx进程打开的最多文件描述符数,理论值应该是最多打开文件数(系统值ulimit -n)与nginx进程数相除,但是nginx分配请求并不均匀,所以建议与ulimit -n的值保持一致.
#工作模式与连接数上限
events {
use epoll; # 事件驱动模型epoll [默认就是epool],use [kqueue | rtsig |epoll |/dev/poll |select |poll]; epoll是linux2.6以上版本内核中的高性能网络I/O模型,如果跑在FreeBSD上面,就用kqueue模型.
worker_connections 1024; # 每个worker进程允许处理的最大连接数,标准值10240,服务器配置高可以调成65535,具体性需要对网站做压力测试获得,服务器能够接受的最大的连接数是:worker_connection * work_processors
}
#设定http服务器
http {
include /etc/nginx/mime.types; # 文件扩展名与文件类型映射表
default_type application/octet-stream; # 默认文件类型
# charset utf-8; # 默认编码
log_format main '$remote_addr - $remote_user [$time_local] "$request" ' # 日志格式设定
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
server_names_hash_bucket_size 128; # 服务器名字的hash表大小
client_header_buffer_size 32k; # 上传文件大小限制
large_client_header_buffers 4 64k; # 设定请求缓存
client_max_body_size 8m; # 设定请求缓存
server_tokens off; # 隐藏版本号,apache是在配置文件加入一行serverSignature off
sendfile on; #开启高效文件传输模式,sendfile指令指定nginx是否调用sendfile函数来输出文件,对于普通应用设为no,如果用来进行下载等应用磁盘IO重负载应用,可设置为off,以平衡磁盘与网络I/O处理速度,降低系统的负载.注意: 如果图片显示不正常改成off。
autoindex on; #开启目录列表访问,合适下载服务器,默认关闭
#tcp_nopush on; #防止网络堵塞
#tcp_nodelay on; #防止网络堵塞
keepalive_timeout 65; #长连接超时时间,单位是秒
# Fastcgi相关参数是为了改善网站的性能,减少资源占用,提高访问速度,下面参数看字面意思都能理解.
fastcgi_connect_timeout 300;
fastcgi_send_timeout 300;
fastcgi_read_timeout 300;
fastcgi_buffer_size 64k;
fastcgi_buffers 4 64k;
fastcgi_busy_buffers_size 128k;
fastcgi_temp_file_write_size 128k;
# gzip模块设置
gzip on; # 开启gzip压缩输出
gzip_min_length 1k; # 最小压缩文件大小
gzip_buffers 4 16k; # 压缩缓冲区
gzip_http_version 1.0; # 压缩版本(默认1.1,前端如果squit2.5请使用1.0)
gzip_comp_level 2; # 压缩等级
gzip_types text/plain application/x-javascript text/css application/xml; # 压缩类型,默认就已经包含text/html,所以下面就不用再写了,写上去也不会有问题,但是会有一个warn.
gzip_vary on;
#limit_zone crawler $binary_remote_addr 10m; # 开启限制Ip连接数的时候需要使用.
upstream blog.ha97.com {
server 192.168.122.3:80 weight=3;
server 192.168.122.4:80 weight=4;
server 192.168.122.5:80 weight=5;
}
include /etc/nginx/conf.d/*.conf;
}
整体规划:
http {
server {
location {}
location {}
}
}
server{ } #一对server就是nginx的一个虚拟主机
location{} #定义客户端的URL地址,根据URL地址不同,给客户端不同的响应,需要使用正则表达式
# 虚拟主机配置
cat /etc/nginx/conf.d/default.conf
server {
listen 80; # 监听端口
server_name localhost; # 虚拟主机的主机名,也可以是域名,可以有多个,用逗号隔开
#charset koi8-r; # 字符集
#access_log /var/log/nginx/host.access.log main; # 使用main这种日志格式,nginx的日志格式都需要先定义,然后才能使用,唯独combined是nginx默认就是支持的日志格式
location / { # 网站根目录,URI地址; 客户端所访问的URI地址其实是location里面root后面的目录名+location后面的URI的组合
root /usr/share/nginx/html; # 网站的主目录
index index.html index.htm; # 首页文件
}
# 图片缓存时间设置
location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$
{
expires 10d
}
location / {
alias img/;
autoindex on;
# 每秒1k的速度传输,防止大文件把带宽跑满
set $limit_rate 1k;
}
# JS和CSS缓存时间设置
location ~ .*\.(js|css)?$
{
expires 1h;
}
#error_page 404 /404.html; # 当请求页面不存在时,返回码404显示的页面
# redirect server error pages to the static page /50x.html # 如果客户端访问nginx服务器,nginx服务器给客户端返回500 502 503或者504的错误,那么客户端在浏览器里面看到的就是50x.html页面
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
# 对"/"启用反向代理
location / {
proxy_pass http://127.0.0.1:80;
proxy_redirect off;
proxy_set_header X-Read-IP $remote_addr; # 后端的web服务器可以通过X-Forwarded-For获取用户真实IP
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# 以下是一些反向代理的配置,可选
proxy_set_header Host $host;
client_max_body_size 10m; # 允许客户端请求的最大单文件字节数
client_body_buffer_size 128k; # 缓冲区代理缓冲用户端请求的最大字节数
proxy_connect_timeout 90; # nginx跟后端服务器连接超时时间(代理连接超时)
proxy_send_timeout 90; # 后端服务器数据回传时间(代理发送超时)
proxy_read_time 90; # 连接成功后,后端服务器的响应时间(代理接收超时)
proxy_buffer_size 4k; # 设置代理服务器(nginx)保存用户头信息的缓冲区大小
proxy_buffers 4 32k; # proxy_buffers缓冲区,网页平均在32k以下的设置
proxy_busy_buffers_size 64k; # 高负荷下缓冲大小 (proxy_buffers*2)
proxy_temp_file_write_size 64k; # 设定缓存文件夹大小,大于这个值,将从upstream服务器传
}
# 设定查看Nginx状态的地址
location /NginxStatus {
stub_status on;
access_log on;
auth_basic "NginxStatus";
auth_basic_user_file conf/htpasswd;
# htpasswd文件的内容可以用apache提供的htpasswd工具产生
}
# 本地动静分离反向代理设置
# 所有jsp的页面均交由tomocat或resin处理
location ~ .(jsp|jspx|do)?$ {
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_pass http://127.0.0.1:8080;
}
# 所有静态文件由nginx直接读取不经过tomcat或resin
location ~ .*.(htm|html|gif|jpg|jpeg|png|bmp|swf|ioc|rar|zip|txt|flv|mid|doc|ppt|pdf|xls|mp3|wma)$
{ expires 15d; }
location ~ .*.(js|css)?$
{ expires 1h; }
# proxy the PHP scripts to Apache listening on 127.0.0.1:80
#location ~ \.php$ {
# proxy_pass http://127.0.0.1;
#}
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
#location ~ \.php$ {
# root html;
# fastcgi_pass 127.0.0.1:9000;
# fastcgi_index index.php;
# fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
# include fastcgi_params;
#}
# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
#location ~ /\.ht {
# deny all;
#}
}