Nginx核心知识100讲学习笔记(陶辉)Nginx架构基础(二)
一、网络收发与Nginx事件间的对应关系
1、网络传输
2、TCP流与报文
3、TCP协议与非阻塞接口
二、Nginx网络事件实例演示
1、TCP层:本地打开了53842,Nginx打开的是8080端口 进程与进程通信这件事情
2、IP层:本机IP地址:192.168.0.109 nginx服务器的IP地址:192.168.0.123(机器和机器之前怎么互相找到的问题)
3、三次握手
- windows先向nginx发送一个SYN
- 相反的nginx所在的linux也会向windos发送一个SYN,这个时候nginx是没有感知到的、因为这是一个半打开的状态
- 直到widows再向nginx所在的linux服务器发送一个ACK时,linux操作系统才会通知nginx这时有一个读事件需要处理
三、 Nginx的事件驱动模型
1、Nginx的事件驱动模型
知道Nginx事件循环有什么好处?
- 第三方模块做大量的CPU计算,导致我处理一个事件会特别长,会导致后续队列中的大量事件长事件得不到处理
- 所以nginx无法容忍第三方模块长时间使用CPU执行计算任务
- 我们看到gzip模块不是一次计算而是分段计算
四、epoll的优劣和原理
1、epoll的优劣
2、epoll的原理
3、场景描述:
有100万用户同时与一个进程保持着TCP连接,而每一时刻只有几十个或几百个TCP连接是活跃的(接收到TCP包),
也就是说,在每一时刻,进程只需要处理这100万连接中的一小部分连接。那么,如何才能高效地处理这种场景呢?
进程是否在每次询问操作系统收集有事件发生的TCP连接时,把这100万个连接告诉操作系统,然后由操作系统找出其中有事件发生的几百个连接呢?
4、select和poll如何处理:
每次收集事件时,都把这100万连接的套接字传给操作系统(这首先就是用户态内存到内核态内存的大量复制),而由操作系统内核寻找这些连接上有没有未处理的事件,将会是巨大的资源浪费
这里有个非常明显的问题,即在某一时刻,进程收集有事件的连接时,其实这100万连接中的大部分都是没有事件发生的。
5、epoll如何处理
它在Linux内核中申请了一个简易的文件系统,把原先的一个select或者poll调用分成了3个部分:
- 调用epoll_create建立1个epoll对象(在epoll文件系统中给这个句柄分配资源)
- 调用epoll_ctl向epoll对象中添加这100万个连接的套接字
- 调用epoll_wait收集发生事件的连接。
这样,只需要在进程启动时建立1个epoll对象,并在需要的时候向它添加或删除连接就可以了
因此,在实际收集事件时,epoll_wait的效率就会非常高,因为调用epoll_wait时并没有向它传递这100万个连接,内核也不需要去遍历全部的连接。
6、这是如何实现的
维护了一个epitem的数据结构,他通过两种数据结构把这两件事件分开实现
也就是Nginx每次取活跃连接的时候,我们只需要去遍历一个链表,这个链表里仅仅只有活跃的的连接、这样我们速度效率就会很高
1、创建:Nginx收到80端口建立连接的请求,请求连接成功以后,这时候我要添加一个读事件,这个读事件是用来读取http消息的,这个时候我可能会添加一个新的事件、或者是写事件
这个添加我只会放到红黑树中,二叉平衡树能保证我的插入效率是logn的复杂度
2、添加:当操作系统接收到网卡中发送来一个报文的时候,这个链表就会增加一个链接
3、修改:读取一个事件的时候链表自然就没了
4、删除:如果我我不想再处理读事件和写事件,我只要从这个平衡二叉树移除一个节点
5、获取句柄:就是遍历活跃链接的链表,从内核态读取到用户态
五、Nginx的请求切换、同步&异步、阻塞&非阻塞之间的区别
1、Nginx的请求切换
每做一次切换大概需要5微妙,虽然很小,当并发量很大时切换需要的时间是指数级的增加
而Nginx直接在用户态进行切换、操作系统给了nginx足够处理请求的时间
2、阻塞调用
3、非阻塞调用
4、非阻塞调用下的同步与异步
反向代理的有一个特点:去考虑上游的服务处理请求是不足的,所以如果是一个有body的http请求,先把body接收完、再向上游发起连接
六、 Nginx的模块究竟是什么?
1、前提
1、提供了那些配置项:gzip模块官网查询
http://nginx.org/en/docs/http/ngx_http_gzip_module.html
2、我如何确定某个模块编译到nginx中呢?
有一个数组叫ngx_module_t *ngx_modules[]这个数组包含了编译进了nginx的模块,我们找一gzip摸快
[root@nginx objs]# pwd /usr/local/src/nginx-1.14.2/objs [root@nginx objs]# cat ngx_modules.c #include <ngx_config.h> #include <ngx_core.h> extern ngx_module_t ngx_core_module; ...... extern ngx_module_t ngx_http_not_modified_filter_module; ngx_module_t *ngx_modules[] = { &ngx_core_module, ...... &ngx_http_gzip_filter_module, ...... &ngx_http_not_modified_filter_module, NULL }; char *ngx_module_names[] = { "ngx_core_module", ...... "ngx_http_not_modified_filter_module", NULL };
3、如何确定支持那些指令?
ngx_command_t 这个结构体是一个数组、数组中的每一个成员是他所支持的指令名
[root@luoahong modules]# pwd /usr/local/src/openresty-1.13.6.2/bundle/nginx-1.13.6/src/http/modules [root@luoahong modules]# cat -n ngx_http_gzip_filter_module.c ...... static ngx_command_t ngx_http_gzip_filter_commands[] = { { ngx_string("gzip"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF |NGX_CONF_FLAG, ngx_conf_set_flag_slot, NGX_HTTP_LOC_CONF_OFFSET, offsetof(ngx_http_gzip_conf_t, enable), NULL }, { ngx_string("gzip_buffers"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2, ngx_conf_set_bufs_slot, NGX_HTTP_LOC_CONF_OFFSET, offsetof(ngx_http_gzip_conf_t, bufs), NULL }, { ngx_string("gzip_types"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE, ngx_http_types_slot, NGX_HTTP_LOC_CONF_OFFSET, offsetof(ngx_http_gzip_conf_t, types_keys), &ngx_http_html_default_types[0] }, { ngx_string("gzip_comp_level"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, ngx_conf_set_num_slot, NGX_HTTP_LOC_CONF_OFFSET, offsetof(ngx_http_gzip_conf_t, level), &ngx_http_gzip_comp_level_bounds }, { ngx_string("gzip_window"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, ngx_conf_set_size_slot, NGX_HTTP_LOC_CONF_OFFSET, offsetof(ngx_http_gzip_conf_t, wbits), &ngx_http_gzip_window_p }, { ngx_string("gzip_hash"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, ngx_conf_set_size_slot, NGX_HTTP_LOC_CONF_OFFSET, offsetof(ngx_http_gzip_conf_t, memlevel), &ngx_http_gzip_hash_p }, { ngx_string("postpone_gzipping"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, ngx_conf_set_size_slot, NGX_HTTP_LOC_CONF_OFFSET, offsetof(ngx_http_gzip_conf_t, postpone_gzipping), NULL }, { ngx_string("gzip_no_buffer"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, ngx_conf_set_flag_slot, NGX_HTTP_LOC_CONF_OFFSET, offsetof(ngx_http_gzip_conf_t, no_buffer), NULL }, { ngx_string("gzip_min_length"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, ngx_conf_set_size_slot, NGX_HTTP_LOC_CONF_OFFSET, offsetof(ngx_http_gzip_conf_t, min_length), NULL }, ngx_null_command }; ......