這幾天群里來了安正超大神,一下子群情'波'濤洶涌呀,什么圃郊?你不知道超神是誰,這是他的個人網(wǎng)站可以去瞧一瞧.
.......對了,差點(diǎn)忘了,群里也來了一個'似乎'沒有存在感的仁兄 - Drupal獵人(QQ號:打上馬賽克),為什么說他呢,因?yàn)槁犝f他技術(shù)也很厲害,不過在某些方面比他的技術(shù)還要那啥,你懂得(嗶嗶,學(xué)生卡)观挎。
名言篇
留下 1/3 的時間學(xué)習(xí)挡逼,留下 1/3 的時間思考窗轩,剩下 1/3 才是寫代碼 --- Little
干正事吧桩撮,好好學(xué)習(xí)雷绢,也可以跟大神一樣溜 --- Jellybool?
人生如此短暫难咕,我花費(fèi)了打炮的時間來學(xué)門技術(shù)课梳,我容易嗎我? --- Drupal獵人
Js事件的冒泡用法 --- Little
js推薦這種把事件綁定在body上余佃,用冒泡來做暮刃,不要直接在每個元素上都綁事件。
寫js爆土,也是寫php面向?qū)ο箢愃仆职谩G懊娑x各種類、方法步势、屬性氧猬,最后把事件綁定在body上,通過冒泡找id或者找元素坏瘩。這樣你哪怕?lián)Q了模板盅抚,只要流程不是有大變化,js也不用大改的倔矾。
比如:開始音樂和暫停音樂妄均。只不過是click觸發(fā)的,如果加一個 ESC按鍵觸發(fā)哪自,只需要改個觸發(fā)事件即可丰包。
很少在 js 里會注冊 window. 下的全局變量,一切都是私有變量壤巷。內(nèi)部的用 _邑彪,注冊到外面,一般只用 APP. 這樣的大寫類隙笆。$ 開頭的表示 jquery selector锌蓄,閉包?return?出去了升筏。
PHP opcache --- Little
群友問:php 開啟了 opcache, 如果在命令行執(zhí)行 opcache_reset(), 會重置 包括 php-pfm 的緩存么
答:不會,每個php-cli進(jìn)程都有自己的opcache空間撑柔,所有php-fpm進(jìn)程是一個opcache空間,
生產(chǎn)環(huán)境opcache的timestamp檢查關(guān)掉,發(fā)布代碼的時候再更新下opcache您访,可以避免很多stat系統(tǒng)調(diào)用
※ 深入淺出FastCGI/php-fpm --- Little
這一個話題包括Little講解php-fpm和PHP與Mysql連接的整合,方方覺得兩個丟在一起可以更能理解
先看個圖铅忿,標(biāo)準(zhǔn)的PHP單進(jìn)程CLI和CGI生命周期。php進(jìn)程啟動灵汪,需要zend core檀训、加載擴(kuò)展(MINIT)柑潦、接收請求(RINIT) 這樣的。一個進(jìn)程只服務(wù)一次命令行或HTTP請求峻凫,就退出渗鬼。
而FastCGI/php-fpm 就是改造后的多進(jìn)程的 CGI,類似于資源池荧琼,預(yù)先啟動 100個 php-fpm 進(jìn)程譬胎,提前MINT,nginx的請求來了命锄,直接進(jìn)入 RINIT -> RSHUTDOWN 循環(huán)堰乔。請求結(jié)束,進(jìn)程不退出脐恩,一個進(jìn)程至少服務(wù)上萬次請求才退出恒序。
為什么一定要退出涮较?怕RINIT->RSHUTDOWN循環(huán),有哪個代碼寫的不好,變量一直沒釋放呵曹,內(nèi)存泄露GC又回收不了。php-fpm里的pm.max_requests配置就是設(shè)置RINT循環(huán)多少次啡专,退出進(jìn)程冲杀。
再來看幾個 TSF、swoole身堡、workerman邓尤、php-pm,都是 php 啟動cli進(jìn)程贴谎,用php管理子進(jìn)程汞扎,php解析HTTP協(xié)議。
生命周期連?RINIT?->?MINIT?循環(huán)都省了擅这,沒寫在?類屬性里的變量澈魄,裸寫的變量都是?進(jìn)程級全局變量,比?php-fpm?下的?$_GET仲翎、$_POST痹扇、$_SERVER、$_SESSION溯香、$_COOKIE?這些全局變量范圍還大鲫构,是進(jìn)程級的。意味著你?寫了個?a.php玫坛,里面定義了?$a?=?1;?賦值之后结笨,下次請求過來,只要正好分配到了這個進(jìn)程,依然還能取到普通定義的?$a?變量炕吸。
這意味著什么伐憾?像?Laravel?里的?$app?這些變量,只要寫在最外面赫模,因?yàn)闆]有觸發(fā)?RSHUTDOWN树肃,又沒有主動?unset,GC引用計數(shù)器一直大于?0瀑罗,變量不會消失扫外。
那怎么解決每次請求?$_GET?和?$_POST?不一樣的問題?這些?swoole廓脆、workerman?進(jìn)程管理器自己實(shí)現(xiàn)了小型化的?INIT?->?SHUTDOWN?過程筛谚,維護(hù)一些引用計數(shù)唄,自己的?a.php?完成后停忿,這種框架幫你?unset($_GET)驾讲。
問題來了,穩(wěn)定不穩(wěn)定席赂?swoole吮铭、workman框架本身穩(wěn)定,但因?yàn)橥耆淖兞藀hp生命周期颅停,業(yè)務(wù)開發(fā)人員不熟悉谓晌,一不小心寫了?global、static?這樣的變量癞揉,全局用了纸肉,內(nèi)存越占越大,崩潰喊熟。又或者?寫了個?exit柏肪,把整個進(jìn)程?exit?而不是?request?ext?了。
舉個例子來理解芥牌,用 swoole烦味、php-pm 這種進(jìn)程模式,假設(shè)只啟動一個進(jìn)程壁拉,可能會出現(xiàn)以下情況谬俄。
1、寫個頁面 http://www.xxx.com/a.php弃理,內(nèi)容是 $a = 1溃论,而到一個完全不相關(guān)的頁面 http://www.xxx.com/b.php,內(nèi)容就是var_dump($a); 居然能輸出 int(1); 很神奇
2案铺、寫個頁面 http://www.xxx.com/c.php蔬芥,里面執(zhí)行完一段邏輯后梆靖,exit('error')控汉,本以為頁面輸出個 error笔诵,是正常的拒絕訪問。再刷新姑子,502了乎婿,什么情況。
那哪種情況比較適合使用swoole
Little答:
特別繁忙的某個接口街佑、業(yè)務(wù)邏輯簡單谢翎、依賴較少的情況,可以用沐旨。有良好的編碼習(xí)慣森逮,不用全局變量,不寫 exit 只用 return 不會有問題磁携。但是無法保證用到的哪個 vendor 不出現(xiàn)這些東西褒侧,所以不能大規(guī)模使用。
Abraham因?yàn)樯婕拜^多框架,深切表示很多 vendor 里面 的寫法真是千奇百怪谊迄,有的根本都沒見過,
比如解析 var_dump 去判斷對象
當(dāng)然我只是看了這些進(jìn)程早期版本的實(shí)現(xiàn)闷供,現(xiàn)在php不是有某種注入技術(shù),可以改寫原生函數(shù)么统诺。說不定啟動swoole的時候歪脏,已經(jīng)用某種方法把 exit 改寫了呢。
這里是Little對于的一些理解,讀者還是需要與現(xiàn)在版本進(jìn)行比較
對于swoole粮呢、workman等框架本身穩(wěn)定婿失,但因?yàn)橥耆淖兞藀hp生命周期是否意味著更適合做一些微框架,寫純Restful API?
Little答:
這種完全改寫生命周期的事情啄寡,就有點(diǎn)像 HHVM 對 PHP做成預(yù)定義變量類型的改變移怯,性能提升很大,但是用起來要謹(jǐn)慎这难,并不是全兼容的舟误。
Little在這里并沒有直接回答此問題,因?yàn)樵谥熬徒榻B了,Little對于項目是超越框架的,不局限于框架之類的東西.所以方方感覺也是蠻正常的
websocket最好不要php直接來做,目前php的websocket包姻乓,都是啟動一個獨(dú)立的進(jìn)程監(jiān)聽端口解析協(xié)議嵌溢,跟 swoole、workerman 這些東西同一種性質(zhì)蹋岩,不能確保100%好用及可用赖草。
推薦 借助 openresty(nginx) + lua + redis 來做。
openresty(nginx) 通過 redis 插件 監(jiān)聽websocket剪个,同時掛起一個到 redis 的連接秧骑,用 redis 的 sub 方法,訂閱某個 key。php 這邊只需要 調(diào)用 Redis 的 pub 方法乎折,寫入 redis 的 key 即可绒疗。
一個由TIME_WAIT 引起的話題 --- Little
TIME_WAIT多了
Abraham回答
fpm?每個進(jìn)程結(jié)束都銷毀連接,無法利用持久連接骂澄,持久連接指的是請求內(nèi)的吧,你的情況可以減小?mysql?的等待超時時間吓蘑,或者直接更改操作系統(tǒng)維護(hù)的?tcp?連接數(shù)
little最后解答
我剛那個 TIME_WAIT 問題改成php-fpm 連接 mysql 用 persistent 是可以解決的。剛剛只是改錯了文件坟冲,沒想到有個老項目的代碼還在這臺機(jī)器上跑磨镶。
雖然php并沒有mysql連接池,但是 PDO 的persistent參數(shù)是基于單個php-fpm進(jìn)程健提,仔細(xì)看了下php-fpm的生命周期琳猫,我配置了 204800 個request請求才會重啟這個php-fpm進(jìn)程,所以連接復(fù)用的情況還是很大私痹,單機(jī)400個php-fpm進(jìn)程脐嫂,單個進(jìn)程要跑滿20萬次請求等重啟,怎么都要一兩天才行侄榴。
Abraham的理解
以前一直以為持久連接是基于 fpm 子進(jìn)程中處理 request 的線程雹锣。
為什么上面要放Abraham最開始的回復(fù)以及后來的理解,一來是Abraham對于很多人而言其實(shí)已經(jīng)技術(shù)很好了,但是仍然對某些深層的不能正確理解,拿出來讓其他人看看是否自己也有這種理解失誤;二來嘛,嘿嘿嘿,拖出去,彈雞雞彈到死
Little
關(guān)掉持久連接,會在request shutdown 階段close mysql連接癞蚕。而打開持久連接蕊爵,并不會每次請求都關(guān)閉,是同一個php-fpm進(jìn)程中復(fù)用連接桦山,直到這個php-fpm進(jìn)程結(jié)束了攒射。
然而php-fpm的mysql并沒有連接池,比如開了400個php-fpm進(jìn)程恒水,那就會和mysql保持400個連接会放,無論現(xiàn)在訪問量高還是低。如果前端機(jī)器太多钉凌,mysql服務(wù)器會保持太多的連接數(shù)咧最,mysql服務(wù)器并不能承受太多個連接,哪怕這個連接什么事都沒干御雕,所以并不是一個很好的解決辦法矢沿,只能再加一層mysql?proxy。而java的實(shí)現(xiàn)就有連接池酸纲,好很多捣鲸,果當(dāng)前并發(fā)請求量只有100,那么只會有100個java到mysql的連接闽坡。這100個連接在所有java線程中復(fù)用栽惶。
Abraham再提問
如果能保持?php-fpm?的進(jìn)程數(shù)那么多個連接愁溜。show?status?like?'%connections%',理論上應(yīng)該不變的對吧?
Little 回復(fù)
1:15 的時候外厂,我在一臺機(jī)器上開了持久連接冕象。1:40左右的時候,我多開了一臺php機(jī)器酣衷。
所以我的結(jié)論是 php-fpm 到 mysql交惯,應(yīng)當(dāng)使用 persistent次泽。如果機(jī)器數(shù)穿仪、php-fpm進(jìn)程數(shù)很多,后端mysql掛不了這么多空閑連接意荤。那在 php-fpm 與 mysql 之間加一層 mysql proxy啊片。這個 mysql proxy 就是相當(dāng)于多進(jìn)程多機(jī)器的連接池。
多機(jī)器多進(jìn)程?php-fpm?(可能有5000個連接)?->?mysql?proxy?->?(可能就剩20個并發(fā)執(zhí)行mysql的活躍連接了)?mysql?server玖像。
默認(rèn)就開啟持久連接才好紫谷,出現(xiàn)問題,再看看是不是考慮關(guān)掉捐寥。畢竟?php?連mysql笤昨,一個新連接會多三次?TCP握手過程,雖然是內(nèi)網(wǎng)握恳,速度感覺不出來瞒窒。我這是給一個老項目做優(yōu)化,讓他暫時不掛乡洼。我別的項目都是直接上持久連接崇裁。
開啟持久連接, 可能會導(dǎo)致那些問題
Little答
理論上是沒有什么問題,就是看你的mysql服務(wù)器受不受得住束昵,受不住就要加 proxy拔稳。
另外,有空閑連接锹雏,如果你的網(wǎng)站并發(fā)量比較小巴比,空閑連接時間長了,可能會被mysql踢掉礁遵,會產(chǎn)生一個?mysql?has?gone?away?這個錯誤轻绞,你要程序中處理,我不知道?laravel?有沒有自動處理榛丢,理論上這種全棽颍框架應(yīng)該都會有個配置自動處理這個問題。
我全文搜了下?gone?away晰赞,發(fā)現(xiàn)?laravel?里有處理gone?away稼病,業(yè)務(wù)層就不用關(guān)心了选侨。
Illuminate\Databasetry\Connection? -> run() 和 tryAgainIfCausedByLostConnection()
我可不可以這樣理解,當(dāng)你的項目已經(jīng)需要利用 php-fpm 持久連接提供的性能福利時然走,你同時也需要審視你的數(shù)據(jù)訪問層架構(gòu)援制,重新設(shè)計它
Little答
應(yīng)該這么說,持久連接應(yīng)該是在每一個環(huán)節(jié)都是盡量使用的芍瑞。比如用戶瀏覽器到nginx晨仑,用HTTP/1.1,開keepalive拆檬。nginx到php-fpm洪己,upstream里開keepalive,fastcgi conn 還要配個什么竟贯。php到mysql答捕,也開持久連接。這樣每個環(huán)節(jié)都省掉多次不必要的TCP三次握手屑那。而MySQL性能問題和這個連接關(guān)系并不是太大拱镐,只是mysql服務(wù)器一直以來都有個毛病,連接數(shù)超過一定的數(shù)量就受不了持际,哪怕這個連接是空閑的什么事都沒干沃琅,不像nginx隨便掛上十幾萬的連接數(shù)都輕輕松松。
整理者方方小結(jié) --- 還是好好學(xué)習(xí)