Nginx與php工作原理

1.? Nginx的模塊與工作原理

Nginx由內(nèi)核和模塊組成肛捍,其中共虑,內(nèi)核的設(shè)計(jì)非常微小和簡(jiǎn)潔允扇,完成的工作也非常簡(jiǎn)單缠局,僅僅通過(guò)查找配置文件將客戶端請(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ù)自己的需要開(kāi)發(fā)的模塊都屬于第三方模塊粥脚。正是有了這么多模塊的支撐窃肠,Nginx的功能才會(huì)如此強(qiáng)大。

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

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

Filters (過(guò)濾器模塊)。此類模塊主要對(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)的過(guò)程萝映。

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

Nginx本身做的工作實(shí)際很少,當(dāng)它接到一個(gè)HTTP請(qǐng)求時(shí)序臂,它僅僅是通過(guò)查找配置文件將此次請(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è)模塊來(lái)完成。

2. ?Nginx的進(jìn)程模型

在工作方式上圆到,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)程模式。

Nginx在啟動(dòng)后白胀,會(huì)有一個(gè)master進(jìn)程和多個(gè)worker進(jìn)程椭赋。

master進(jìn)程

主要用來(lái)管理worker進(jìn)程,包含:接收來(lái)自外界的信號(hào)或杠,向各worker進(jìn)程發(fā)送信號(hào)哪怔,監(jiān)控worker進(jìn)程的運(yùn)行狀態(tài),當(dāng)worker進(jìn)程退出后(異常情況下)向抢,會(huì)自動(dòng)重新啟動(dòng)新的worker進(jìn)程认境。

master進(jìn)程充當(dāng)整個(gè)進(jìn)程組與用戶的交互接口,同時(shí)對(duì)進(jìn)程進(jìn)行監(jiān)護(hù)挟鸠。它不需要處理網(wǎng)絡(luò)事件叉信,不負(fù)責(zé)業(yè)務(wù)的執(zhí)行,只會(huì)通過(guò)管理worker進(jìn)程來(lái)實(shí)現(xiàn)重啟服務(wù)艘希、平滑升級(jí)硼身、更換日志文件硅急、配置文件實(shí)時(shí)生效等功能。

我們要控制nginx佳遂,只需要通過(guò)kill向master進(jìn)程發(fā)送信號(hào)就行了营袜。比如kill

-HUP

pid,則是告訴nginx讶迁,從容地重啟nginx,我們一般用這個(gè)信號(hào)來(lái)重啟nginx核蘸,或重新加載配置巍糯,因?yàn)槭菑娜莸刂貑ⅲ虼朔?wù)是不中斷的客扎。master進(jìn)程在接收到HUP信號(hào)后是怎么做的呢祟峦?首先master進(jìn)程在接到信號(hào)后,會(huì)先重新加載配置文件徙鱼,然后再啟動(dòng)新的worker進(jìn)程宅楞,并向所有老的worker進(jìn)程發(fā)送信號(hào),告訴他們可以光榮退休了袱吆。新的worker在啟動(dòng)后厌衙,就開(kāi)始接收新的請(qǐng)求,而老的worker在收到來(lái)自master的信號(hào)后绞绒,就不再接收新的請(qǐng)求婶希,并且在當(dāng)前進(jìn)程中的所有未處理完的請(qǐng)求處理完成后,再退出蓬衡。當(dāng)然喻杈,直接給master進(jìn)程發(fā)送信號(hào),這是比較老的操作方式狰晚,nginx在0.8版本之后筒饰,引入了一系列命令行參數(shù),來(lái)方便我們管理壁晒。比如瓷们,./nginx

-s reload,就是來(lái)重啟nginx秒咐,./nginx -s

stop换棚,就是來(lái)停止nginx的運(yùn)行。如何做到的呢反镇?我們還是拿reload來(lái)說(shuō)固蚤,我們看到,執(zhí)行命令時(shí)歹茶,我們是啟動(dòng)一個(gè)新的nginx進(jìn)程夕玩,而新的nginx進(jìn)程在解析到reload參數(shù)后你弦,就知道我們的目的是控制nginx來(lái)重新加載配置文件了,它會(huì)向master進(jìn)程發(fā)送信號(hào)燎孟,然后接下來(lái)的動(dòng)作禽作,就和我們直接向master進(jìn)程發(fā)送信號(hào)一樣了。

worker進(jìn)程:

而基本的網(wǎng)絡(luò)事件揩页,則是放在worker進(jìn)程中來(lái)處理了旷偿。多個(gè)worker進(jìn)程之間是對(duì)等的,他們同等競(jìng)爭(zhēng)來(lái)自客戶端的請(qǐng)求爆侣,各進(jìn)程互相之間是獨(dú)立的萍程。一個(gè)請(qǐng)求,只可能在一個(gè)worker進(jìn)程中處理兔仰,一個(gè)worker進(jìn)程茫负,不可能處理其它進(jìn)程的請(qǐng)求。worker進(jìn)程的個(gè)數(shù)是可以設(shè)置的乎赴,一般我們會(huì)設(shè)置與機(jī)器cpu核數(shù)一致忍法,這里面的原因與nginx的進(jìn)程模型以及事件處理模型是分不開(kāi)的。

worker進(jìn)程之間是平等的榕吼,每個(gè)進(jìn)程饿序,處理請(qǐng)求的機(jī)會(huì)也是一樣的。當(dāng)我們提供80端口的http服務(wù)時(shí)羹蚣,一個(gè)連接請(qǐng)求過(guò)來(lái)嗤堰,每個(gè)進(jìn)程都有可能處理這個(gè)連接,怎么做到的呢度宦?首先踢匣,每個(gè)worker進(jìn)程都是從master進(jìn)程fork過(guò)來(lái),在master進(jìn)程里面戈抄,先建立好需要listen的socket(listenfd)之后离唬,然后再fork出多個(gè)worker進(jìn)程。所有worker進(jìn)程的listenfd會(huì)在新連接到來(lái)時(shí)變得可讀划鸽,為保證只有一個(gè)進(jìn)程處理該連接输莺,所有worker進(jìn)程在注冊(cè)listenfd讀事件前搶accept_mutex,搶到互斥鎖的那個(gè)進(jìn)程注冊(cè)listenfd讀事件裸诽,在讀事件里調(diào)用accept接受該連接嫂用。當(dāng)一個(gè)worker進(jìn)程在accept這個(gè)連接之后,就開(kāi)始讀取請(qǐng)求丈冬,解析請(qǐng)求嘱函,處理請(qǐng)求,產(chǎn)生數(shù)據(jù)后埂蕊,再返回給客戶端往弓,最后才斷開(kāi)連接疏唾,這樣一個(gè)完整的請(qǐng)求就是這樣的了。我們可以看到函似,一個(gè)請(qǐng)求槐脏,完全由worker進(jìn)程來(lái)處理,而且只在一個(gè)worker進(jìn)程中處理撇寞。worker進(jìn)程之間是平等的顿天,每個(gè)進(jìn)程,處理請(qǐng)求的機(jī)會(huì)也是一樣的蔑担。當(dāng)我們提供80端口的http服務(wù)時(shí)牌废,一個(gè)連接請(qǐng)求過(guò)來(lái),每個(gè)進(jìn)程都有可能處理這個(gè)連接钟沛,怎么做到的呢畔规?首先局扶,每個(gè)worker進(jìn)程都是從master進(jìn)程fork過(guò)來(lái)恨统,在master進(jìn)程里面,先建立好需要listen的socket(listenfd)之后三妈,然后再fork出多個(gè)worker進(jìn)程畜埋。所有worker進(jìn)程的listenfd會(huì)在新連接到來(lái)時(shí)變得可讀,為保證只有一個(gè)進(jìn)程處理該連接畴蒲,所有worker進(jìn)程在注冊(cè)listenfd讀事件前搶accept_mutex悠鞍,搶到互斥鎖的那個(gè)進(jìn)程注冊(cè)listenfd讀事件,在讀事件里調(diào)用accept接受該連接模燥。當(dāng)一個(gè)worker進(jìn)程在accept這個(gè)連接之后咖祭,就開(kāi)始讀取請(qǐng)求,解析請(qǐng)求蔫骂,處理請(qǐng)求么翰,產(chǎn)生數(shù)據(jù)后,再返回給客戶端辽旋,最后才斷開(kāi)連接浩嫌,這樣一個(gè)完整的請(qǐng)求就是這樣的了充蓝。我們可以看到靠抑,一個(gè)請(qǐng)求清钥,完全由worker進(jìn)程來(lái)處理弄痹,而且只在一個(gè)worker進(jìn)程中處理赤兴。

nginx的進(jìn)程模型管宵,可以由下圖來(lái)表示:

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

1懊悯、什么是 FastCGI

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

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

FastCGI接口方式采用C/S結(jié)構(gòu)苹威,可以將HTTP服務(wù)器和腳本解析服務(wù)器分開(kāi),同時(shí)在腳本解析服務(wù)器上啟動(dòng)一個(gè)或者多個(gè)腳本解析守護(hù)進(jìn)程驾凶。當(dāng)HTTP服務(wù)器每次遇到動(dòng)態(tài)程序時(shí)牙甫,可以將其直接交付給FastCGI進(jìn)程來(lái)執(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)必須通過(guò)FastCGI接口來(lái)調(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í)候玷过,通過(guò)FastCGI接口爽丹,wrapper接收到請(qǐng)求,然后Fork(派生)出一個(gè)新的線程辛蚊,這個(gè)線程調(diào)用解釋器或者外部程序處理腳本并讀取返回?cái)?shù)據(jù)粤蝎;接著,wrapper再將返回的數(shù)據(jù)通過(guò)FastCGI接口袋马,沿著固定的socket傳遞給Nginx初澎;最后,Nginx將返回的數(shù)據(jù)(html頁(yè)面或者圖片)發(fā)送給客戶端。這就是Nginx+FastCGI的整個(gè)運(yùn)作過(guò)程碑宴,如圖1-3所示软啼。

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

通過(guò)調(diào)用fastcgi(庫(kù))的函數(shù)通過(guò)socket和ningx通信(讀寫(xiě)socket是fastcgi內(nèi)部實(shí)現(xiàn)的功能祸挪,對(duì)wrapper是非透明的)

調(diào)度thread,進(jìn)行fork和kill

和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完全解放出來(lái),可以更好地進(jìn)行響應(yīng)和并發(fā)處理峻仇。

spawn-fcgi與PHP-FPM的異同:

1)spawn-fcgi是HTTP服務(wù)器lighttpd的一部分公黑,目前已經(jīng)獨(dú)立成為一個(gè)項(xiàng)目,一般與lighttpd配合使用來(lái)支持PHP摄咆。但是ligttpd的spwan-fcgi在高并發(fā)訪問(wèn)的時(shí)候凡蚜,會(huì)出現(xiàn)內(nèi)存泄漏甚至自動(dòng)重啟FastCGI的問(wèn)題。即:PHP腳本處理器當(dāng)機(jī)豆同,這個(gè)時(shí)候如果用戶訪問(wèn)的話番刊,可能就會(huì)出現(xiàn)白頁(yè)(即PHP不能被解析或者出錯(cuò))含鳞。

2)Nginx是個(gè)輕量級(jí)的HTTP server影锈,必須借助第三方的FastCGI處理器才可以對(duì)PHP進(jìn)行解析,因此其實(shí)這樣看來(lái)nginx是非常靈活的蝉绷,它可以和任何第三方提供解析的處理器實(shí)現(xiàn)連接從而實(shí)現(xiàn)對(duì)PHP的解析(在nginx.conf中很容易設(shè)置)鸭廷。nginx也可以使用spwan-fcgi(需要一同安裝lighttpd,但是需要為nginx避開(kāi)端口熔吗,一些較早的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比較起來(lái)有如下優(yōu)點(diǎn):

由于它是作為PHP的patch補(bǔ)丁來(lái)開(kāi)發(fā)的中跌,安裝的時(shí)候需要和php源碼一起編譯咨堤,也就是說(shuō)編譯到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則沒(méi)有這種煩惱。

FastCGI 的主要優(yōu)點(diǎn)是把動(dòng)態(tài)語(yǔ)言和HTTP Server分離開(kāi)來(lái)蚂维,所以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ù)即可開(kāi)啟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)聽(tīng)的ip地址以及端口

start_servers

min_spare_servers

max_spare_servers

Nginx配置運(yùn)行php:編輯nginx.conf加入如下語(yǔ)句:

location ~ \.php$ {

root html;

fastcgi_pass 127.0.0.1:9000;指定了fastcgi進(jìn)程偵聽(tīng)的端口,nginx就是通過(guò)這里與php交互的

fastcgi_index index.php;

include fastcgi_params;

fastcgi_param SCRIPT_FILENAME?? /usr/local/nginx/html$fastcgi_script_name;

}

Nginx通過(guò)location指令,將所有以php為后綴的文件都交給127.0.0.1:9000來(lái)處理颁独,而這里的IP地址和端口就是FastCGI進(jìn)程監(jiān)聽(tīng)的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)聽(tīng)9000端口。

fastcgi子進(jìn)程等待來(lái)自Web Server的連接坯墨。

2)寂汇、當(dāng)客戶端請(qǐng)求到達(dá)Web Server Nginx是時(shí),Nginx通過(guò)location指令捣染,將所有以php為后綴的文件都交給127.0.0.1:9000來(lái)處理骄瓣,即Nginx通過(guò)location指令,將所有以php為后綴的文件都交給127.0.0.1:9000來(lái)處理耍攘。

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)程接著等待并處理來(lái)自FastCGI進(jìn)程管理器(運(yùn)行在 WebServer中)的下一個(gè)連接。

4. ? Nginx+PHP正確配置

一般web都做統(tǒng)一入口:把PHP請(qǐng)求都發(fā)送到同一個(gè)文件上吝羞,然后在此文件里通過(guò)解析「REQUEST_URI」實(shí)現(xiàn)路由兰伤。

Nginx配置文件分為好多塊,常見(jiàn)的從外到內(nèi)依次是「http」钧排、「server」敦腔、「location」等等,缺省的繼承關(guān)系是從外到內(nèi)恨溜,也就是說(shuō)內(nèi)層塊會(huì)自動(dòng)獲取外層塊的值作為缺省值符衔。

例如:

[plain]view plaincopy

print?

server?{

listen?80;

server_name?foo.com;

root?/path;

location?/?{

index?index.html?index.htm?index.php;

if?(!-e?$request_filename)?{

rewrite?.?/index.php?last;

}

}

location?~?\.php$?{

include?fastcgi_params;

fastcgi_param?SCRIPT_FILENAME?/path$fastcgi_script_name;

fastcgi_pass?127.0.0.1:9000;

fastcgi_index?index.php;

}

}

1) ?不應(yīng)該在location

模塊定義index

一旦未來(lái)需要加入新的「location」,必然會(huì)出現(xiàn)重復(fù)定義的「index」指令筒捺,這是因?yàn)槎鄠€(gè)「location」是平級(jí)的關(guān)系柏腻,不存在繼承纸厉,此時(shí)應(yīng)該在「server」里定義「index」系吭,借助繼承關(guān)系,「index」指令在所有的「location」中都能生效颗品。

2)使用try_files

接下來(lái)看看「if」指令肯尺,說(shuō)它是大家誤解最深的Nginx指令毫不為過(guò):

if (!-e $request_filename) {

rewrite . /index.php last;

}

很多人喜歡用「if」指令做一系列的檢查,不過(guò)這實(shí)際上是「try_files」指令的職責(zé):

try_files $uri $uri/ /index.php;

除此以外躯枢,初學(xué)者往往會(huì)認(rèn)為「if」指令是內(nèi)核級(jí)的指令则吟,但是實(shí)際上它是rewrite模塊的一部分,加上Nginx配置實(shí)際上是聲明式的锄蹂,而非過(guò)程式的氓仲,所以當(dāng)其和非rewrite模塊的指令混用時(shí),結(jié)果可能會(huì)非你所愿。

3)fastcgi_params」配置文件

include fastcgi_params;

Nginx有兩份fastcgi配置文件敬扛,分別是「fastcgi_params」和「fastcgi.conf」晰洒,它們沒(méi)有太大的差異,唯一的區(qū)別是后者比前者多了一行「SCRIPT_FILENAME」的定義:

fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;

注意:$document_root 和 $fastcgi_script_name 之間沒(méi)有 /啥箭。

原本Nginx只有「fastcgi_params」谍珊,后來(lái)發(fā)現(xiàn)很多人在定義「SCRIPT_FILENAME」時(shí)使用了硬編碼的方式,于是為了規(guī)范用法便引入了「fastcgi.conf」急侥。

不過(guò)這樣的話就產(chǎn)生一個(gè)疑問(wèn):為什么一定要引入一個(gè)新的配置文件砌滞,而不是修改舊的配置文件?這是因?yàn)椤竑astcgi_param」指令是數(shù)組型的坏怪,和普通指令相同的是:內(nèi)層替換外層贝润;和普通指令不同的是:當(dāng)在同級(jí)多次使用的時(shí)候,是新增而不是替換铝宵。換句話說(shuō)题暖,如果在同級(jí)定義兩次「SCRIPT_FILENAME」,那么它們都會(huì)被發(fā)送到后端捉超,這可能會(huì)導(dǎo)致一些潛在的問(wèn)題胧卤,為了避免此類情況,便引入了一個(gè)新的配置文件拼岳。

此外枝誊,我們還需要考慮一個(gè)安全問(wèn)題:在PHP開(kāi)啟「cgi.fix_pathinfo」的情況下,PHP可能會(huì)把錯(cuò)誤的文件類型當(dāng)作PHP文件來(lái)解析惜纸。如果Nginx和PHP安裝在同一臺(tái)服務(wù)器上的話叶撒,那么最簡(jiǎn)單的解決方法是用「try_files」指令做一次過(guò)濾:

try_files $uri =404;

依照前面的分析,給出一份改良后的版本耐版,是不是比開(kāi)始的版本清爽了很多:

[plain]view plaincopy

print?

server?{

listen?80;

server_name?foo.com;

root?/path;

index?index.html?index.htm?index.php;

location?/?{

try_files?$uri?$uri/?/index.php;

}

location?~?\.php$?{

try_files?$uri?=404;

include?fastcgi.conf;

fastcgi_pass?127.0.0.1:9000;

}

}

5. ? Nginx為啥性能高-多進(jìn)程IO模型

參考http://mp.weixin.qq.com/s?__biz=MjM5NTg2NTU0Ng==&mid=407889757&idx=3&sn=cfa8a70a5fd2a674a91076f67808273c&scene=23&srcid=0401aeJQEraSG6uvLj69Hfve#rd

1祠够、nginx采用多進(jìn)程模型好處

首先,對(duì)于每個(gè)worker進(jìn)程來(lái)說(shuō)粪牲,獨(dú)立的進(jìn)程古瓤,不需要加鎖,所以省掉了鎖帶來(lái)的開(kāi)銷腺阳,同時(shí)在編程以及問(wèn)題查找時(shí)落君,也會(huì)方便很多。

其次亭引,采用獨(dú)立的進(jìn)程绎速,可以讓互相之間不會(huì)影響,一個(gè)進(jìn)程退出后焙蚓,其它進(jìn)程還在工作纹冤,服務(wù)不會(huì)中斷歇攻,master進(jìn)程則很快啟動(dòng)新的worker進(jìn)程乌助。當(dāng)然缠犀,worker進(jìn)程的異常退出俊柔,肯定是程序有bug了,異常退出枫夺,會(huì)導(dǎo)致當(dāng)前worker上的所有請(qǐng)求失敗将宪,不過(guò)不會(huì)影響到所有請(qǐng)求,所以降低了風(fēng)險(xiǎn)橡庞。

1较坛、nginx多進(jìn)程事件模型:異步非阻塞

雖然nginx采用多worker的方式來(lái)處理請(qǐng)求,每個(gè)worker里面只有一個(gè)主線程扒最,那能夠處理的并發(fā)數(shù)很有限啊丑勤,多少個(gè)worker就能處理多少個(gè)并發(fā),何來(lái)高并發(fā)呢吧趣?非也法竞,這就是nginx的高明之處,nginx采用了異步非阻塞的方式來(lái)處理請(qǐng)求强挫,也就是說(shuō)岔霸,nginx是可以同時(shí)處理成千上萬(wàn)個(gè)請(qǐng)求的。一個(gè)worker進(jìn)程可以同時(shí)處理的請(qǐng)求數(shù)只受限于內(nèi)存大小俯渤,而且在架構(gòu)設(shè)計(jì)上呆细,不同的worker進(jìn)程之間處理并發(fā)請(qǐng)求時(shí)幾乎沒(méi)有同步鎖的限制,worker進(jìn)程通常不會(huì)進(jìn)入睡眠狀態(tài)八匠,因此絮爷,當(dāng)Nginx上的進(jìn)程數(shù)與CPU核心數(shù)相等時(shí)(最好每一個(gè)worker進(jìn)程都綁定特定的CPU核心),進(jìn)程間切換的代價(jià)是最小的梨树。

而apache的常用工作方式(apache也有異步非阻塞版本坑夯,但因其與自帶某些模塊沖突,所以不常用)抡四,每個(gè)進(jìn)程在一個(gè)時(shí)刻只處理一個(gè)請(qǐng)求柜蜈,因此,當(dāng)并發(fā)數(shù)上到幾千時(shí)床嫌,就同時(shí)有幾千的進(jìn)程在處理請(qǐng)求了跨释。這對(duì)操作系統(tǒng)來(lái)說(shuō),是個(gè)不小的挑戰(zhàn)厌处,進(jìn)程帶來(lái)的內(nèi)存占用非常大,進(jìn)程的上下文切換帶來(lái)的cpu開(kāi)銷很大岁疼,自然性能就上不去了阔涉,而這些開(kāi)銷完全是沒(méi)有意義的缆娃。

為什么nginx可以采用異步非阻塞的方式來(lái)處理呢,或者異步非阻塞到底是怎么回事呢瑰排?

我們先回到原點(diǎn)贯要,看看一個(gè)請(qǐng)求的完整過(guò)程:首先,請(qǐng)求過(guò)來(lái)椭住,要建立連接崇渗,然后再接收數(shù)據(jù),接收數(shù)據(jù)后京郑,再發(fā)送數(shù)據(jù)宅广。

具體到系統(tǒng)底層,就是讀寫(xiě)事件些举,而當(dāng)讀寫(xiě)事件沒(méi)有準(zhǔn)備好時(shí)跟狱,必然不可操作,如果不用非阻塞的方式來(lái)調(diào)用户魏,那就得阻塞調(diào)用了驶臊,事件沒(méi)有準(zhǔn)備好,那就只能等了叼丑,等事件準(zhǔn)備好了关翎,你再繼續(xù)吧。阻塞調(diào)用會(huì)進(jìn)入內(nèi)核等待鸠信,cpu就會(huì)讓出去給別人用了笤休,對(duì)單線程的worker來(lái)說(shuō),顯然不合適症副,當(dāng)網(wǎng)絡(luò)事件越多時(shí)店雅,大家都在等待呢,cpu空閑下來(lái)沒(méi)人用贞铣,cpu利用率自然上不去了闹啦,更別談高并發(fā)了。好吧辕坝,你說(shuō)加進(jìn)程數(shù)窍奋,這跟apache的線程模型有什么區(qū)別,注意酱畅,別增加無(wú)謂的上下文切換琳袄。所以,在nginx里面纺酸,最忌諱阻塞的系統(tǒng)調(diào)用了窖逗。不要阻塞,那就非阻塞嘍餐蔬。非阻塞就是碎紊,事件沒(méi)有準(zhǔn)備好佑附,馬上返回EAGAIN,告訴你仗考,事件還沒(méi)準(zhǔn)備好呢音同,你慌什么,過(guò)會(huì)再來(lái)吧秃嗜。好吧权均,你過(guò)一會(huì),再來(lái)檢查一下事件锅锨,直到事件準(zhǔn)備好了為止叽赊,在這期間,你就可以先去做其它事情橡类,然后再來(lái)看看事件好了沒(méi)蛇尚。雖然不阻塞了,但你得不時(shí)地過(guò)來(lái)檢查一下事件的狀態(tài)顾画,你可以做更多的事情了取劫,但帶來(lái)的開(kāi)銷也是不小的。

關(guān)于IO模型:http://blog.csdn.NET/hguisu/article/details/7453390

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

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

select– 標(biāo)準(zhǔn)方法。 如果當(dāng)前平臺(tái)沒(méi)有更有效的方法庶诡,它是編譯時(shí)默認(rèn)的方法惦银。你可以使用配置參數(shù) –with-select_module 和 –without-select_module 來(lái)啟用或禁用這個(gè)模塊。

poll– 標(biāo)準(zhǔn)方法末誓。 如果當(dāng)前平臺(tái)沒(méi)有更有效的方法扯俱,它是編譯時(shí)默認(rèn)的方法。你可以使用配置參數(shù) –with-poll_module 和 –without-poll_module 來(lái)啟用或禁用這個(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ù)器來(lái)說(shuō)是低效的尔当;所以有必要通過(guò)調(diào)節(jié)內(nèi)核參數(shù) /proc/sys/kernel/rtsig-max 來(lái)增加隊(duì)列的大小±糯撸可是從Linux內(nèi)核版本2.6.6-mm2開(kāi)始居凶, 這個(gè)參數(shù)就不再使用了虫给,并且對(duì)于每個(gè)進(jìn)程有一個(gè)獨(dú)立的信號(hào)隊(duì)列藤抡,這個(gè)隊(duì)列的大小可以用 RLIMIT_SIGPENDING 參數(shù)調(diào)節(jié)侠碧。當(dāng)這個(gè)隊(duì)列過(guò)于擁塞,nginx就放棄它并且開(kāi)始使用 poll 方法來(lái)處理連接直到恢復(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)核崩潰的問(wèn)題瓷式, 有必要安裝這個(gè)安全補(bǔ)丁替饿。

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

下面再來(lái)看看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)程打開(kāi)大數(shù)目的socket描述符(FD)

select 最不能忍受的是一個(gè)進(jìn)程所打開(kāi)的FD是有一定限制的妒挎,由FD_SETSIZE設(shè)置绳锅,默認(rèn)值是2048。對(duì)于那些需要支持的上萬(wàn)連接數(shù)目的IM服務(wù)器來(lái)說(shuō)顯 然太少了酝掩。這時(shí)候你一是可以選擇修改這個(gè)宏然后重新編譯內(nèi)核鳞芙,不過(guò)資料也同時(shí)指出這樣會(huì)帶來(lái)網(wǎng)絡(luò)效率的下降,二是可以選擇多進(jìn)程的解決方案(傳統(tǒng)的 Apache方案)期虾,不過(guò)雖然linux上面創(chuàng)建進(jìn)程的代價(jià)比較小原朝,但仍舊是不可忽視的,加上進(jìn)程間數(shù)據(jù)同步遠(yuǎn)比不上線程間同步的高效镶苞,所以也不是一種完

美的方案喳坠。不過(guò) epoll則沒(méi)有這個(gè)限制,它所支持的FD上限是最大可以打開(kāi)文件的數(shù)目宾尚,這個(gè)數(shù)字一般遠(yuǎn)大于2048,舉個(gè)例子,在1GB內(nèi)存的機(jī)器上大約是10萬(wàn)左 右丙笋,具體數(shù)目可以cat /proc/sys/fs/file-max察看,一般來(lái)說(shuō)這個(gè)數(shù)目和系統(tǒng)內(nèi)存關(guān)系很大。

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

傳統(tǒng)的select/poll另一個(gè)致命弱點(diǎn)就是當(dāng)你擁有一個(gè)很大的socket集合煌贴,不過(guò)由于網(wǎng)絡(luò)延時(shí)御板,任一時(shí)間只有部分的socket是”活躍”的,但 是select/poll每次調(diào)用都會(huì)線性掃描全部的集合牛郑,導(dǎo)致效率呈現(xiàn)線性下降怠肋。但是epoll不存在這個(gè)問(wèn)題,它只會(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有什么效率,相 反歼捐,如果過(guò)多使用epoll_ctl,效率相比還有稍微的下降何陆。但是一旦使用idle connections模擬WAN環(huán)境,epoll的效率就遠(yuǎn)在select/poll之上了。

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

這 點(diǎn)實(shí)際上涉及到epoll的具體實(shí)現(xiàn)了贷盲。無(wú)論是select,poll還是epoll都需要內(nèi)核把FD消息通知給用戶空間,如何避免不必要的內(nèi)存拷貝就很 重要剥扣,在這點(diǎn)上巩剖,epoll是通過(guò)內(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)吃引,但是你無(wú)法回避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)的大小— 通過(guò)echo XXXX>/proc/sys/net/core/hot_list_length完成。再比如listen函數(shù)的第2個(gè)參數(shù)(TCP完成3次握手 的數(shù)據(jù)包隊(duì)列長(zhǎng)度)并思,也可以根據(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)百科)

推薦設(shè)置worker的個(gè)數(shù)為cpu的核數(shù)弄砍,在這里就很容易理解了,更多的worker數(shù)输涕,只會(huì)導(dǎo)致進(jìn)程來(lái)競(jìng)爭(zhēng)cpu資源了音婶,從而帶來(lái)不必要的上下文切換。而且莱坎,nginx為了更好的利用多核特性衣式,提供了cpu親緣性的綁定選項(xiàng),我們可以將某一個(gè)進(jìn)程綁定在某一個(gè)核上,這樣就不會(huì)因?yàn)檫M(jìn)程的切換帶來(lái)cache的失效碴卧。像這種小的優(yōu)化在nginx中非常常見(jiàn)弱卡,同時(shí)也說(shuō)明了nginx作者的苦心孤詣。比如住册,nginx在做4個(gè)字節(jié)的字符串比較時(shí)婶博,會(huì)將4個(gè)字符轉(zhuǎn)換成一個(gè)int型,再作比較界弧,以減少cpu的指令數(shù)等等凡蜻。

代碼來(lái)總結(jié)一下nginx的事件處理模型:

[cpp]view plaincopy

print?

while(true)?{

fort?in?run_tasks:

t.handler();

update_time(&now);

timeout?=?ETERNITY;

fort?in?wait_tasks:/*?sorted?already?*/

if(t.time?<=?now)?{

t.timeout_handler();

}else{

timeout?=?t.time?-?now;

break;

}

nevents?=?poll_function(events,?timeout);

fori?in?nevents:

task?t;

if(events[i].type?==?READ)?{

t.handler?=?read_handler;

}else{/*?events[i].type?==?WRITE?*/

t.handler?=?write_handler;

}

run_tasks_add(t);

}

6. ? Nginx優(yōu)化

1. 編譯安裝過(guò)程優(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文件,在其中找到如下幾行:

#?debug

CFLAGS=”$CFLAGS?-g”

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

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

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

--with-cc-opt='-O3'

--with-cpu-opt=CPU#為特定的?CPU?編譯,有效的值包括:

pentium,?pentiumpro,?pentium3,?#?pentium4,?athlon,?opteron,?amd64,?sparc32,?sparc64,?ppc64

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

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

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

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

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

1).安裝libunwind庫(kù)

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

[root@localhost?home]#tar?zxvf?libunwind-0.99-alpha.tar.gz

[root@localhost?home]#?cd?libunwind-0.99-alpha/

[root@localhost?libunwind-0.99-alpha]#CFLAGS=-fPIC?./configure

[root@localhost?libunwind-0.99-alpha]#makeCFLAGS=-fPIC

[root@localhost?libunwind-0.99-alpha]#makeCFLAGS=-fPIC?install

2).安裝google-perftools

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

[root@localhost?home]#tar?zxvf?google-perftools-1.8.tar.gz

[root@localhost?home]#cd?google-perftools-1.8/

[root@localhost?google-perftools-1.8]#?./configure

[root@localhost?google-perftools-1.8]#make?&&?make?install

[root@localhost?google-perftools-1.8]#echo?"/usr/

local/lib">/etc/ld.so.conf.d/usr_local_lib.conf

[root@localhost?google-perftools-1.8]#?ldconfig

至此,google-perftools安裝完成荣茫。

3).重新編譯Nginx

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

[root@localhostnginx-0.7.65]#./configure?\

>--with-google_perftools_module?--with-http_stub_status_module--prefix=/opt/nginx

[root@localhost?nginx-0.7.65]#make

[root@localhost?nginx-0.7.65]#make?install

到這里Nginx安裝完成啡莉。

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

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

[root@localhost?home]#mkdir?/tmp/tcmalloc

[root@localhost?home]#chmod?0777?/tmp/tcmalloc

5).修改Nginx主配置文件

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

#pid????????logs/nginx.pid;

google_perftools_profiles?/tmp/tcmalloc;

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

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

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

[root@?localhost?home]#?lsof?-n?|?grep?tcmalloc

nginx??????2395?nobody???9w??REG????8,8???????0????1599440?/tmp/tcmalloc.2395

nginx??????2396?nobody???11w?REG???8,8???????0????1599443?/tmp/tcmalloc.2396

nginx??????2397?nobody???13w?REG??8,8????????0????1599441??/tmp/tcmalloc.2397

nginx?????2398?nobody????15w?REG??8,8?????0????1599442?/tmp/tcmalloc.2398

由于在Nginx配置文件中設(shè)置worker_processes的值為4衩椒,因此開(kāi)啟了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í)例以供參考右遭。

net.ipv4.tcp_max_tw_buckets=6000

net.ipv4.ip_local_port_range=102465000

net.ipv4.tcp_tw_recycle=1

net.ipv4.tcp_tw_reuse=1

net.ipv4.tcp_syncookies=1

net.core.somaxconn=262144

net.core.netdev_max_backlog=262144

net.ipv4.tcp_max_orphans=262144

net.ipv4.tcp_max_syn_backlog=262144

net.ipv4.tcp_synack_retries=1

net.ipv4.tcp_syn_retries=1

net.ipv4.tcp_fin_timeout=1

net.ipv4.tcp_keepalive_time=30

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

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

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

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

net.ipv4.ip_local_port_range:選項(xiàng)用來(lái)設(shè)定允許系統(tǒng)打開(kāi)的端口范圍。在高并發(fā)情況否則端口號(hào)會(huì)不夠用宵距。

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

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

net.ipv4.tcp_syncookies:選項(xiàng)用于設(shè)置開(kāi)啟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ù)來(lái)調(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è)用戶文件句柄上着绷。如果超過(guò)這個(gè)數(shù)字,孤立連接將立即被復(fù)位并打印出警告信息锌云。這個(gè)限制只是為了防止簡(jiǎn)單的DoS攻擊荠医。不能過(guò)分依靠這個(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)存,但是其生存期長(zhǎng)些颈畸。

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-FPM管理FastCGI礁苗,這些技巧也許對(duì)您有用:

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

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

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

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

然后增加PHP-FPM打開(kāi)文件描述符的限制:

# vi /path/to/php-fpm.conf

找到“1024”

把1024更改為4096或者更高.

重啟PHP-FPM.

ulimit -n 要調(diào)整為65536甚至更大考廉。如何調(diào)這個(gè)參數(shù)秘豹,可以參考網(wǎng)上的一些文章。命令行下執(zhí)行 ulimit -n65536即可修改昌粤。如果不能修改既绕,需要設(shè)置??/etc/security/limits.conf,加入

* hard nofile65536

* soft nofile65536

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

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

500

4. nginx.conf的參數(shù)優(yōu)化

nginx要開(kāi)啟的進(jìn)程數(shù)一般等于cpu的總核數(shù) 其實(shí)一般情況下開(kāi)4個(gè)或8個(gè)就可以。

每個(gè)nginx進(jìn)程消耗的內(nèi)存10兆的模樣

worker_cpu_affinity

僅適用于linux袱讹,使用該選項(xiàng)可以綁定worker進(jìn)程和CPU(2.4內(nèi)核的機(jī)器用不了)

假如是8 cpu 分配如下:

worker_cpu_affinity 00000001 00000010 00000100 00001000 00010000

00100000 01000000 10000000

nginx可以使用多個(gè)worker進(jìn)程疲扎,原因如下:

to use SMP

to decrease latency when workers blockend on disk I/O

to limit number of connections per process when select()/poll() is

used?The worker_processes and worker_connections from the event sections

allows you to calculate maxclients value: k max_clients = worker_processes * worker_connections

worker_rlimit_nofile 102400;

每個(gè)nginx進(jìn)程打開(kāi)文件描述符最大數(shù)目 配置要和系統(tǒng)的單進(jìn)程打開(kāi)文件數(shù)一致,linux 2.6內(nèi)核下開(kāi)啟文件打開(kāi)數(shù)為65535,worker_rlimit_nofile就相應(yīng)應(yīng)該填寫(xiě)65535 nginx調(diào)度時(shí)分配請(qǐng)求到進(jìn)程并不是那么的均衡捷雕,假如超過(guò)會(huì)返回502錯(cuò)誤椒丧。我這里寫(xiě)的大一點(diǎn)

use epoll

Nginx使用了最新的epoll(Linux 2.6內(nèi)核)和kqueue(freebsd)網(wǎng)絡(luò)I/O模型,而Apache則使用的是傳統(tǒng)的select模型救巷。

處理大量的連接的讀寫(xiě)壶熏,Apache所采用的select網(wǎng)絡(luò)I/O模型非常低效。在高并發(fā)服務(wù)器中浦译,輪詢I/O是最耗時(shí)間的操作 目前Linux下能夠承受高并發(fā)

訪問(wèn)的Squid棒假、Memcached都采用的是epoll網(wǎng)絡(luò)I/O模型。

worker_connections 65535;

每個(gè)工作進(jìn)程允許最大的同時(shí)連接數(shù) (Maxclient = work_processes * worker_connections)

keepalive_timeout 75

keepalive超時(shí)時(shí)間

這里需要注意官方的一句話:

The parameters can differ from each other. Line Keep-Alive:

timeout=time understands Mozilla and Konqueror. MSIE itself shuts

keep-alive connection approximately after 60 seconds.

client_header_buffer_size 16k

large_client_header_buffers 4 32k

客戶請(qǐng)求頭緩沖大小

nginx默認(rèn)會(huì)用client_header_buffer_size這個(gè)buffer來(lái)讀取header值精盅,如果header過(guò)大帽哑,它會(huì)使用large_client_header_buffers來(lái)讀取

如果設(shè)置過(guò)小HTTP頭/Cookie過(guò)大 會(huì)報(bào)400 錯(cuò)誤 nginx 400 bad request

求行如果超過(guò)buffer,就會(huì)報(bào)HTTP 414錯(cuò)誤(URI Too Long)?nginx接受最長(zhǎng)的HTTP頭部大小必須比其中一個(gè)buffer大叹俏,否則就會(huì)報(bào)400的HTTP錯(cuò)誤(Bad Request)妻枕。

open_file_cache max 102400

使用字段:http, server, location 這個(gè)指令指定緩存是否啟用,如果啟用,將記錄文件以下信息: ·打開(kāi)的文件描述符,大小信息和修改時(shí)間. ·存在的目錄信息. ·在搜索文件過(guò)程中的錯(cuò)誤信息 -- 沒(méi)有這個(gè)文件,無(wú)法正確讀取,參考o(jì)pen_file_cache_errors 指令選項(xiàng):

·max - 指定緩存的最大數(shù)目,如果緩存溢出,最長(zhǎng)使用過(guò)的文件(LRU)將被移除

例: open_file_cache max=1000 inactive=20s; open_file_cache_valid 30s; open_file_cache_min_uses 2; open_file_cache_errors on;

open_file_cache_errors

語(yǔ)法:open_file_cache_errors on | off 默認(rèn)值:open_file_cache_errors off 使用字段:http, server, location 這個(gè)指令指定是否在搜索一個(gè)文件是記錄cache錯(cuò)誤.

open_file_cache_min_uses

語(yǔ)法:open_file_cache_min_uses number 默認(rèn)值:open_file_cache_min_uses 1 使用字段:http, server, location 這個(gè)指令指定了在open_file_cache指令無(wú)效的參數(shù)中一定的時(shí)間范圍內(nèi)可以使用的最小文件數(shù),如 果使用更大的值,文件描述符在cache中總是打開(kāi)狀態(tài).

open_file_cache_valid

語(yǔ)法:open_file_cache_valid time 默認(rèn)值:open_file_cache_valid 60 使用字段:http, server, location 這個(gè)指令指定了何時(shí)需要檢查open_file_cache中緩存項(xiàng)目的有效信息.

開(kāi)啟gzip

gzip on;

gzip_min_length 1k;

gzip_buffers 4 16k;

gzip_http_version 1.0;

gzip_comp_level 2;

gzip_types text/plain application/x-JavaScripttext/css

application/xml;

gzip_vary on;

緩存靜態(tài)文件:

location ~* ^.+\.(swf|gif|png|jpg|js|css)$ {

root /usr/local/ku6/ktv/show.ku6.com/;

expires 1m;

}

7. ? 錯(cuò)誤排查

1、Nginx 502 Bad Gateway

php-cgi進(jìn)程數(shù)不夠用她肯、php執(zhí)行時(shí)間長(zhǎng)(mysql慢)佳头、或者是php-cgi進(jìn)程死掉,都會(huì)出現(xiàn)502錯(cuò)誤

一般來(lái)說(shuō)Nginx 502 Bad Gateway和php-fpm.conf的設(shè)置有關(guān)晴氨,而Nginx 504 Gateway Time-out則是與nginx.conf的設(shè)置有關(guān)

1)康嘉、查看當(dāng)前的PHP FastCGI進(jìn)程數(shù)是否夠用:

netstat -anpo | grep "php-cgi" | wc -l

如果實(shí)際使用的“FastCGI進(jìn)程數(shù)”接近預(yù)設(shè)的“FastCGI進(jìn)程數(shù)”,那么籽前,說(shuō)明“FastCGI進(jìn)程數(shù)”不夠用亭珍,需要增大敷钾。

2)、部分PHP程序的執(zhí)行時(shí)間超過(guò)了Nginx的等待時(shí)間肄梨,可以適當(dāng)增加

nginx.conf配置文件中FastCGI的timeout時(shí)間阻荒,例如:

http?{

......

fastcgi_connect_timeout 300;

fastcgi_send_timeout 300;

fastcgi_read_timeout 300;

......

}

2、413 Request Entity Too Large

解決:增大client_max_body_size

client_max_body_size:指令指定允許客戶端連接的最大請(qǐng)求實(shí)體大小,它出現(xiàn)在請(qǐng)求頭部的Content-Length字段. 如果請(qǐng)求大于指定的值,客戶端將收到一個(gè)"Request Entity Too Large" (413)錯(cuò)誤. 記住,瀏覽器并不知道怎樣顯示這個(gè)錯(cuò)誤.

php.ini中增大

post_max_size 和upload_max_filesize

3 Ngnix error.log出現(xiàn):upstream

sent too big header while reading response header from upstream錯(cuò)誤

1)如果是nginx反向代理

proxy是nginx作為client轉(zhuǎn)發(fā)時(shí)使用的众羡,如果header過(guò)大侨赡,超出了默認(rèn)的1k,就會(huì)引發(fā)上述的upstream sent too big header (說(shuō)白了就是nginx把外部請(qǐng)求給后端server粱侣,后端server返回的header太大nginx處理不過(guò)來(lái)就導(dǎo)致了羊壹。

server {

listen80;

server_name*.xywy.com ;

large_client_header_buffers 4 16k;

location / {

#添加這3行

proxy_buffer_size 64k;

proxy_buffers32 32k;

proxy_busy_buffers_size 128k;

proxy_set_header Host $host;

proxy_set_header X-Real-IP$remote_addr;

proxy_set_header X-Forwarded-For$proxy_add_x_forwarded_for;

}

}

2) 如果是 nginx+PHPcgi

錯(cuò)誤帶有?upstream: "fastcgi://127.0.0.1:9000"。就該

多加:

fastcgi_buffer_size 128k;

fastcgi_buffers 4 128k;

server {

listen ? ? ? 80;

server_name ?ddd.com;

index index.html index.htm index.php;

client_header_buffer_size 128k;

large_client_header_buffers 4 128k;

proxy_buffer_size 64k;

proxy_buffers 8 64k;

fastcgi_buffer_size 128k;

fastcgi_buffers 4 128k;

location / {

......

}

}

8. ? Nginx的php漏洞

漏洞介紹:nginx是一款高性能的web服務(wù)器齐婴,使用非常廣泛油猫,其不僅經(jīng)常被用作反向代理,也可以非常好的支持PHP的運(yùn)行柠偶。80sec發(fā)現(xiàn)其中存在一個(gè)較為嚴(yán)重的安全問(wèn)題情妖,默認(rèn)情況下可能導(dǎo)致服務(wù)器錯(cuò)誤的將任何類型的文件以PHP的方式進(jìn)行解析,這將導(dǎo)致嚴(yán)重的安全問(wè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決定,而通過(guò)分析可以看到$fastcgi_script_name是直接由URI環(huán)境變量控制的匀哄,這里就是產(chǎn)生問(wèn)題的點(diǎn)。而為了較好的支持PATH_INFO的提取雏蛮,在PHP的配置選項(xiàng)里存在cgi.fix_pathinfo選項(xiàng)涎嚼,其目的是為了從SCRIPT_FILENAME里取出真正的腳本名。

那么假設(shè)存在一個(gè)http://www.80sec.com/80sec.jpg挑秉,我們以如下的方式去訪問(wèn)

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

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

/80sec.jpg/80sec.php

經(jīng)過(guò)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

所以不存在此問(wèn)題。

后端的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)一般配置開(kāi)啟产喉。Php通過(guò)該選項(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來(lái)解析任何類型的文件了鸥昏。

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

訪問(wèn)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

訪問(wèn)訪問(wèn)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的變化說(shuō)明了后端負(fù)責(zé)解析的變化吏垮,該站點(diǎn)就可能存在漏洞。

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

解決方案:

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

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

或者

if ( $fastcgi_script_name ~ ..*/.*php ) {

return 403;

}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末膳汪,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子尤莺,更是在濱河造成了極大的恐慌旅敷,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,013評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件颤霎,死亡現(xiàn)場(chǎng)離奇詭異媳谁,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)友酱,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,205評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén)晴音,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人缔杉,你說(shuō)我怎么就攤上這事锤躁。” “怎么了或详?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,370評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵系羞,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我霸琴,道長(zhǎng)椒振,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,168評(píng)論 1 278
  • 正文 為了忘掉前任梧乘,我火速辦了婚禮澎迎,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘选调。我一直安慰自己夹供,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,153評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布仁堪。 她就那樣靜靜地躺著哮洽,像睡著了一般。 火紅的嫁衣襯著肌膚如雪枝笨。 梳的紋絲不亂的頭發(fā)上袁铐,一...
    開(kāi)封第一講書(shū)人閱讀 48,954評(píng)論 1 283
  • 那天揭蜒,我揣著相機(jī)與錄音,去河邊找鬼剔桨。 笑死屉更,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的洒缀。 我是一名探鬼主播瑰谜,決...
    沈念sama閱讀 38,271評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼树绩!你這毒婦竟也來(lái)了萨脑?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 36,916評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤饺饭,失蹤者是張志新(化名)和其女友劉穎渤早,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體瘫俊,經(jīng)...
    沈念sama閱讀 43,382評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡鹊杖,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,877評(píng)論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了扛芽。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片骂蓖。...
    茶點(diǎn)故事閱讀 37,989評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖川尖,靈堂內(nèi)的尸體忽然破棺而出登下,到底是詐尸還是另有隱情,我是刑警寧澤叮喳,帶...
    沈念sama閱讀 33,624評(píng)論 4 322
  • 正文 年R本政府宣布被芳,位于F島的核電站,受9級(jí)特大地震影響馍悟,放射性物質(zhì)發(fā)生泄漏筐钟。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,209評(píng)論 3 307
  • 文/蒙蒙 一赋朦、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧李破,春花似錦宠哄、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,199評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至妇菱,卻和暖如春承粤,著一層夾襖步出監(jiān)牢的瞬間暴区,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,418評(píng)論 1 260
  • 我被黑心中介騙來(lái)泰國(guó)打工辛臊, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留仙粱,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,401評(píng)論 2 352
  • 正文 我出身青樓彻舰,卻偏偏與公主長(zhǎng)得像伐割,于是被迫代替她去往敵國(guó)和親两蟀。 傳聞我的和親對(duì)象是個(gè)殘疾皇子萨惑,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,700評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容

  • Nginx的工作原理 1.Nginx的模塊與工作原理 Nginx由內(nèi)核和模塊組成,其中竟痰,內(nèi)核的設(shè)計(jì)非常微小和簡(jiǎn)潔尚胞,...
    架構(gòu)飛毛腿閱讀 5,997評(píng)論 1 27
  • 第一章 Nginx簡(jiǎn)介 Nginx是什么 沒(méi)有聽(tīng)過(guò)Nginx硬霍?那么一定聽(tīng)過(guò)它的“同行”Apache吧!Ngi...
    JokerW閱讀 32,639評(píng)論 24 1,002
  • Nginx簡(jiǎn)介 解決基于進(jìn)程模型產(chǎn)生的C10K問(wèn)題,請(qǐng)求時(shí)即使無(wú)狀態(tài)連接如web服務(wù)都無(wú)法達(dá)到并發(fā)響應(yīng)量級(jí)一萬(wàn)的現(xiàn)...
    魏鎮(zhèn)坪閱讀 1,988評(píng)論 0 9
  • 上一篇《WEB請(qǐng)求處理一:瀏覽器請(qǐng)求發(fā)起處理》笼裳,我們講述了瀏覽器端請(qǐng)求發(fā)起過(guò)程唯卖,通過(guò)DNS域名解析服務(wù)器IP,并建...
    七寸知架構(gòu)閱讀 80,923評(píng)論 21 356
  • 原文github地址 1.PHP概述 1.1 PHP的歷史發(fā)展 1995年由Lerdorf創(chuàng)建PHP侍咱,高級(jí)腳本語(yǔ)言...
    10xjzheng閱讀 1,488評(píng)論 0 2