01. Nginx介绍
1.1 什么是Nginx
Nginx是一款轻量级的Web 服务器、反向代理服务器、电子邮件(IMAP/POP3)代理服务器,并在一个BSD-like 协议下发行。
其特点是占有内存少,并发能力强,事实上nginx的并发能力确实在同类型的网页服务器中表现较好,中国大陆使用nginx网站用户有:百度、京东、新浪、网易、腾讯、淘宝等。
1.2 Nginx优势
- 更快
正常情况下单次请求得到更快的响应,高峰期(数以万计的并发时)Nginx可以比其它web服务器更快的响应请求。
- 高扩展性
低耦合设计的模块组成,丰富的第三方模块支持。
- 高可靠性
经过大批网站检验,每个worker进程相对独立,master进程在一个worker 进程出错时,可以快速开启新的worker进程提供服务。
- 低内存消耗
一般情况下,10000个非活跃的HTTP Keep-Alive连接在Nginx中仅消耗 2.5M内存,这是Nginx支持高并发的基础。
-
单机支持10万以上的并发连接取决于内存,10万远未封顶。
-
热部署
master和worker的分离设计,可实现7x24小时不间断服务的前提下,升级Nginx可执行文件,当然也支持更新配置项和日志文件。
- 最自由的BSD许可协议
BSD许可协议允许用户免费使用Nginx、修改Nginx源码,然后再发布。这吸引了无数的开发者继续为 Nginx贡献智慧。
1.3 Nginx相关资源
Nginx维护包的官方网站:http://nginx.org
Nginx官方文档:http://nginx.org/en/docs/
02. Nginx安装
2.0 资源下载
链接:https://pan.baidu.com/s/1Wb21Ol4a0HuxpXhcyvi4YA
提取码:7itf
2.1 解压文件
:~/nginx$ ls
nginx-1.13.12.zip pcre-8.42.zip
openssl-1.0.2o.tar.gz zlib-1.2.11.tar.gz
:~/nginx$ tar -xzvf openssl-1.0.2o.tar.gz
:~/nginx$ tar -xzvf zlib-1.2.11.tar.gz
:~/nginx$ unzip pcre-8.42.zip
:~/nginx$ unzip nginx-1.13.12.zip
2.2 生成makefile
:~/nginx/nginx-release-1.13.12$ pwd
/home/deng/nginx/nginx-release-1.13.12
:~/nginx/nginx-release-1.13.12$
:~/nginx/nginx-release-1.13.12$ ./auto/configure --with-pcre=../pcre-8.42 --with-zlib=../zlib-1.2.11 --with-openssl=../openssl-1.0.2o
2.3 编译
:~/nginx/nginx-release-1.13.12$ make
2.4 安装
:~/nginx/nginx-release-1.13.12$ sudo make install
2.5 验证
:~/nginx/nginx-release-1.13.12$ sudo /usr/local/nginx/sbin/nginx
:~/nginx/nginx-release-1.13.12$ ps aux | grep nginx
root 32836 0.0 0.0 20616 388 ? Ss 22:02 0:00 nginx: master process /usr/local/nginx/sbin/nginx
nobody 32837 0.0 0.1 25444 2836 ? S 22:02 0:00 nginx: worker process
deng 32839 0.0 0.0 21536 1148 pts/1 S+ 22:02 0:00 grep --color=auto nginx
使用浏览器访问
创建软连接
:~/nginx/nginx-release-1.13.12$ sudo ln -s /usr/local/nginx/sbin/nginx /usr/local/bin/nginx
03. nginx目录介绍
安装完成之后就可以在/usr/local/nginx 中找到nginx下的目录
:/usr/local/nginx$ tree .
.
├── client_body_temp [error opening dir]
├── conf
│ ├── fastcgi.conf
│ ├── fastcgi.conf.default
│ ├── fastcgi_params
│ ├── fastcgi_params.default
│ ├── koi-utf
│ ├── koi-win
│ ├── mime.types
│ ├── mime.types.default
│ ├── nginx.conf
│ ├── nginx.conf.default
│ ├── scgi_params
│ ├── scgi_params.default
│ ├── uwsgi_params
│ ├── uwsgi_params.default
│ └── win-utf
├── fastcgi_temp [error opening dir]
├── html
│ ├── 50x.html
│ └── index.html
├── logs
│ ├── access.log
│ ├── error.log
│ └── nginx.pid
├── proxy_temp [error opening dir]
├── sbin
│ └── nginx
├── scgi_temp [error opening dir]
└── uwsgi_temp [error opening dir]
conf: nginx服务器的配置文件都存放到这里
logs: nginx服务器的日志文件存放目录
- error.log:错误日志,服务器启动出错时可以在此日志查找原因
- access.log:访问日志,记录客户端连接服务器后一些访问信息
html: nginx服务器的默认网页案例存放目录
04. nginx命令使用
4.1 帮助命令
:/usr/local/nginx$ nginx -h
nginx version: nginx/1.13.12
Usage: nginx [-?hvVtTq] [-s signal] [-c filename] [-p prefix] [-g directives]
Options:
-?,-h : this help
-v : show version and exit
-V : show version and configure options then exit
-t : test configuration and exit
-T : test configuration, dump it and exit
-q : suppress non-error messages during configuration testing
-s signal : send signal to a master process: stop, quit, reopen, reload
-p prefix : set prefix path (default: /usr/local/nginx/)
-c filename : set configuration file (default: conf/nginx.conf)
-g directives : set global directives out of configuration file
4.2 启动Nginx服务器
:/usr/local/nginx$ sudo nginx
:/usr/local/nginx$ ps aux | grep nginx
root 4402 0.0 0.0 20616 436 ? Ss 10:33 0:00 nginx: master process nginx
nobody 4403 0.0 0.1 25380 2888 ? S 10:33 0:00 nginx: worker process
aswad 4405 0.0 0.0 21536 1108 pts/1 R+ 10:33 0:00 grep --color=auto ngin
这时,会自动读取配置文件:/usr/local/nginx/conf/nginx.conf
测试:
打开浏览器访问此机器的IP,如果浏览器出现 Welcome to nginx! 则表示 Nginx 已经安装并运行成功
4.3 测试配置文件
:/usr/local/nginx$ sudo nginx -t
nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful
4.4 指定配置文件启动Nginx
:/usr/local/nginx$ sudo nginx -c /usr/local/nginx/conf/nginx.conf
4.5 暴力停止服务
:/usr/local/nginx$ sudo nginx -s stop
:/usr/local/nginx$ ps aux | grep nginx
dfaf 4445 0.0 0.0 21536 1148 pts/1 S+ 10:40 0:00 grep --color=auto ngin
4.6 优雅停止服务
:/usr/local/nginx$ sudo nginx -s quit
暴力停止服务和优雅停止服务的区别:
- 当暴力停止服务时,worker进程与master进程在收到信号立即退出进程。
- 当优雅停止服务时,首先会关闭监听端口,停止接收新的连接,然后把当前正在处理的连接全部处理完,最后再退出进程。
可以直接发送QUIT信号给master进程来停止服务,其效果与执行-s quit命令时一样的:
:/usr/local/nginx$ sudo nginx
:/usr/local/nginx$ ps aux |grep nginx
root 4485 0.0 0.0 20616 432 ? Ss 10:43 0:00 nginx: master process nginx
nobody 4486 0.0 0.1 25380 2776 ? S 10:43 0:00 nginx: worker process
deng 4488 0.0 0.0 21536 1104 pts/1 R+ 10:43 0:00 grep --color=auto ngin
:/usr/local/nginx$ sudo kill -SIGQUIT 4485
4.7 重新加载配置文件
:/usr/local/nginx$ sudo nginx -s reload
05. 初探nginx架构
nginx性能高,而nginx的高性能与其架构是分不开的。那么nginx究竟是怎么样的呢?我们先来初识一下nginx框架吧。
nginx在启动后,在unix系统中会以daemon的方式在后台运行,后台进程包含一个master进程和多个worker进程。我们也可以手动地关掉后台模式,让nginx在前台运行,并且通过配置让nginx取消master进程,从而可以使nginx以单进程方式运行。很显然,生产环境下我们肯定不会这么做,所以关闭后台模式,一般是用来调试用的。
nginx在启动后,会有一个master进程和多个worker进程。master进程主要用来管理worker进程,包含:接收来自外界的信号,向各worker进程发送信号,监控worker进程的运行状态,当worker进程退出后(异常情况下),会自动重新启动新的worker进程。而基本的网络事件,则是放在worker进程中来处理了。多个worker进程之间是对等的,他们同等竞争来自客户端的请求,各进程互相之间是独立的。一个请求,只可能在一个worker进程中处理,一个worker进程,不可能处理其它进程的请求。worker进程的个数是可以设置的,一般我们会设置与机器cpu核数一致,这里面的原因与nginx的进程模型以及事件处理模型是分不开的。nginx的进程模型,可以由下图来表示:
在nginx启动后,如果我们要操作nginx,要怎么做呢?从上文中我们可以看到,master来管理worker进程,所以我们只需要与master进程通信就行了。master进程会接收来自外界发来的信号,再根据信号做不同的事情。所以我们要控制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进程发送信号一样了。
现在,我们知道了当我们在操作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采用这种进程模型有什么好处呢?当然,好处肯定会很多了。首先,对于每个worker进程来说,独立的进程,不需要加锁,所以省掉了锁带来的开销,同时在编程以及问题查找时,也会方便很多。其次,采用独立的进程,可以让互相之间不会影响,一个进程退出后,其它进程还在工作,服务不会中断,master进程则很快启动新的worker进程。当然,worker进程的异常退出,肯定是程序有bug了,异常退出,会导致当前worker上的所有请求失败,不过不会影响到所有请求,所以降低了风险。
06. Nginx配置
Nginx配置系统
nginx的配置系统由一个主配置文件和其他一些辅助的配置文件构成。这些配置文件均是纯文本文件,全部位于nginx安装目录下的conf目录下。
:/usr/local/nginx/conf$ pwd
/usr/local/nginx/conf
:/usr/local/nginx/conf$ ls
fastcgi.conf koi-utf nginx.conf uwsgi_params
fastcgi.conf.default koi-win nginx.conf.default uwsgi_params.default
fastcgi_params mime.types scgi_params win-utf
fastcgi_params.default mime.types.default scgi_params.default
配置文件中以#开始的行,或者是前面有若干空格或者TAB,然后再跟#的行,都被认为是注释,也就是只对编辑查看文件的用户有意义,程序在读取这些注释行的时候,其实际的内容是被忽略的。
由于除主配置文件nginx.conf以外的文件都是在某些情况下才使用的,而只有主配置文件是在任何情况下都被使用的。所以在这里我们就以主配置文件为例,来解释nginx的配置系统。
在nginx.conf中,包含若干配置项。每个配置项由配置指令和指令参数2个部分构成。指令参数也就是配置指令对应的配置值。
6.1 配置指令
配置指令是一个字符串,可以用单引号或者双引号括起来,也可以不括。但是如果配置指令包含空格,一定要引起来。
6.2 指令参数
指令的参数使用一个或者多个空格或者TAB字符与指令分开。指令的参数有一个或者多个TOKEN串组成。TOKEN串之间由空格或者TAB键分隔。
TOKEN串分为简单字符串或者是复合配置块。复合配置块即是由大括号括起来的一堆内容。一个复合配置块中可能包含若干其他的配置指令。
如果一个配置指令的参数全部由简单字符串构成,也就是不包含复合配置块,那么我们就说这个配置指令是一个简单配置项,否则称之为复杂配置项。例如下面这个是一个简单配置项:
error_page 500 502 503 504 /50x.html;
对于简单配置,配置项的结尾使用分号结束。对于复杂配置项,包含多个TOKEN串的,一般都是简单TOKEN串放在前面,复合配置块一般位于最后,而且其结尾,并不需要再添加分号。例如下面这个复杂配置项:
location / {
root /home/jizhao/nginx-book/build/html;
index index.html index.htm;
}
6.3 指令上下文
nginx.conf中的配置信息,根据其逻辑上的意义,对它们进行了分类,也就是分成了多个作用域,或者称之为配置指令上下文。不同的作用域含有一个或者多个配置项。
当前nginx支持的几个指令上下文:
配置层次 | 描述 |
---|---|
main | nginx在运行时与具体业务功能(比如http服务或者email服务代理)无关的一些参数,比如工作进程数,运行的身份等。 |
http | 与提供http服务相关的一些配置参数。例如:是否使用keepalive啊,是否使用gzip进行压缩等。 |
server | http服务上支持若干虚拟主机。每个虚拟主机一个对应的server配置项,配置项里面包含该虚拟主机相关的配置。在提供mail服务的代理时,也可以建立若干server.每个server通过监听的地址来区分。 |
location | http服务中,某些特定的URL对应的一系列配置项。 |
实现email相关的SMTP/IMAP/POP3代理时,共享的一些配置项(因为可能实现多个代理,工作在多个监听地址上)。 |
指令上下文,可能有包含的情况出现。例如:通常http上下文和mail上下文一定是出现在main上下文里的。在一个上下文里,可能包含另外一种类型的上下文多次。例如:如果http服务,支持了多个虚拟主机,那么在http上下文里,就会出现多个server上下文。
我们来看一个示例配置:
user nobody;
worker_processes 1;
error_log logs/error.log info;
events {
worker_connections 1024;
}
http {
server {
listen 80;
server_name www.linuxidc.com;
access_log logs/linuxidc.access.log main;
location / {
index index.html;
root /var/www/linuxidc.com/htdocs;
}
}
server {
listen 80;
server_name www.Androidj.com;
access_log logs/androidj.access.log main;
location / {
index index.html;
root /var/www/androidj.com/htdocs;
}
}
}
mail {
auth_http 127.0.0.1:80/auth.php;
pop3_capabilities "TOP" "USER";
imap_capabilities "IMAP4rev1" "UIDPLUS";
server {
listen 110;
protocol pop3;
proxy on;
}
server {
listen 25;
protocol smtp;
proxy on;
smtp_auth login plain;
xclient off;
}
}
在这个配置中,上面提到个五种配置指令上下文都存在。
存在于main上下文中的配置指令如下:
- user
- worker_processes
- error_log
- events
- http
存在于http上下文中的指令如下:
- server
存在于mail上下文中的指令如下:
- server
- auth_http
- imap_capabilities
存在于server上下文中的配置指令如下:
- listen
- server_name
- access_log
- location
- protocol
- proxy
- smtp_auth
- xclient
存在于location上下文中的指令如下:
- index
- root
当然,这里只是一些示例。具体有哪些配置指令,以及这些配置指令可以出现在什么样的上下文中,需要参考nginx的使用文档。
07. 反向代理
7.1 什么是反向代理
反向代理(Reverse Proxy) 方式是指以代理服务器来接受internet上的连接请求,然后将请求转发给内部网络上的服务器,并将从服务器上得到的结果返回给internet上请求连接的客户端,此时代理服务器对外就表现为一个反向代理服务器。
一般情况下,Nginx在前端抗负载和处理静态页面请求,后端服务器可以挂接Apache、Tomcat、IIS等处理复杂业务的动态Web服务器。
7.2 正向代理和反向代理区别
我们常说的代理也就是只正向代理,正向代理的过程,它隐藏了真实的请求客户端,服务端不知道真实的客户端是谁,客户端请求的服务都被代理服务器代替来请求 。
反向代理
大家都有过这样的经历,拨打10086客服电话,可能一个地区的10086客服有几个或者几十个,你永远都不需要关心在电话那头的是哪一个,叫什么,男的,还是女的,漂亮的还是帅气的,你都不关心,你关心的是你的问题能不能得到专业的解答,你只需要拨通了10086的总机号码,电话那头总会有人会回答你,只是有时慢有时快而已。那么这里的10086总机号码就是我们说的反向代理。客户不知道真正提供服务人的是谁。
反向代理隐藏了真实的服务端,当我们请求 www.baidu.com 的时候,就像拨打10086一样,背后可能有成千上万台服务器为我们服务,但具体是哪一台,你不知道,也不需要知道,你只需要知道反向代理服务器是谁就好了,www.baidu.com 就是我们的反向代理服务器,反向代理服务器会帮我们把请求转发到真实的服务器那里去。Nginx就是性能非常好的反向代理服务器,用来做负载均衡。
两者的区别在于代理的对象不一样:正向代理代理的对象是客户端,反向代理代理的对象是服务端
7.3 虚拟主机
一个nginx可以同时支持多个站点的部署
192.168.31.109
http://www.nginx1.cn
http://www.nginx2.cn
如何通过不同的域名来访问 nginx 服务器,nginx能够做到识别
访问nginx1,就返回nginx1的页面
访问nginx2,就返回nginx2的页面
第一种方式:不同的站点部署在不同的端口 nginx1 8000 nginx2 8080
修改配置文件
server {
listen 8000;
server_name www.nginx1.cn;
location / {
root /usr/local/nginx/www/nginx1;
index index.html;
}
}
server {
listen 8080;
server_name www.nginx2.cn;
location / {
root /usr/local/nginx/www/nginx2;
index index.html;
}
}
测试:
浏览器中输入 192.168.31.109:8000 192.168.31.109:8080
第二种方式:使用同一个端口部署不同站点
比如都是80 部署两站点,传输层是没有办法做区分,靠应用层 , http 请求头 Host 关键字,告诉nginx服务器访问的是什么站点
当使用不同的域名来访问nginx服务器,应该能够看到不同的内容
修改配置文件
server {
listen 80;
server_name www.nginx1.cn;
location / {
root /usr/local/nginx/www/nginx1;
index index.html;
}
}
server {
listen 80;
server_name www.nginx2.cn;
location / {
root /usr/local/nginx/www/nginx2;
index index.html;
}
}
测试:
浏览器中输入 www.nginx1.cn www.nginx2.cn
7.4 反向代理配置
配置文件
location / {
proxy_pass http://192.168.31.138:10080;
}
7.5 负载均衡
示例:
192.168.13.142作为Nginx服务器反向代理负载均衡服务器
192.168.13.138:10080
192.168.13.138:10081
语法规则
定义服务器群组
upstream 自己命名 {
server ip1:port1;
server ip2:port2;
server /tmp/xxx.sock; #可以是本地套接字
....
}
location / {
proxy_pass http://自己的服务器群组名;
}
配置文件
#定义在http模块下,跟server模块同级
upstream qqqqq.com{
server 192.168.13.138:10080;
server 192.168.13.138:10081;
}
server {
listen 80;
server_name localhost;
#charset koi8-r;
charset utf-8;
#access_log logs/host.access.log main;
location / {
proxy_pass http://qqqqq.com;
}
}
负载均衡策略:默认使用轮询
也可设置权重
upstream qqqqq.com{
server 192.168.13.138:10080 weight=90;
server 192.168.13.138:10081 weight=10;
}
配置文件
#定义在http模块下,跟server模块同级
upstream qqqqq.com{
server 192.168.13.138:10080;
server 192.168.13.138:10081;
}
server {
listen 80;
server_name localhost;
#charset koi8-r;
charset utf-8;
#access_log logs/host.access.log main;
location / {
proxy_pass http://qqqqq.com;
}
}
负载均衡策略:默认使用轮询
也可设置权重
upstream qqqqq.com{
server 192.168.13.138:10080 weight=90;
server 192.168.13.138:10081 weight=10;
}