Nginx入门学习
Nginx是一个高性能的HTTP和反向代理服务器,也是一个IMAP/POP3/SMTP代理服务器,在高连接并发的情况下Nginx是Apache服务器不错的替代品。其特点是占有内存少,并发能力强,事实上Nginx的并发能力确实在同类型的网页服务器中表现较好。
Nginx作为负载均衡服务器,既可以在内部直接支持Rails和PHP程序对外进行服务,也可以支持作为HTTP代理服务器对外进行服务。Nginx用C进行编写,配置文件简洁(支持Perl语法),启动容易,几乎可以做到服务不间断运行和版本升级。
nginx的设计可以说是高度模块化,每个模块就是一个功能模块,只负责自身的功能,模块之间严格遵循高内聚,低耦合的原则。
下载Windows版本的zip包解压,双击nginx.exe即可。在任务管理器的进程窗口可以看到两个nginx进程,分别是master和worker进程。退出Nginx服务的方法:
./nginx.exe -s stop
@echo off
echo stopping nginx service...
net stop nginx
echo Kill nginx process...
taskkill /F /IM nginx.exe>nul
Linux下安装Nginx,至少需要依赖以下几个模块(编译模块时按照这个顺序):
分别搜索得到其下载的地址(包括Nginx),在Linux下执行wget
即可,然后tar zxvf *.tar.gz
,
然后到解压后的目录下执行:
./config #检查本机的的安装环境
make #从Makefile中读取指令然后编译
makeinstall #从Makefile中读取指令并安装到指定的位置
验证Nginx是否安装成功:
cd /usr/local/nginx/sbin
./nginx -t #检验nginx.conf文件的基本有效性
./nginx #启动Nginx
netstat -ntlp #查看默认的80端口,如果端口占用,则可以修改/etc/nginx.conf文件里面的http.server.listen 82
同时也可以通过打开localhost:82,成功的话可以看到Nginx的欢迎页面。
注意:在pcre官网会看到pcre2这个版本的库文件,不要下载安装这个,否则会安装Nginx失败:
./configure: error: the HTTP rewrite module requires the PCRE library.
You can either disable the module by using --without-http_rewrite_module
option, or install the PCRE library into the system, or build the PCRE library
statically from the source withNginxby using --with-pcre= option.
最简单的方法:brew install nginx
The default port has been set in /usr/local/etc/nginx/nginx.conf to 8080 so that nginx can run without sudo。
nginx will load all files in /usr/local/etc/nginx/servers/.
To have launchd start nginx now and restart at login: brew services start nginx
Or, if you don’t want/need a background service you can just run: nginx
停止:nginx -s stop
nginx原生自带或者支持的命令:
nginx -c /etc/nginx.conf #-c 参数指定自定义配置文件路径
nginx -s stop #快速关闭Nginx,可能不保存相关信息,并迅速终止web服务。(快速退出)
nginx -s quit #平稳关闭Nginx,保存相关信息,有安排的结束web服务。(平滑退出)
nginx -s reload #重新加载配置文件
nginx -s reopen #重新加载日志文件。
Nginx网站服务器在生产环境中运行时需要进行实时监控;专业的监控软件如Nagios, Zabbix, Munin的网络监控支持Nginx监控,并给出综合性报告或者长期数据统计功能。
ngxtop命令行工具,可以快速简便地监控Nginx服务器的请求,通过分析 Nginx 或者其他日志文件,使用类似 top 命令的界面实时展示出来的。采用python编写,可以通过pip install ngxtop
来安装。
ngxtop [options] (print|top|avg|sum)
选项:
-l : 指定日志文件的完整路径 (Nginx 或 Apache2)
-f : 日志格式
–no-follow: 处理当前已经写入的日志文件,而不是实时处理新添加到日志文件的日志
-t : 更新频率
-n : 显示行号
-o : 排序规则(默认是访问计数)
-a …: 添加表达式(一般是聚合表达式如: sum, avg, min, max 等)到输出中。
-v: 输出详细信息
-i : 只处理符合规则的记录
一些内置变量:
实例:
ngxtop #列出10个 Nginx 服务,按请求数量排序
ngxtop -n 20 #显示前20个最频繁的请求
ngxtop info #获取Nginx基本信息
ngxtop top remote_addr #显示请求最多的客户端IP地址
ngxtop -i 'status == 404' print request status #显示状态码是404的请求
ssh user@remote_server tail -f /var/log/apache2/access.log | ngxtop -f common #使用普通格式从远程服务器解析apache日志
ngxtop -l access.log --no-follow -i 'http_user_agent.find('iPhone')' #搜索客户端为 iPhone 的 log
参考:
ngxtop:在命令行实时监控 Nginx 的神器
高性能得益于多进程和异步机制,异步机制使用的是异步非阻塞方式。
多进程
服务器每当收到一个客户端时,由服务器master主进程生成一个worker子进程,和客户端建立连接进行交互,直到连接断开,该子进程就结束。
优点
缺点
异步非阻塞
每个工作进程使用异步非阻塞方式,可以处理多个客户端请求。当某个工作进程接收到客户端的请求以后,调用 IO 进行处理,如果不能立即得到结果,就去处理其他的请求(即为非阻塞);而客户端在此期间也无需等待响应,可以去处理其他事情(即为异步);当 IO 返回时,就会通知此工作进程;该进程得到通知,暂时挂起当前处理的事务去响应客户端请求。
在 Nginx 的异步非阻塞机制中,工作进程在调用 IO 后,就去处理其他的请求,当 IO 调用返回后,会通知该工作进程。对于这样的系统调用,主要使用 Nginx 服务器的事件驱动模型来实现。
Nginx 的事件驱动模型由事件收集器、事件发送器和事件处理器三部分基本单元组成。事件收集器负责收集 worker 进程的各种 IO 请求,事件发送器负责将 IO 事件发送到事件处理器,而事件处理器负责各种事件的响应工作。
事件发送器将每个请求放入一个待处理事件的列表,使用非阻塞 I/O 方式调用“事件处理器”来处理该请求。其处理方式称为“多路 IO 复用方法”,常见的包括以下三种:select 模型、poll 模型、epoll 模型。
Nginx 服务器使用 master/worker 多进程模式。多线程启动和执行的流程如下:主程序 Master process 启动后,通过一个 for 循环来接收和处理外部信号;主进程通过 fork() 函数产生子进程,每个子进程执行一个 for 循环来实现 Nginx 服务器对事件的接收和处理。
一般推荐 worker 进程数与 cpu 内核数一致,这样一来不存在大量的子进程生成和管理任务,避免进程之间竞争 CPU 资源和进程切换的开销。而且 Nginx 为了更好的利用多核特性,提供 cpu 亲缘性的绑定选项,可以将某一个进程绑定在某一个核上,这样就不会因为进程的切换带来 cache 的失效。
对于每个请求,有且只有一个工作进程对其处理。每个 worker 进程都是从 master 进程 fork 过来,在 master 进程里面,先建立好需要 listen 的 socket(listenfd)之后,然后再 fork 出多个 worker 进程。所有 worker 进程的 listenfd 会在新连接到来时变得可读,为保证只有一个进程处理该连接,所有 worker 进程在注册 listenfd 读事件前抢 accept_mutex,抢到互斥锁的那个进程注册 listenfd 读事件,在读事件里调用 accept 接受该连接。
当一个 worker 进程在 accept 这个连接之后,就开始读取请求,解析请求,处理请求,产生数据后,再返回给客户端,最后才断开连接,这样一个完整的请求就是这样的了。一个请求,完全由 worker 进程来处理,而且只在一个 worker 进程中处理。
在 Nginx 服务器的运行过程中,主进程和工作进程需要进程交互。交互依赖于 Socket 实现的管道来实现。
upstream按照轮询(默认,即没有任何配置信息时)方式进行负载,每个请求按时间顺序逐一分配到不同的后端服务器,如果后端服务器down掉,能自动剔除。简便、成本低廉。缺点:可靠性低和负载分配不均衡。适用于图片服务器集群和纯静态页面服务器集群。
请求会分配给响应最快和活跃连接数最少的backend;
指定轮询几率,weight和访问比率成正比,用于后端服务器性能不均的情况。下面的负载均衡实战就是使用权重的方式。
每个请求按访问ip的hash函数结果分配,IPv4会考虑前3个octet,IPv6会考虑所有的地址位,这样每个访客固定访问一个后端服务器,可以解决session sticky问题。配置只需要在upstream中加入ip_hash;
即可:
upstream tomcatserver {
ip_hash;
server 127.0.0.1:8080;
server 127.0.0.1:8090;
}
Nginx会把下一个连接分配给具有最小活动连接的服务器,常用于一些请求需要更长的时间才能完成的情况,nginx将尽量不会把过多的请求来使忙碌的应用程序服务器超负荷运行,而是将新的请求分发到不太忙的服务器。把上面的配置信息中的 ip_hash 换成 least_conn 即可。
按后端服务器的响应时间来分配请求,响应时间短的优先分配。与weight分配策略类似。需要安装第三方模块。如何得知响应时间长短?
upstream tomcatserver {
server 127.0.0.1:8080;
server 127.0.0.1:8090;
fair;
}
和IP哈希类似,只不过针对请求的url进行hash(基于缓存的server,页面静态化)。后端服务器为缓存、文件、静态服务器时比较有效。在upstream中加入hash语句,server语句中不能写入weight等其他的参数,hash_method是使用的hash算法。缺点是当后端服务器宕机的时候,url_hash不会自动跳转的其他缓存服务器,而是返回给用户一个503错误。
upstream tomcatserver {
server 127.0.0.1:8080;
server 127.0.0.1:8090;
hash $request_uri;
hash_method crc32;
}
正向代理:一个位于客户端和原始服务器之间的服务器,为了从原始服务器取得内容,客户端向代理发送一个请求并指定目标(原始服务器),然后代理向原始服务器转交请求并将获得的内容返回给客户端。如VPN;
反向代理:指以代理服务器来接受Internet上的连接请求,然后将请求转发给内部网络上的服务器,并将从服务器上得到的结果返回给Internet上请求连接的客户端,此时代理服务器对外就表现为一个服务器。
下面的负载均衡实战,nginx就是一个反向代理服务器;
负载均衡,可用于优化资源的利用率, 最大化吞吐量,减少延迟并确保容错配置。
下面以一个偏前端 nginx server 搭配两个后端 Tomcat server 来实现一个超级简单的负载均衡;以Windows 系统为例,其他系统类似;主要步骤:
<Server port="18005" shutdown="SHUTDOWN">
<Connector port="18080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
<Connector port="18009" protocol="AJP/1.3" redirectPort="8443" />
worker_processes 1;#工作进程的个数,一般与计算机的cpu核数一致
events {
worker_connections 1024;#单个进程最大连接数(最大连接数=连接数*进程数)
}
http {
include mime.types; #文件扩展名与文件类型映射表
default_type application/octet-stream;#默认文件类型
sendfile on;#开启高效文件传输模式,sendfile指令指定nginx是否调用sendfile函数来输出文件,对于普通应用设为 on,如果用来进行下载等应用磁盘IO重负载应用,可设置为off,以平衡磁盘与网络I/O处理速度,降低系统的负载。注意:如果图片显示不正常把这个改成off。
keepalive_timeout 65; #长连接超时时间,单位是秒
gzip on;#启用Gizp压缩
# 服务器的集群
upstream nginxloadbalance.com {#集群名字
# upstream还可以为每个设备设置状态值:
# down:表示当前server暂时不参与负载;
# weight:默认为1.weight越大,负载的权重就越大;
# max_fails:允许请求失败的次数默认为1。当超过最大次数时,返回proxy_next_upstream 模块定义的错误。
# fail_timeout : max_fails次失败后,暂停的时间。
# backup: 其它所有的非backup机器down或者忙的时候,请求backup机器。所以这台机器压力会最轻。
# 健康检查:max_fails 指令设置在fail_timeout期间与nginx服务器连续的不成功的尝试连接的通信数量。默认情况下,max_fails为1,当设置为0时,该服务器的运行状况检查会被禁用。fail_timeout还定义服务器将被标记为失效的时间。在服务器发生故障后的 fail_timeout间隔之后,nginx将开始以实时客户端的请求优雅地探测服务器。如果探测成功,则将服务器标记为活动的。
server 127.0.0.1:8080 weight=1; # 待验证:不要写localhost,不然访问速度会很慢
server 127.0.0.1:18080 weight=2;
}
#当前的Nginx的配置
server {
listen 81;#监听81端口,可配置
server_name localhost; #当前服务的域名
location / {
proxy_pass http://nginxloadbalance.com;
proxy_redirect default;
# 以下配置可用于模拟一台tomcat宕机时,nginx的自动剔除和切换
proxy_connect_timeout 1; #连接超时时间
proxy_read_timeout 1;
proxy_send_timeout 1;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
浏览器访问 http://localhost:81/index.jsp,刷新页面,看到出现 Tomcat2 字样的页面(即请求到达后端Tomcat server 2)的概率是 Tomcat server 1 的2倍,这正是负载均衡算法在起作用。
虽然 nginx 已经足够强大,性能优越,并且有非常多的扩展模块(可以理解为插件)可以考虑安装使用,但是很多大公司依旧不满意,于是催生出一系列 nginx 的进阶版:
参考:
Nginx开发从入门到精通
nginx
nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)
nginx: [emerg] bind() to [::]:80 failed (98: Address already in use)
nginx: [emerg] still could not bind()
nginx -c /etc/nginx/conf.d/nacos.conf
nginx: [emerg] “upstream” directive is not allowed here in /etc/nginx/conf.d/nacos.conf:1