摘要:作為開發(fā)中應(yīng)用最廣泛的開源腳本語(yǔ)言,憑借庫(kù)類豐富,使用簡(jiǎn)單,安全等特點(diǎn),成為和等互聯(lián)網(wǎng)巨頭和全球超過(guò)網(wǎng)站的主要開發(fā)語(yǔ)言,然而性能問題是一直以來(lái)飽受詬病的,來(lái)自開發(fā)組的高馳濤同學(xué)將為我們帶來(lái)他對(duì)性能優(yōu)化方面的思考和建議。
PHP作為Web開發(fā)中應(yīng)用最廣泛的開源腳本語(yǔ)言,憑借庫(kù)類豐富,使用簡(jiǎn)單,安全等特點(diǎn),成為Facebook和BAT等互聯(lián)網(wǎng)巨頭和全球超過(guò)70%網(wǎng)站的主要開發(fā)語(yǔ)言,然而性能問題是PHP一直以來(lái)飽受詬病的,來(lái)自PHP/PECL開發(fā)組的高馳濤同學(xué)將為我們帶來(lái)他對(duì)PHP性能優(yōu)化方面的思考和建議。
本期主講:高馳濤,Neeke Gao,PHP/PECL開發(fā)組成員,同時(shí)是SeasLog,JsonNet-PHP的作者,目前在云智慧擔(dān)任架構(gòu)師。
今天主要從PHP的發(fā)展和性能優(yōu)化歷史,來(lái)談PHP語(yǔ)言在性能優(yōu)化方面所做過(guò)的努力,以及我們的一些研究成果。
談起PHP,我們先來(lái)了解幾個(gè)數(shù)字:
1995年, PHP發(fā)布了第一個(gè)版本,這要感謝PHP之父Rasmus Lerdorf的辛苦努力。PHP在問世之初是Personal Home Page的縮寫,那時(shí)候只是被當(dāng)作制作個(gè)人網(wǎng)頁(yè)的一門簡(jiǎn)單語(yǔ)言;后來(lái)隨著互聯(lián)網(wǎng)的發(fā)展以及開源社區(qū)的貢獻(xiàn),PHP逐步成長(zhǎng)成為一門被廣泛應(yīng)用的高級(jí)語(yǔ)言,其英文含義也進(jìn)化為PHP: Hypertext Preprocessor,即超級(jí)文本預(yù)處理語(yǔ)言。
官方統(tǒng)計(jì)數(shù)字顯示,全球排名前1000萬(wàn)的網(wǎng)站應(yīng)用中,有81.9%是使用PHP語(yǔ)言開發(fā)的。而且,每天有416個(gè)新增PHP網(wǎng)站進(jìn)入全球前1000萬(wàn)排名,數(shù)量還在不斷增加。發(fā)展到今天,PHP經(jīng)歷了4,5,7幾個(gè)非常重大的版本迭代,最新的release版本是7.0.6。在二十多年的發(fā)展過(guò)程中,應(yīng)用最廣泛的PHP版本是PHP 5,同時(shí)也是目前全球互聯(lián)網(wǎng)上應(yīng)用最為廣泛的一個(gè)語(yǔ)言版本。
為什么沒有PHP6,而是直接從PHP5到PHP7,這里面有一個(gè)小故事。目前的PHP5.6,其實(shí)就是原預(yù)計(jì)發(fā)布的PHP6,但由于各項(xiàng)改動(dòng)不足以支撐一個(gè)全新的PHP分支,組織內(nèi)投票沒有通過(guò)發(fā)布,而最終作為了PHP5.6進(jìn)行發(fā)布。
PHP7又稱為PHP NG,即“PHP Next Generation(下一代PHP)”,在性能和穩(wěn)定性方面做了非常大的提升。為什么這么說(shuō)呢,要從PHP的業(yè)務(wù)模型說(shuō)起。
1、PHP Transaction Module業(yè)務(wù)模型
下面我先帶大家過(guò)一下PHP5幾個(gè)重大版本改動(dòng)中的性能優(yōu)化點(diǎn),下面這張圖是PHP整個(gè)運(yùn)行過(guò)程中的幾個(gè)關(guān)鍵點(diǎn)。
在PHP運(yùn)行過(guò)程中,在Script Entry接收到請(qǐng)求之后。
首先經(jīng)過(guò)語(yǔ)法解析器(Parser),此時(shí)會(huì)拋出一些致命的語(yǔ)法錯(cuò)誤或警告(后續(xù)的版本改動(dòng)中,會(huì)有一些致命錯(cuò)誤轉(zhuǎn)換為exception拋出);
其次經(jīng)過(guò)編譯器(Compiler),這部分內(nèi)容中會(huì)進(jìn)行更高級(jí)的解析,并測(cè)試將PHP高級(jí)語(yǔ)言編譯成OpCode;
然后交給Execute進(jìn)行執(zhí)行;執(zhí)行過(guò)程中發(fā)現(xiàn)有新的文件或類被引入,會(huì)再進(jìn)行Compiler,往復(fù)執(zhí)行。
從這里可以看出,其實(shí)PHP也是“編譯型”語(yǔ)言,只不過(guò)是每次請(qǐng)求都編譯,或稱動(dòng)態(tài)編譯。那么,后續(xù)的優(yōu)化過(guò)程中就可以進(jìn)行針對(duì)性優(yōu)化,即:將編譯后的內(nèi)容緩存起來(lái),直接執(zhí)行,以節(jié)省編譯時(shí)間。
了解一點(diǎn)PHP的同學(xué)都知道,PHP通常被認(rèn)為是簡(jiǎn)單、低效,這并不是沒有道理。我們來(lái)看一段PHP源碼,從而向大家解釋為什么“簡(jiǎn)單”,為什么“低效”。
這段結(jié)構(gòu)是PHP5及以前版本中所有變量和方法執(zhí)行的核心,這是通用的變量存儲(chǔ)結(jié)構(gòu)。可以看到,同一個(gè)變量能夠同時(shí)有多個(gè)屬性,或long,或double,或char,或int,或array,或Object。這給工程師以充分的自由度,同樣的一個(gè)數(shù)字,或字符串,不需要預(yù)設(shè)類型,就可以直接生成并使用。這就是為什么“簡(jiǎn)單”,這是對(duì)工程師來(lái)說(shuō)的。
而同時(shí)丟給Zend引擎(解析執(zhí)行引擎)的,有著大量的負(fù)擔(dān),因?yàn)樾枰嬖诿恳淮问褂没蜻\(yùn)算時(shí),都要不停的判斷類型究竟是什么類型屬性。這就是為什么“低效”的一個(gè)最直接原因。
2、PHP Performance Difficulty 性能之坑
對(duì)于一個(gè)使用PHP開發(fā)的應(yīng)用來(lái)說(shuō),經(jīng)過(guò)大量的實(shí)踐,可以總結(jié)出4個(gè)最影響性能的點(diǎn):
IO, Memory, CPU, NetWork,是不是非常眼熟?沒錯(cuò),這其實(shí)并不單單是PHP語(yǔ)言的性能瓶頸,任何一門語(yǔ)言,或者就目前我們所處的世界中,凡是使用計(jì)算機(jī)語(yǔ)言開發(fā)的服務(wù)或應(yīng)用,都存在這4個(gè)瓶頸。
3、Optimize from PHP5 to PHP7 優(yōu)化之旅
下面就為大家介紹一下PHP5圍繞以上4個(gè)點(diǎn)所做的一些性能優(yōu)化。在聊具體的性能優(yōu)化方法之前,我們可以拋開之前的知識(shí)儲(chǔ)備,打開腦洞,發(fā)散思維,思考應(yīng)該如何入手。每個(gè)人的想法完全不一樣,我的想法是這樣的:
?會(huì)不會(huì)是PHP本身的運(yùn)行模型(或業(yè)務(wù)模型)或者Zend引擎設(shè)計(jì)存在問題?
?有沒有可能將PHP語(yǔ)言在發(fā)布運(yùn)行之前進(jìn)行預(yù)編譯,把它轉(zhuǎn)變成Bytecode?
?有沒有可能通過(guò)一種解析器把PHP轉(zhuǎn)變成C或C++語(yǔ)言,然后進(jìn)行make或build?
?能不能開發(fā)另一套解析運(yùn)行引擎?
?會(huì)不會(huì)出現(xiàn)另一套完全不一樣的運(yùn)行模型(或業(yè)務(wù)模型)?
?等等。
這些想法在PHP社區(qū)內(nèi)屢見不鮮,并不僅僅是我一個(gè)人在這么想,非常多PHP資深專家也在思考,而且在各個(gè)方向上都有一些開源的工具或服務(wù)發(fā)布了。由于PHP5有非常多版本,這里我們僅就應(yīng)用最廣的PHP5.4和PHP5.5-5.6版本來(lái)簡(jiǎn)要說(shuō)明性能優(yōu)化的幾個(gè)點(diǎn)。
PHP5.4 最主要的性能改進(jìn)是在數(shù)組的生成和應(yīng)用上面,一個(gè)簡(jiǎn)單的延后分配節(jié)省了非常大量的內(nèi)存,因?yàn)槎鄶?shù)情況數(shù)組在直接引用上并不進(jìn)行運(yùn)算,從而并不進(jìn)行內(nèi)存建立與分配工作。另外,PHP5.4在運(yùn)行時(shí)中添加了Literal Table和Binding Cache操作,這兩個(gè)改動(dòng)相對(duì)上面延后分配內(nèi)存是更復(fù)雜一些的,它在運(yùn)行過(guò)程中節(jié)省了大量的CPU運(yùn)算。
PHP5.5及5.6放在一起來(lái)說(shuō),因?yàn)樗鼈冋娴暮芟瘢以谀壳癙HP5整個(gè)大分支的維護(hù)過(guò)程中,一般是在PHP5.5上進(jìn)行,然后把相關(guān)修改向5.6同步。5.5和5.6最重要的一個(gè)性能改進(jìn),是使用了編譯Cache。前面我們了解了PHP的運(yùn)行過(guò)程中會(huì)存在“編譯->OpCode->執(zhí)行”的過(guò)程,而將編譯結(jié)果緩存起來(lái)是一個(gè)重要的性能優(yōu)化點(diǎn),OpCache就是做這個(gè)工作的。OpCache從此進(jìn)入了PHP的內(nèi)核,而不再是一個(gè)第三方擴(kuò)展。
同時(shí)Zend引擎還有同樣一個(gè)Cache優(yōu)化擴(kuò)展版本產(chǎn)生,即Zend O+,可以認(rèn)為是Zend的Plus版本,在內(nèi)存和CPU上,都做了一些改進(jìn)。
最后來(lái)看看PHP7的幾個(gè)優(yōu)化點(diǎn):PHP7直接修改了Zend Zval結(jié)構(gòu),這算得上是一個(gè)很大改動(dòng)。同時(shí)在PHP7中,數(shù)組的結(jié)構(gòu)也變得更加的不一樣,這又是一個(gè)傷筋動(dòng)骨的改動(dòng)。官方數(shù)據(jù)中PHP7較PHP5.6有近兩倍的性能提升,主要就集中在這兩個(gè)點(diǎn)上。
看一下PHP源碼:
在一個(gè)Zval結(jié)構(gòu)中,一個(gè)變量仍然可以屬于各種類型的,但在使用的時(shí)候,可以快速判斷是哪種類型,因?yàn)椴煌念愋蜁?huì)存儲(chǔ)在不同的指針中;而且內(nèi)存使用也由于不同的指針類型而大量地降低;由于內(nèi)存使用大量降低,從而為CPU更快地尋址和操作帶來(lái)了更好的可能性。所以有了Zval的結(jié)構(gòu)變動(dòng)帶來(lái)35%性能提升的結(jié)論。
同一個(gè)數(shù)組,在PHP5中的內(nèi)存使用是跳躍不連貫的,而在PHP7中是連續(xù)有序的,這使得內(nèi)存使用和CPU使用都更加地高效,數(shù)組的結(jié)構(gòu)變動(dòng),給PHP7帶來(lái)了接近50%的性能提升。
4、PHP Performance Tools 工具推薦
前面在我們發(fā)散思維時(shí)列舉了很多PHP性能優(yōu)化的點(diǎn),幾個(gè)開源社區(qū)中已經(jīng)發(fā)布過(guò)針對(duì)這些的優(yōu)化工具,給大家推薦一些:
Facebook發(fā)布的HHVM:
HHVM (HipHop Virtual Machine)類似于C#的CLR和Java的JVM,會(huì)將PHP代碼轉(zhuǎn)換成高級(jí)別的字節(jié)碼(通常稱為中間語(yǔ)言),然后在運(yùn)行時(shí)通過(guò)即時(shí)(JIT)編譯器將這些字節(jié)碼轉(zhuǎn)換為x64的機(jī)器碼。
下面是一些在開發(fā)調(diào)試過(guò)程中經(jīng)常使用的工具和軟件服務(wù):
此類開發(fā)工具和服務(wù)很多,可以為開發(fā)者和運(yùn)維同學(xué)節(jié)省大量的定位和解決問題時(shí)間。
以我開發(fā)的SeasLog為例,由于使用內(nèi)存buffer/批量IO,替代直接IO,可以直接為服務(wù)的QPS能力提升帶來(lái)強(qiáng)勁動(dòng)力,下圖是SeasLog和log4php的性能對(duì)比:
最后為東家打個(gè)小廣告,云智慧的APM應(yīng)用性能管理產(chǎn)品透視寶www.toushibao.com,可以提供更為強(qiáng)勁的性能管理分析的商業(yè)支持方案,目前支持包括PHP,Java,DotNet,Python,IOS,Android在內(nèi)各種主流應(yīng)用的性能監(jiān)測(cè)和管理分析能力,歡迎大家交流體驗(yàn)。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/21703.html