144 作者 happy江柳清 关注
2015.10.26 17:23* 字数 2536 阅读 1753评论 2喜欢 8
本文主要从 Nginx 的进程模块、事件模块、http网络模块三方面介绍了 Nginx 的底层实现原理,希望你通过本文能对Nginx 的基本实现有一定了解。

进程模块

Nginx 默认采用守护模式启动,守护模式让master进程启动后在后台运行,不在窗口上卡住。

Nginx 启动后会有一个 Master 进程和多个Worker 进程,Master 进程主要用来管理 Worker 进程,对网络事件进程进行收集和分发,调度哪个模块可以占用 CPU 资源,从而处理请求。一般配置Worker进程的个数与机器cpu个数一致,从而打到cpu资源的最大化利用,也避免由于进程资源分配带来的额外开销。

进程 icon

图片来自网络

Master进程工作原理

Master 进程的工作包括

接收来自外界的信号

向各worker进程发送信号

监控worker进程的运行状态,当worker进程退出后(异常情况下),会自动重新启动新的worker进程

惊群现象

惊群现象 是指请求到来的时候,只有可以成功accept的那个进程会惊醒,其他进程会继续阻塞。nginx 采用accept-mutex来解决惊群问题,当一个请求到达的时候,只有竞争到锁的worker进程才能处理请求,其他进程结合timer_solution 配置的最大的超时时间,再去获取监听锁
来看源码

void
ngx_process_events_and_timers(ngx_cycle_t *cycle)
{
ngx_uint_t flags;
ngx_msec_t timer, delta;
if (ngx_timer_resolution) {
timer = NGX_TIMER_INFINITE;
flags = 0;
} else {
timer = ngx_event_find_timer();
flags = NGX_UPDATE_TIME;

if (NGX_THREADS)

if (timer == NGX_TIMER_INFINITE || timer > 500) {timer = 500;
}

endif

}
/* 检测是否启用mutex,多worker进程下一般都会启用 */
if (ngx_use_accept_mutex) {if (ngx_accept_disabled > 0) {ngx_accept_disabled--;} else {if (ngx_trylock_accept_mutex(cycle) == NGX_ERROR) {/* 尝试获取锁,不管成功还是失败都会立即返回 */return;}if (ngx_accept_mutex_held) {/* 获取到锁之后添加flag */flags |= NGX_POST_EVENTS;} else {/* 如果获取不到锁需要结合timer事件设置下一次抢锁的时间 */if (timer == NGX_TIMER_INFINITE|| timer > ngx_accept_mutex_delay){timer = ngx_accept_mutex_delay;}}}
}
delta = ngx_current_msec;/* 开始epoll收集处理事件 */
(void) ngx_process_events(cycle, timer, flags);/* delta就是epoll_wait消耗掉的时间 */
delta = ngx_current_msec - delta;ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,"timer delta: %M", delta);
/* accept事件已经被加入到单独的任务队列并会被优先处理 */
ngx_event_process_posted(cycle, &ngx_posted_accept_events);/* accept事件处理完之后先释放accept锁,因为其它事件的处理可能耗时较长,不要占着茅坑不睡觉 */
if (ngx_accept_mutex_held) {ngx_shmtx_unlock(&ngx_accept_mutex);
}
if (delta) {ngx_event_expire_timers();
}/* 之后可以放心处理其它事件了 */
ngx_event_process_posted(cycle, &ngx_posted_events);

}
Worker进程工作原理

当一个worker进程在accept这个连接之后,就开始读取请求,解析请求,处理请求,产生数据后,再返回给客户端,最后才断开连接,这样一个完整的请求就是这样的了。我们可以看到,一个请求,完全由worker进程来处理,而且只在一个worker进程中处理。

采用这种方式的好处:

节省锁带来的开销。对于每个worker进程来说,独立的进程,不需要加锁,所以省掉了锁带来的开销,同时在编程以及问题查上时,也会方便很多
独立进程,减少风险。采用独立的进程,可以让互相之间不会影响,一个进程退出后,其它进程还在工作,服务不会中断,master进程则很快重新启动新的worker进程
在一次请求里无需进程切换
相关配置

user nobody nobody;
worker_processes 8;
worker_cpu_affinity 00000001 00000010 00000100 00001000 00010000 00100000 01000000 10000000;
worker_rlimit_nofile 65535;
error_log logs/error.log info;
事件模块

对于一个基本的 WEB 服务器来说,事件通常有三种类型,网络事件、信号和定时器。

一个请求的基本过程:建立连接 - 接受连接 - 发送数据,在系统底层就是读写事件。

Epoll 模型

Epoll出现在 linux2.6以后,Nginx采用 Epoll 这种异步非阻塞的事件处理机制。这种机制的原理就是把一个完整的请求,划分成多个事件,比如accept(), recv(),磁盘I/O,send(),每个事件都有不同的模块进行处理。一个请求由一个worker进程处理,在请求多的时候,无需频繁的切换进程。

事件模块 icon

图片来自网络

master进程先建好需要listen的socket后,然后再fork出多个woker进程,这样每个work进程都可以去accept这个socket
当一个client连接到来时,所有accept的work进程都会受到通知,但只有一个进程可以accept成功,其它的则会accept失败,Nginx提供了一把共享锁accept_mutex来保证同一时刻只有一个work进程在accept连接,从而解决惊群问题
当一个worker进程accept这个连接后,就开始读取请求,解析请求,处理请求,产生数据后,再返回给客户端,最后才断开连接,这样一个完成的请求就结束了
Epoll 是基于一个进程处理多个连接、非阻塞IO的策略,Nginx多使用这种策略。
Select 模型

Select 模型在启动的时候创建多个进程,放在一个进程池里,并且进程池里的进程数会随着请求数目的增加而增加,对于每一个连接,都是在一个进程内处理完毕。所以Select模型能接收的并发量受到所能开启的进程数影响,进程之间是互相阻塞的,且频繁的切换进程造成大量开销。

Select 是基于一个线程处理一个请求的非阻塞IO的策略,Apache使用这种策略。
相关配置

events {
use epoll;
worker_connections 1024;
}
网络模块

最大连接数

当作为http服务器的时候:

max_clients = worker_processes * worker_connections;
当作为反向代理的时候:

max_clients = worker_processes * worker_connections/4
负载均衡

nginx的upstream目前支持的5种方式的分配

轮询(默认)
每个请求按时间顺序逐一分配到不同的后端服务器,如果后端服务器down掉,能自动剔除。

upstream backserver {
server host:port;
server host:port;
}
weight
指定轮询几率,weight和访问比率成正比,用于后端服务器性能不均的情况

upstream backserver {
server host:port weight=10;
server host:port weight=10;
}
ip_hash
每个请求按访问ip的hash结果分配,这样每个访客固定访问一个后端服务器,可以解决session的问题

upstream backserver {
ip_hash;
server host:port;
server host:port;
}
fair(第三方)
按后端服务器的响应时间来分配请求,响应时间短的优先分配。

upstream backserver {
server server1;
server server2;
fair;
}
url_hash(第三方)
按访问url的hash结果来分配请求,使每个url定向到同一个后端服务器,后端服务器为缓存时比较有效

upstream backserver {
server squid1:3128;
server squid2:3128;
hash $request_uri;
hash_method crc32;
}
在需要使用负载均衡的server中增加

proxy_pass http://backserver/ ;
upstream backserver{
ip_hash;
server host:port down; (down 表示单前的server暂时不参与负载)
server host:port weight=2; (weight 默认为1.weight越大,负载的权重就越大)
server host:port
server host:port backup; (其它所有的非backup机器down或者忙的时候,请求backup机器)
}
代理缓存

代理缓冲区相关配置

proxy_buffer_size   128k;
proxy_buffers   4 256k;
proxy_busy_buffers_size   256k;# 通过令牌桶原理实现用户访问次数限制
limit_req_zone  $http_x_forwarded_for zone=req_one:10m rate=30r/s;#设置Web缓存区名称为cache_web,内存缓存空间大小为300MB,1天没有被访问的内容自动清除,硬盘缓存空间
#大小为3GB。
proxy_temp_path   /xxx/proxy_temp_dir 1 2;
proxy_cache_path  /xxx/proxy_cache_dir levels=1:2 keys_zone=cache_web:300m inactive=1d max_size=1g;

访问控制

location ~ /.ht {
deny all;
}
相关配置

一个http指令下可以配置多个server指令块,一个server指令块里可以根据不同的url做配置

http {
include /xxx/nginx/conf/mime.types;
default_type application/octet-stream;

log_format    main  '$remote_addr^A $remote_user^A [$time_local]^A $request^A ''$status^A $body_bytes_sent^A $http_referer^A ''$http_user_agent^A $http_x_forwarded_for^A ''$request_body^A $http_X_Cache^A $upstream_http_X_Cache^A ''$upstream_cache_status^A $http_x_accel_expires^A $dna_device';access_log    /xxx/nginx/logs/access.log  main;sendfile      on;
tcp_nopush    on;#server_names_hash_bucket_size 128;
#client_header_buffer_size 8k;
open_file_cache max=10240 inactive=20s;// max打开文件指定缓存数量,inactive指多长时间没请求就删除缓存
open_file_cache_valid 30s; // 30s检查一次缓存的有效信息
open_file_cache_min_uses 1;// 最少使用次数,如果超过这个数字,就一直在缓存中打开
keepalive_timeout  60;# 代理缓冲区相关配置
proxy_buffer_size   128k;
proxy_buffers   4 256k;
proxy_busy_buffers_size   256k;# 通过令牌桶原理实现用户访问次数限制
limit_req_zone  $http_x_forwarded_for zone=req_one:10m rate=30r/s;#设置Web缓存区名称为cache_web,内存缓存空间大小为300MB,1天没有被访问的内容自动清除,硬盘缓存空间
#大小为3GB。
proxy_temp_path   /xxx/proxy_temp_dir 1 2;
proxy_cache_path  /xxx/proxy_cache_dir levels=1:2 keys_zone=cache_web:300m inactive=1d max_size=1g;upstream www_backend_server {server   host:port;
}upstream m_backend_server {server   host:port;
}server {listen          80;server_name     www.xxx.com;access_log      logs/xxx.access.log main;location ~ \.php {fastcgi_pass 127.0.0.1:9000;fastcgi_index /index.php;include /xxx/nginx/conf/fastcgi_params;fastcgi_buffer_size 128k;fastcgi_buffers 4 256k;fastcgi_busy_buffers_size 256k;fastcgi_split_path_info       ^(.+\.php)(/.+)$;fastcgi_param PATH_INFO       $fastcgi_path_info;fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info;fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;}location ~ /\.ht {deny all;}
}server {listen          80;server_name     www.xxx.com;access_log      logs/xxx.access.log main;location / {index index.html;root  /xxx/htdocs;}
}

}
其他

启动流程

时间、正则、错误日志、ssl等初始化
读入命令行参数
OS相关初始化
读入并解析配置
核心模块初始化
创建各种暂时文件和目录
创建共享内存
打开listen的端口
所有模块初始化
启动worker进程
Nginx和PHP交互

通过fastcgi模块进行交互,交互模式有两种:

fastcgi_pass unix:/xxx/php/var/php-cgi.sock;

fastcgi_pass 127.0.0.1:9000;
Mail配置

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;
}

}
下期预告: Nginx 之扩展模块的开发

Nginx 之实现原理相关推荐

  1. nginx反向代理原理讲解

    一 .概述                  反向代理(Reverse Proxy)方式是指以代理服务器来接受Internet上的连接请求,然后将请求转发给内部网络上的服务器:并将从服务器上得到的结果 ...

  2. nginx部分实现原理解析

    nginx底层实现有几个主要的模块: 进程模块 事件模块 网络模块 进程模块 默认采用守护模式启动,守护模式让master进程启动后在后台运行,不在窗口上卡住. Nginx 启动后会有一个 Maste ...

  3. c/s架构nginx+php-fpm通信原理

        FastCGI是一个运用于Http Server和动态脚本语言间通信的接口,多数流行的Http Server都支持FastCGI,包括Apache.Nginx和lighttpd等.同时,Fas ...

  4. nginx的工作原理与nginx的配置

    1.nginx的工作原理 nginx的模块直接被编译进nginx,因此属于静态编译方式. 启动nginx后,nginx的模块被自动加载,与Apache不一样,首先将模块编译为一个so文件,然后在配置文 ...

  5. 详解Nginx的核心原理

    Nginx的核心原理 本节为大家介绍Nginx的核心原理,包含Reactor模型.Nginx的模块化设计.Nginx的请求处理阶段. 虽然本节的知识有一定的理论深度,但是与另一个有名的Java底层通信 ...

  6. 【云计算基础服务-Nginx WEB服务器---原理及简介详解】

    文章目录 前言: 一.云计算基础服务-Nginx WEB服务器 详解 1.Nginx简介及原理 1.1 Nginx web简介 1.2 Nginx工作原理 前言: 本专栏专门讲解云计算服务基础知识,适 ...

  7. 万字多图,搞懂 Nginx 高性能网络工作原理!

    在单进程的网络编程模型中.所有的网络相关的动作都是在一个进程里完成的,如监听 socket 的创建, bind.listen.再比如 epoll 的创建.要监听事件的添加,以及 epoll_wait ...

  8. Nginx介绍和原理

    文章目录 nginx介绍 nginx的特性 nginx的优点 nginx的基本功能 nginx的应用类别 nginx模块分类 nginx的工作原理 nginx介绍 nginx是一款轻量级的Web服务器 ...

  9. Nginx架构篇(一)动态网站架构、LNMP、FastCGI、nginx+fastcgi运行原理

    一.动态网站架构 资源文件识别 语言识别 框架识别 index.php 开源的php Window/Linux+nginx+php+mysql index.py 开源的python Window/Li ...

  10. 阿里限流神器Sentinel夺命连环 17 问?,nginx请求转发原理

    阿里限流神器Sentinel夺命连环 17 问?,nginx请求转发原理 前沿技术精品 2021-11-17 10:43:04 阅读数:77 评论数:0 点赞数:0 收藏数:0 标签:Sentinel ...

最新文章

  1. 计算机组成原理两数相加指令,计算机组成原理复习题
  2. javaMail发邮件
  3. RPM安装rabbitMQ
  4. 神策数据张涛:如何让用户标签价值落地?
  5. tensorflow 按维度相加_人工智能 TensorFlow 必知必会编程概念整理
  6. JavaScript回调函数(callback)概念和应用,千万别错过!
  7. 怎么计算末年某月某天有几个星期天公司
  8. 第二篇:Spring Boot 热部署
  9. Linux(五):Ubuntu 16.04 更改系统语言为简体中文(Chinese simplified)
  10. python中的dict是什么数据类型_Python基本数据类型之dict
  11. Starting Programe
  12. 读者提问:如何提高效率?
  13. 文件夹访问被拒绝 你需要权限来执行此操作,你需要来自SYSTEM的权限才能对此文件夹进行更改
  14. 青柠起始页-浏览器起始页(一个简洁、美观、实用的浏览器起始页。)
  15. Java中关于子类重写父类方法的坑
  16. 创建线程以及怎样创建有返回值的线程
  17. 凸优化“傻瓜”教程-----凸优化基础知识
  18. 从提示框:适用于Windows的iPad接口仿真,Easy Access iPhone手电筒和Kindle收藏管理...
  19. Git fatal unable to auto-detect email address
  20. 2019年山东事业单位面试真题

热门文章

  1. 鸿蒙系统内核为什么还是安卓,鸿蒙系统和安卓的区别
  2. 【云扩RPA】Timing
  3. IDEA 中 使用 git 进行上传和下载项目
  4. 你所需要的java基础提升篇大总结
  5. Harbor镜像库搭建以及如何在idea上构建镜像并推送Harbor
  6. 【LeetCode-中等】55. 跳跃游戏(详解)
  7. 获取buff市场的价格
  8. WerFault.exe 占用CPU 100%的问题处理
  9. html飘窗效果,js实现网页飘窗效果-Javascript-舒彬琪博客|前端技术博客|CMS教程|PbootCMS|JizhiCMS-www.cnsbq.com...
  10. 软件性能测试场景设计,性能测试场景设计杂谈