震撼!全网第一张源码分析全景图揭秘Nginx
不管是C/C++技术栈,还是PHP,Java技术栈,从事后端开发的朋友对nginx一定不会陌生。
想要深入学习nginx,阅读源码一定是非常重要的一环,但nginx源码量毕竟还是不算少,一不小心就容易陷入某个细节,迷失在茫茫码海之中。
如果有一张地图,让我们开启上帝视角,总览全局,帮助我们快速学习整体框架结构,又能不至于迷失其中那就再好不过了!
看到这篇文章的你有福了,笔者花了不少时间,把这件事给做了,先来看个全貌(限于平台图片尺寸设定,这里只能看个大概,想获取高清大图请看文末):
下面选取一些关键部分来一窥神秘的nginx。
主进程启动
nginx主进程启动后,进行一系列的初始化,包括但不限于:
- 命令行参数解析
- 时间初始化
- 日志初始化
- ssl初始化
- 操作系统相关初始化
- 一致性hash表初始化
- 模块编号处理
核心初始化
另外一个最重要的初始化由ngx_init_cycle()
函数完成,该函数围绕nginx中非常核心的一个全局数据结构ngx_cycle_t
展开。
该函数完成了几个核心初始化:
- 配置文件解析
- 创建并监听socket
- 初始化nginx各模块
nginx核心模块群
nginx是一个模块化设计的软件,优秀的架构设计使得nginx可以扩展非常多的模块。
要一一描绘出这些模块显得有些杂乱和工作量巨大,仅选取一些关键核心模块进行了展示:
每个模块有一个支持的命令解析列表,在初始化过程中,主进程将会遍历所有模块的命令列表,进行配置文件中的命令解析,如经常用的ngx_http_proxy_module
:
ngx_http_core_module
模块:
main函数的最后,根据是否启用多进程模型,分别进入多进程版本的ngx_master_process_cycle
和单进程版本的ngx_single_process_cycle()
。
以常见的多进程版本为例,进入该函数后,首先设置进程名称为:"master process",随后启动各工作子进程。
启动子进程
经过几层封装,最终通过fork
启动多个子进程:
除了工作子进程,还启动了缓存管理进程。
之后主进程进入工作循环,周期性更新时间并检查各全局标记,根据不同情况给子进程发送不同信号。
子进程工作循环
子进程启动后,进入ngx_worker_process_cycle
,进行一些工作进程的初始化,随后修改进程名称为:"worker process"。
接着进入工作循环函数ngx_process_events_and_timers
,在该函数中主要负责:
- 竞争互斥锁,拿到锁的进程才能执行accept接受新的连接,以此在多进程之间解决惊群效应
- 通过epoll异步IO模型处理网络IO事件,包括新的连接事件和已建立连接发生的读写事件
- 处理定时器队列中到期的定时器事件,定时器通过红黑树的方式存储
HTTP请求预处理
当连接有数据产生时,工作线程读取socket中到来的数据,并根据HTTP协议格式进行解析,最终封装成ngx_request_t请求对象,提交处理。
HTTP请求处理的11个阶段
在nginx中各HTTP模块是以挂载的形式串接而成,以流水线工作模式进行HTTP请求的处理,nginx将一个HTTP请求的处理划分为11个阶段。
typedef enum {
NGX_HTTP_POST_READ_PHASE = 0,
NGX_HTTP_SERVER_REWRITE_PHASE,
NGX_HTTP_FIND_CONFIG_PHASE,
NGX_HTTP_REWRITE_PHASE,
NGX_HTTP_POST_REWRITE_PHASE,
NGX_HTTP_PREACCESS_PHASE,
NGX_HTTP_ACCESS_PHASE,
NGX_HTTP_POST_ACCESS_PHASE,
NGX_HTTP_PRECONTENT_PHASE,
NGX_HTTP_CONTENT_PHASE,
NGX_HTTP_LOG_PHASE
} ngx_http_phases;
每阶段(部分阶段保留,不允许挂载)允许多个模块挂载,一个模块也可以挂载到多个阶段。因此,初次完成挂载的存储结构是一个二维数组的形式。
不过在初始化过程中,ngx_http_init_phase_handlers
函数将该二维数组转换成了一维数组。下图是nginx中各模块挂载情况:
全景图
最后,再来看一看全貌:
总结
nginx不仅是一款优秀的高性能web服务器,对于C/C++技术栈的同学来说,还是一个很好的学习对象,其良好的架构设计,优美的代码风格和经典的编程技法无一不值得细细品来。
不过限于笔者水平和时间有限,虽然号称全景图,但依然无法覆盖到nginx的方方面面,欢迎读者朋友留言交流,让此图日渐完善,谢谢大家。
获取完整高清大图,可在公众号里回复“nginx”自动获取。
往期热门回顾
Python一键转Jar包,Java调用Python新姿势!
扫码关注,更多精彩
震撼!全网第一张源码分析全景图揭秘Nginx的更多相关文章
- Django搭建及源码分析(三)---+uWSGI+nginx
每个框架或者应用都是为了解决某些问题才出现旦生的,没有一个事物是可以解决所有问题的.如果觉得某个框架或者应用使用很不方便,那么很有可能就是你没有将其使用到正确的地方,没有按开发者的设计初衷来使用它,当 ...
- 4.Sentinel源码分析— Sentinel是如何做到降级的?
各位中秋节快乐啊,我觉得在这个月圆之夜有必要写一篇源码解析,以表示我内心的高兴~ Sentinel源码解析系列: 1.Sentinel源码分析-FlowRuleManager加载规则做了什么? 2. ...
- 鸿蒙内核源码分析(内存管理篇) | 虚拟内存全景图是怎样的 | 百篇博客分析OpenHarmony源码 | v12.04
百篇博客系列篇.本篇为: v12.xx 鸿蒙内核源码分析(内存管理篇) | 虚拟内存全景图是怎样的 | 51.c.h .o 内存管理相关篇为: v11.xx 鸿蒙内核源码分析(内存分配篇) | 内存有 ...
- 《深入理解Spark-核心思想与源码分析》(一)总体规划和第一章环境准备
<深入理解Spark 核心思想与源码分析> 耿嘉安著 本书共计486页,计划每天读书20页,计划25天完成. 2018-12-20 1-20页 凡事豫则立,不豫则废:言前定,则不跲:事 ...
- Mybaits 源码解析 (九)----- 全网最详细,没有之一:一级缓存和二级缓存源码分析
像Mybatis.Hibernate这样的ORM框架,封装了JDBC的大部分操作,极大的简化了我们对数据库的操作. 在实际项目中,我们发现在一个事务中查询同样的语句两次的时候,第二次没有进行数据库查询 ...
- 第一篇:Spark SQL源码分析之核心流程
/** Spark SQL源码分析系列文章*/ 自从去年Spark Submit 2013 Michael Armbrust分享了他的Catalyst,到至今1年多了,Spark SQL的贡献者从几人 ...
- Nginx源码分析:3张图看懂启动及进程工作原理
编者按:高可用架构分享及传播在架构领域具有典型意义的文章,本文由陈科在高可用架构群分享.转载请注明来自高可用架构公众号「ArchNotes」. 导读:很多工程师及架构师都希望了解及掌握高性能服务器 ...
- 阅读《RobHess的SIFT源码分析:综述》笔记
今天总算是机缘巧合的找到了照样一篇纲要性质的文章. 如是能早一些找到就好了.不过“在你认为为时已晚的时候,其实还为时未晚”倒是也能聊以自慰,不过不能经常这样迷惑自己,毕竟我需要开始跑了! 就照着这个大 ...
- 鸿蒙内核源码分析(内存规则篇) | 内存管理到底在管什么 | 百篇博客分析OpenHarmony源码 | v16.02
百篇博客系列篇.本篇为: v16.xx 鸿蒙内核源码分析(内存规则篇) | 内存管理到底在管什么 | 51.c.h .o 内存管理相关篇为: v11.xx 鸿蒙内核源码分析(内存分配篇) | 内存有哪 ...
随机推荐
- $api 回调函数then应用
getReceiveListAPI (param) { return new Promise(resolve => { let params = { // idCard: this.idCard ...
- Android网络开发
1. WebView用法 ①布局文件新建一个WebView,特别注意线性布局和控件的宽高都要匹配父控件 <LinearLayout xmlns:android="http://sche ...
- 集群搭建_02_集群多机版安装 HDFS HA+Federation-YARN
1.配置hosts 至少四个节点(机器) 每个节点的hosts文件都要配置这些 10.10.64.226 SY-0217 10.10.64.234 SY-0225 10.10.64.235 SY-02 ...
- Natas34 Writeup(闯关结束!)
Natas34: 登录什么都不用做,闯关结束!撒花~~~
- hbase 面试问题汇总
一.Hbase的六大特点: (1).表大:一个表可以有数亿行,上百万列. (2).无模式:每行都有一个可排序的主键和任意多的列,列可以根据需要动态增加,同一个表中的不同行的可以有截然不同的列. (3) ...
- spring容器概述
这篇博客写一下对spring和springmvc父子容器的理解. 一.首先明确: (1)spring是一个大的父容器,springmvc是其中的一个子容器.父容器不能访问子容器对象,但是子容器可以访问 ...
- 第十七周Java实验作业
实验十七 线程同步控制 实验时间 2018-12-10 1.实验目的与要求 (1) 掌握线程同步的概念及实现技术: 多线程并发运行不确定性问题解决方案:引入线程同步机制,使得另一线程使用该方法,就只 ...
- 参加Folding@Home(FAH)项目,为战胜新冠肺炎贡献出自己的一份力量
鉴于新冠病毒(COVID-19)在全球范围内的大规模传播,PCMR和NVIDIA呼吁全球PC用户加入Folding@home项目贡献自己闲置的GPU计算力,协助抗击新冠状病毒疫情. 目前全球有超过40 ...
- 初识js(第一篇)
初识javascript js是前端中作交互控制的语言,有了它,我们的前端页面才能"活"起来.学好这么语言显得非常重要,但是存在一定难度,所以一定要认真学习,充满耐心. js书写规 ...
- Make编译Ardupilot源码的两种方法
编译环境准备 Ardupilot源码下载和PX4 toolchain工具链下载 (见https://www.cnblogs.com/BlogsOfLei/p/7707485.html) 注 ...