Nginx的使用总结(三)

Nginx的使用总结(三)

Nginx架构分析

nginx模块化结构
Nginx涉及到的模块分为核心模块、标准HTTP模块、可选HTTP模块、邮件服务模块以及第三方模块等五大类。


核心模块
核心模块是指Nginx服务器正常运行时必不可少的模块,它们提供了Nginx最基本最核心的服务,如进程管理、权限控制、错误日志记录等。
主要包含对两类功能的支持,一类是主体功能,包括进程管理、权限控制、错误日志记录、配置解析等,
另一类是用于响应请求事件必需的功能,包括事件驱动机制、正则表达式解析等。

包含以下模块:

ngx_core_module
ngx_errlog_module
ngx_conf_module
ngx_regex_module
ngx_events_module
ngx_event_core_module
ngx_epoll_module

标准HTTP模块

标准HTTP模块是编译Nginx后包含的模块,其支持Nginx服务器的标准HTTP功能。

模块	                          功能
ngx_http_core	                配置端口,URI分析,服务器响应错误处理,别名控制以及其他HTTP核心事务
ngx_http_access_module	        基于IP地址的访问控制(允许/拒绝)
ngx_http_auth_basic_module      基于HTTP的身份认证
ngx_http_autoindex_module       处理以“/”结尾的请求并自动生成目录列表
ngx_http_browser_module	        解析HTTP请求头中的“User-Agent”域的值
ngx_http_charset_module	        指定网页编码
ngx_http_empty_gif_module       从内存创建一个1 x 1的透明gif图片,可以快速调用
ngx_http_fastcgi_module	        对FastCGI的支持
ngx_http_geo_module	            将客户端的IP转化为键值对变量,该模块主要用来针对客户的的IP来定义变量
ngx_http_gzip_module	        压缩请求响应,可以减少数据传输
ngx_http_headers_filter_module	设置HTTP响应头
ngx_http_index_module	        处理以“/”结尾的请求,如果没有找到该目录下的index页,就将请求转给ngx_http_autoindex_module模块处理
ngx_http_limit_req_module	    限制来自客户端的请求的响应和处理速率
ngx_http_limit_conn_module	    限制来自客户端的连接的响应和处理速率
ngx_http_log_module	            自定义access日志
ngx_http_map_module	            创建任意键值对变量
ngx_http_memcached_module	    对Memcached的支持
ngx_http_proxy_module	        支持代理事务
ngx_http_referer_module	        对HTTP头中的”referer”进行过滤处理,比如,实现防盗链功能
ngx_http_rewrite_module	        实现nginx的rewrite功能
ngx_http_scgi_module	        对SCGI的支持
ngx_http_upstream_module	    定义一组服务器,可以接收来自代理、Fastcgi、Memcached的中重定向,主要用于负载均衡

可选HTTP模块

可选HTTP模块主要用于扩展标准的HTTP功能,使其能够处理一些特殊的HTTP请求。在编译Nginx时,如果不指定这些模块,默认是不会安装的。

模块	                        功能
ngx_http_addition_module	  在响应请求的页面开始或者结尾添加文本信息
ngx_http_degradation_module	  在低内存的情形下允许Nginx服务器返回444错误或204错误
ngx_http_perl_module	      在Nginx的配置文件中可以使用Perl脚本
ngx_http_flv_module	          支持将Flash多媒体信息按照流文件传输,可以根据客户端指定的开始位置返回Flash
ngx_http_geoip_module	      支持解析基于GeoIP数据库的客户端请求
ngx_google_perflools_module	  支持Google Performance Tools的一套用于C++Profile的工具集
ngx_http_image_filter_module  支持将H.264/AAC编码的多媒体信息(后缀名通常为mp4、m4v或m4a)按照流文件传输,常与ngx_http_flv_module模块一起使用
ngx_http_random_index_module  Nginx接收到以“/”结尾的请求时,在对应的目录下随机选择一个文件作为index文件
ngx_http_secure_link_module	  支持对请求链接的有效性检查
ngx_http_ssl_module	          对HTTPS/SSL支持
ngx_http_stub_status_module	  支持返回Nginx服务器的统计信息,一般包括处理连接的数量、连接成功的数量、处理的请求数、读取和返回的Header信息数等信息
ngx_http_sub_module	          使用指定的字符串替换响应信息中的信息
ngx_http_dav_module	          支持HTTP协议和WebDAV协议中PUT、DELETE、MKCOL、COPY和MOVE方法
ngx_http_xslt_module	      将XML响应信息使用XSLT(拓展样式表转换语言)进行转换

邮件服务模块
主要用于支持Ningx的邮件服务。

第三方模块
并非有Nginx官方提供,而是由第三方机构或者个人开发的模块,用于实现某种特殊功能。
echo-nginx-module 支持在Nginx配置文件中使用echo、sleep、time以及exec等类shell命令,
lua-nginx-module 使Nginx支持lua脚本语言。

nginx的web请求机制


同步机制
同步、异步发生在当客户端发起请求后,服务端处理客户端的请求时。
同步机制,是指客户端发送请求后,需要等待服务端(内核)返回信息后,再继续发送下一个请求。
在同步机制中,所有的请求在服务器端得到同步,即发送方和接收方对请求的处理步调是一致的。

异步机制
异步机制,是指客户端发出一个请求后,不等待服务端(内核)返回信息,就继续发送下一个请求。
在异步机制中,所有来自发送方的请求形成一个队列,接收方处理完后再通知发送方。

举例:一家酒店前台,在旺季的高峰时间段会接很多预定酒席的电话。
如果是同步机制情况下,前台每接一个电话后先不挂掉电话,而是去查询有无剩余酒席,查到结果后,告诉客户。
如果是异步机制情况下,前台每接一个预定电话直接回复客户,一会回复,此时前台把查询这件事情交给了另外的同事,
该前台挂掉电话后,继续处理其他客户的事情,当另外的同事查询到结果后再通知给前台,前台再通知客户。

阻塞
阻塞与非阻塞发生在IO调度中,比如内核到磁盘IO。
阻塞方式下,进程/线程在获取最终结果之前,被系统挂起了,也就是所谓的阻塞了,在阻塞过程中该进程什么都干不了,
直到最终结果反馈给它时,它才恢复运行状态。

非阻塞
非阻塞方式和阻塞相反,进程/线程在获取最终结果之前,并没有进入被挂起的状态,而是该进程可以继续执行新的任务。
当有最终结果反馈给该进程时,它再把结果交给客户端。

举例:依然是酒店前台接待预定酒席电话的案例。
此时角色不再是前台,而是她的查询有无剩余酒席的同事。如果是阻塞方式,该同事在查询有无剩余酒席的过程中,需要傻傻地
等待酒店管理系统给他返回结果,在此期间不能做其他事情。
如果是非阻塞,该同事在等待酒店管理系统给他返回结果这段时间,可以做其他事情,比如可以通知前台剩余酒席的情况。

nginx的请求机制
Nginx之所以可以支持高并发,是因为Nginx用的是异步非阻塞的机制,而Nginx是靠事件驱动模型来实现这种机制的。

在Nginx的事件驱动模型下,客户端发起的所有请求在服务端都会被标记为一个事件,Nginx会把这些事件收集到“事件收集器”里,
然后再把这些事件交给内核去处理。

nginx事件驱动模型
事件驱动模型是实现异步非阻塞的一个手段。事件驱动模型中,一个进程(线程)就可以了。

对于web服务器来说,客户端A的请求连接到服务端时,服务端的某个进程(Nginx worker process)会处理该请求,
此进程在没有返回给客户端A结果时,它又去处理了客户端B的请求。
服务端把客户端A以及客户端B发来的请求作为事件交给了“事件收集器”,
而“事件收集器”再把收集到的事件交由“事件发送器”发送给“事件处理器”进行处理。
最后“事件处理器”处理完该事件后,通知服务端进程,服务端进程再把结果返回给客户端A、客户端B。

在这个过程中,服务端进程做的事情属于用户级别的,而事件处理这部分工作属于内核级别的。
也就是说这个事件驱动模型是需要操作系统内核来作为支撑的。

nginx的事件驱动模型

Nginx的事件驱动模型,支持select、poll、epoll、rtsig、kqueue、/dev/poll、eventport等。
最常用的是前三种,其中kqueue模型用于支持BSD系列平台的事件驱动模型。kqueue是poll模型的一个变种,本质上和epoll一样。
/dev/poll是Unix平台的事件驱动模型,其主要在Solaris7及以上版本、HP/UX11.22及以上版本、IRIX6.5.15及以上版本、
Tru64 Unix 5.1A及以上版本的平台使用。
eventport是用于支持Solaris10及以上版本的事件驱动模型

select模型

Linux和Windows都支持,使用select模型的步骤是:

1. 创建所关注事件的描述符集合,对于一个描述符,可以关注其上面的读(Read)事件、写(Write)事件以及异常发生(Exception)事件。
在select模型中,要创建这3类事件描述符集合。

2. 调用底层提供的select()函数,等待事件发生。

3. 轮询所有事件描述符集合中的每一个事件描述符,检查是否有相应的事件发生,如果有就进行处理

poll模型

poll模型是Linux平台上的事件驱动模型,在Linux2.1.23中引入的,Windows平台不支持该模型。 poll模型和select模型工作方式基本相同,区别在于,select模型创建了3个描述符集合,而poll模型只创建一个描述符集合

epoll模型

epoll模型属于poll模型的变种,在Linux2.5.44中引入。epoll比poll更加高效,原因在于它不需要轮询整个描述符集合, 而是Linux内核会关注事件集合,当有变动时,内核会发来通知

nginx架构
Nginx服务器使用 master/worker 多进程模式。

主进程(Master process)启动后,会接收和处理外部信号;
主进程启动后通过fork( ) 函数产生一个或多个子进程(Worker process),每个子进程会进行进程初始化、模块调用以及对事件的接收和处理等工作。

主进程(Master process)

主要功能是和外界通信和对内部其他进程进行管理,具体来说有以下几点:

* 读取Nginx配置文件并验证其有效性和正确性

* 建立、绑定和关闭socket

* 按照配置生成、管理工作进程

* 接收外界指令,比如重启、关闭、重载服务等指令

* 日志文件管理

子进程(Worker process)

是由主进程生成,生成数量可以在配置文件中定义。该进程主要功能有:

* 接收客户端请求

* 将请求依次送入各个功能模块进行过滤处理

* IO调用,获取响应数据

* 与后端服务器通信,接收后端服务器处理结果

* 数据缓存,访问缓存索引,查询和调用缓存数据

* 发送请求结果,响应客户端请求

* 接收主进程指令,如重启、重载、退出等

子进程(Worker process)

是由主进程生成,生成数量可以在配置文件中定义。该进程主要功能有:

* 接收客户端请求

* 将请求依次送入各个功能模块进行过滤处理

* IO调用,获取响应数据

* 与后端服务器通信,接收后端服务器处理结果

* 数据缓存,访问缓存索引,查询和调用缓存数据

* 发送请求结果,响应客户端请求

* 接收主进程指令,如重启、重载、退出等

Nginx虚拟主机配置
同一台机器上可能跑多个站点,即多个域名。在生产环境下,我们通常会配置虚拟主机来满足需求。

Nginx默认虚拟主机
默认虚拟主机 就是不管什么域名解析到该服务器上,都会访问到默认虚拟主机。

前面讲过,nginx主配置文件 nginx.conf 中每一个 server{} 都是一个虚拟主机(站点)。一般情况下,如果没有指定,那么第一个 server{} 就是默认虚拟主机的配置。

当然, 我们还可以指定,可以在 server{} 里面的 listen 80 后面加上 default_server ,这样就指明这个 server{} 是默认虚拟主机。

linsten 80 default_server;        #以80端口为例

通常为了规范,并不会在主配置文件下配置好多个 server{} ,而是在 conf 目录下面创建 vhost目录,然后在 vhost 目录下创建虚拟主机的配置文件,只需要在主配置文件中加上一行:

# vim /usr/local/nginx/conf/nginx.conf           #在http{}配置部分加上一行
include vhost/*.conf;
  • 查看主配置文件:
# cat /usr/local/nginx/conf/nginx.conf

user nobody nobody;         #全局配置部分
worker_processes 2;
error_log /usr/local/nginx/logs/nginx_error.log crit;
pid /usr/local/nginx/logs/nginx.pid;
worker_rlimit_nofile 51200;

events                      #events配置部分
{
    use epoll;
    worker_connections 6000;
}

http                        #http配置部分,server{}属于http配置部分
{
    include mime.types;
    default_type application/octet-stream;
    server_names_hash_bucket_size 3526;
    server_names_hash_max_size 4096;
    log_format combined_realip '$remote_addr $http_x_forwarded_for [$time_local]'
    ' $host "$request_uri" $status'
    ' "$http_referer" "$http_user_agent"';
    sendfile on;
    tcp_nopush on;
    keepalive_timeout 30;
    client_header_timeout 3m;
    client_body_timeout 3m;
    send_timeout 3m;
    connection_pool_size 256;
    client_header_buffer_size 1k;
    large_client_header_buffers 8 4k;
    request_pool_size 4k;
    output_buffers 4 32k;
    postpone_output 1460;
    client_max_body_size 10m;
    client_body_buffer_size 256k;
    client_body_temp_path /usr/local/nginx/client_body_temp;
    proxy_temp_path /usr/local/nginx/proxy_temp;
    fastcgi_temp_path /usr/local/nginx/fastcgi_temp;
    fastcgi_intercept_errors on;
    tcp_nodelay on;
    gzip on;
    gzip_min_length 1k;
    gzip_buffers 4 8k;
    gzip_comp_level 5;
    gzip_http_version 1.1;
    gzip_types text/plain application/x-javascript text/css text/htm
    application/xml;

    include vhost/*.conf;
}
  • 创建两个server{ } 配置文件:
# mkdir -p /data/wwwroot/www.1.com /data/wwwroot/www.2.com

# echo "www.1.com" > /data/wwwroot/www.1.com/index.html

# echo "www.2.com" > /data/wwwroot/www.2.com/index.html

# mkdir /usr/local/nginx/conf/vhost

# vim /usr/local/nginx/conf/vhost/www.1.com.conf          #写入下面内容
server {
    listen 80;
    server_name www.1.com;
    root /data/wwwroot/www.1.com;
}

# vim /usr/local/nginx/conf/vhost/www.2.com.conf          #写入下面内容
server {
    listen 80;
    server_name www.2.com;
    root /data/wwwroot/www.2.com;
}
  • 重载配置:
# /usr/local/nginx/sbin/nginx -t

# /usr/local/nginx/sbin/nginx -s reload
  • 访问测试:
# curl -x127.0.0.1:80 www.1.com
www.1.com

# curl -x127.0.0.1:80 www.2.com
www.2.com

# curl -x127.0.0.1:80 www.3.com          #可以看出来,www.1.com是默认虚拟主机,虽然我们没有指定
www.1.com

一般情况下,我们需要指定默认虚拟主机,因为不指定就是排在第一个的server{}是默认虚拟主机,这样有点不稳定。

  • 指定默认虚拟主机:
# vim /usr/local/nginx/conf/vhost/default.conf             #写入下面内容
server {
    listen 80 default_server;            #指定默认虚拟主机
    deny all;            #将非该服务器上的站点访问拒绝
}
# /usr/local/nginx/sbin/nginx -t

# /usr/local/nginx/sbin/nginx -s reload
  • 访问测试:
# curl -x127.0.0.1:80 www.3.com
<html>
<head><title>403 Forbidden</title></head>              #提示403禁止访问
<body bgcolor="white">
<center><h1>403 Forbidden</h1></center>
<hr><center>nginx/1.14.0</center>
</body>
</html>

这样看起来就比较合理,服务器上没有的站点一律拒绝访问,而不是指向默认虚拟主机。

虚拟主机配置规范
一般规范来说,在主配置文件中include虚拟主机配置文件,然后在 conf 目录下创建 vhost 目录,在 vhost目录下定义虚拟主机配置,也就是 server{}配置部分。

上面在指定默认虚拟主机前的访问我们在 www.1.com.conf 和 www.2.com.conf 中没有指定index(索引页),它默认会访问 index.html ,那如果指定的index不是 index.html 呢?

  • 指定index:
# vim /usr/local/nginx/conf/vhost/www.1.com.conf      
server {
    listen 80;
    server_name www.1.com;
    index 1.html;                                #添加这一行
    root /data/wwwroot/www.1.com;
}
# /usr/local/nginx/sbin/nginx -t

# /usr/local/nginx/sbin/nginx -s reload
  • 访问测试:
# curl -x127.0.0.1:80 www.1.com         
<html>
<head><title>403 Forbidden</title></head>             #提示403禁止访问,索引页有个特性:找不到会提示403,而不是404
<body bgcolor="white">
<center><h1>403 Forbidden</h1></center>
<hr><center>nginx/1.14.0</center>
</body>
</html>
# echo "111111" > /data/wwwroot/www.1.com/1.html           

# curl -x127.0.0.1:80 www.1.com
111111                #有了1.html之后就会默认访问到索引页

同时,server{} 配置部分还支持域名泛解析,一个主域名下面可能会有很多个二级域名,这就会用到泛解析。

  • 指定泛解析:
# vim /usr/local/nginx/conf/vhost/www.2.com.conf 
server {
    listen 80;
    server_name *.2.com;             #指定域名泛解析,假如2.com是主域名
    root /data/wwwroot/www.2.com;
    index index.html;
}
# /usr/local/nginx/sbin/nginx -t

# /usr/local/nginx/sbin/nginx -s reload
  • 访问测试:
# curl -x127.0.0.1:80 2.com
<html>
<head><title>403 Forbidden</title></head>              #直接访问主域名,提示403禁止访问
<body bgcolor="white">
<center><h1>403 Forbidden</h1></center>
<hr><center>nginx/1.14.0</center>
</body>
</html>

# curl -x127.0.0.1:80 1.2.com
www.2.com

# curl -x127.0.0.1:80 2.2.com
www.2.com

# curl -x127.0.0.1:80 sdjwefwe.2.com            #访问二级域名才可以访问到index
www.2.com

要想连主域名一起访问到index,可以以空格分隔域名:

server_name 2.com *.2.com; 

基于端口的虚拟主机

虚拟主机不一定是监听80端口,只不过同一端口下的域名不能重复,不同端口下的域名是可以重复的。

  • 定义同端口相同域名:
# vim /usr/local/nginx/conf/vhost/www.1.com.conf              
server {
    listen 80;
    server_name www.1.com;
    index index.html;                        #更改index
    root /data/wwwroot/www.1.com;
}

# cp /usr/local/nginx/conf/vhost/www.1.com.conf /usr/local/nginx/conf/vhost/www.1.com.bak.conf

# cat !$
server {
    listen 80;
    server_name www.1.com;
    index index.html;
    root /data/wwwroot/www.1.com;
}

# /usr/local/nginx/sbin/nginx -t             
nginx: [warn] conflicting server name "www.1.com" on 0.0.0.0:80, ignored            #会有报错提示,server name 冲突
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
  • 定义不同端口相同域名:
# mkdir /data/wwwroot/www.1.com.bak

# echo "www.1.com:8080" > /data/wwwroot/www.1.com.bak/index.html

# vim /usr/local/nginx/conf/vhost/www.1.com.bak.conf
server {
    listen 8080;               #更改监听端口
    server_name www.1.com;
    index index.html;
    root /data/wwwroot/www.1.com.bak;
}
# /usr/local/nginx/sbin/nginx -t

# /usr/local/nginx/sbin/nginx -s reload
  • 访问测试:
# curl -x127.0.0.1:80 www.1.com
www.1.com

# curl -x127.0.0.1:8080 www.1.com
www.1.com:8080
发布了370 篇原创文章 · 获赞 88 · 访问量 29万+

猜你喜欢

转载自blog.csdn.net/qq_35029061/article/details/100100698
今日推荐