一、Nginx如何通过连接池处理网络请求

 1、连接池

Nginx核心知识100讲学习笔记(陶辉)Nginx架构基础(三)-冯金伟博客园

 

1、预分配的connections_n 个链接

http://nginx.org/en/docs/ngx_core_module.html#worker_connections

Syntax:	worker_connections number;
Default:	
worker_connections 512;
Context:	events

1、设置的越大,占用的内存越多
2、每一个connections到底是用了多大的内存呢?
64位操作系统中:大小232字节事件大小为96 一个连接就是328

2、仅当在一次read中,没有收到请求头,才会算成超时。

http://nginx.org/en/docs/http/ngx_http_core_module.html#client_header_timeout

Syntax:	client_header_timeout time;
Default:	
client_header_timeout 60s;
Context:	http, server

定义用于读取客户端请求体的超时时间。超时仅设置在两个连续读取操作之间的时间段内,而不是用于整个请求体的传输。如果客户端在此时间内不发送任何内容,则请求终止(408)(请求超时)错误。

3、nginx返回给客户端的字节数,包括响应头和响应体

http://nginx.org/en/docs/http/ngx_http_core_module.html#variables
$bytes_sent
number of bytes sent to a client (1.3.8, 1.2.5)

NGIXN日志中的使用

log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status [$request_length:$bytes_sent] "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';

访问日志

192.168.0.109 - - [01/Mar/2020:17:57:58 +0800] "GET /plus.gif HTTP/1.1" 304 [435:179] "http://192.168.0.123:8080/" "Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/82.0.4068.5 Safari/537.36" "-

重点看:[435:179]

2、核心数据结构

Nginx核心知识100讲学习笔记(陶辉)Nginx架构基础(三)-冯金伟博客园

二、内存池对性能的影响

 Nginx核心知识100讲学习笔记(陶辉)Nginx架构基础(三)-冯金伟博客园

1、允许精确调整每个连接内存分配connection_pool_size size

http://nginx.org/en/docs/http/ngx_http_core_module.html#connection_pool_size

Syntax:	connection_pool_size size;
Default:	
connection_pool_size 256|512; 
Context:	http, server

还可以分配更大的 、可以减少分配的次数

2、request_pool_size size

http://nginx.org/en/docs/http/ngx_http_core_module.html#request_pool_size

Syntax:	request_pool_size size;
Default:	
request_pool_size 4k; $
Context:	http, server

为什么这么小?对于连接而言需要的上下文信息特别少

三、所有worker进程协同工作的关键:共享内存

1、Nginx进程间的通讯方式

Nginx核心知识100讲学习笔记(陶辉)Nginx架构基础(三)-冯金伟博客园

2、自旋锁

当锁的条件没有满足:也就是这把锁被1号work进程正在使用、那么2号进程去请求锁只要1号进程没有释放、那么2号会一直不停的请求这把锁

假入一把锁锁住了一扇门、如果work1号进程已经拿到这把锁、那么work2号去敲门发现里面已经有人了、就会就地休息、等待1号进程出来以后通知她、而自旋锁就不一样work2进程发现门里有人会持续的敲门

3、共享内存:nginx那些模块使用到了共享内存:单链表

1、为什么需要一个链表?

因为这个10M是有限的、但我们的lua代码涉及到了应用代码、我们的应用代码很容易超过10M的限制
当超过了10M的限制、他用LRU淘汰、最早set或get不同的节点会被淘汰掉

2、单链表模块

Ngx_http_upstream_zone_module
Ngx_stream_upstream_zone_module

4、nginx那些模块使用到了共享内存:红黑树

比如我们想做限速、流控不能容忍在内存中做的、否则一个work进程对于某一个用户触发了一个流控、而其他的work进程确不知道、所以我们只能在共享内存中做的

Ngx_stream_limit_conn_module
Ngx_http_limit_conn_module
Ngx_stream_limit_req_module

			Ngx_http_file_cache
			Ngx_http_proxy_module
http cache              Ngx_http_scgi_module
			Ngx_http_uwsgi_module
			Ngx_http_fastcgi_module

			Ngx_http_ssl_modul
ssl			Ngx_mail_ssl_module
			Ngx_stream_ssl_module

这些模块都有一个共同的特点:我需要快速的插入和删除
比如我现在发现了一个客户端、需要对他限速、如果限速达到了、我要把这个客户端从我的限速容器中移出、都需要非常的快速

3、Ngx_http_lua_api :OpenResty共享内存代码示例

定义了一个sdk sdk的名称叫做lua_shared_dict

当这个指令出现的时候它会分配一块共享内存大小为:10M 这块共享名称叫做dogs

Nginx核心知识100讲学习笔记(陶辉)Nginx架构基础(三)-冯金伟博客园

使用红黑树来保存每一个key value

四、 用好共享内存的工具:Slab管理器

1、Slab内存管理

1、这样的数据结构会有内存的浪费、那么最多会浪费多少了?

最多两倍内存消耗

2、应用场景:适合小对象

因为我们要分配的内存特别小、比如分配小于一个页面的大小、因为它很少会有碎片 有时候我分配的内存数据机构是固定大小的甚至需要初始化、那么原来的数据结构都还在、这样就避免了重复初始化

2、ngx_slab_stat模块安装

1、下载

wget http://tengine.taobao.org/download/tengine-2.3.2.tar.gz
tar xf tengine-2.3.2.tar.gz 
[root@ceph-client ngx_slab_stat]# pwd
/usr/local/src/tengine-2.3.2/modules/ngx_slab_stat
[root@ceph-client ngx_slab_stat]# ll
total 44
-rw-rw-r--. 1 root root   204 Sep  5  2019 config
-rw-rw-r--. 1 root root  6627 Sep  5  2019 ngx_http_slab_stat_module.c
-rw-rw-r--. 1 root root  3465 Sep  5  2019 README.cn
-rw-rw-r--. 1 root root  3501 Sep  5  2019 README.md
-rw-rw-r--. 1 root root 21430 Sep  5  2019 slab_stat.patch
drwxrwxr-x. 2 root root    20 Sep  5  2019 t

2、编译安装

[root@ceph-client openresty-1.13.6.2]# pwd
/usr/local/src/openresty-1.13.6.2
[root@ceph-client openresty-1.13.6.2]#./configure --add-module=../tengine-2.3.2/modules/ngx_slab_stat/
[root@ceph-client openresty-1.13.6.2]#make
[root@ceph-client openresty-1.13.6.2]#make install

3、替换nginx二进制文件 ,当前nginx文件最好备份下,避免出问题

[root@ceph-client conf]# nginx -s reload  
[root@ceph-client conf]# netstat -lntup|grep 80
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      22522/nginx: master
[root@ceph-client]#cp /usr/local/openresty/nginx/sbin/nginx  /usr/local/bin/nginx
[root@ceph-client bin]# ll /usr/local/bin/
total 15464
lrwxrwxrwx. 1 root root       37 Mar  4 09:57 nginx -> /usr/local/openresty/nginx/sbin/nginx
-rwxr-xr-x. 1 root root 15832600 Aug 19 11:11 nginx_no_slab_stat
/usr/local/openresty/nginx/sbin/nginx

4、验证是否安装成功

[root@ceph-client ~]# nginx -V
nginx version: openresty/1.13.6.2
built by gcc 4.8.5 20150623 (Red Hat 4.8.5-39) (GCC) 
built with OpenSSL 1.0.2k-fips  26 Jan 2017
TLS SNI support enabled
configure arguments: --prefix=/usr/local/openresty/nginx --with-cc-opt=-O2 
--add-module=../ngx_devel_kit-0.3.0 
..... 
--add-module=/usr/local/src/openresty-1.13.6.2/../tengine-2.3.2/modules/ngx_slab_stat 
--with-stream 
--with-stream_ssl_module 
--with-http_ssl_module

3、统计Slab使用状态

nginx配置文件

[root@ceph-client ~]# grep -vE "#|^$" /usr/local/openresty/nginx/conf/nginx.conf
worker_processes  2;
events {
    worker_connections  1024;
}
http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;
    lua_shared_dict dogs 10m;
    server {
        listen       80;
        server_name  localhost;
        location = /slab_stat {
        slab_stat;
    }
        
      location = /set {
          content_by_lua_block{
              local dogs = ngx.shared.dogs
          dogs:set("JIM",8)
          ngx.say("STORED")
           }
           }
        
        
       location = /get {
           content_by_lua_block{
               local dogs = ngx.shared.dogs
           ngx.say(dogs:get("JIM"))
        }
        }
        
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }
}

5、查看服务状态

[root@ceph-client ~]# curl localhost:80/set
STORED
[root@ceph-client ~]# curl localhost:80/get
8
[root@ceph-client conf]# curl http://localhost:80/slab_stat
* shared memory: dogs
total:       10240(KB) free:       10168(KB) size:           4(KB)
pages:       10168(KB) start:00007F2DE5FFC000 end:00007F2DE69EC000
slot:           8(Bytes) total:           0 used:           0 reqs:           0 fails:           0
slot:          16(Bytes) total:           0 used:           0 reqs:           0 fails:           0
slot:          32(Bytes) total:         127 used:           1 reqs:           1 fails:           0
slot:          64(Bytes) total:           0 used:           0 reqs:           0 fails:           0
slot:         128(Bytes) total:          32 used:           1 reqs:           1 fails:           0
slot:         256(Bytes) total:           0 used:           0 reqs:           0 fails:           0
slot:         512(Bytes) total:           0 used:           0 reqs:           0 fails:           0
slot:        1024(Bytes) total:           0 used:           0 reqs:           0 fails:           0
slot:        2048(Bytes) total:           0 used:           0 reqs:           0 fails:           

五、 哈希表的max_size与bucket_size如何配置

1、Nginx容器

Nginx核心知识100讲学习笔记(陶辉)Nginx架构基础(三)-冯金伟博客园

2、Nginx哈希表

1、nginx的哈希表和我们正常见得到hash表有什么不同?

从实现层面看:是相似的、哪里不同?应用场景不同:

仅仅应用于静态不变的内容、也就是在运行过程中这个hash表通常不会存在插入和删除的操作也就是说刚启动的时候已经确定hash表中一共有多少元素

Nginx核心知识100讲学习笔记(陶辉)Nginx架构基础(三)-冯金伟博客园

3、哈希表配置

1、Max size的作用

Max size是最大的Bucket size、而不是实际上使用的的多少、Max size的作用限制了最大化的使用我们的内存

2、我们的哈希表为什么要向64节对齐了?

如果一个Bucket是59字节、如果是紧密排列在一起的、这样你取第一个字节取了两个元素、然后第二个元素就要取两次、为了这种取两次的的问题nginx在它的代码中自动的向上对齐了

3、配置Bucket size需要注意两个问题

所以我们在配置Bucket size需要注意两个问题

如果没有特殊需求建议配置不要超过64字节、避免一个元素取两次
如果你配置70字节、它就会给我们分配128字节

4、所有使用hash表的结构的模块都有哪些特点了?

他们对所有的变量使用了hash表

Nginx核心知识100讲学习笔记(陶辉)Nginx架构基础(三)-冯金伟博客园