首页 » SEO优化 » mephp_rdr技巧_大年夜多半轨范员接触过的技能_负载均衡但大年夜多半都不知其核心事理

mephp_rdr技巧_大年夜多半轨范员接触过的技能_负载均衡但大年夜多半都不知其核心事理

访客 2024-12-13 0

扫一扫用手机浏览

文章目录 [+]

/Nginx二进制可实行文件由各模块源码编译出的一个文件Nginx配置文件掌握Nginx的行为Access.log访问日志记录每一条http要求信息Error.log缺点日志定位问题/

Nginx进程构造

/有两种进程构造,一种是单进程的,一样平常测试,调试,开拓用,生产环境一样平常都是多进程,由于生产环境要担保Nginx足够健壮,发挥多核特性,一样平常默认是是多进程.他的进程架构一样平常是有一个父进程, 叫Master进程,他有很多子进程,分为两类,一个是Work进程,一个是Cache进程.nginx做他的进程设计也是考虑到高可用高可靠,让第三方模块不会在master加入功能设计,虽然nginx许可第三方模块,但一样平常不会这样做,master一样平常做worker进程管理,所有的worker进程是处理真正要求的,master是监控worker是不是在事情,热支配,重新载入配置文件,缓存便是在多个worker共享,还要在CacheManager,CacheLoader共享,为后端代理动态要求缓存利用的,CacheLoaer做缓存载入,缓存管理进程间通信是通过共享内存办理的/

nginx之以是用多进程不用单进程由于:

mephp_rdr技巧_大年夜多半轨范员接触过的技能_负载均衡但大年夜多半都不知其核心事理

要担保高可靠性,高可用性,当nginx启用了多线程时候,由于线程之间是共享一个内存地址空间的,以是当某一个第三方模块引发一个地址空间导致的段缺点,在地址越界缺点时,全体nginx会挂掉,多进程则不会.

mephp_rdr技巧_大年夜多半轨范员接触过的技能_负载均衡但大年夜多半都不知其核心事理
(图片来自网络侵删)

Nginx要求处理流程

/ 从Nginx内部看,有Web,EMAIL,TCP流量,分别有三种状态机,传输层状态机,HTTP状态机,MAIL状态机,之以是叫状态机是由于他利用的非壅塞事宜驱动处理,epoll,一样平常利用异步处理引擎要利用状态性能力将要求精确识别和处理,以是我们在解析要求的时候分别走须要访问静态资源他就会找到静态资源,但会涌现当内存不敷以完备缓存所有文件信息,sedfile,io会退化成壅塞的IO操作,以是这里会有一个线程池处理,反向代理就会做磁盘缓存,要求完成会将日志记录在access,error,也可以远程到其他做事器.更多的时候,Nginx作为反向代理,负载均衡的,通过协议级传输到后面做事器,也可以通过运用层,fastcgi,uwsgi代理到运用做事器./

旗子暗记管理Nginx的父子进程

/Master进程监控worker进程CHLD管理worker进程接管旗子暗记TERM,INT 急速停滞NginxQUIT 优雅停滞Nginx,但是不要对用户发送急速结束连接向TCP reset的报文HUP 重载配置文件USR1 重新打开日志文件USR2 这两个旗子暗记须要kill找到master的pid才能发送,上面可以直接nginx 发送旗子暗记WINCHWorker进程接管旗子暗记TERM,INTQUITUSR1WINCHnginx命令行reload: HUPreopen: USR1stop: TERMquit: QUIT/Nginx reload的事理

/1. 向master进程发送HUP旗子暗记(reload命令)2. master进程考验配置与法是否精确.3. master进程打开新的监听端口.4. master进程用新配置启动新的worker子进程.5. master进程向老worker子进程发送QUIT旗子暗记.6. 老worker进程关闭监听句柄,处理完当前连接后结束进程./Nginx热升级流程

/1. 将旧Nginx文件换成新Nginx文件(把稳备份)2. 向master进程发送USR2旗子暗记3. master进程修正pid文件名,加后缀.oldbin4. master进程用新Nginx文件启动新Master进程5. 向老master进程发送WINCH旗子暗记,关闭老worker6. 回滚: 向老master发送HUP,向新master发送QUIT/

一直机载入新配置文件

worker进程优雅的关闭

/1. 设置定时器: worker_shutdown_timeout2. 关闭监听句柄3. 关闭空闲连接4. 在循环中等待全部连接关闭5. 退出进程/

Nginx平滑升级流程

# 在上面源码编译安装Nginx1.14的根本长进级到1.16wget //nginx.org/download/nginx-1.16.0.tar.gztar xf nginx-1.16.0.tar.gz -C /usr/local/src/cd /usr/local/src/nginx-1.16.0/./configure --prefix=/usr/local/nginx116 --with-http_stub_status_module --with-http_ssl_module --user=nginx --group=nginx make && make install# 备份原来老的Nginx文件,紧张是为了回退cp ./nginx/sbin/nginx ./nginx/sbin/nginx.bak# 将新版的Nginx二进制文件更换已安装的Nginx的二进制文件cp nginx116/sbin/nginx nginx/sbin/nginx -rf./nginx/sbin/nginx -v# nginx version: nginx/1.16.0# 给Nginx旧的主进程发送一个USR2旗子暗记,让新主进程和旧进程同时事情.# 再发一个Winch给旧的主进程号让子进程退出,如果主进程还在,方便回滚kill -USR2 17522

版本回滚

cp nginx.bak ./nginx/sbin/nginx -rf# 发送HUP旗子暗记唤醒旧版本kill -HUP `cat /usr/local/nginx/logs/nginx.pid.oldbin `# 关闭新版本的主进程和Worker进程kill -USR2 24148kill -WINCH 24148[root@test1 local]# ./nginx/sbin/nginx -v# nginx version: nginx/1.14.2网络收发与Nginx事宜间对应关系

接下来看上面这张图,比如主机 A 便是一台家里的条记本电脑,那么主机 B 便是一台做事器,上面跑着 Nginx 做事。
从主机 A 发送一个 HTTP 的 GET 要求到主机 B,这样的一个过程中紧张经历了哪些事宜?通过上图数据流部分可以看出:

/ 运用层发送了一个GET要求 -> 到了传输层,这一步紧张做一件事,便是浏览器打开一个端口,在windows的任务管理器可以看到这一点, 他会把这个端口记下来以及把Nginx打开的端口如80或者443记到传输层--> 然后网络层会记下我们主机所在的IP和目标主机,也便是Nginx所在做事器公网IP--> 到链路层往后--> 经由以太网-->到达家里的路由器(网络层),家里的路由器会记录所在运营商下一段的IP --> 通过广域网 --> 跳转到主机B所在的机器中 --> 报文会经由链路层 --> 网络层 --> 到传输层, 在传输层操作系统就知道给那个打开了80或者443进程, 这个进程自然便是Nginx --> 那么Nginx在他的HTTP状态机里面(运用层)就会处理这个要求./

TCP流与报文

/数据链路层会在数据的前面Header部分和Footer部分添加上源MAC地址和源目的地址 -->到了网络层则是Nginx的公网地址(目的IP地址)和浏览器的公网地址(源IP地址) --> 到了TCP层(传输层),指定了Nginx打开的端口(目的端口)和浏览器打开的端口(源端口) -->然后运用层便是HTTP协议了.这便是一个报文,也便是说我们发送的HTTP协议会被切割成很多小的报文,在网络层切割叫MTU,以太网的每个MTU是1500字节; 在TCP层(传输层)会考虑中间每个环节最大的一个MTU值,这个时候每每每个报文只有几百字节,这个报文我们称为MSS,以是每收到一个MSS小于这么大小的一个报文实在便是一个网络事宜.这个时候,我们来看下TCP协议是若何和我们日常调用的一些接口(比如Accept,Read,Write,Close)是若何关联在一起的?/

要求建立TCP连接事宜实际上是发送了一个TCP报文,通过上面第二部分讲解的那样的一个流程到达了Nginx,对应的是读事宜,由于对付Nginx来说,我读到了一个报文,以是便是Accept建立链接事宜. 如果是TCP链接可读事宜,便是发送了一个,对付Nginx也是一个读事宜,便是Read读. 如果是对端(也便是浏览器)主动地关掉了,相称于 windows 操作系统会去发送一个哀求关闭链接的一个事宜,对付 Nginx 来说还是一个读事宜,由于他只是去读取一个报文。
那什么是写事宜呢?当我们的浏览器须要向浏览器发送相应的时候,须要把写到操作系统中,哀求操作系统发送到网络中,这便是一个写事宜。
像这样的一些网络读写事宜,常日在 Nginx 中或者任何一个异步事宜的处理框架中,他会有个东西叫事宜网络、分发器。
会定义每类事宜处理的消费者,也便是说事宜是一个生产者,是通过网络中自动的生产到我们的 Nginx 中的,我们要对每种事宜建立一个消费者。
比如连接建立事宜消费者,便是对 Accept 调用,HTTP 模块就会去建立一个新的连接。
还有很多读或者写,在 HTTP 状态机中不同的韶光段会调用不同的方法也便是每个消费者处理。
以上便是一个事宜分发、消费器,包括 AIO 像异步读写磁盘事宜,还有定时器事宜,比如是否超时(workershutdowntimeout)。

文章福利 Linux后端开拓网络底层事理知识学习提升,私信(Linux),完善技能栈,内容知识点包括Linux,Nginx,ZeroMQ,MySQL,Redis,线程池,MongoDB,ZK,Linux内核,CDN,P2P,epoll,Docker,TCP/IP,协程,DPDK等等。

Nginx事宜循环

/当Nginx刚刚启动时,在等待事宜部分,也便是打开了80或443端口,这个时候在等待新的韶光进来,比如新的客户端连上了nginx向我们发起了连接,此步每每对应epoll的epoll wait方法,这个时候的Nginx实在是处于sleep这样一个进程状态的,当操作系统收到了一个建立TCP连接的握手报文时并且处理完握手流程后,操作系统就会关照epoll wait这个壅塞方法,见告他可以往下走了,同时唤醒Nginx worker进程.接着往下走之后,会去找操作系统索要事宜,操作系统会把他准备好的事宜,放到事宜行列步队中,从这个事宜行列步队中可以获取到须要处理的事宜,比如建立连接或者收到一个TCP要求报文/

取出往后就会进行循环处理事宜,如上便是处理事宜的一个循环:当创造行列步队中不为空,就把事宜取出来开始处理事宜;在处理事宜的过程中,可能又天生新的事宜,比如说创造一个连接新建立了,可能要添加一个超时时间,比如默认的 60 秒,也便是说 60 秒之内如果浏览器不向 Nginx 发送要求的话,Nginx 就会把这个连接关掉;又比如说当 Nginx 创造已经收完了完全的 HTTP 要求往后,可以天生 HTTP 相应了,那么这个天生相应是须要 Nginx 可以向操作系统的写缓存中央里面去把相应写进去,哀求操作系统尽快的把这样一段相应内容发到浏览器上,也便是说可能在处理过程中可能会产生新的事宜,便是循环处理事宜部分指向的事宜行列步队部分,等待下一次来处理。
如果所有的事宜都处理完成往后呢,又会返回到等待事宜部分。
在学习了 Nginx 事宜循环后,我们再去理解,有时候利用一些第三方模块,这些第三方模块可能会做大量的 CPU 运算,这样的打算任务会导致处理一个事宜的韶光非常的长;在上面的一个流程图中,可以看到会导致行列步队中的大量事宜会永劫光得不到处理,从而引发恶性循环,也便是他们的超时时间可能到了;大量的 CPU、Nginx 的任务都花费在处理连接不正常的断开,以是 Nginx 不能容忍有些第三方模块永劫光的花费大量的 CPU 进行打算任务便是这样一个缘故原由。
我们可以看到像 GZIP 这样的模块,他们都不会在一次利用大量的 CPU 而是分段利用,这些都与 Nginx 的事宜循环有关的

运用处景优缺陷运用处景

// 1.静态要求// 2.反向代理// 3.负载均衡// 4.资源缓存// 5.安全防护// 6.访问限定IP// 7.访问认证/核心紧张因此下三个运用:静态资源做事: 通过本地文件系统供应做事反向代理做事: Nginx的强大性能,缓存,负载均衡API: OpenResty/优点

/ 1.功能模块少 2.代码模块少 3.高可靠,热支配,可扩展. 4.BSD容许证. 是一个给于利用者很大自由的协议,BSD 代码鼓励代码共享,但须要尊重代码作者的著作权。
BSD由于许可利用者修正和重新发布代码,大概可利用或在BSD代码上开拓商业软件发布和发卖, 因此是对商业集成很友好的协议。
而很多的公司企业在选用开源产品的时候都首选BSD协议, 由于可以完备掌握这些第三方的代码,在必要的时候可以修正或者二次开拓。
5.CPU亲和 CPU亲和是一种把CPU核心跟nginx事情进程绑定在一起,把每个worker进程固定在一个CPU上实行,减少切换CPU的cache miss,得到更好的性能。
6.事宜驱动模型.(此处很有可能被细问,最好研究清楚)/
Nginx同类型产品发动机

/Tengine是由淘宝网发起的Web做事器项目,他在Nginx的根本上,针对大量访问网站的需求,增加了很多高等功能和特性,Tengine的性能和稳定性已经在大型网站如淘宝网,天猫商城得到了很好的考验,他的目标便是打造一个高效,稳定,安全易用的平台./OpenResty

/这个开源Web平台紧张由章亦春掩护,2011年之前由淘宝资助,后来12-16由美国的CloudFlare公司供应支持,目前由OpenResty软件基金会和OpenRest lnc公司供应支持.由于大部分Nginx模块都是由软件包的掩护者开拓,以是可以确保这些模块及其他组件可以很好的一起事情.由于Nginx模块开拓非常难,而他把nginx的事宜驱动,非以lua措辞开拓然后供应给开拓者,兼具高性能开拓效率提升特点./Epoll的利害与事理epoll与poll比较

/epoll存储生动的连接,每次只处理生动的连接数量占比很小poll是每次将所有的连接交给操作系统去遍历,找出生动的连接,因此连接越多,耗时越长/epoll如何实现只处理生动连接

/epoll实现了eventpoll数据构造数据构造中rdlist将生动连接存储在链表中,当网卡发送报文时,增加节点,当读取一个事宜后,链表删除节点,须要得到生动连接就只须要遍历链表数据构造中rdr利用红黑树(自平衡二叉树)将事宜存储,例如:当有读事宜时,就新增节点,事宜繁芜度为log/

Nginx模块模块分类

/核心模块:HTTP模块: 用来发布http web做事网站的模块event模块: 用来处理nginx,访问要求,并进行规复.mail模块: 卖力邮箱处理和发布的.根本模块:HTTP Access模块: 用来进行虚拟主机发布访问模块,起到记录访问日志;HTTP FastCGI模块: 用于和PHP程序进行交互的模块,卖力将来访问nginx的php要求转发到后真个PHP上.HTTP Proxy模块: 配置反向代理转发的模块,卖力向后端通报参数.HTTP Rewrite模块: 支持Rewrite规则重写,支持域名跳转.第三方模块: HTTP Upstream Request Hash模块: 利用hash算法进行负载均衡的模块.HTTP Access Key模块: http要求访问校验模块Limit_req模块: http要求限定模块Upstream check module: 检测后端负载转发的模块./Nginx如何通过连接池处理网络要求

/每一个worker进程里面都有一个独立的ngx_cycle_t这样一个数据构造;现在不要对他里面的细节来纠结,这里三个紧张的数组要看一下:/

/个中connections这便是我们所谓的连接池,他指向我们这个数组有多大尼,可以看下有一个配置项:/

默认会有一个512大小的数组,这里的每一个数组便是一个连接,可以看到512实在是非常小的,由于我们nginx动则处理万,十万,百万级的打算,以是我们每每是须要去修正的;而且官方提示很清楚,这个连接不止去用于客户真个连接,也用于面向上有做事器的连接,以是如果我们做反向代理的时候,每个客户端意味着花费我们两个connections;

每一个连接自动的对应一个读事宜和一个写事宜,以是在ngx_cycle_t中还有个write_event_s;它们指向的数组的大小也跟worker_connections这个配置是一样的;以是connections连接事宜,读事宜,写事宜是通过序号对应起来的;以是我们在考虑nginx能够开释多大性能的时候,首先要担保worker_connections足够我们利用;但是worker_connections所指向的数组,同时影响了我们所打开的内存,当我们配置了更大的worker_connections的时候,也就意味着nginx利用了更大的内存;以是每一个connections连接到底利用了多大的内存尼?   我们可以看一下,每一个ngx_connection_s这样的一个构造体在64位操作系统中它占用的字节数大约是232字节;具体会因nginx版天职歧,可能会有眇小的差异;   每一个ngx_connection_s这样的一个构造体它对应着两个事宜,一个读事宜,一个写事宜,我们之前谈到网络事宜谈到了它的许多特性;   那么在nginx中每一个事宜对应一个构造体叫做ngx_event_s;每个事宜对应的构造体它所对应的字节数是96字节;   以是我们在利用一个连接的时候它大概花费的字节为(232+96)2;我们的worker_connections配置的越大,那么初始化的时候就会预分配这么多的内存;

ngx_event_s里面有哪些成员呢?

这里我们比较关注的是handler这是一个回调方法;也便是说很多第三方模块会把这个handler设置为自己的实现;这里还有个timer,也便是说当我们对http要求做读超时和写超时时候等等设置的时候,实在是在操作读事宜和写事宜中的tmer;这个timer实在便是nginx实现超时定时器,也便是基于rbtree中的红黑树去实现的构造体;这里定时器实在也是可配的,这里我们看下它的配置;

默认设置为60s,实在这个60s也便是在我们刚刚某个连接上,在准备读它的header时,我们在它的读事宜上添加个60s的定时器; 当多个事宜形成行列步队的时候我们可以利用ngx_queue_t; 我们再来看下ngx_connections_s 每个连接有些什么样的成员?   read 和 write分别是它的读写事宜;   recv和send是它的一个抽象的操作系统的底层方法;怎么样发送和接管;   这里还有一个变量叫sent (off_t:表示无符号的整型)它表示这个连接上已经发送了多少字节,也便是在配置中常常利用到的$bytes_sent   还是在ngx_http_core_module 模块中 我们先找到它的内置变量;

$bytes_sent:它表示向客户端发送了多少字节;  常日在access.log记录nginx处理了哪些要求中我们可以记录这么一个变量,我们在ngixn.conf配置中添加了这么一个变量

小结

/当我们须要配置高并发的nginx的时候,必须把connections的数目配置的足够大,而每个connections将对应两个event,都会花费一定的内存,还有nginx的许多构造体中,它们的一些成员和我们的内置变量是可以对应起来的;/

文章福利 Linux后端开拓网络底层事理知识学习提升 ,私信(Linux)获取,完善技能栈,内容知识点包括Linux,Nginx,ZeroMQ,MySQL,Redis,线程池,MongoDB,ZK,Linux内核,CDN,P2P,epoll,Docker,TCP/IP,协程,DPDK等等。

内存池对性能的影响

如果你开拓过nginx的第三方模块,虽然我们在写C措辞代码,但是不须要关心内存的开释,如果你现在在配置一些罕见场景的nginx的时候,你可能会须要去修正nginx在要乞降连接上初始分配的内存池大小,但是nginx官方上推举常日不须要修正这样的配置,那么我们究竟要不要修正这些内存池的大小尼?   下面我们来看下 内存池 究竟是怎么运转的?   在上讲中我们看到一个构造体ngx_connection_s也便是每一个连接须要这么一个构造体;而这个构造体中,有一个成员变量pool;   它对应着这个连接所利用的内存池

这个内存池可以通过一个变量connection_pool_size配置来定义,那么为什么我们须要内存池尼?

如果有一些工具的话,我们会创造,nginx它所产生的内存碎片是非常小的;这便是内存池的一个功劳,那么内存池尼它会把内存提前分配好一批,而且当我们利用小块内存的时候,每次我们利用的小块内存的时候,它会利用last,end,next,failed一个个连接在一起,每次我们利用的东西比较小的时候尼,在第二次再分配小块内存,它还会再进行连接一起,这样就大大减少了我们的内存碎片,当然当我们分配大块内存的时候尼,会走操作系统的 alloc模块.

对付Nginx有什么好处尼?

由于它紧张在处理WEB要求,WEB要求特殊是对http要求;它有两个非常明显的特点便是每当我们有个tcp连接的时候,这个tcp连接上面可能会有很多http要求;也便是所谓的http keepalive要求,连接没有关闭;实行完一条要求往后 还卖力实行其余一条要求;那么有一些内存尼 我为连接分配一次就够了;比如说我去读取每一个要求的前1k字节;在连接内存池上我分配一次;只要这个连接不关闭,那么这个1k的内存我永久不要开释;什么时候须要开释尼?连接关闭的时候我再开释,没有任何问题; 要求内存池尼?每一个http要求我开始分配的时候尼,我不知道分配多大,但是http要求特殊是http1.1而言,常日我们会分配4k大小的内存;由于我们的url或者header须要分配这么多;如果没有内存池尼,我们可能须要频繁的分配(小块的分配);而分配内存池尼,我们是有代价的;如果我们一次性的分配较多的内存尼,就没有这样的问题;而要求实行完毕往后,哪怕连接我们还可以复用;我们也可以把要求内存池给销毁;而这样所有的nginx第三方模块开拓者就不须要去关注内在什么时候去开释;它只须要关注它是从要求内存池里面申请分配的内存;还是从连接内存池里申请分配的内存;只要这个逻辑讲得通;比如说要求结束往后,连接人想连续利用,你可以在连接内存池里分配;

可以看下具体例子: ngx_http_core_module这个模块

里面有个connection_pool_size点开往后他默认是256或512

这跟我们的操作系统位数有关的. 内存池配置512并不是代表这里我们只能分配512的字节. 当我们分配的内存超过预分配大小时候,还是可以连续分配的,这里只是说我们提前预分配了足够大小的空间可以减少我分配内存的次数.

那么我们再看其余一个配置叫request_pool_size

也便是每一个要求的内存池的大小,我们这里可以看到他的默认大小是4k; 为什么会差距这么大呢? 之以是会差距8倍,那是由于对连接而言,它须要保存的高下文信息非常的少;它只须要帮助后面的要求,读取最月朔部分字节就行了,而对付要求而言,我们须要保存大量的高下文信息,比如说所有读取到的url或者header我须要保存下来,url常日还比较长,以是我们须要4k的大小;当然官方文档中说 它对性能的影响比较小,如果我们在极度场景下,如果你的url特殊大,可以考虑把这个值分配的更大,常日来说你是很小内存的,url特殊小,header也非常少,可以考虑将这个值降落一些,这样nginx花费的内存会小一些;也意味着可以做更大并发量的要求;

总结

以上我们先容了内存池的事理,以及要求内存池和连接内存池,它们的配置代表了怎么样的意义,内存池对减少我们内存碎片,对第三方模块的快速开拓,是有很大意义的;可能有些第三方模块不当利用了内存池,比如本该在要求内存池里分配内存,却在连接内存池里连接内存;可能会导致内存的延期开释,导致nginx的内存无谓的增加;这须要我们把稳;

nginx共享内存

nginx的进程间的通讯办法紧张有两种

1 . 第一种是旗子暗记,之前我们在说如何管理Nginx的过程中已经有比较详细地先容过了:

2 . 共享内存: 如果须要做数据的同步,只能通过共享内存,所谓共享内存,也便是我们打开了一块内存,比如说10M,一整块0到10M之间,多个worker进程之间可以同时的访问他; 包括读取和写入,那么为了利用好这样一个共享内存就会引入其余两个问题;第一个问题便是说, 由于多个worker进程同时操作一块内存,一定会存在竞争关系;以是我们须要加锁,在Nginx的锁中,在早期,它还有基于旗子暗记量的锁,旗子暗记量是nginx比较久远的进程同步办法,它会导致你的进程进入休眠状态;也便是发送了主动切换;而现在大多数操作系统版本中,nginx所利用的锁都是自旋锁,而不会基于旗子暗记量;自旋锁也便是说当这个锁的条件没有知足比如说,这块内存现在被1号worker进程利用,2号worker进程须要去获取锁的时候,只要1号进程没有开释锁,2号进程会一贯要求这把锁,就彷佛如果是基于旗子暗记量的早期的nginx锁,那么假设这把锁锁住了一扇门,如果worker进程1已经拿到了这把锁进到屋里,worker进程2是试图拿锁,拍门,创造里面已经有人了,那么worker进程2就会就地安歇;等待worker进程1从门里出来往后关照它,而自旋锁不一样,那么worker进程2创造屋里已经有worker进程1了;它就会一贯持续的去拍门,以是利用自旋锁哀求所有的nginx模块,必须快速地利用共享内存,也便是快速的取得锁往后,快速的开释锁,一旦创造有第三方模块不遵守这样的规则,就可能会导致涌现去世锁或者说性能低落的问题;那么有了这样的一块共享内存;会引入第二个问题;由于一整块共享内存是每每是给许多工具同时利用的;如果我们在模块中手动的去编写,分配把这些内存给到不同的工具,这是非常繁琐的;以是这个时候 我们利用了Slab内存管理器;

那么Nginx那些模块利用了共享内存尼?

利用共享内存紧张利用了两种数据构造: 1 . Rbtree: 红黑树, 比如我们想做限速和流控等等场景时,我们是不能容忍在内存中做的, 否则一个worker进程对某一个用户触发了流控,而其他worker进程还不知道,以是我们只能在共享内存中做; 红黑树有一个特点: 便是他的插入删除非常的快,当然也可以做遍历,以是如下模块有一个特点: 须要做快速的插入和删除:

比如我创造了一个客户端我对他限速,限速如果达到了,我须要他从我的数据构造容器中移除,都须要非常的快速. 那么第二个常用的数据构造是单链表,也便是说我只须要把这些共享的元素串联起来就可以了,比如:

我们来看个非常繁芜的例子便是: ngx_http_lua_api ngx_http_lua_api 这个模块实在是openresty的核心模块;openresty在这个模块中定义了一个SDK,这个SDK叫lua_shared_dict;当这个指令涌现的时候,它会分配一块共享内存;比如说这里我们分了10m;这个共享内存会有一个名称叫做 dogs;

接下来我们在lua代码中,比如content_by_lua_block;对应着我们nginx收到了 set这个url的时候;须要做一些什么样的事情,我们首先从dogs共享内存中取出;然后设置了一个key-value; Jim-8;然后向客户端返回我已存储;   然后在get要求中我们把Jim的值8取出来;返回给用户;   那么在这一段代码中呢,我们同时利用了我们刚刚利用的红黑树和单链表 那么这个lua_shared_dict dogs 10m中利用红黑树来保存每一个key-value;红黑树中每一个节点便是Jim它的value便是8;那么为什么我还须要一个链表呢?是由于这个10m是有限的;当我们的Lua代码涉及到了我们的运用业务代码;很随意马虎就超过了10m的限定;当我们涌现10m限定的时候尼,会有很多种处理方法;比如让它写入失落败;但是lua_shared_dict 采取了其余一种实现办法它用lru淘汰;也便是我最早set,最早get 永劫光不用的那一个节点;比如前面还有Jim即是7或者即是6的节点;会优先被淘汰掉;当已经达到10m的最大值时;以是这个lua_shared_dict同时知足了红黑树和链表;   共享内存是nginx跨worker进程通讯的最有效的手段;只要我们须要让一段业务逻辑在多个worker进程中同时生效;比如很多在做集群的流控上;那么必须利用共享内存;而不能在每一个worker内存中去操作;

文章福利 Linux后端开拓网络底层事理知识学习提升,私信(Linux)获取,完善技能栈,内容知识点包括Linux,Nginx,ZeroMQ,MySQL,Redis,线程池,MongoDB,ZK,Linux内核,CDN,P2P,epoll,Docker,TCP/IP,协程,DPDK等等。

Slab管理器

刚刚我们谈到nginx不同的worker进程间须要共享信息的时候,须要通过共享内存;我们也谈到了共享内存上可以利用链表或者红黑树这样的数据构造;但是每一个红黑树上有许多节点;每一个节点你都须要分配内存去存放;那么怎么样把一整块共享内存切割成一小块给红黑树上的每一个节点利用呢?   下面我们来看下Slab内存分配管理是怎么样运用于共享内存上的;首先我们来看下Slab内存管理是怎么样的一种形式;

它首先会把整块的共享内存分为很多页面;那么每个页面例如4k;会切分为很多slot;比如32字节是一种slot;64字节又是一种slot;128字节又是一种slot;那么这些slot因此乘2的办法向上增长的;如果现在有一个51字节须要分配的内存会放到哪里呢?会放于小于它最大的一个slot的一个环节;比如说64字节;以是上图中slot便是指向不同大小的块;以是这样的一种数据构造尼 它有一个特点;会有内存的摧残浪费蹂躏的;就像我们刚刚所说的;51字节它会用64字节来存放;那么其它的13字节就摧残浪费蹂躏了;那么最多会有多少内存花费呢?会有两倍;这种利用的办法叫做Bestfit;Bestfit这种分配内存的办法有什么好处尼?它适宜小工具;如果我们要分配的工具的内存非常小,比如小于一个页面的大小,就非常得当;由于它很少有碎片,那么每分配一块内存,就会沿着还未分配的空缺的地方连续利用就可以了;当一个页面利用满往后,我再拿一个空缺的页面连续给此类slot大小的内存连续利用就可以.那么有时候我分配在某段内存上的数据构造它是固定的,乃至须要初始化;那么这样的话,原来的数据构造都还在;当我重复利用的话,也避免了初始化;Slab内存管理中,我们怎么做数据的监控和统计呢? 那么tng上有一个模块叫做slab_stat;slab_stat可以帮我们看不同的slot;

比如说:8字节 16 字节 。



等等;
  一共目前分配了多少,利用了多少,有多少个要求在访问,失落败了多少次,这个对我们来监控Slab是非常有用处的;   下面我们来看下怎么样在openresty的场景下去利用tng上的slab_stat这个模块;   首先我们打开tengine的页面 //tengine.taobao.org/document/ngx_slab_stat.html   但是会创造在这个模块上没有github的地址;也便是说它没有作为一个独立的模块供应出来;那这个时候该怎么办呢?   那么tengine怎么下载下来?从download里;

[root@server ~]# wget //tengine.taobao.org/download/tengine-2.2.3.tar.gz[root@server ~]# tar xf tengine-2.2.3.tar.gz[root@server ~]# cd openresty-1.13.6.2/[root@server openresty-1.13.6.2]# ./configure --add-module=../tengine-2.2.3/modules/ngx_slab_stat/[root@server openresty-1.13.6.2]# make[root@server openresty-1.13.6.2]# cp build/nginx-1.13.6/objs/nginx /usr/local/openresty/nginx/sbin/nginx

nginx.conf

[root@server nginx]# cat conf/nginx.confworker_processes 1;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 8090; server_name localhost;location = /slab_stat{ slab_stat; }location /set { content_by_lua_block {local dogs = ngx.shared.dogsdogs:set("Jim",8)ngx.say("STORED"); }}location /get { content_by_lua_block {local dogs = ngx.shared.dogsngx.say(dogs:get("Jim")); }} location / { root html; index index.html index.htm; } error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } }}

测试

[root@server nginx]# curl localhost:8090/setSTORED[root@server nginx]# curl localhost:8090/get8[root@server nginx]# curl localhost:8090/slab_stat shared memory: dogstotal: 10240(KB) free: 10168(KB) size: 4(KB)pages: 10168(KB) start:00007F7A4C7FE000 end:00007F7A4D1EE000slot: 8(Bytes) total: 0 used: 0 reqs: 0 fails: 0slot: 16(Bytes) total: 0 used: 0 reqs: 0 fails: 0slot: 32(Bytes) total: 127 used: 1 reqs: 1 fails: 0slot: 64(Bytes) total: 0 used: 0 reqs: 0 fails: 0slot: 128(Bytes) total: 32 used: 2 reqs: 2 fails: 0slot: 256(Bytes) total: 0 used: 0 reqs: 0 fails: 0slot: 512(Bytes) total: 0 used: 0 reqs: 0 fails: 0slot: 1024(Bytes) total: 0 used: 0 reqs: 0 fails: 0slot: 2048(Bytes) total: 0 used: 0 reqs: 0 fails: 0/配置项写完,把nginx启动看他的实行效果;每一个slot及其slot对应的大小; 分配了多少个,利用了多少个,失落败了多少个.所谓分配便是10m是一个非常大的内存,他会划分很多歌页面; 对付比较小的比如32字节,一个页面可以有128个, 这里127可用,已经利用了一个./

总结

/以上我们先容了Slab内存的利用方法; slab利用了Bestfit思想,他也是Linux操作系统常常利用的内存分配办法;那么通畅我们在利用共享内存时, 都须要利用slab_stat去分配相应的内存给工具,再利用上层的数据构造掩护这些数据工具;/哈希表的max_size与bucket_size如何配置

nginx容器

/数组链表行列步队哈希表红黑树基数树/

哈希表

nginx哈希表仅用于静态不变的内容,nginx启动时候就能确定这个哈希表里面有多少个元素,以是,当利用哈希表这些模块会暴露出bucketsize,maxsize, 我们的bucketsize仅仅掌握了最大哈希表bucketsize的个数,而不是实际个数, max size意义在于限定最大化的利用.

nginx红黑树

/nginx内存中会大量利用红黑树,它是一个二叉树.同时是一个查找二叉树,他有可能退化为一个链表,利用了红黑树的模块,再增编削查是非常快的./nginx动态模块提升运维效率

我们在利用动态模块之前,先来看下在不适用动态模块的方法里,我们是怎么样利用Nginx;   首先我们不才载完nginx的源代码,供应了一个叫config的脚本,以及在源代码中先容的auto目录;这里都在帮助nginx在建立编译系统;那么nginx源代码中供应了很多官方模块,但我们也可能添加许多的第三方模块,不管是官方模块还是第三方模块,这些模块的源码都会和Nginx的框架源码放到一起,进行编译,末了编译出一个nginx可实行文件;那么这是不该用动态模块的一种办法;

那么利用了动态模块呢?

我们在编译的时候,指定了某些模块,利用动态模块的办法去编译;那么末了尼,除了天生nginx的二进制可实行文件,还会天生一个动态库,也便是我们指定了模块的那个动态库;

动态库和静态库有什么差异?

静态库: 是直接把所有源代码编译进终极的二进制可实行文件中; 动态库: 在nginx二进制可实行文件里,只保留了他的位置或者说地址,那么我们须要这个动态库的功能时尼, 由nginx的可实行文件去调用这个动态库,再去完成这样的功能, 以是这里好处就表现为仅仅须要修正某一个模块或者升级这个模块功能时,特殊是我们nginx编译了大量第三方模块,那么这个时候,我们仅仅重新编译这个动态库,而不用去更换我的二进制文件,由于这里很有可能会漏了或者多编译进一些nginx模块或者参数利用了缺点, 而我编译出新的动态库往后,我只要更换掉这个动态库,然后nginx -s reload一遍; 我就可以利用新的模块功能了.

详细利用时候,分为6个步骤

1 . 首先,要在nginx源代码加入configure加入动态模块必须指明这个模块是利用动态模块办法编译进nginx; 这里有一个潜台词,不是所有的nginx模块都可以以动态模块的办法加入到nginx中;只有一些模块才可以以动态模块的办法加入; 2 . 开始实行make,编译出binary; 3 . 到第三步的时候,也便是说我们开始启动nginx了;启动nginx的时候尼我们去读ngx_module里的数组; 4 . 读到模块数组中尼,我们创造了利用了一个动态模块,接下来我们会看到一个nginx的conf中加入的一个配置项,这个配置项叫load_module配置;指明了这个 动态模块所在的路径; 5 . 那么接下来我们就可以在nginx的进程中打开这个动态库加入模块数组, 6 . 末了再进行一个初始化的过程(基于模块数组进程初始化); 这是动态模块的一个事情流程,下面为一个大略演示:

标签:

相关文章

php中表单全选技巧_全选全不选的jquery实现

通过勾选全选/全不选的复选框来实现项目的全选和全不选。怎么实现呢?首先全选/全不选的复选框和项目的复选框要区分开;其次,当点击全选...

SEO优化 2024-12-15 阅读0 评论0

phplink乱码技巧_wifissid下作弊乱码检测

有些作弊用户用仿照器天生的ssid会是乱码,对ssid中的乱码进行检测不仅可以为作弊检测供应依据,其核心方法也可以进一步泛化到邮箱...

SEO优化 2024-12-15 阅读0 评论0