Nginx是一款轻量级高性能的Web服务器和反向代理服务器,并且还是一个邮件代理服务器。Nginx与apache的区别
1.Nginx默认是异步多进程非阻塞工作模式,一个工作进程连接多个线程,一个线程对应一个请求连接,采用epoll(事件驱动)IO模型,占用资源少,高性能高并发,最大可支持50000个并发连接。;apache是同步多进程阻塞型工作模式,采用select标准IO模型,一个进程对应一个请求连接,处理并发请求效果较差。
2.Nginx具有内置的健康检查模块,可以通过加载内置模块(端口)对后端服务器进行健康检查,达到负载均衡的效果。
3.Nginx静态文件处理效果比apache强,但其动态文件处理不如apache,原因是nginx不支持对php以及jsp等动态语言的解析,可以使用fastcgi接口进行解析。
4.Nginx具有高可用性,支持热部署,启动速度迅速,可以在不间断服务的状态下,对软件版本进行升级。
5.Nginx所有模块都支持静态(不依赖动态链接库),而apache所有模块支持动静态编译(依赖动态链接库)。
6.Apache的rewrite模块功能较nginx强大。
7.Nginx的配置比较简单,代码简洁;apache配置比较复杂,模块的配置文件比较分散。
Nginx较其他Web服务器的优势
1.作为Web服务器,处理静态文件,索引文件效率较高,可以自动索引。
2.作为代理服务器,可以实现无缓存的反向代理加速,提高网站加载速度。
3.作为负载均衡器,内部支持Rails(一种Web框架)和PHP模块,也支持HTTP代理服务器对外服务,还支持简单的容错和利用算法进行负载均衡。
4.性能方面,注重效率,采用内核epoll(事件驱动)模型,可以支持较多的并发连接,对系统内存资源消耗较低。
5.稳定性方面,采用分阶段资源分配技术(即根据需求的阶段性分配资源,而不是一次调用全部请求资源,减少系统资源占用和系统负载),所以外部的系统攻击对于Nginx服务器的损害不大。
6.高可用方面,支持热部署,启动速度特别迅速,可以实现7x24小时不间断服务。
Nginx模块
Nginx由<strong>内核和模块</strong>组成。
内核的功能主要是通过查找配置文件将客户请求映射到一个location模块上(location是nginx的一个模块,用于URL匹配),根据location模块中配置的指令去启动不同的模块完成请求响应。
模块:
结构上:核心模块(http模块(处理请求时调用响应的模块指令处理);Main模块(定义全局设置);event模块(定义IO工作模式和服务器可连接的最大连接数));
基础模块(http access模块(http访问控制模块);http fastcgi模块(允许nginx同FastCGI协同工作,并且控制参数被安全传递);http proxy模块(代理模块,用于转发请求));
第三方模块(http upstream request hash模块(设置负载均衡);Notice模块(指定日志输出级别);http access key模块(用于限制某些客户端的访问))。
功能上:handlers模块:直接处理请求,并对输出内容进行修改,一般只有一个。Filters模块:主要对其他处理器模块输出内容进行修改,最后由nginx输出。Proxies模块:主要与后端服务器进行交互,实现代理和负载均 衡功能。Nginx工作原理:请求过程:客户端——》nginx内核(选择处理器模块)——》handlers模块(生成处理结果)——》filters模块(处理修改处理结果)——》nginx响应请求——》客户端。数据包流向:
客户端(请求数据包)——》nginx服务器——》七层,逐层传递数据包——》处理器——》七层,逐层传递——》nginx服务器——》客户端
Nginx进程模型
Nginx在启动后,会有一个master进程和多个worker进程。
master进程
主要用来管理worker进程,包含:接收来自外界的信号,向各worker进程发送信号,监控worker进程的运行状态,当worker进程退出后(异常情况下),会自动重新启动新的worker进程。
master进程充当整个进程组与用户的交互接口,同时对进程进行监护。它不需要处理网络事件,不负责业务的执行,只会通过管理worker进程来实现重启服务、平滑升级、更换日志文件、配置文件实时生效等功能。
我们要控制nginx,只需要通过kill向master进程发送信号就行了。比如kill -HUP pid,则是告诉nginx,从容地重启nginx,我们一般用这个信号来重启nginx,或重新加载配置,因为是从容地重启,因此服务是不中断的。master进程在接收到HUP信号后是怎么做的呢?首先master进程在接到信号后,会先重新加载配置文件,然后再启动新的worker进程,并向所有老的worker进程发送信号,告诉他们可以光荣退休了。新的worker在启动后,就开始接收新的请求,而老的worker在收到来自master的信号后,就不再接收新的请求,并且在当前进程中的所有未处理完的请求处理完成后,再退出。当然,直接给master进程发送信号,这是比较老的操作方式,nginx在0.8版本之后,引入了一系列命令行参数,来方便我们管理。比如,./nginx -s reload,就是来重启nginx,./nginx -s stop,就是来停止nginx的运行。如何做到的呢?我们还是拿reload来说,我们看到,执行命令时,我们是启动一个新的nginx进程,而新的nginx进程在解析到reload参数后,就知道我们的目的是控制nginx来重新加载配置文件了,它会向master进程发送信号,然后接下来的动作,就和我们直接向master进程发送信号一样了。
worker进程:
而基本的网络事件,则是放在worker进程中来处理了。多个worker进程之间是对等的,他们同等竞争来自客户端的请求,各进程互相之间是独立的。一个请求,只可能在一个worker进程中处理,一个worker进程,不可能处理其它进程的请求。worker进程的个数是可以设置的,一般我们会设置与机器cpu核数一致,这里面的原因与nginx的进程模型以及事件处理模型是分不开的。
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的进程模型,可以由下图来表示:
Nginx安装
软件:nginx-1.8.0.tar.gz
依赖性软件:gcc gcc-c++(设置编译环境) zlib-devel pcre-devel(支持nginx的http rewrite功能) openssl-devel(支持http ssl模块)
解压,编译,安装:
# tar zxf nginx-1.8.0.tar.gz
# /root/nginx-1.8.0/configure
--prefix=/usr/local/nginx ##nginx安装目录
--with-http_stub_status_module ##监控nginx状态模块
--with-http_ssl_module ##加密认证模块
## make && make install
设置nginx启动命令
# ln -s /usr/local/nginx/sbin/nginx /usr/sbin/nginx
开启ngixn服务:
# nginx
查看默认开启端口:
# netstat -anutpl
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 3410/nginx
查看nginx目录大小:
# du -sh /usr/local/nginx
5.3M /usr/local/nginx
查看本地站点信息
# curl -I localhost
HTTP/1.1 200 OK ##http请求返回状态及http版本
Server: nginx ##nginx版本信息(已经隐藏版本)
Date: Sat, 16 Apr 2016 11:07:09 GMT ##(请求时间)
Content-Type: text/html ##文本格式为text/html
Content-Length: 612 ##文本长度
Last-Modified: Fri, 15 Apr 2016 09:08:03 GMT ##nginx安装时间
Connection: keep-alive ##连接状态
ETag: "5710af73-264"
Accept-Ranges: bytes
检测:
浏览器“172.25.48.10”,结果显示nginx的主页面,表明访问成功。Nginx编译优化(在编译过程前或者编译过程中进行)
1.站点信息优化
# curl -I localhost
Server: nginx/1.8.0
# vim /root/nginx-1.8.0/src/core/nginx.h
#define NGINX_VER "nginx" ##删除版本信息
检测:
# curl -I localhost
Server: nginx ##隐藏Nginx版本信息
2.目录编译优化
原理:在编译nginx时,默认以debug模式(输出级别)进行,而在debug模式下,会插入很多跟踪和ASSERT之类的信息,在编译前取消nginx的debug模式,会极大减少nginx的占用资源。
# du -sh /usr/local/nginx
5.3M /usr/local/nginx
# vim /root/nginx-1.8.0/auto/cc/gcc
#debug ##注释debug,可缩小nginx目录所占内存
#CFLAGS="$CFLAGS -g"
# du -sh /usr/local/nginx
848k /usr/local/nginx
3.cpu编译类型优化
原理:编译nginx时,默认的GCC参数时“-O”。
查看cpu类型
# cat /proc/cpuinfo | grep "model name"
model name : QEMU Virtual CPU version 1.5.3
本机cpu为QEMU内型。
编译时加上以下参数:
--with-cc-opt=’-O3’
--with-cpu-opt=CPUNginx配置案例
nginx的配置文件是一个纯文本文件,一般在Nginx的安装目录中的conf下,整个文件以block形式组织,每个block以一个大“{ }”表示,main(全局设置,指令位于最高层,接下来是Events、http等层级,http层中包含server层,即server block,server block块中又分为location层,并且一个server block中可以包含多个location block中。
main部分设置全局设置,server指令制定主机和端口,events指令指定工作模式,location指定匹配网页位置,upstream指令指定一系列后端服务器, 1.设置nginx用户
# groupadd -g 48 nginx
# useradd -u 48 -g 48 -s /sbin/nologin -d /usr/local/lnmp/nginx -M nginx
# id nginx ##查看nginx用户信息
uid=48(nginx) gid=48(nginx) groups=48(nginx)
# vim /usr/local/lnmp/nginx/conf/nginx.conf
user nginx; ##主模块指令,指定nginx用户及用户组
Worker_processes 1|2; ##主模块指令,指定开启的进程数,一般进程数等于系统CPU数
量1|2为系统cpu数
#error_log logs/error.log notice; ##主模块指令,定义全局错误日志文件。日志
的输出级别有[ debug | info | notice |
warn | error | crit ]日志详细程度逐级递
减,即debug最详细,crit最少。
#pid logs/nginx.pid ##主模块指令,指定nginx进程id的存储文件位置
events { ##event模块,指定IO的工作模式
use epoll; ##use事件模块指令,用于指定nginx的工作模型(I/O复用方式)
worker_connections 1024;
}
# nginx -t ##检测配置是否正确
# nginx -s reload ##重新加载nginx
Nginx支持如下处理连接的方法(I/O复用方法)
这些方法可以通过use指令指定。
select– 标准方法。 如果当前平台没有更有效的方法,它是编译时默认的方法。你可以使用配置参数 –with-select_module 和 –without-select_module 来启用或禁用这个模块。
poll– 标准方法。 如果当前平台没有更有效的方法,它是编译时默认的方法。你可以使用配置参数 –with-poll_module 和 –without-poll_module 来启用或禁用这个模块。
kqueue– 高效的方法,使用于 FreeBSD 4.1+, OpenBSD 2.9+, NetBSD 2.0 和 MacOS X. 使用双处理器的MacOS X系统使用kqueue可能会造成内核崩溃。
epoll – 高效的方法,使用于Linux内核2.6版本及以后的系统。在某些发行版本中,如SuSE 8.2, 有让2.4版本的内核支持epoll的补丁。
rtsig – 可执行的实时信号,使用于Linux内核版本2.2.19以后的系统。默认情况下整个系统中不能出现大于1024个POSIX实时(排队)信号。这种情况 对于高负载的服务器来说是低效的;所以有必要通过调节内核参数 /proc/sys/kernel/rtsig-max 来增加队列的大小。可是从Linux内核版本2.6.6-mm2开始, 这个参数就不再使用了,并且对于每个进程有一个独立的信号队列,这个队列的大小可以用 RLIMIT_SIGPENDING 参数调节。当这个队列过于拥塞,nginx就放弃它并且开始使用 poll 方法来处理连接直到恢复正常。
/dev/poll – 高效的方法,使用于 Solaris 7 11/99+, HP/UX 11.22+ (eventport), IRIX 6.5.15+ 和 Tru64 UNIX 5.1A+.
eventport – 高效的方法,使用于 Solaris 10. 为了防止出现内核崩溃的问题, 有必要安装这个 安全补丁。
在linux下面,只有epoll是高效的方法
epoll的优点
支持一个进程打开大数目的socket描述符(FD)
select 模式中一个进程所打开的FD是有一定限制的,由FD_SETSIZE设置,默认值是2048。对于那些需要支持的上万连接数目的服务器来说显 然太少了。这时候你一是可以选择修改这个宏然后重新编译内核,不过资料也同时指出这样会带来网络效率的下降,二是可以选择多进程的解决方案(传统的 Apache方案),不过虽然linux上面创建进程的代价比较小,但仍旧是不可忽视的,加上进程间数据同步远比不上线程间同步的高效,所以也不是一种完 美的方案。不过 epoll则没有这个限制,它所支持的FD上限是最大可以打开文件的数目,这个数字一般远大于2048,举个例子,在1GB内存的机器上大约是10万左 右,具体数目可以cat /proc/sys/fs/file-max察看,一般来说这个数目和系统内存关系很大。
IO效率不随FD数目增加而线性下降
传统的select/poll另一个致命弱点就是当你拥有一个很大的socket集合,不过由于网络延时,任一时间只有部分的socket是”活跃”的,但 是select/poll每次调用都会线性扫描全部的集合,导致效率呈现线性下降。但是epoll不存在这个问题,它只会对”活跃”的socket进行操作—这是因为在内核实现中epoll是根据每个fd上面的callback函数实现的。那么,只有”活跃”的socket才会主动的去调用callback函数,其他idle状态socket则不会,在这点上,epoll实现了一个”伪”AIO,因为这时候推动力在os内核。在一些 benchmark中,如果所有的socket基本上都是活跃的—比如一个高速LAN环境,epoll并不比select/poll有什么效率,相反,如果过多使用epoll_ctl,效率相比还有稍微的下降。但是一旦使用idle connections模拟WAN环境,epoll的效率就远在select/poll之上了。
使用mmap加速内核与用户空间的消息传递。
涉及到epoll的具体实现,无论是select,poll还是epoll都需要内核把FD消息通知给用户空间,如何避免不必要的内存拷贝就很重要,在这点上,epoll是通过内核与用户空间mmap同一块内存实现的。
注:mmap:将一个文件或者其它对象映射进内存。文件被映射到多个页上,如果文件的大小不是所有页的大小之和,最后一个页不被使用的空间将会清零。mmap在用户空间映射调用系统中作用很大。
内核微调(linux系统的整体优势)
2.添加https认证
# cd /etc/pki/tls/certs/
# make nginx.pem ##生成ssl证书
Country Name (2 letter code) [XX]:CN ##国家
State or Province Name (full name) []:Shaanxi ##省份
Locality Name (eg, city) [Default City]:xi'an ##城市
Organization Name (eg, company) [Default Company Ltd]:westos ##组织
Organizational Unit Name (eg, section) []:linux ##单位
Common Name (eg, your name or your server's hostname) []:vm4.example.com ##主机
Email Address []:997165724@qq.com ##管理员邮箱
# mv nginx.pem /usr/local/lnmp/nginx/conf/ ##将证书移至nginx的配置目录下
# cd /usr/local/lnmp/nginx/conf/
# vim nginx.conf
http {
server {
listen 443 ssl; ##默认开启端口为443
server_name localhost; ##服务器名称
ssl_certificate nginx.pem; ## 认证文件
ssl_certificate_key nginx.pem; ##认证密钥文件
ssl_session_cache shared:SSL:1m; ##session保持时长
ssl_session_timeout 5m; ##session超时时长
ssl_ciphers HI504 Gateway TimeoutGH:!aNULL:!MD5; ##加密方式
ssl_prefer_server_ciphers on;
location / { ##URL模块
root html; ##默认发布目录
index index.html index.htm; ##默认人发布主页格式
}
}
}
# nginx -t
# nginx -s reload
打开浏览器,输入"https://172.25.48.10",j进入,会显示没有认证,认证完后,显示nginx主页则表明访问成功。 3.添加虚拟主机
首先要将虚拟主机在物理主机上解析。
# vim /etc/hosts
172.25.48.10 www.haha.com www.heihei.com www.linux.com
进入服务主机,设置nginx虚拟主机。
# vim /usr/local/lnmp/nginx/conf/nginx.conf
http {
server {
listen 80; ##默认端口为80;
server_name www.haha.com; ##指定主机域名
location / {
root /www; ##定义网站的发布目录
index index.html;
}
}
}
# nginx -t ##检测nginx语法
# nginx -s reload
建立虚拟主机默认发布目录,并设置发布主页
# mkdir /www
# cd /www
# vim index.html
vm10.example.com
打开浏览器,输入www.haha.com查看,结果显示:
vm10.example.com
表示设置正确,访问成功。 4.Nginx做负载均衡
# vim /usr/local/lnmp/nginx/conf/nginx.conf
http {
upstream westos { ##upstream负载均衡函数,默认为轮循模式
server 172.25.48.4:80;
server 172.25.48.7:80;
}
server {
listen 80; ##监听80端口
server_name www.heihei.com; ##指定网站
location / {
proxy_pass http://westos; ##反向代理到负载均衡器westos上。
}
}
}
# nginx -t
# nginx -s reload
结果验证
打开虚拟机172.25.48.10(desktop.example.com)和主机172.25.254.48 (www.zhuji.com)做负载均衡器,并且都下载http服务,并且分别在两个主机的Apache默认发布目录编写index.html主页。
# yum install httpd -y
# /etc/init.d/httpd start
# cd /var/www/html
# vim index.html
desktop.example.com ##172.25.48.7主机
www.zhuji.com ##172.25.48.4主机
打开浏览器,输入“www.qq.com”,不停按f5查看结果。结果会不停在desktop.example.com和www.zhuji.com之间重复出现,表明负载均
衡成功。 5.Nginx的负载均衡模块支持四种调度算法:
1.轮循(Nginx默认),每个请求按时间顺序逐一分配到不同的后端服务器,如果后端服务器中某台服务器挂掉,系统会自动剔除故障服务器,是用户访问不受影响。
2.weight轮询权值,weight权值越大,分配到的访问机率越高,主要用于后端服务器性能不均的情况下。
3.ip_hash,每个请求按照访问ip的hash算法结果分配,可以实现来自东一个ip的客户端请求固定到同一台后端服务器,可以解决动态网页存在的session共享问题,。
4.第三方调度算法
(1).fair,较智能,可以根据页面大小和加载时间长短进行负载均衡,即根据后端服务器的响应时间来分配请求,响应时间段的服务器优先分配。<strong>nginx本身不支持fair算法,需要下载nginx的upstream_fair模块即可</strong>。
(2).url_hash,按照访问的url的hash结果分配请求,使每个url定向到后端同一个服务器,可以进一步提高后端缓存服务器的效率。需要安 装nginx的hash软件包。6.Nginx的server模块支持设定后端服务器的状态。
1.down,表示当前的server不参与负载均衡,但服务器状态正常,只是不会被分配到任何请求。
2.backup,预留的备份机器,当其他所有的非backup服务器出现故障或者忙的时候,backup服务器才会处理请求。
3.max_fails,允许请求失败的次数,默认为1,当超过最大次数时,返回proxy_next_upstream模块定义的错误。
4.fail_timeout,在经历了max_fails次失败后,暂停服务的时间。mail_fials和max_timeout可以结合使用。7.Nginx的status状态监控模块
stubstatus模块能够获取nginx自上次启动以来的工作状态,非核心模块,需要在编译过程中编译此模块。“--with-http_stub_status_module”.
功能:可以检测某一时间段内服务器被访问的次数,以此来判断服务器的并发量。
# vim /usr/local/lnmp/nginx/conf/nginx.conf
http {
server{
listen 80;
server_name 172.25.48.10;
location /status {
stub_status on; ##激活状态
access_log off; ##日志接收关闭
}
}
}
# nginx -t
# nginx -s reload
打开浏览器,输入“172.25.48.9/status”,查看结果显示,并且用f5刷新,每刷新一次,访问值增加1.结果显示:
Active connections: 1
server accepts handled requests
10 10 126
Reading: 0 Writing: 1 Waiting: 0 8.Nginx重写模块
功能:在同一个公司内,会存在不同的公司主页网址。客户可以通过相同的网址访问不同的主页。
# vim /usr/local/lnmp/nginx/conf/nginx.conf
http {
server{
listen 80;
server_name 172.25.48.10;
location / {
root html;
index index.html index.htm;
rewrite ^(/.*)$ http://172.25.48.7;##将所有在浏览器上输入的网址全部重定向到http://172.25.48.7主页上。
}
}
}
# nginx -t
# nginx -s reload
打开浏览器,输入:172.25.48.10,均定向到“http://172.25.48.7”上面。 9.Nginx反向代理模块
功能:nginx做反向代理器,后台多个主机分别充当不同功能的服务器,达到数据有序存放的目的。
# vim /usr/local/lnmp/nginx/conf/nginx.conf
http {
server {
listen 80;
server_name 172.25.48.10;
#location /bbs {
# proxy_pass http://172.25.48.7/bbs; ##反向代理到其他主机的默认发布目录。
#}
location ~ ^/bbs { ##正则表达式,当使用正则表达式时,则反向代理所指定的网址不需要指定目录。
proxy_pass http://172.25.48.7;
}
}
}
# nginx -t
# nginx -s reload
在172.25.48.7主机中的nginx默认发布目录/var/www//html中建立bbs目录。在bbs目录中建立网页index.html.
# mkdir -p /var/www/html/bbs
# vim /var/www/html/bbs/index.html
bbs.site server3.example.com
打开浏览器,输入“172.25.48.10/bbs”,结果会显示172.25.48.7主机/var/www/html/bbs/index.html中的网页内容。10.Nginx缓存机制+负载均衡
功能:当出现高并发访问时,利用此机制可以减小后台压力,在一定时间内,客户可以通过访问缓存来达到诉求。
级别:level级别 = 1:2 ##1表示一级目录,为一个字符。2表示2级目录,为两个字符。最多为三层目录。定义目录。
Keys_zone=one:10m ##定义一个缓存文件区域大小。
max_size=512m; ##设置缓存最大值为512m。
# mkdir -p /dev/shm/nginx/cache ##建立系统缓存目录。
# vim /etc/rc.local ##此脚本在系统开机时会自动执行,将建立缓存目录命令行写入此目录中,则会在系统开机时自动建立系统缓存目录。
mkdir -p /dev/shm/nginx/cache
# vim /usr/local/lnmp/nginx/conf/nginx.conf
http {
upstream westos { ##负载均衡
server 172.25.48.7:80; ##nginx轮循规则
server 172.25.48.4:80;
}
##cache缓存机制,分别指定
proxy_cache_path /dev/shm/nginx/cache levels=1:2 keys_zone=one:10m max_size=512m;
add_header X-Cache $upstream_cache_status;
server {
listen 80;
server_name www.heihei.com;
location / { ##正则表达式指定路径
proxy_pass http://redhat; ##westos为负载均衡名称,与upstream对应。
proxy_cache one; ##指定缓存区域,与keys_zone对应。
proxy_cache_valid 200 10s; ##指定缓存时间,超过缓存时间,缓存失效,请求重新从后端获取数据,200是http的状态
码,表示正确。100表示静态界面,300表示重定向。
}
}
}
# nginx -t
# nginx -s reload
分别在172.25.48.7和172.25.48.4主机的nginx的默认发布目录/var/www/html目录中分别建立网页,打开浏览器,输入“www.heihei.com”,
不停按f5,每隔10s,结果会在vm7.example.com和vm7.example.com之间变换,并且会在/dev/shm/nginx/cache目录中产生大量缓存文件。
并且不间断执行“curl -I localhost”命令会出现以下结果:
# curl -I localhost
HTTP/1.1 200 OK
Server: nginx
X-Cache: EXPIRED ##表示缓存已经失效,此次访问是直接访问后台。
立刻再次执行,会出现以下结果;
# curl -I localhost
HTTP/1.1 200 OK
Server: nginx
X-Cache: HIT ##表示此次访问是访问缓存,而不是直接访问后台.