偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

Badoo 告訴你切換到 PHP7 節(jié)省了 100 萬(wàn)美元

開發(fā) 后端
我們成功的把我們的應(yīng)用遷移到了php7上面(數(shù)百臺(tái)機(jī)器的集群),而且運(yùn)行的很好,據(jù)說(shuō)我們是第二個(gè)把如此規(guī)模的應(yīng)用切換到php7的企業(yè),在切 換的過程我們發(fā)現(xiàn)了一些php7字節(jié)碼緩存的bug,慶幸的是這些bug現(xiàn)在已經(jīng)被修復(fù)了,現(xiàn)在我們把這個(gè)激動(dòng)人心的消息分享給所有的php社 區(qū):php7現(xiàn)在已經(jīng)可以穩(wěn)定的運(yùn)行在商用環(huán)境上,而且比以前更加節(jié)省內(nèi)存,性能也有的很大的提高。

介紹

我們成功的把我們的應(yīng)用遷移到了php7上面(數(shù)百臺(tái)機(jī)器的集群),而且運(yùn)行的很好,據(jù)說(shuō)我們是第二個(gè)把如此規(guī)模的應(yīng)用切換到php7的企業(yè),在切 換的過程我們發(fā)現(xiàn)了一些php7字節(jié)碼緩存的bug,慶幸的是這些bug現(xiàn)在已經(jīng)被修復(fù)了,現(xiàn)在我們把這個(gè)激動(dòng)人心的消息分享給所有的php社 區(qū):php7現(xiàn)在已經(jīng)可以穩(wěn)定的運(yùn)行在商用環(huán)境上,而且比以前更加節(jié)省內(nèi)存,性能也有的很大的提高。

下面我會(huì)詳細(xì)的介紹下我們是如何把應(yīng)用前移動(dòng)php7的,我們?cè)谶@中間遇到的問題及處理情況,還有最終的結(jié)果。但首先讓我們回頭看看一些更常見的問題:

Web項(xiàng)目的瓶頸在于數(shù)據(jù)庫(kù)持久化這是一個(gè)常見的誤解。一個(gè)設(shè)計(jì)良好的系統(tǒng)應(yīng)該是平衡的:當(dāng)訪問量增長(zhǎng)時(shí),由系統(tǒng)的各個(gè)部分分?jǐn)傔@些壓力,同樣的, 當(dāng)達(dá)到系統(tǒng)閥值時(shí),系統(tǒng)的所有組件(不僅僅包括硬盤數(shù)據(jù)庫(kù),還有處理器和網(wǎng)絡(luò))共同分?jǐn)倝毫Α;谶@個(gè)事實(shí),應(yīng)用集群的處理能力才應(yīng)該是最重要的因素。在 很多項(xiàng)目中,這種集群由數(shù)以百計(jì)甚至數(shù)以千計(jì)的服務(wù)器組成,這是因?yàn)榛〞r(shí)間去調(diào)整集群的處理能力更加經(jīng)濟(jì)實(shí)益(我們因此節(jié)省一百多萬(wàn))。

PHP的Web應(yīng)用,處理器的消耗跟其他動(dòng)態(tài)高級(jí)語(yǔ)言一樣多。但是PHP開發(fā)者面對(duì)著一個(gè)特別的障礙(這讓他們成為其他社區(qū)惡意攻擊的的受害者): 缺少JIT,至少?zèng)]有一個(gè)像C/C++語(yǔ)言那樣的可編譯文本的生成器。PHP社區(qū)無(wú)力在核心項(xiàng)目框架上去實(shí)現(xiàn)一個(gè)類似的解決方案更是樹立了一種不良的風(fēng) 氣:主要的開發(fā)成員開始整合他們的解決方案,所以HHVM在Facebook上誕生了,KPHP在VKontakte上誕生,還有其他類似的方案。幸運(yùn)地 是,在2015年,隨著PHP7的正式發(fā)布,PHP要開始”Grow up”啦。雖然還是沒有JIT,但很難去評(píng)定這些改變?cè)?rdquo;engine”中有多重要?,F(xiàn)在,盡管沒有JIT,PHP7可以跟HHVM相匹敵( Benchmarks from the LightSpeed blog  or PHP devs benchmarks)。新的PHP7體系架構(gòu)將會(huì)讓JIT的實(shí)現(xiàn)變得簡(jiǎn)單。

在Badoo的平臺(tái)開發(fā)者已經(jīng)非常關(guān)注近些年出現(xiàn)的每一次問題,包括HHVM試點(diǎn)項(xiàng)目,但是我們還是決定等待很有前途的PHP7的到來(lái)。現(xiàn)在我們啟 動(dòng)了已經(jīng)基于PHP7的Baboo!這是一個(gè)史詩(shī)般的項(xiàng)目,擁有300多萬(wàn)行的PHP代碼,并且經(jīng)歷了60000次的測(cè)試。我們?yōu)榱颂幚磉@些挑戰(zhàn),提出了 一個(gè)新的PHP引用測(cè)試框架(當(dāng)然,也是開源的),并且在整個(gè)過程中節(jié)省了上百萬(wàn)美元。

HHVM的試驗(yàn)

在切換到PHP7之前,我們?cè)瞬簧贂r(shí)間來(lái)尋找優(yōu)化后端的方法。當(dāng)然,第一步就是從HHVM下手。在試驗(yàn)了幾周之后,我們獲得了值得關(guān)注的結(jié)果:在給框架中的JIT熱身之后,我們看到速度與CPU使用率上升了三倍。

另一方面,HHVM 被證實(shí)有一些嚴(yán)重的缺點(diǎn):

  • 部署困難而且慢。在部署過程中,你不得不首先啟動(dòng)JIT-cache。當(dāng)機(jī)器啟動(dòng)的時(shí)候,它不能負(fù)載產(chǎn)品流量,因?yàn)樗械氖虑檫M(jìn)行的相當(dāng)慢。 HHVM 團(tuán)隊(duì)同樣不推薦啟動(dòng)并行請(qǐng)求。順便一提,大量聚類操作在啟動(dòng)階段并不快速。此外,對(duì)于幾百個(gè)機(jī)器構(gòu)成的大集群你必須學(xué)習(xí)如何分批部署。這樣體系結(jié)構(gòu)和部署 過程相當(dāng)繁瑣,而且很難估算出所需要的時(shí)間。對(duì)于我們來(lái)說(shuō),部署應(yīng)該盡可能簡(jiǎn)單快捷。我們的開發(fā)者將在同一天提供兩個(gè)開發(fā)版并且釋出許多補(bǔ)丁。

  • 測(cè)試不便。我們非常依賴runkit擴(kuò)展,但是它在HHVM中卻不可用。稍后我們將詳細(xì)介紹runkit,但是無(wú)需多言,它是一個(gè)能讓你幾乎隨心 所欲更改變量、類、方法、函數(shù)行為的擴(kuò)展。這是通過一個(gè)抵達(dá)PHP核心的集成來(lái)實(shí)現(xiàn)的。HHVM引擎僅僅顯示了略微相像的PHP外觀,但是他們各自的核心 十分不同。鑒 于擴(kuò)展的特定功能,在HHVM上獨(dú)立地實(shí)現(xiàn)runkit異常困難,而且我們不得不重寫數(shù)萬(wàn)測(cè)試用例以確保HHVM和我們的代碼正確的工作。這看起來(lái)似乎不 值得。公平的說(shuō),我們以后在處理所有其他選項(xiàng)時(shí)也會(huì)遇到同樣的問題,而且我們?cè)谶w移到PHP7時(shí)仍然要重做許多事情包括擺脫runkit。但是以后會(huì)更 多。

  • 兼容性。主要問題是不完全兼容PHP5.5(參考此處) ,并且不兼容現(xiàn)有的擴(kuò)展(許多PHP5.5的)。這些所有的不兼容性導(dǎo)致了這個(gè)項(xiàng)目的明顯缺點(diǎn): HHVM 不是被大社區(qū)開發(fā)的,相反只是Facebook的一個(gè)分支。在這種情況下公司很容易不參考社區(qū)就修改內(nèi)部規(guī)則和標(biāo)準(zhǔn),而且大量的代碼包含其中。換句話說(shuō), 他們關(guān)起門來(lái)利用自己的資源解決了問題。因此,為了解決相似的問題,一個(gè)公司需要有Facebook一樣的資源不僅投入最初的實(shí)現(xiàn)同樣要投入后續(xù)支持。這 個(gè)提議不僅有風(fēng)險(xiǎn)而且可能開銷很大,所以我們決定拒絕它。

  • 潛力。盡管Facebook是一個(gè)大公司而且擁有無(wú)數(shù)頂尖程序員,我們?nèi)匀粦岩伤麄兊腍HVM開發(fā)者比整個(gè)PHP社區(qū)更強(qiáng)。我們猜想PHP的類似于HHVM的東西會(huì)很快出現(xiàn),而前者將慢慢淡出我們的視野。

讓我們耐心等待PHP7。

切換到新版本的PHP7解釋器是一個(gè)重要和艱難的過程,我們準(zhǔn)備建立一個(gè)精確的計(jì)劃。這個(gè)計(jì)劃包括三個(gè)階段:

  • 修改PHP構(gòu)建/部署的基礎(chǔ)設(shè)施和為大量的擴(kuò)展調(diào)整現(xiàn)有的code

  • 改變基礎(chǔ)設(shè)施和測(cè)試環(huán)境

  • 修改PHP應(yīng)用程序的代碼。

我們稍后會(huì)給出這些這些階段的細(xì)節(jié)。

引擎和擴(kuò)展的變化

在Badoo中, 我們有積極的支持和更新的PHP分支,我們?cè)赑HP7正式版release之前我們就已經(jīng)開始切換到php7了. 所以我們不得 不在我們的代碼樹經(jīng)常整合(rebase)PHP7上游的代碼,以便它來(lái)更新每個(gè)候選發(fā)布版。我們每天在工作中所用的補(bǔ)丁和自定義的code都需要在兩個(gè) 版本之間進(jìn)行移植。

下載和構(gòu)建依賴庫(kù)、擴(kuò)展程序、還包括PHP 5.5和7.0的構(gòu)建這些過程都是自動(dòng)化的完成的。這不僅簡(jiǎn)化了我們目前的工作,也預(yù)示著未來(lái):在版本7.1出來(lái)時(shí), 也許這一切(解析引擎和擴(kuò)展等等)都已經(jīng)準(zhǔn)備到位了;

如上所述,我們將注意力轉(zhuǎn)向擴(kuò)展。我們提供超過70種擴(kuò)展,已經(jīng)比基于我們產(chǎn)品改寫的開源產(chǎn)品的半數(shù)還要多。

為了盡快能夠切換到它們,我們已經(jīng)決定開始同時(shí)進(jìn)展兩件事情。第一個(gè)是逐一重寫各個(gè)關(guān)鍵擴(kuò)展,包括blitz模板引擎,共享內(nèi)存/APCu中的數(shù)據(jù) 緩存,pinba數(shù)據(jù)分析采集器,以及其他內(nèi)部服務(wù)的自定義擴(kuò)展(總的來(lái)說(shuō),我們已經(jīng)通過自己的力量完成大概20種擴(kuò)展的重寫了)。

第二個(gè)是積極的清理僅僅在架構(gòu)中那些非關(guān)鍵部分使用的擴(kuò)展,讓整個(gè)架構(gòu)更加簡(jiǎn)潔。我們已經(jīng)迅速清理了11種擴(kuò)展,都是那些無(wú)足輕重的!

另外,我們也同那些維護(hù)主要開放擴(kuò)展的作者,一起積極地討論P(yáng)HP7的兼容性(特別感謝xdebug的開發(fā)者Derick Rethans)。

我們遲點(diǎn)將進(jìn)入更詳細(xì)的關(guān)于移植PHP7擴(kuò)展的技術(shù)細(xì)節(jié)。

開發(fā)者已經(jīng)對(duì)PHP7中的內(nèi)部API做了大量修改,意味著我們可以修改大量的擴(kuò)展代碼了。

下面是幾個(gè)最重要的變更:

  • zval * -> zval。在早期的版本中,zval一直為新變量來(lái)分配內(nèi)存,但是現(xiàn)在引入了棧。

  • char * -> zend_string。PHP7的引擎使用了更先進(jìn)的字符串緩存機(jī)制。理由是,當(dāng)字符串與自身的長(zhǎng)度同時(shí)存儲(chǔ)時(shí),新的引擎可以將普通字符串完整的轉(zhuǎn)換為zend-string格式。

  • 數(shù)組API的改變。zend_string作為key來(lái)使用,同時(shí)基于雙向鏈表的數(shù)組實(shí)現(xiàn)方法也被替代為普通的數(shù)組,需要強(qiáng)調(diào)的是,數(shù)組占用一個(gè)大的文件塊,而不是很多小的空間。

所有這些都可以從根本上減少小型內(nèi)存分配的數(shù)量,結(jié)果是,提高PHP引擎2%的速度。

我們能夠注意到,所有這些修改都至少需要改變所有的擴(kuò)展(即使不是完全重寫)。雖然我們可以依賴內(nèi)置擴(kuò)展的作者進(jìn)行必要的修改,我們也當(dāng)然有責(zé)任自己修改他們,雖然工作量很大。由于內(nèi)部API的修改,使得只修改一些代碼段變得簡(jiǎn)單。

不幸的是,引入使代碼執(zhí)行速度提升的垃圾回收機(jī)制讓引擎變得更加復(fù)雜并且變得更加難以定位問題。涉及到OpCache的問題。在緩存刷新期間,當(dāng)可 用于別的進(jìn)程的已緩存的文件字節(jié)碼在此時(shí)損壞,就會(huì)導(dǎo)致崩潰。這就是它從外部看起來(lái)的樣子(zend_string):使用方法名或者常量突然崩潰并且垃 圾就會(huì)出現(xiàn)。

鑒于我們使用了大量的內(nèi)部擴(kuò)展,其中許多處理都是專門針對(duì)字符串的,我們懷疑這個(gè)問題與如何使用字符串在內(nèi)部擴(kuò)展有關(guān)。我們寫了大量的測(cè)試,并進(jìn)行了大量的實(shí)驗(yàn),但沒有得到我們預(yù)期的結(jié)果。最后,我們從PHP引擎開發(fā)人員 Dmitri Stogov 那里尋求了幫助。
他的第一個(gè)問題是“你有沒有清除緩存?”我們解釋說(shuō),事實(shí)上,我們每一次都在清除緩存。在這一點(diǎn)上,我們意識(shí)到這個(gè)問題并不在我們這里,而是 opcache。我們很快就轉(zhuǎn)載了這一案例,這有助于我們?cè)趲滋靸?nèi)回復(fù)并解決這個(gè)問題。在7.0.4版本,這個(gè)修復(fù)沒有出來(lái),就不可能使php7進(jìn)入穩(wěn)定 產(chǎn)品。

更改測(cè)試基礎(chǔ)設(shè)施

我們?yōu)槲覀冊(cè)贐adoo上做測(cè)試感到特別驕傲。我們部署服務(wù)器的PHP代碼到產(chǎn)品環(huán)境,每天兩次,每次部署包含20-50份任務(wù)量(我們使用功能分 支Git和自動(dòng)化緊JIRA集成版本)。鑒于這種時(shí)間表和任務(wù)量,我們沒有辦法不選擇自動(dòng)測(cè)試。目前,我們大約有6萬(wàn)個(gè)單元測(cè)試,約50%的覆蓋率,其運(yùn) 行在云上,平均2-3分鐘(參見我們的文章了解更多)。除了單元測(cè)試,我們使用更高級(jí)別的自動(dòng)測(cè)試,集成和系統(tǒng)測(cè)試,并為網(wǎng)頁(yè)做了Selenium測(cè)試,為手機(jī)客戶端做了Calabash測(cè)試。作為一個(gè)整體,這使我們能夠迅速達(dá)成與結(jié)論有關(guān)的代碼,每個(gè)具體版本的質(zhì)量,并應(yīng)用相應(yīng)的解決方案。

切換到新版本的解釋器是一個(gè)充滿潛在問題的重大變化,所以所有測(cè)試工作都是極其重要的。為了弄清我們到底做了什么,以及我們?nèi)绾卧O(shè)法做到這一點(diǎn),讓我們來(lái)看看近幾年測(cè)試開發(fā)在Badoo上是如何演變的。

通常,當(dāng)我們開始考慮實(shí)施產(chǎn)品測(cè)試(或在某些情況下,已經(jīng)開始實(shí)施的話)時(shí),在測(cè)試過程中我們會(huì)發(fā)現(xiàn)他們的代碼“并沒有達(dá)到測(cè)試階段”。出于這個(gè)原 因,在大多數(shù)情況下,開發(fā)者在寫代碼時(shí)要牢記,代碼的可測(cè)試性是很重要的。架構(gòu)師應(yīng)允許用單元測(cè)試去取代調(diào)用和外部依賴對(duì)象,以便代碼測(cè)試能與外部環(huán)境相 隔離。當(dāng)然,毫無(wú)疑問這是一個(gè)備受憎恨的要求,很多程序員認(rèn)為寫“可測(cè)試性”的代碼是完全不可接受的。他們認(rèn)為,這些限制完全不顧“優(yōu)秀代碼”的標(biāo)準(zhǔn)而且 通常不會(huì)取得成功。你能想象到,大量不按規(guī)則編寫的代碼,導(dǎo)致測(cè)試為了等“一個(gè)更好的時(shí)機(jī)”被延遲,或者通過運(yùn)行小型測(cè)試來(lái)滿足并且在測(cè)試結(jié)果被推遲,或 實(shí)驗(yàn)者為了使自己運(yùn)行的小測(cè)試能夠通過,只做了能夠通過的那部分(也就是指測(cè)試沒有產(chǎn)生預(yù)期的結(jié)果)。
我并不是說(shuō)我們公司是一個(gè)例外,從一開始,我們的項(xiàng)目也未執(zhí)行測(cè)試。因?yàn)橐廊挥袔仔写a在生產(chǎn)過程中正常運(yùn)作,帶來(lái)效益,所以正如文獻(xiàn)中建議的,如果只是為了運(yùn)行測(cè)試重寫代碼將是一件愚蠢的事情。那將占用太長(zhǎng)的時(shí)間,花費(fèi)太多。

幸運(yùn)的是我們有一個(gè)很棒的工具來(lái)解決“未測(cè)試代碼”的大問題——runkit。當(dāng)腳本在運(yùn)行時(shí),這個(gè) PHP 擴(kuò)展允許你對(duì)方法、類及函數(shù)進(jìn)行增、刪、改的操作。此工具還有很多其它的功能但我們這里用不到它們。從 2005 年到 2008 年這個(gè)工具由 Sara Goleman(就職于 Facebook,有趣的是他在做 HHVM 方向的工作)開發(fā)和支持了多年。從 2008 年至今則由 Dmitri Zenovich (帶領(lǐng) Begun 和 Mail.ru 的測(cè)試部門)進(jìn)行維護(hù)。我們也對(duì)這個(gè)項(xiàng)目做了些許貢獻(xiàn)。

同時(shí),runkit 是一個(gè)非常危險(xiǎn)的擴(kuò)展,它允許你在使用它的腳本在運(yùn)行的時(shí)候?qū)ΤA?、函?shù)及類進(jìn)行修改。就像是一個(gè)允許你在飛行中重建飛機(jī)的工具。runkit 有直達(dá) PHP “心臟”的權(quán)力,一個(gè)小錯(cuò)誤或缺陷就能讓一切毀掉,導(dǎo)致 PHP 失敗或者你要用很多時(shí)間來(lái)查找內(nèi)存泄漏或做一些底層的調(diào)試。盡管如此,這個(gè)工具對(duì)于我們的測(cè)試還是必要的:不需要做大的重構(gòu)來(lái)完成項(xiàng)目測(cè)試只能在程序運(yùn)行 的時(shí)候改變代碼來(lái)實(shí)現(xiàn)。

但是在切換到PHP7的時(shí)候發(fā)現(xiàn)runkit帶來(lái)了很大麻煩,因?yàn)樗⒉恢С中碌陌姹?。我們?dāng)然也可以在新版本中添加支持,但是從長(zhǎng)遠(yuǎn)考慮,這看起來(lái)并不是最可靠的解決途徑。因此我們選擇了其他方法。

最適合的方法之一就是從runkit遷移到uopz。后者也是PHP的擴(kuò)展,有著(與runkit)類似的功能性,于2014年正式推出。我在 Wamba的同事建議使用uopz,它將有很好的速度體驗(yàn)。順便說(shuō)一下uopz的維護(hù)者就是Joe Watkins(First Beat Media公司,英國(guó))。不幸的是我們遷移到uopz的測(cè)試程序無(wú)論怎樣都無(wú)法成功運(yùn)行。在某些地方總會(huì)發(fā)生致命的錯(cuò)誤,出現(xiàn)在段錯(cuò)誤中。我們提交了一些 報(bào)告,但很遺憾他們并沒有動(dòng)作(e.g. https://github.com/krakjoe/uopz/issues/18)。為了解決這種困境而重寫測(cè)試程序的付出將會(huì)非常高昂,即使重寫了也很容易再次暴露出問題。

鑒于我們不得不重寫大量的代碼,而且還要依賴于runkit和uopz這種不知道有沒有問題的項(xiàng)目。很明顯,我們有了結(jié)論:我們應(yīng)該重寫我們的代 碼,而且要盡可能獨(dú)立。我們也承諾將盡一切可能來(lái)避免今后發(fā)生類似的問題,即使我們最終切換到HHVM或任何類似的產(chǎn)品。最終我們做出來(lái)了自己的框架。
我們的系統(tǒng)名為“SoftMocks”,“soft”意思是純php實(shí)現(xiàn),未使用擴(kuò)展。該項(xiàng)目目前是一個(gè)開源的php庫(kù)。 SoftMocks不跟PHP引擎綁定,它是在運(yùn)行中動(dòng)態(tài)重寫代碼,功能類似于Go語(yǔ)言的AOP!框架
以下功能在我們的代碼里已經(jīng)測(cè)試過:

  1. override類方法

  2. 覆蓋函數(shù)執(zhí)行結(jié)果

  3. 更改全局常量或類常量的值

  4. 類新增方法

所有這些東西都是用runkit實(shí)現(xiàn)的。動(dòng)態(tài)修改代碼使項(xiàng)目臨時(shí)變更有了可能性。

我們沒有更多篇幅來(lái)討論關(guān)于SoftMocks的細(xì)節(jié),但我們計(jì)劃寫一篇關(guān)于這個(gè)主題的文章。 這里我們給出一些關(guān)鍵點(diǎn):

  • 通過重寫中間函數(shù)來(lái)適配原有的用戶代碼。因此所有的包含操作將自動(dòng)被中間函數(shù)重寫。

  • 在每一個(gè)用戶定義的方法內(nèi)都增加了是否有重寫的檢查。如果存在重寫,相應(yīng)的重寫代碼就會(huì)被執(zhí)行。 原來(lái)直接函數(shù)調(diào)用的方式將被通過中間函數(shù)調(diào)用的方式所替換;這樣內(nèi)嵌函數(shù)和用戶自定義函數(shù)都能被執(zhí)行到。

  • 對(duì)中間函數(shù)的動(dòng)態(tài)調(diào)用將覆蓋代碼中變量的訪問權(quán)限

SoftMocks 可以和 Nikita Popov’s 的 PHP-Parser 配合: 這個(gè)庫(kù)不是很快(解析速度大概比token_get_all 慢15倍),但他的接口讓你繞過語(yǔ)法解析樹,并且包含了一個(gè)方便的API 用來(lái)處理不確定的語(yǔ)法結(jié)構(gòu)。

現(xiàn)在讓我們回到本文主題:切換到PHP 7.0版本。  當(dāng)我們通過SoftMocks把整個(gè)項(xiàng)切換過來(lái)后,我們依然有1000多個(gè)測(cè)試需要手動(dòng)處理。你可以說(shuō)這還不算太差的結(jié)果,和我們?cè)陂_始時(shí)提到的 60000個(gè)測(cè)試相比的話。 和runkit相比,測(cè)試速度沒有下降,所以SoftMocks并沒有性能問題。 為了公平起見,我們認(rèn)為uopz 明顯的快很多。

盡管PHP7包含了許多新功能,但是仍然存在一些與老版本兼容的問題。首要的解決辦法是閱讀官方的移植文檔,之后我們會(huì)馬上明白如果不去修改現(xiàn)有代 碼,我們將會(huì)面對(duì)的不僅僅是在生產(chǎn)環(huán)境中遇到致命的未知錯(cuò)誤并且由于升級(jí)后代碼的改變,我們無(wú)法在日志中查找到任何信息。這將會(huì)導(dǎo)致程序無(wú)法正常運(yùn)行。

Badoo中有許多PHP代碼倉(cāng)庫(kù),其中最大的有超過2百萬(wàn)行代碼。此外,我們還使用PHP實(shí)現(xiàn)了很多功能,從網(wǎng)站業(yè)務(wù)邏輯到手機(jī)應(yīng)用后段再到集成 測(cè)試和代碼部署。就目前來(lái)說(shuō),我們的情況很復(fù)雜,畢竟Badoo有很長(zhǎng)的歷史,我們使用它已經(jīng)快十年了,最不幸的是仍然有采用PHP4的環(huán)境在運(yùn)行。在 Badoo中,我們不推薦用‘just stare at it long enough’的方式來(lái)發(fā)現(xiàn)問題。一套所謂的’Brazilian’系統(tǒng)將代碼部署在生產(chǎn)環(huán)境,你需要等待直到它發(fā)生錯(cuò)誤,這很容易引發(fā)大面積用戶在使用 中遇到業(yè)務(wù)上的錯(cuò)誤,使其不明原因。綜上所訴,我們開始尋找一種方法能自動(dòng)發(fā)現(xiàn)不兼容的地方。

最初,我們?cè)噲D用IDE的,這是開發(fā)者中很受歡迎,但不幸的是,他們要么不支持PHP7的語(yǔ)法和特征,要么沒有函數(shù)可以在代碼中找到所有的明顯的危險(xiǎn)的地方,發(fā)現(xiàn)所有明顯危險(xiǎn)的地方。進(jìn)行了一些研究(如谷歌搜索)后,我們決定嘗試php7mar工具,它是用PHP實(shí)現(xiàn)一個(gè)靜態(tài)代碼分析儀。這PHP7工具使用起來(lái)非常簡(jiǎn)單,很快工程,并為您提供了一個(gè)文本文件。當(dāng)然,它不是萬(wàn)能的; 找特別是精心隱藏的問題點(diǎn)。盡管如此,該實(shí)用程序幫助我們鏟除約 90%的問題,大大加快和簡(jiǎn)化了準(zhǔn)備 PHP7 的代碼的過程。

對(duì)我們來(lái)說(shuō),最常遇到的和潛在危險(xiǎn)的問題是以下內(nèi)容:

  • 在func_get_arg()以及func_get_args的行為變化()。在PHP的第5版本中,這些功能中的傳輸?shù)臅r(shí)刻返回參數(shù)值,但在 七個(gè)版本發(fā)生這種情況的時(shí)刻時(shí)func_get_args()被調(diào)用。換句話說(shuō),如果函數(shù)內(nèi)func_get_args前參數(shù)變量的變化()被調(diào)用,則該 代碼的行為可以由五個(gè)版本不同。同樣的事情發(fā)生時(shí),應(yīng)用程序的業(yè)務(wù)邏輯壞了,但并沒有什么在日志中。

  • 間接訪問對(duì)象變量,屬性和方法。并再次,危險(xiǎn)在于,該行為可以更改“靜默”。對(duì)于那些尋找更多的信息,版本間的差異進(jìn)行了詳細(xì)的描述在這里。

  • 使用保留類名。在PHP7,可以不再使用布爾,整型,浮點(diǎn),字符串,空,真假類名稱。,是的,我們有一個(gè)空的類。它的缺席實(shí)際上使事情變得更容易,但因?yàn)樗3?dǎo)致錯(cuò)誤。

  • 使用引用許多潛在的問題的foreach結(jié)構(gòu)被發(fā)現(xiàn)了。由于我們?cè)噲D早不改變迭代數(shù)組中的foreach或雖在其內(nèi)部指針數(shù),幾乎所有的人都表現(xiàn)在版本5和7相同。

剩余的不兼容性的情況下也很少遇到了 (像 ‘e’ 修飾符在正則表達(dá)式),或他們固定的一個(gè)簡(jiǎn)單的替換 (例如,現(xiàn)在所有構(gòu)造函數(shù)應(yīng)該被命名為 __construct()。類名稱不允許使用)。
但是,我們即使在開始修復(fù)代碼之前,我們很擔(dān)心,一些開發(fā)商做一些必要的兼容性變化,其他人會(huì)繼續(xù)寫不符合 PHP7 的代碼。為了解決這一問題,我們把 pre-receive 鉤在已更改的文件 (換句話說(shuō),確保語(yǔ)法匹配 PHP7) 上執(zhí)行 php7-l 在每一個(gè) git 存儲(chǔ)庫(kù)中。這并不能保證不會(huì)有任何兼容性問題,但它不會(huì)清除主機(jī)問題。在其他情況下,開發(fā)人員只是不得不變得更加專注。除此之外,我們開始在 PHP7 上運(yùn)行的測(cè)試整個(gè)集并與 PHP5 的結(jié)果進(jìn)行了比較。

此外,開發(fā)者不允許使用任何PHP7的新功能,例如,我們沒有禁止老版本的預(yù)接收鉤子 php5 -l。這允許我們讓代碼兼容PHP5和PHP7。為什么這個(gè)很重要?因?yàn)槌藀hp代碼的問題之外,還有PHP7極其自身擴(kuò)展的一些潛在的問題(這些都可 以證實(shí))。并且不幸的是,不是所有的問題都可以在測(cè)試環(huán)境中重現(xiàn)出來(lái);有一些我們只在產(chǎn)品的大負(fù)載時(shí)才見過。

實(shí)踐出真知

很明顯我們需要一種簡(jiǎn)單快速的方法在任何數(shù)量以及類型的服務(wù)器上切換php版本。要啟用的話,所有指向CLI-interpreter的代碼路徑都 替換成了 /local/php,相應(yīng)的,是/local/php5或者/local/php7。這樣的話,要在服務(wù)器上改變php版本,需要改變鏈接(為cli腳 本操作設(shè)置原子操作是很重要的),停止php5-fpm,然后啟動(dòng)php7-fpm。在nginx中,我們使用不同的端口為php-fpm和啟動(dòng) php5-fpm,php7-fom設(shè)置兩個(gè)不同的upstream,但我們不喜歡復(fù)雜的nginx配置。

在執(zhí)行完以上的清單后,我們接著在預(yù)發(fā)布環(huán)境運(yùn)行Selenium 測(cè)試,這個(gè)階段暴露更多我們?cè)缙跊]注意到的問題。這些問題涉及到PHP代碼(比如,我們不再使用過期全局變量$HTTP_RAW_POST_DATA,取 而代之是 file_get_contents(“php://input”))以及擴(kuò)展(這里存在各種不同類型的段錯(cuò)誤)。
修復(fù)完早期發(fā)現(xiàn)的問題和重寫單元測(cè)試(這個(gè)過程中我們也發(fā)現(xiàn)若干隱藏在解析器的BUG比如這里)后,進(jìn)入到我們稱為“隔離”發(fā)布階段。這個(gè)階段我們?cè)谝欢〝?shù)量的服務(wù)器上運(yùn)行新版PHP。一開始我們?cè)诿總€(gè)主要PHP集群(Web后臺(tái),移動(dòng)APP后臺(tái),云平臺(tái)) 上只啟動(dòng)一個(gè)服務(wù),然后在沒有錯(cuò)誤出現(xiàn)情況下,一點(diǎn)一點(diǎn)增加服務(wù)數(shù)量。云平臺(tái)是第一個(gè)完全切換到PHP7的大集群,因?yàn)檫@個(gè)集群沒有php-fpm需求。 fpm 集群必須等到我們找到或者Dmitri Stogov修復(fù)了OpCache問題。之后,我們也會(huì)將fpm集群切換到PHP7。

現(xiàn)在看下結(jié)果,簡(jiǎn)單的說(shuō),他們是非常出色的。在這里,你能看到響應(yīng)時(shí)間圖,包括內(nèi)存消耗和我們的最大的集群(包括263服務(wù)器)的處理器的使用情況,以及在 Prague 數(shù)據(jù)中心的移動(dòng)應(yīng)用后端的使用。

響應(yīng)時(shí)間分布:

 

RUsage (CPU 時(shí)間):

 

內(nèi)存使用:

 

CPU 加載 (%)-移動(dòng)后臺(tái)集群

 

這一切到位,處理時(shí)間減少了一半,從而提高整體響應(yīng)時(shí)間約40%,由于一定量的請(qǐng)求處理時(shí)間是花在與數(shù)據(jù)庫(kù)和守護(hù)進(jìn)程通信。從邏輯上講,我們不希望 這部分加快切換到php7。除此之外,由于超線程技術(shù),集群的整體負(fù)載下降到50%以下,進(jìn)一步促進(jìn)了令人印象深刻的結(jié)果。廣義而言,當(dāng)負(fù)載增加超過 50%,HT-engines,而不是作為有用的物理引擎開始工作。但這已經(jīng)是另一篇文章的主題。此外,記憶的使用,這從來(lái)沒有一個(gè)瓶頸,我們,減少了大 約八倍以上!最后,我們節(jié)省了機(jī)器的數(shù)量。換句話說(shuō),服務(wù)器的數(shù)量可以承受更大的負(fù)載,從而降低獲取和維修設(shè)備的費(fèi)用。在剩余的聚類結(jié)果相似,除云上的收 益是一個(gè)更溫和的(大約40%個(gè)CPU),由于opcache操作的減少。

來(lái)算算我們能節(jié)省多少費(fèi)用呢?大致測(cè)算一下,一個(gè)Badoo應(yīng)用服務(wù)器集群大概包含600多臺(tái)服務(wù)器。如果cpu使用率減半,我們可以節(jié)省大約 300臺(tái)服務(wù)器。考慮服務(wù)器的硬件成本和折舊,每臺(tái)大約4000美元。總的算下來(lái)我們能節(jié)省大約100萬(wàn)美元,另加每年10萬(wàn)的主機(jī)托管費(fèi)。而且這還沒有 計(jì)算對(duì)服務(wù)云性能的提升帶來(lái)的價(jià)值,這個(gè)結(jié)果很令人振奮。

另外,您是否也考慮切換到PHP 7.0版本呢? 我們很希望聽聽您關(guān)于此問題的觀點(diǎn),而且非常愿意在下面的評(píng)論中回答您的疑問。

Badoo 團(tuán)隊(duì)

責(zé)任編輯:王雪燕 來(lái)源: oschina
相關(guān)推薦

2023-05-04 07:22:22

微軟Windows

2012-02-10 09:34:02

2021-07-23 11:41:49

Edge睡眠標(biāo)簽微軟

2016-05-12 16:44:26

IBM大型機(jī)LinuxONE

2019-07-17 21:41:55

Windows 7操作系統(tǒng)Windows

2021-02-14 09:59:55

黑客網(wǎng)絡(luò)安全勒索

2023-09-20 14:30:36

K8s亞馬遜谷歌

2023-06-21 11:10:12

人工智能AI

2017-08-03 09:18:48

PCCore i5SSD

2023-01-10 23:36:22

AI律師辯護(hù)

2021-10-11 14:07:28

比特幣虛擬貨幣加密貨幣

2015-09-23 12:25:53

2011-03-21 10:02:42

甲骨文sunsun.com

2013-01-28 10:56:48

開心農(nóng)場(chǎng)云服務(wù)

2015-09-08 16:05:24

2011-11-30 13:27:19

Puppet

2011-03-21 10:05:48

甲骨文Sun

2022-12-14 15:49:31

2020-12-03 19:17:22

GDPR數(shù)據(jù)保護(hù)數(shù)據(jù)安全

2011-07-07 14:28:23

PHP
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)