PHP做爲Web開發中應用最普遍的開源腳本語言,憑藉庫類豐富,使用簡單,安全等特色,成爲Facebook和BAT等互聯網巨頭和全球超過70%網站的主要開發語言,然而性能問題是PHP一直以來飽受詬病的,來自PHP/PECL開發組的高馳濤同窗將爲咱們帶來他對PHP性能優化方面的思考和建議。
php
本期主講:高馳濤,Neeke Gao,PHP/PECL開發組成員,同時是SeasLog,JsonNet-PHP的做者,目前在雲智慧擔任架構師。
今天主要從PHP的發展和性能優化歷史,來談PHP語言在性能優化方面所作過的努力,以及咱們的一些研究成果。
談起PHP,咱們先來了解幾個數字:
數組
1995年, PHP發佈了第一個版本,這要感謝PHP之父Rasmus Lerdorf的辛苦努力。PHP在問世之初是Personal Home Page的縮寫,那時候只是被看成製做我的網頁的一門簡單語言;後來隨着互聯網的發展以及開源社區的貢獻,PHP逐步成長成爲一門被普遍應用的高級語言,其英文含義也進化爲PHP: Hypertext Preprocessor,即超級文本預處理語言。緩存
官方統計數字顯示,全球排名前1000萬的網站應用中,有81.9%是使用PHP語言開發的。並且,天天有416個新增PHP網站進入全球前1000萬排名,數量還在不斷增長。發展到今天,PHP經歷了4,5,7幾個很是重大的版本迭代,最新的release版本是7.0.6。在二十多年的發展過程當中,應用最普遍的PHP版本是PHP 5,同時也是目前全球互聯網上應用最爲普遍的一個語言版本。安全
爲何沒有PHP6,而是直接從PHP5到PHP7,這裏面有一個小故事。目前的PHP5.6,其實就是原預計發佈的PHP6,但因爲各項改動不足以支撐一個全新的PHP分支,組織內投票沒有經過發佈,而最終做爲了PHP5.6進行發佈。性能優化
PHP7又稱爲PHP NG,即「PHP Next Generation(下一代PHP)」,在性能和穩定性方面作了很是大的提高。爲何這麼說呢,要從PHP的業務模型提及。架構
一、PHP Transaction Module業務模型
下面我先帶你們過一下PHP5幾個重大版本改動中的性能優化點,下面這張圖是PHP整個運行過程當中的幾個關鍵點。
運維
在PHP運行過程當中,在Script Entry接收到請求以後。
首先通過語法解析器(Parser),此時會拋出一些致命的語法錯誤或警告(後續的版本改動中,會有一些致命錯誤轉換爲exception拋出);
其次通過編譯器(Compiler),這部份內容中會進行更高級的解析,並測試將PHP高級語言編譯成OpCode;工具
而後交給Execute進行執行;執行過程當中發現有新的文件或類被引入,會再進行Compiler,往復執行。性能
從這裏能夠看出,其實PHP也是「編譯型」語言,只不過是每次請求都編譯,或稱動態編譯。那麼,後續的優化過程當中就能夠進行鍼對性優化,即:將編譯後的內容緩存起來,直接執行,以節省編譯時間。開發工具
瞭解一點PHP的同窗都知道,PHP一般被認爲是簡單、低效,這並非沒有道理。咱們來看一段PHP源碼,從而向你們解釋爲何「簡單」,爲何「低效」。
這段結構是PHP5及之前版本中全部變量和方法執行的核心,這是通用的變量存儲結構。能夠看到,同一個變量可以同時有多個屬性,或long,或double,或char,或int,或array,或Object。這給工程師以充分的自由度,一樣的一個數字,或字符串,不須要預設類型,就能夠直接生成並使用。這就是爲何「簡單」,這是對工程師來講的。
而同時丟給Zend引擎(解析執行引擎)的,有着大量的負擔,由於須要引擎在每一次使用或運算時,都要不停的判斷類型到底是什麼類型屬性。這就是爲何「低效」的一個最直接緣由。
二、PHP Performance Difficulty 性能之坑
對於一個使用PHP開發的應用來講,通過大量的實踐,能夠總結出4個最影響性能的點:
IO, Memory, CPU, NetWork,是否是很是眼熟?沒錯,這其實並不僅僅是PHP語言的性能瓶頸,任何一門語言,或者就目前咱們所處的世界中,凡是使用計算機語言開發的服務或應用,都存在這4個瓶頸。
三、Optimize from PHP5 to PHP7 優化之旅
下面就爲你們介紹一下PHP5圍繞以上4個點所作的一些性能優化。在聊具體的性能優化方法以前,咱們能夠拋開以前的知識儲備,打開腦洞,發散思惟,思考應該如何入手。每一個人的想法徹底不同,個人想法是這樣的:
會不會是PHP自己的運行模型(或業務模型)或者Zend引擎設計存在問題?
有沒有可能將PHP語言在發佈運行以前進行預編譯,把它轉變成Bytecode?
有沒有可能經過一種解析器把PHP轉變成C或C++語言,而後進行make或build?
能不能開發另外一套解析運行引擎?
會不會出現另外一套徹底不同的運行模型(或業務模型)?
等等。
這些想法在PHP社區內家常便飯,並不只僅是我一我的在這麼想,很是多PHP資深專家也在思考,並且在各個方向上都有一些開源的工具或服務發佈了。因爲PHP5有很是多版本,這裏咱們僅就應用最廣的PHP5.4和PHP5.5-5.6版原本簡要說明性能優化的幾個點。
PHP5.4 最主要的性能改進是在數組的生成和應用上面,一個簡單的延後分配節省了很是大量的內存,由於多數狀況數組在直接引用上並不進行運算,從而並不進行內存創建與分配工做。另外,PHP5.4在運行時中添加了Literal Table和Binding Cache操做,這兩個改動相對上面延後分配內存是更復雜一些的,它在運行過程當中節省了大量的CPU運算。
PHP5.5及5.6放在一塊兒來講,由於它們真的很像,並且在目前PHP5整個大分支的維護過程當中,通常是在PHP5.5上進行,而後把相關修改向5.6同步。5.5和5.6最重要的一個性能改進,是使用了編譯Cache。前面咱們瞭解了PHP的運行過程當中會存在「編譯->OpCode->執行」的過程,而將編譯結果緩存起來是一個重要的性能優化點,OpCache就是作這個工做的。OpCache今後進入了PHP的內核,而再也不是一個第三方擴展。
同時Zend引擎還有一樣一個Cache優化擴展版本產生,即Zend O+,能夠認爲是Zend的Plus版本,在內存和CPU上,都作了一些改進。
最後來看看PHP7的幾個優化點:PHP7直接修改了Zend Zval結構,這算得上是一個很大改動。同時在PHP7中,數組的結構也變得更加的不同,這又是一個傷筋動骨的改動。官方數據中PHP7較PHP5.6有近兩倍的性能提高,主要就集中在這兩個點上。
看一下PHP源碼:
在一個Zval結構中,一個變量仍然能夠屬於各類類型的,但在使用的時候,能夠快速判斷是哪一種類型,由於不一樣的類型會存儲在不一樣的指針中;並且內存使用也因爲不一樣的指針類型而大量地下降;因爲內存使用大量下降,從而爲CPU更快地尋址和操做帶來了更好的可能性。因此有了Zval的結構變更帶來35%性能提高的結論。
同一個數組,在PHP5中的內存使用是跳躍不連貫的,而在PHP7中是連續有序的,這使得內存使用和CPU使用都更加地高效,數組的結構變更,給PHP7帶來了接近50%的性能提高。
四、PHP Performance Tools 工具推薦
前面在咱們發散思惟時列舉了不少PHP性能優化的點,幾個開源社區中已經發布過針對這些的優化工具,給你們推薦一些:
Facebook發佈的HHVM:
HHVM (HipHop Virtual Machine)相似於C#的CLR和Java的JVM,會將PHP代碼轉換成高級別的字節碼(一般稱爲中間語言),而後在運行時經過即時(JIT)編譯器將這些字節碼轉換爲x64的機器碼。
下面是一些在開發調試過程當中常用的工具和軟件服務:
此類開發工具和服務不少,能夠爲開發者和運維同窗節省大量的定位和解決問題時間。
以我開發的SeasLog爲例,因爲使用內存buffer/批量IO,替代直接IO,能夠直接爲服務的QPS能力提高帶來強勁動力,下圖是SeasLog和log4php的性能對比:
最後爲東家打個小廣告,雲智慧的APM應用性能管理產品透視寶www.toushibao.com,能夠提供更爲強勁的性能管理分析的商業支持方案,目前支持包括PHP,Java,DotNet,Python,IOS,Android在內各類主流應用的性能監測和管理分析能力,歡迎你們交流體驗。