• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            Nginx工作原理和優(yōu)化、漏洞 (轉(zhuǎn))

            (peakflys注:本篇文章轉(zhuǎn)自http://blog.csdn.net/hguisu/article/details/8930668)

            1.  Nginx的模塊與工作原理

            Nginx由內(nèi)核和模塊組成,其中,內(nèi)核的設(shè)計(jì)非常微小和簡潔,完成的工作也非常簡單,僅僅通過查找配置文件將客戶端請(qǐng)求映射到一個(gè)location block(location是Nginx配置中的一個(gè)指令,用于URL匹配),而在這個(gè)location中所配置的每個(gè)指令將會(huì)啟動(dòng)不同的模塊去完成相應(yīng)的工作。

            Nginx的模塊從結(jié)構(gòu)上分為核心模塊、基礎(chǔ)模塊和第三方模塊:

            核心模塊:HTTP模塊、EVENT模塊和MAIL模塊

            基礎(chǔ)模塊:HTTP Access模塊、HTTP FastCGI模塊、HTTP Proxy模塊和HTTP Rewrite模塊,

            第三方模塊:HTTP Upstream Request Hash模塊、Notice模塊和HTTP Access Key模塊。

            用戶根據(jù)自己的需要開發(fā)的模塊都屬于第三方模塊。正是有了這么多模塊的支撐,Nginx的功能才會(huì)如此強(qiáng)大。

            Nginx的模塊從功能上分為如下三類。

            Handlers(處理器模塊)。此類模塊直接處理請(qǐng)求,并進(jìn)行輸出內(nèi)容和修改headers信息等操作。Handlers處理器模塊一般只能有一個(gè)。

            Filters (過濾器模塊)。此類模塊主要對(duì)其他處理器模塊輸出的內(nèi)容進(jìn)行修改操作,最后由Nginx輸出。

            Proxies (代理類模塊)。此類模塊是Nginx的HTTP Upstream之類的模塊,這些模塊主要與后端一些服務(wù)比如FastCGI等進(jìn)行交互,實(shí)現(xiàn)服務(wù)代理和負(fù)載均衡等功能。

            圖1-1展示了Nginx模塊常規(guī)的HTTP請(qǐng)求和響應(yīng)的過程。


                                   圖1-1展示了Nginx模塊常規(guī)的HTTP請(qǐng)求和響應(yīng)的過程。

            Nginx本身做的工作實(shí)際很少,當(dāng)它接到一個(gè)HTTP請(qǐng)求時(shí),它僅僅是通過查找配置文件將此次請(qǐng)求映射到一個(gè)location block,而此location中所配置的各個(gè)指令則會(huì)啟動(dòng)不同的模塊去完成工作,因此模塊可以看做Nginx真正的勞動(dòng)工作者。通常一個(gè)location中的指令會(huì)涉及一個(gè)handler模塊和多個(gè)filter模塊(當(dāng)然,多個(gè)location可以復(fù)用同一個(gè)模塊)。handler模塊負(fù)責(zé)處理請(qǐng)求,完成響應(yīng)內(nèi)容的生成,而filter模塊對(duì)響應(yīng)內(nèi)容進(jìn)行處理。

            Nginx的模塊直接被編譯進(jìn)Nginx,因此屬于靜態(tài)編譯方式。啟動(dòng)Nginx后,Nginx的模塊被自動(dòng)加載,不像Apache,首先將模塊編譯為一個(gè)so文件,然后在配置文件中指定是否進(jìn)行加載。在解析配置文件時(shí),Nginx的每個(gè)模塊都有可能去處理某個(gè)請(qǐng)求,但是同一個(gè)處理請(qǐng)求只能由一個(gè)模塊來完成。 

            在工作方式上,Nginx分為單工作進(jìn)程和多工作進(jìn)程兩種模式。在單工作進(jìn)程模式下,除主進(jìn)程外,還有一個(gè)工作進(jìn)程,工作進(jìn)程是單線程的;在多工作進(jìn)程模式下,每個(gè)工作進(jìn)程包含多個(gè)線程。Nginx默認(rèn)為單工作進(jìn)程模式。

            2.  Nginx+FastCGI運(yùn)行原理

            1、什么是 FastCGI

            FastCGI是一個(gè)可伸縮地、高速地在HTTP server和動(dòng)態(tài)腳本語言間通信的接口。多數(shù)流行的HTTP server都支持FastCGI,包括Apache、Nginx和lighttpd等。同時(shí),F(xiàn)astCGI也被許多腳本語言支持,其中就有PHP。

            FastCGI是從CGI發(fā)展改進(jìn)而來的。傳統(tǒng)CGI接口方式的主要缺點(diǎn)是性能很差,因?yàn)槊看蜨TTP服務(wù)器遇到動(dòng)態(tài)程序時(shí)都需要重新啟動(dòng)腳本解析器來執(zhí)行解析,然后將結(jié)果返回給HTTP服務(wù)器。這在處理高并發(fā)訪問時(shí)幾乎是不可用的。另外傳統(tǒng)的CGI接口方式安全性也很差,現(xiàn)在已經(jīng)很少使用了。

            FastCGI接口方式采用C/S結(jié)構(gòu),可以將HTTP服務(wù)器和腳本解析服務(wù)器分開,同時(shí)在腳本解析服務(wù)器上啟動(dòng)一個(gè)或者多個(gè)腳本解析守護(hù)進(jìn)程。當(dāng)HTTP服務(wù)器每次遇到動(dòng)態(tài)程序時(shí),可以將其直接交付給FastCGI進(jìn)程來執(zhí)行,然后將得到的結(jié)果返回給瀏覽器。這種方式可以讓HTTP服務(wù)器專一地處理靜態(tài)請(qǐng)求或者將動(dòng)態(tài)腳本服務(wù)器的結(jié)果返回給客戶端,這在很大程度上提高了整個(gè)應(yīng)用系統(tǒng)的性能。

            2、Nginx+FastCGI運(yùn)行原理

            Nginx不支持對(duì)外部程序的直接調(diào)用或者解析,所有的外部程序(包括PHP)必須通過FastCGI接口來調(diào)用。FastCGI接口在Linux下是socket(這個(gè)socket可以是文件socket,也可以是ip socket)。

            wrapper:為了調(diào)用CGI程序,還需要一個(gè)FastCGI的wrapper(wrapper可以理解為用于啟動(dòng)另一個(gè)程序的程序),這個(gè)wrapper綁定在某個(gè)固定socket上,如端口或者文件socket。當(dāng)Nginx將CGI請(qǐng)求發(fā)送給這個(gè)socket的時(shí)候,通過FastCGI接口,wrapper接收到請(qǐng)求,然后Fork(派生)出一個(gè)新的線程,這個(gè)線程調(diào)用解釋器或者外部程序處理腳本并讀取返回?cái)?shù)據(jù);接著,wrapper再將返回的數(shù)據(jù)通過FastCGI接口,沿著固定的socket傳遞給Nginx;最后,Nginx將返回的數(shù)據(jù)(html頁面或者圖片)發(fā)送給客戶端。這就是Nginx+FastCGI的整個(gè)運(yùn)作過程,如圖1-3所示。

                   


                  所以,我們首先需要一個(gè)wrapper,這個(gè)wrapper需要完成的工作:

            1. 通過調(diào)用fastcgi(庫)的函數(shù)通過socket和ningx通信(讀寫socket是fastcgi內(nèi)部實(shí)現(xiàn)的功能,對(duì)wrapper是非透明的)
            2. 調(diào)度thread,進(jìn)行fork和kill
            3. 和application(php)進(jìn)行通信

            3、spawn-fcgi與PHP-FPM

                   FastCGI接口方式在腳本解析服務(wù)器上啟動(dòng)一個(gè)或者多個(gè)守護(hù)進(jìn)程對(duì)動(dòng)態(tài)腳本進(jìn)行解析,這些進(jìn)程就是FastCGI進(jìn)程管理器,或者稱為FastCGI引擎。 spawn-fcgi與PHP-FPM就是支持PHP的兩個(gè)FastCGI進(jìn)程管理器。因此HTTPServer完全解放出來,可以更好地進(jìn)行響應(yīng)和并發(fā)處理。
                   
                   spawn-fcgi與PHP-FPM的異同:
                   1)spawn-fcgi是HTTP服務(wù)器lighttpd的一部分,目前已經(jīng)獨(dú)立成為一個(gè)項(xiàng)目,一般與lighttpd配合使用來支持PHP。但是ligttpd的spwan-fcgi在高并發(fā)訪問的時(shí)候,會(huì)出現(xiàn)內(nèi)存泄漏甚至自動(dòng)重啟FastCGI的問題。即:PHP腳本處理器當(dāng)機(jī),這個(gè)時(shí)候如果用戶訪問的話,可能就會(huì)出現(xiàn)白頁(即PHP不能被解析或者出錯(cuò))。
                   2)Nginx是個(gè)輕量級(jí)的HTTP server,必須借助第三方的FastCGI處理器才可以對(duì)PHP進(jìn)行解析,因此其實(shí)這樣看來nginx是非常靈活的,它可以和任何第三方提供解析的處理器實(shí)現(xiàn)連接從而實(shí)現(xiàn)對(duì)PHP的解析(在nginx.conf中很容易設(shè)置)。nginx也可以使用spwan-fcgi(需要一同安裝lighttpd,但是需要為nginx避開端口,一些較早的blog有這方面安裝的教程),但是由于spawn-fcgi具有上面所述的用戶逐漸發(fā)現(xiàn)的缺陷,現(xiàn)在慢慢減少用nginx+spawn-fcgi組合了。

                   由于spawn-fcgi的缺陷,現(xiàn)在出現(xiàn)了第三方(目前已經(jīng)加入到PHP core中)的PHP的FastCGI處理器PHP-FPM,它和spawn-fcgi比較起來有如下優(yōu)點(diǎn):

                   由于它是作為PHP的patch補(bǔ)丁來開發(fā)的,安裝的時(shí)候需要和php源碼一起編譯,也就是說編譯到php core中了,因此在性能方面要優(yōu)秀一些;

            同時(shí)它在處理高并發(fā)方面也優(yōu)于spawn-fcgi,至少不會(huì)自動(dòng)重啟fastcgi處理器。因此,推薦使用Nginx+PHP/PHP-FPM這個(gè)組合對(duì)PHP進(jìn)行解析。

                  相對(duì)Spawn-FCGI,PHP-FPM在CPU和內(nèi)存方面的控制都更勝一籌,而且前者很容易崩潰,必須用crontab進(jìn)行監(jiān)控,而PHP-FPM則沒有這種煩惱。
                   FastCGI 的主要優(yōu)點(diǎn)是把動(dòng)態(tài)語言和HTTP Server分離開來,所以Nginx與PHP/PHP-FPM經(jīng)常被部署在不同的服務(wù)器上,以分擔(dān)前端Nginx服務(wù)器的壓力,使Nginx專一處理靜態(tài)請(qǐng)求和轉(zhuǎn)發(fā)動(dòng)態(tài)請(qǐng)求,而PHP/PHP-FPM服務(wù)器專一解析PHP動(dòng)態(tài)請(qǐng)求。

            4、Nginx+PHP-FPM

                  PHP-FPM是管理FastCGI的一個(gè)管理器,它作為PHP的插件存在,在安裝PHP要想使用PHP-FPM時(shí)在老php的老版本(php5.3.3之前)就需要把PHP-FPM以補(bǔ)丁的形式安裝到PHP中,而且PHP要與PHP-FPM版本一致,這是必須的)

               PHP-FPM其實(shí)是PHP源代碼的一個(gè)補(bǔ)丁,旨在將FastCGI進(jìn)程管理整合進(jìn)PHP包中。必須將它patch到你的PHP源代碼中,在編譯安裝PHP后才可以使用。
               PHP5.3.3已經(jīng)集成php-fpm了,不再是第三方的包了。PHP-FPM提供了更好的PHP進(jìn)程管理方式,可以有效控制內(nèi)存和進(jìn)程、可以平滑重載PHP配置,比spawn-fcgi具有更多優(yōu)點(diǎn),所以被PHP官方收錄了。在./configure的時(shí)候帶 –enable-fpm參數(shù)即可開啟PHP-FPM。

                  fastcgi已經(jīng)在php5.3.5的core中了,不必在configure時(shí)添加 --enable-fastcgi了。老版本如php5.2的需要加此項(xiàng)。

                  當(dāng)我們安裝Nginx和PHP-FPM完后,配置信息:

                 PHP-FPM的默認(rèn)配置php-fpm.conf
                 listen_address  127.0.0.1:9000 #這個(gè)表示php的fastcgi進(jìn)程監(jiān)聽的ip地址以及端口
                  start_servers
                  min_spare_servers
                  max_spare_servers

                  Nginx配置運(yùn)行php: 編輯nginx.conf加入如下語句:
                  location ~ \.php$ {
                        root html;   
                        fastcgi_pass 127.0.0.1:9000; 指定了fastcgi進(jìn)程偵聽的端口,nginx就是通過這里與php交互的
                        fastcgi_index index.php;
                        include fastcgi_params;
                         fastcgi_param SCRIPT_FILENAME   /usr/local/nginx/html$fastcgi_script_name;
                }
                Nginx通過location指令,將所有以php為后綴的文件都交給127.0.0.1:9000來處理,而這里的IP地址和端口就是FastCGI進(jìn)程監(jiān)聽的IP地址和端口。
               
                 其整體工作流程:
                 1)、FastCGI進(jìn)程管理器php-fpm自身初始化,啟動(dòng)主進(jìn)程php-fpm和啟動(dòng)start_servers個(gè)CGI 子進(jìn)程。
                       主進(jìn)程php-fpm主要是管理fastcgi子進(jìn)程,監(jiān)聽9000端口。
                       fastcgi子進(jìn)程等待來自Web Server的連接。
                 2)、當(dāng)客戶端請(qǐng)求到達(dá)Web Server Nginx是時(shí),Nginx通過location指令,將所有以php為后綴的文件都交給127.0.0.1:9000來處理,即Nginx通過location指令,將所有以php為后綴的文件都交給127.0.0.1:9000來處理。
                  3)FastCGI進(jìn)程管理器PHP-FPM選擇并連接到一個(gè)子進(jìn)程CGI解釋器。Web server將CGI環(huán)境變量和標(biāo)準(zhǔn)輸入發(fā)送到FastCGI子進(jìn)程。
                  4)、FastCGI子進(jìn)程完成處理后將標(biāo)準(zhǔn)輸出和錯(cuò)誤信息從同一連接返回Web Server。當(dāng)FastCGI子進(jìn)程關(guān)閉連接時(shí),請(qǐng)求便告處理完成。
                  5)、FastCGI子進(jìn)程接著等待并處理來自FastCGI進(jìn)程管理器(運(yùn)行在 WebServer中)的下一個(gè)連接。
             

            3.   Nginx的IO模型

                 首先nginx支持的事件模型如下(nginx的wiki):

                   Nginx支持如下處理連接的方法(I/O復(fù)用方法),這些方法可以通過use指令指定。

            • select – 標(biāo)準(zhǔn)方法。 如果當(dāng)前平臺(tái)沒有更有效的方法,它是編譯時(shí)默認(rèn)的方法。你可以使用配置參數(shù) –with-select_module 和 –without-select_module 來啟用或禁用這個(gè)模塊。
            • poll – 標(biāo)準(zhǔn)方法。 如果當(dāng)前平臺(tái)沒有更有效的方法,它是編譯時(shí)默認(rèn)的方法。你可以使用配置參數(shù) –with-poll_module 和 –without-poll_module 來啟用或禁用這個(gè)模塊。
            • kqueue – 高效的方法,使用于 FreeBSD 4.1+, OpenBSD 2.9+, NetBSD 2.0 和 MacOS X. 使用雙處理器的MacOS X系統(tǒng)使用kqueue可能會(huì)造成內(nèi)核崩潰。
            • epoll – 高效的方法,使用于Linux內(nèi)核2.6版本及以后的系統(tǒng)。在某些發(fā)行版本中,如SuSE 8.2, 有讓2.4版本的內(nèi)核支持epoll的補(bǔ)丁。
            • rtsig – 可執(zhí)行的實(shí)時(shí)信號(hào),使用于Linux內(nèi)核版本2.2.19以后的系統(tǒng)。默認(rèn)情況下整個(gè)系統(tǒng)中不能出現(xiàn)大于1024個(gè)POSIX實(shí)時(shí)(排隊(duì))信號(hào)。這種情況 對(duì)于高負(fù)載的服務(wù)器來說是低效的;所以有必要通過調(diào)節(jié)內(nèi)核參數(shù) /proc/sys/kernel/rtsig-max 來增加隊(duì)列的大小。可是從Linux內(nèi)核版本2.6.6-mm2開始, 這個(gè)參數(shù)就不再使用了,并且對(duì)于每個(gè)進(jìn)程有一個(gè)獨(dú)立的信號(hào)隊(duì)列,這個(gè)隊(duì)列的大小可以用 RLIMIT_SIGPENDING 參數(shù)調(diào)節(jié)。當(dāng)這個(gè)隊(duì)列過于擁塞,nginx就放棄它并且開始使用 poll 方法來處理連接直到恢復(fù)正常。
            • /dev/poll – 高效的方法,使用于 Solaris 7 11/99+, HP/UX 11.22+ (eventport), IRIX 6.5.15+ 和 Tru64 UNIX 5.1A+.
            • eventport – 高效的方法,使用于 Solaris 10. 為了防止出現(xiàn)內(nèi)核崩潰的問題, 有必要安裝這個(gè) 安全補(bǔ)丁。

                    在linux下面,只有epoll是高效的方法

                    下面再來看看epoll到底是如何高效的
                   Epoll是
            Linux內(nèi)核為處理大批量句柄而作了改進(jìn)的poll。 要使用epoll只需要這三個(gè)系統(tǒng)調(diào)用:epoll_create(2), epoll_ctl(2), epoll_wait(2)。它是在2.5.44內(nèi)核中被引進(jìn)的(epoll(4) is a new API introduced in Linux kernel 2.5.44),在2.6內(nèi)核中得到廣泛應(yīng)用。

                    epoll的優(yōu)點(diǎn)

            • 支持一個(gè)進(jìn)程打開大數(shù)目的socket描述符(FD)

                    select 最不能忍受的是一個(gè)進(jìn)程所打開的FD是有一定限制的,由FD_SETSIZE設(shè)置,默認(rèn)值是2048。對(duì)于那些需要支持的上萬連接數(shù)目的IM服務(wù)器來說顯 然太少了。這時(shí)候你一是可以選擇修改這個(gè)宏然后重新編譯內(nèi)核,不過資料也同時(shí)指出這樣會(huì)帶來網(wǎng)絡(luò)效率的下降,二是可以選擇多進(jìn)程的解決方案(傳統(tǒng)的 Apache方案),不過雖然linux上面創(chuàng)建進(jìn)程的代價(jià)比較小,但仍舊是不可忽視的,加上進(jìn)程間數(shù)據(jù)同步遠(yuǎn)比不上線程間同步的高效,所以也不是一種完 美的方案。不過 epoll則沒有這個(gè)限制,它所支持的FD上限是最大可以打開文件的數(shù)目,這個(gè)數(shù)字一般遠(yuǎn)大于2048,舉個(gè)例子,在1GB內(nèi)存的機(jī)器上大約是10萬左 右,具體數(shù)目可以cat /proc/sys/fs/file-max察看,一般來說這個(gè)數(shù)目和系統(tǒng)內(nèi)存關(guān)系很大。

            • IO效率不隨FD數(shù)目增加而線性下降

                     傳統(tǒng)的select/poll另一個(gè)致命弱點(diǎn)就是當(dāng)你擁有一個(gè)很大的socket集合,不過由于網(wǎng)絡(luò)延時(shí),任一時(shí)間只有部分的socket是”活躍”的,但 是select/poll每次調(diào)用都會(huì)線性掃描全部的集合,導(dǎo)致效率呈現(xiàn)線性下降。但是epoll不存在這個(gè)問題,它只會(huì)對(duì)”活躍”的socket進(jìn)行操 作—這是因?yàn)樵趦?nèi)核實(shí)現(xiàn)中epoll是根據(jù)每個(gè)fd上面的callback函數(shù)實(shí)現(xiàn)的。那么,只有”活躍”的socket才會(huì)主動(dòng)的去調(diào)用 callback函數(shù),其他idle狀態(tài)socket則不會(huì),在這點(diǎn)上,epoll實(shí)現(xiàn)了一個(gè)”偽”AIO,因?yàn)檫@時(shí)候推動(dòng)力在os內(nèi)核。在一些 benchmark中,如果所有的socket基本上都是活躍的—比如一個(gè)高速LAN環(huán)境,epoll并不比select/poll有什么效率,相 反,如果過多使用epoll_ctl,效率相比還有稍微的下降。但是一旦使用idle connections模擬WAN環(huán)境,epoll的效率就遠(yuǎn)在select/poll之上了。

            • 使用mmap加速內(nèi)核與用戶空間的消息傳遞。

                    這 點(diǎn)實(shí)際上涉及到epoll的具體實(shí)現(xiàn)了。無論是select,poll還是epoll都需要內(nèi)核把FD消息通知給用戶空間,如何避免不必要的內(nèi)存拷貝就很 重要,在這點(diǎn)上,epoll是通過內(nèi)核于用戶空間mmap同一塊內(nèi)存實(shí)現(xiàn)的。而如果你想我一樣從2.5內(nèi)核就關(guān)注epoll的話,一定不會(huì)忘記手工 mmap這一步的。

            • 內(nèi)核微調(diào)

                     這一點(diǎn)其實(shí)不算epoll的優(yōu)點(diǎn)了,而是整個(gè)linux平臺(tái)的優(yōu)點(diǎn)。也許你可以懷疑linux平臺(tái),但是你無法回避linux平臺(tái)賦予你微調(diào)內(nèi)核的能力。比如,內(nèi)核TCP/IP協(xié) 議棧使用內(nèi)存池管理sk_buff結(jié)構(gòu),那么可以在運(yùn)行時(shí)期動(dòng)態(tài)調(diào)整這個(gè)內(nèi)存pool(skb_head_pool)的大小— 通過echo XXXX>/proc/sys/net/core/hot_list_length完成。再比如listen函數(shù)的第2個(gè)參數(shù)(TCP完成3次握手 的數(shù)據(jù)包隊(duì)列長度),也可以根據(jù)你平臺(tái)內(nèi)存大小動(dòng)態(tài)調(diào)整。更甚至在一個(gè)數(shù)據(jù)包面數(shù)目巨大但同時(shí)每個(gè)數(shù)據(jù)包本身大小卻很小的特殊系統(tǒng)上嘗試最新的NAPI網(wǎng)卡驅(qū)動(dòng)架構(gòu)。

                (epoll內(nèi)容,參考epoll_互動(dòng)百科)

             

            4.   Nginx優(yōu)化

            1. 編譯安裝過程優(yōu)化

            1).減小Nginx編譯后的文件大小

            在編譯Nginx時(shí),默認(rèn)以debug模式進(jìn)行,而在debug模式下會(huì)插入很多跟蹤和ASSERT之類的信息,編譯完成后,一個(gè)Nginx要有好幾兆字節(jié)。而在編譯前取消Nginx的debug模式,編譯完成后Nginx只有幾百千字節(jié)。因此可以在編譯之前,修改相關(guān)源碼,取消debug模式。具體方法如下:

            在Nginx源碼文件被解壓后,找到源碼目錄下的auto/cc/gcc文件,在其中找到如下幾行:

             

            1. # debug  
            2. CFLAGS=”$CFLAGS -g” 

            注釋掉或刪掉這兩行,即可取消debug模式。

            2.為特定的CPU指定CPU類型編譯優(yōu)化

            在編譯Nginx時(shí),默認(rèn)的GCC編譯參數(shù)是“-O”,要優(yōu)化GCC編譯,可以使用以下兩個(gè)參數(shù):

             

            1. --with-cc-opt='-O3' 
            2. --with-cpu-opt=CPU  #為特定的 CPU 編譯,有效的值包括:
              pentium, pentiumpro, pentium3, # pentium4, athlon, opteron, amd64, sparc32, sparc64, ppc64 

            要確定CPU類型,可以通過如下命令:

             

            1. [root@localhost home]#cat /proc/cpuinfo | grep "model name" 

            2. 利用TCMalloc優(yōu)化Nginx的性能

            TCMalloc的全稱為Thread-Caching Malloc,是谷歌開發(fā)的開源工具google-perftools中的一個(gè)成員。與標(biāo)準(zhǔn)的glibc庫的Malloc相比,TCMalloc庫在內(nèi)存分配效率和速度上要高很多,這在很大程度上提高了服務(wù)器在高并發(fā)情況下的性能,從而降低了系統(tǒng)的負(fù)載。下面簡單介紹如何為Nginx添加TCMalloc庫支持。

            要安裝TCMalloc庫,需要安裝libunwind(32位操作系統(tǒng)不需要安裝)和google-perftools兩個(gè)軟件包,libunwind庫為基于64位CPU和操作系統(tǒng)的程序提供了基本函數(shù)調(diào)用鏈和函數(shù)調(diào)用寄存器功能。下面介紹利用TCMalloc優(yōu)化Nginx的具體操作過程。

            1).安裝libunwind庫

            可以從http://download.savannah.gnu.org/releases/libunwind下載相應(yīng)的libunwind版本,這里下載的是libunwind-0.99-alpha.tar.gz。安裝過程如下:

             

            1. [root@localhost home]#tar zxvf libunwind-0.99-alpha.tar.gz  
            2. [root@localhost home]# cd libunwind-0.99-alpha/  
            3. [root@localhost libunwind-0.99-alpha]#CFLAGS=-fPIC ./configure  
            4. [root@localhost libunwind-0.99-alpha]#make CFLAGS=-fPIC  
            5. [root@localhost libunwind-0.99-alpha]#make CFLAGS=-fPIC install 

            2).安裝google-perftools

            可以從http://google-perftools.googlecode.com下載相應(yīng)的google-perftools版本,這里下載的是google-perftools-1.8.tar.gz。安裝過程如下:

             

            1. [root@localhost home]#tar zxvf google-perftools-1.8.tar.gz  
            2. [root@localhost home]#cd google-perftools-1.8/  
            3. [root@localhost google-perftools-1.8]# ./configure  
            4. [root@localhost google-perftools-1.8]#make && make install  
            5. [root@localhost google-perftools-1.8]#echo "/usr/
              local/lib" 
              > /etc/ld.so.conf.d/usr_local_lib.conf  
            6. [root@localhost google-perftools-1.8]# ldconfig 

            至此,google-perftools安裝完成。

            3).重新編譯Nginx

            為了使Nginx支持google-perftools,需要在安裝過程中添加“–with-google_perftools_module”選項(xiàng)重新編譯Nginx。安裝代碼如下:

             

            1. [root@localhostnginx-0.7.65]#./configure \  
            2. >--with-google_perftools_module --with-http_stub_status_module  --prefix=/opt/nginx  
            3. [root@localhost nginx-0.7.65]#make  
            4. [root@localhost nginx-0.7.65]#make install 

            到這里Nginx安裝完成。

            4).為google-perftools添加線程目錄

            創(chuàng)建一個(gè)線程目錄,這里將文件放在/tmp/tcmalloc下。操作如下:

             

            1. [root@localhost home]#mkdir /tmp/tcmalloc  
            2. [root@localhost home]#chmod 0777 /tmp/tcmalloc 

            5).修改Nginx主配置文件

            修改nginx.conf文件,在pid這行的下面添加如下代碼:

             

            1. #pid        logs/nginx.pid;  
            2. google_perftools_profiles /tmp/tcmalloc; 

            接著,重啟Nginx即可完成google-perftools的加載。

            6).驗(yàn)證運(yùn)行狀態(tài)

            為了驗(yàn)證google-perftools已經(jīng)正常加載,可通過如下命令查看:

             

            1. [root@ localhost home]# lsof -n | grep tcmalloc  
            2. nginx      2395 nobody   9w  REG    8,8       0    1599440 /tmp/tcmalloc.2395  
            3. nginx      2396 nobody   11w REG   8,8       0    1599443 /tmp/tcmalloc.2396  
            4. nginx      2397 nobody   13w REG  8,8        0    1599441  /tmp/tcmalloc.2397  
            5. nginx     2398 nobody    15w REG  8,8     0    1599442 /tmp/tcmalloc.2398 

            由于在Nginx配置文件中設(shè)置worker_processes的值為4,因此開啟了4個(gè)Nginx線程,每個(gè)線程會(huì)有一行記錄。每個(gè)線程文件后面的數(shù)字值就是啟動(dòng)的Nginx的pid值。

            至此,利用TCMalloc優(yōu)化Nginx的操作完成。

            3.Nginx內(nèi)核參數(shù)優(yōu)化

            內(nèi)核參數(shù)的優(yōu)化,主要是在Linux系統(tǒng)中針對(duì)Nginx應(yīng)用而進(jìn)行的系統(tǒng)內(nèi)核參數(shù)優(yōu)化。

            下面給出一個(gè)優(yōu)化實(shí)例以供參考。

             

            1. net.ipv4.tcp_max_tw_buckets = 6000 
            2. net.ipv4.ip_local_port_range = 1024 65000  
            3. net.ipv4.tcp_tw_recycle = 1 
            4. net.ipv4.tcp_tw_reuse = 1 
            5. net.ipv4.tcp_syncookies = 1 
            6. net.core.somaxconn = 262144 
            7. net.core.netdev_max_backlog = 262144 
            8. net.ipv4.tcp_max_orphans = 262144 
            9. net.ipv4.tcp_max_syn_backlog = 262144 
            10. net.ipv4.tcp_synack_retries = 1 
            11. net.ipv4.tcp_syn_retries = 1 
            12. net.ipv4.tcp_fin_timeout = 1 
            13. net.ipv4.tcp_keepalive_time = 30 

            將上面的內(nèi)核參數(shù)值加入/etc/sysctl.conf文件中,然后執(zhí)行如下命令使之生效:

            1. [root@ localhost home]#/sbin/sysctl -p 

            下面對(duì)實(shí)例中選項(xiàng)的含義進(jìn)行介紹:

            net.ipv4.tcp_max_tw_buckets選項(xiàng)用來設(shè)定timewait的數(shù)量,默認(rèn)是180 000,這里設(shè)為6000。

            net.ipv4.ip_local_port_range選項(xiàng)用來設(shè)定允許系統(tǒng)打開的端口范圍。

            net.ipv4.tcp_tw_recycle選項(xiàng)用于設(shè)置啟用timewait快速回收。

            net.ipv4.tcp_tw_reuse選項(xiàng)用于設(shè)置開啟重用,允許將TIME-WAIT sockets重新用于新的TCP連接。

            net.ipv4.tcp_syncookies選項(xiàng)用于設(shè)置開啟SYN Cookies,當(dāng)出現(xiàn)SYN等待隊(duì)列溢出時(shí),啟用cookies進(jìn)行處理。

            net.core.somaxconn選項(xiàng)的默認(rèn)值是128, 這個(gè)參數(shù)用于調(diào)節(jié)系統(tǒng)同時(shí)發(fā)起的tcp連接數(shù),在高并發(fā)的請(qǐng)求中,默認(rèn)的值可能會(huì)導(dǎo)致鏈接超時(shí)或者重傳,因此,需要結(jié)合并發(fā)請(qǐng)求數(shù)來調(diào)節(jié)此值。

            net.core.netdev_max_backlog選項(xiàng)表示當(dāng)每個(gè)網(wǎng)絡(luò)接口接收數(shù)據(jù)包的速率比內(nèi)核處理這些包的速率快時(shí),允許發(fā)送到隊(duì)列的數(shù)據(jù)包的最大數(shù)目。

            net.ipv4.tcp_max_orphans選項(xiàng)用于設(shè)定系統(tǒng)中最多有多少個(gè)TCP套接字不被關(guān)聯(lián)到任何一個(gè)用戶文件句柄上。如果超過這個(gè)數(shù)字,孤立連接將立即被復(fù)位并打印出警告信息。這個(gè)限制只是為了防止簡單的DoS攻擊。不能過分依靠這個(gè)限制甚至人為減小這個(gè)值,更多的情況下應(yīng)該增加這個(gè)值。

            net.ipv4.tcp_max_syn_backlog選項(xiàng)用于記錄那些尚未收到客戶端確認(rèn)信息的連接請(qǐng)求的最大值。對(duì)于有128MB內(nèi)存的系統(tǒng)而言,此參數(shù)的默認(rèn)值是1024,對(duì)小內(nèi)存的系統(tǒng)則是128。

            net.ipv4.tcp_synack_retries參數(shù)的值決定了內(nèi)核放棄連接之前發(fā)送SYN+ACK包的數(shù)量。

            net.ipv4.tcp_syn_retries選項(xiàng)表示在內(nèi)核放棄建立連接之前發(fā)送SYN包的數(shù)量。

            net.ipv4.tcp_fin_timeout選項(xiàng)決定了套接字保持在FIN-WAIT-2狀態(tài)的時(shí)間。默認(rèn)值是60秒。正確設(shè)置這個(gè)值非常重要,有時(shí)即使一個(gè)負(fù)載很小的Web服務(wù)器,也會(huì)出現(xiàn)大量的死套接字而產(chǎn)生內(nèi)存溢出的風(fēng)險(xiǎn)。

            net.ipv4.tcp_syn_retries選項(xiàng)表示在內(nèi)核放棄建立連接之前發(fā)送SYN包的數(shù)量。

            如果發(fā)送端要求關(guān)閉套接字,net.ipv4.tcp_fin_timeout選項(xiàng)決定了套接字保持在FIN-WAIT-2狀態(tài)的時(shí)間。接收端可以出錯(cuò)并永遠(yuǎn)不關(guān)閉連接,甚至意外宕機(jī)。

            net.ipv4.tcp_fin_timeout的默認(rèn)值是60秒。需要注意的是,即使一個(gè)負(fù)載很小的Web服務(wù)器,也會(huì)出現(xiàn)因?yàn)榇罅康乃捞捉幼侄a(chǎn)生內(nèi)存溢出的風(fēng)險(xiǎn)。FIN-WAIT-2的危險(xiǎn)性比FIN-WAIT-1要小,因?yàn)樗疃嘀荒芟?.5KB的內(nèi)存,但是其生存期長些。

            net.ipv4.tcp_keepalive_time選項(xiàng)表示當(dāng)keepalive啟用的時(shí)候,TCP發(fā)送keepalive消息的頻度。默認(rèn)值是2(單位是小時(shí))。

            4. PHP-FPM的優(yōu)化

            如果您高負(fù)載網(wǎng)站使用PHP-FPMFastCGI,這些技巧也許對(duì)您有用:

            1)增加FastCGI進(jìn)程數(shù)

            PHP FastCGI子進(jìn)程數(shù)調(diào)到100或以上,4G內(nèi)存的服務(wù)器上200就可以建議通過壓力測試獲取最佳值。

            2)增加 PHP-FPM打開文件描述符的限制

            標(biāo)簽rlimit_files用于設(shè)置PHP-FPM對(duì)打開文件描述符的限制,默認(rèn)值為1024。這個(gè)標(biāo)簽的值必須和Linux內(nèi)核打開文件數(shù)關(guān)聯(lián)起來,例如,要將此值設(shè)置為65 535,就必須在Linux命令行執(zhí)行“ulimit -HSn 65536”。

                   然后 增加 PHP-FPM打開文件描述符的限制:
                 # vi /path/to/php-fpm.conf
                找到
            “<valuename="rlimit_files">1024</value>”
            把1024更改為 4096或者更高
            .
            重啟 PHP-FPM.


                     3)適當(dāng)增加max_requests

                標(biāo)簽max_requests指明了每個(gè)children最多處理多少個(gè)請(qǐng)求后便會(huì)被關(guān)閉,默認(rèn)的設(shè)置是500。

                <value name="max_requests"> 500 </value>

               

            5.   Nginx的php漏洞

            漏洞介紹:nginx是一款高性能的web服務(wù)器,使用非常廣泛,其不僅經(jīng)常被用作反向代理,也可以非常好的支持PHP的運(yùn)行。80sec發(fā)現(xiàn)其中存在一個(gè)較為嚴(yán)重的安全問題,默認(rèn)情況下可能導(dǎo)致服務(wù)器錯(cuò)誤的將任何類型的文件以PHP的方式進(jìn)行解析,這將導(dǎo)致嚴(yán)重的安全問題,使得惡意的攻擊者可能攻陷支持php的nginx服務(wù)器。


            漏洞分析:nginx默認(rèn)以cgi的方式支持php的運(yùn)行,譬如在配置文件當(dāng)中可以以


            location ~ .php$ {
            root html;
            fastcgi_pass 127.0.0.1:9000;
            fastcgi_index index.php;
            fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
            include fastcgi_params;
            }

            的方式支持對(duì)php的解析,location對(duì)請(qǐng)求進(jìn)行選擇的時(shí)候會(huì)使用URI環(huán)境變量進(jìn)行選擇,其中傳遞到后端Fastcgi的關(guān)鍵變量SCRIPT_FILENAME由nginx生成的$fastcgi_script_name決定,而通過分析可以看到$fastcgi_script_name是直接由URI環(huán)境變量控制的,這里就是產(chǎn)生問題的點(diǎn)。而為了較好的支持PATH_INFO的提取,在PHP的配置選項(xiàng)里存在cgi.fix_pathinfo選項(xiàng),其目的是為了從SCRIPT_FILENAME里取出真正的腳本名。
            那么假設(shè)存在一個(gè)http://www.80sec.com/80sec.jpg,我們以如下的方式去訪問

            http://www.80sec.com/80sec.jpg/80sec.php


            將會(huì)得到一個(gè)URI

            /80sec.jpg/80sec.php

            經(jīng)過location指令,該請(qǐng)求將會(huì)交給后端的fastcgi處理,nginx為其設(shè)置環(huán)境變量SCRIPT_FILENAME,內(nèi)容為

            /scripts/80sec.jpg/80sec.php

            而在其他的webserver如lighttpd當(dāng)中,我們發(fā)現(xiàn)其中的SCRIPT_FILENAME被正確的設(shè)置為

            /scripts/80sec.jpg

            所以不存在此問題。
            后端的fastcgi在接受到該選項(xiàng)時(shí),會(huì)根據(jù)fix_pathinfo配置決定是否對(duì)SCRIPT_FILENAME進(jìn)行額外的處理,一般情況下如果不對(duì)fix_pathinfo進(jìn)行設(shè)置將影響使用PATH_INFO進(jìn)行路由選擇的應(yīng)用,所以該選項(xiàng)一般配置開啟。Php通過該選項(xiàng)之后將查找其中真正的腳本文件名字,查找的方式也是查看文件是否存在,這個(gè)時(shí)候?qū)⒎蛛x出SCRIPT_FILENAME和PATH_INFO分別為

            /scripts/80sec.jpg和80sec.php

            最后,以/scripts/80sec.jpg作為此次請(qǐng)求需要執(zhí)行的腳本,攻擊者就可以實(shí)現(xiàn)讓nginx以php來解析任何類型的文件了。

            POC: 訪問一個(gè)nginx來支持php的站點(diǎn),在一個(gè)任何資源的文件如robots.txt后面加上/80sec.php,這個(gè)時(shí)候你可以看到如下的區(qū)別:

            訪問http://www.80sec.com/robots.txt

            HTTP/1.1 200 OK
            Server: nginx/0.6.32
            Date: Thu, 20 May 2010 10:05:30 GMT
            Content-Type: text/plain
            Content-Length: 18
            Last-Modified: Thu, 20 May 2010 06:26:34 GMT
            Connection: keep-alive
            Keep-Alive: timeout=20
            Accept-Ranges: bytes

            訪問訪問http://www.80sec.com/robots.txt/80sec.php

            HTTP/1.1 200 OK
            Server: nginx/0.6.32
            Date: Thu, 20 May 2010 10:06:49 GMT
            Content-Type: text/html
            Transfer-Encoding: chunked
            Connection: keep-alive
            Keep-Alive: timeout=20
            X-Powered-By: PHP/5.2.6

            其中的Content-Type的變化說明了后端負(fù)責(zé)解析的變化,該站點(diǎn)就可能存在漏洞。

            漏洞廠商:http://www.nginx.org

            解決方案:

            我們已經(jīng)嘗試聯(lián)系官方,但是此前你可以通過以下的方式來減少損失

            關(guān)閉cgi.fix_pathinfo為0

            或者

            if ( $fastcgi_script_name ~ ..*/.*php ) {
            return 403;
            }

            PS: 鳴謝laruence大牛在分析過程中給的幫助

            posted on 2014-12-03 16:50 peakflys 閱讀(171) 評(píng)論(0)  編輯 收藏 引用


            只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。
            網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理


            <2025年5月>
            27282930123
            45678910
            11121314151617
            18192021222324
            25262728293031
            1234567

            導(dǎo)航

            統(tǒng)計(jì)

            公告

            人不淡定的時(shí)候,就愛表現(xiàn)出來,敲代碼如此,偶爾的靈感亦如此……

            常用鏈接

            留言簿(4)

            隨筆分類

            隨筆檔案

            文章檔案

            搜索

            最新評(píng)論

            閱讀排行榜

            評(píng)論排行榜

            久久午夜福利电影| 国产69精品久久久久观看软件| 国产成人综合久久精品红| A级毛片无码久久精品免费| 一本久久a久久精品vr综合| 精品伊人久久久| 伊人色综合久久天天人守人婷 | 久久精品亚洲乱码伦伦中文| 久久综合给合久久国产免费| 人妻精品久久久久中文字幕69| 久久综合亚洲鲁鲁五月天| 亚洲欧美成人久久综合中文网| 日本久久久久久久久久| 日韩欧美亚洲国产精品字幕久久久| 久久精品无码专区免费| 亚洲欧美日韩精品久久亚洲区| 色婷婷久久久SWAG精品| 无码乱码观看精品久久| 伊人色综合久久天天人守人婷| 久久精品卫校国产小美女| 久久人人爽人人人人片av| 亚洲午夜久久久久久噜噜噜| 久久亚洲精品中文字幕| 国内精品久久久久| 精品久久久久久无码中文野结衣 | 99久久精品国产一区二区三区| 久久噜噜电影你懂的| 精品久久人人做人人爽综合| 亚洲精品无码久久久| 亚洲国产精品无码久久| 国产成人久久精品一区二区三区 | 久久精品无码一区二区三区免费| 久久亚洲精品无码观看不卡| 久久伊人精品一区二区三区| 欧美牲交A欧牲交aⅴ久久| 久久夜色精品国产亚洲| 欧美精品福利视频一区二区三区久久久精品 | 久久亚洲精品国产亚洲老地址| 亚洲国产精品无码久久| 国产精品久久久久影院色| 精品国产综合区久久久久久|