惠新宸,百度PHP高級(jí)顧問(wèn),年二十有八,好追根究底,有不良嗜好, 幸性本善。乙酉年識(shí)互聯(lián)網(wǎng),丁亥年入雅虎,翌年入百度。雖性好安穩(wěn),然經(jīng)變無(wú)數(shù),唯常嘆"人生,菠菜湯爾"。 大家好,今天我主要介紹是PHP在百度一個(gè)發(fā)展歷程,最早的時(shí)候百度成立于2000年,2000年的時(shí)候,百度剛剛成立,剛剛在北大資源賓館建立百度,直到2001年的競(jìng)價(jià)排名,我不評(píng)價(jià)這個(gè)產(chǎn)品怎么樣,競(jìng)價(jià)排名當(dāng)時(shí)是第一個(gè)采用PHP,在百度的PHP系統(tǒng)。從2001年到今年已經(jīng)10年時(shí)間了,這10年時(shí)間百度PHP經(jīng)歷一些什么變化呢? 我們現(xiàn)在看到是百度,那天我自己腦子里想了一遍,當(dāng)然不是全部,大家能夠知道的一些用戶(hù)產(chǎn)品,無(wú)線產(chǎn)品,商業(yè)產(chǎn)品。包括貼吧這個(gè)比較大了,還有最新的旅游。對(duì)于貼吧來(lái)說(shuō),前端可能是CUI,或者業(yè)務(wù)邏輯,一直到后來(lái)已經(jīng)遷到PHP。我列出來(lái)這些產(chǎn)品,都是使用了PHP,還有沒(méi)列出來(lái)也是使用了PHP的,很多。所以,如果說(shuō)讓我去介紹每個(gè)產(chǎn)品是怎么用PHP的,我覺(jué)得這個(gè)不太現(xiàn)實(shí),我一共只有30分鐘。 這30分鐘我主要想跟大家分享的我們發(fā)現(xiàn)一些問(wèn)題和怎么去解決,這些問(wèn)題是大家都會(huì)遇到的。我們最早的時(shí)候,就像我剛才提到的我們一些,因?yàn)樘幱谧罡咝阅芤螅约皩?duì)于PHP的不了解,以及對(duì)于外部我們可能覺(jué)得PHP很慢,所以我們以前的時(shí)候,這些大的訪問(wèn)量產(chǎn)品都是用C來(lái)做的。他可能在模板上用Cu-i來(lái)做展現(xiàn),這樣的方式大家都知道開(kāi)發(fā),調(diào)試,部署都很復(fù)雜,成本也比較高,門(mén)檻也比較高,招人也比較難招。 后來(lái)的時(shí)候我們就考慮是不是應(yīng)該去換一個(gè),當(dāng)時(shí)應(yīng)該考慮要是JAVA,或者是PHP。我們?cè)贑的時(shí)候,C-ui和后面進(jìn)程去通訊主要是Nsheader和mcpack,類(lèi)似于上面一些打包傳輸?shù)姆绞?。我們?yōu)槭裁催x了PHP?第一高性能,快速開(kāi)發(fā)要求。我這說(shuō)高性能,可能下面有一些工程師就笑了,你PHP講什么高性能。我說(shuō)的這些高性能是在相對(duì)情況下高性能,當(dāng)我們WAP應(yīng)用程序不僅僅局限PHP,瓶頸更大在于數(shù)據(jù)和文件,以及這些IO方面,在這些方面來(lái)說(shuō),PHP性能已經(jīng)足夠了。 那么開(kāi)放開(kāi)發(fā)就不用說(shuō)了,PHP不需要編譯,不依賴(lài)于環(huán)境,我所改即所建,改了就能看到,這個(gè)調(diào)試開(kāi)發(fā)過(guò)程非???,這是一個(gè)優(yōu)點(diǎn)。穩(wěn)定性,路棒性,安全性,怎么講呢?有一個(gè)玩笑,我跟我們百度幾個(gè)同學(xué)去聊天,他們就抱怨,PHP工程師真的是這個(gè)質(zhì)量層次不齊,再爛的PHP工程師寫(xiě)出的代也能跑,跑完了也正常。這是從一個(gè)方面,可能他的本意是說(shuō)我們招聘有一部分人水平本來(lái)不一樣。但是從另外一個(gè)方面,也體現(xiàn)出來(lái)PHP一個(gè)特點(diǎn)是什么呢?穩(wěn)定,魯棒性很強(qiáng)。再爛,再不懂PHP的新手去寫(xiě),你也不會(huì)把它寫(xiě)垮掉。 說(shuō)到這里我有一個(gè)小問(wèn)題,大家知道怎么PK掉一個(gè)PHP進(jìn)程嗎,最簡(jiǎn)單的方式。其實(shí)這個(gè)問(wèn)題還挺難的,我跟我的朋友講,你們說(shuō)怎么PK掉一個(gè)PHP進(jìn)程,我需要調(diào)試,其實(shí)很簡(jiǎn)單你寫(xiě)一個(gè)無(wú)線遞歸下去就會(huì)打掉。PHP有很多安全措施,比如我們頗為被人爭(zhēng)議GPH選項(xiàng),打開(kāi)之后會(huì)對(duì)客戶(hù)進(jìn)行過(guò)濾。還有PHP對(duì)輸入做各種各樣的轉(zhuǎn)換驗(yàn)證,這方面PHP對(duì)安全性考慮也是多的,當(dāng)然還有是不建議打開(kāi)的,那樣的話更安全。 靈活和豐富的語(yǔ)法就不用多說(shuō)了,一個(gè)PHP怎么寫(xiě),不需要特定格式,隨意性也非常強(qiáng),功能當(dāng)然也很多了。他應(yīng)用面這么廣,自然是一個(gè)例證。良好的運(yùn)行在Linux,可擴(kuò)展C/C++。PHP經(jīng)典搭配是沒(méi)有問(wèn)題的,我們都知道,我們當(dāng)時(shí)不選擇JAVA一個(gè)原因,還有一方面考慮,JAVA那套開(kāi)發(fā)環(huán)境比較復(fù)雜,重啟一下需要30-40秒。更重要一點(diǎn)可擴(kuò)展,因?yàn)槲医酉聛?lái)講的問(wèn)題就是從可擴(kuò)展來(lái)的,我們的優(yōu)化方案。 當(dāng)時(shí)我們就想因?yàn)镻HP應(yīng)用很多,一個(gè)開(kāi)源東西,有很多方便第三方房展,我們經(jīng)常用的PDO,都是擴(kuò)展的方式,并且他的擴(kuò)展也非常容易開(kāi)發(fā),網(wǎng)上有一堆教程,只要你照著教程做一遍。因?yàn)镻HP對(duì)擴(kuò)展做的很好,一行命令把自己代碼寫(xiě)進(jìn)去,就是一個(gè)很完整的擴(kuò)家,一個(gè)擴(kuò)展就能用。易部署,易調(diào)試,更不用說(shuō)了PHP直接拷貝,拷貝到哪都能夠運(yùn)行,不需要依賴(lài)系統(tǒng)的共享庫(kù),不會(huì)因?yàn)閹?kù)的掛接處而出現(xiàn)問(wèn)題,調(diào)試也很容易調(diào)試,最經(jīng)典的方式不停調(diào)試,我們還有一個(gè)PHP調(diào)試技術(shù)手冊(cè),我相信在座很多人都看過(guò),那里面介紹一段做單布跟蹤調(diào)試,這樣的調(diào)試今天在這里講,效率往往還不如直接調(diào)試快,當(dāng)時(shí)只是一種嘗試,或者說(shuō)一種探索去跟大家分享調(diào)試的技術(shù)。 展現(xiàn)邏輯分離這個(gè)也很重要,對(duì)于PHP來(lái)說(shuō),本身生來(lái)就是做WAP開(kāi)發(fā)的,可以把PHP代碼嵌入到WAP里面去,這個(gè)非常適合于做外部開(kāi)發(fā)的。入門(mén)快,剛才也提到了,我們現(xiàn)在招聘新來(lái)這些大學(xué)生其實(shí)他以前可能是做JAVA,是做C,一周時(shí)間就可以開(kāi)始寫(xiě)。所以,入門(mén)非??欤鐓^(qū)活躍,這里我要提一下,在我們百度就我所知有400多名做PHP開(kāi)發(fā),我們這400多名工程師都在一個(gè)群里,大家聊天,問(wèn)一個(gè)問(wèn)題立馬就有人來(lái)回答你,這只是在百度社區(qū),更不用說(shuō)開(kāi)源社區(qū)活躍程度了。 從這些方面我們就覺(jué)得PHP替換現(xiàn)在C的方式是可行的,于是我們就有了經(jīng)典的方案,就像我這大家看到的,用戶(hù)瀏覽器經(jīng)過(guò)的分發(fā),分發(fā)以后后臺(tái)就是這樣一個(gè)用PHP腳本,下面可能有一些擴(kuò)展,再下面就是PIP,后面數(shù)據(jù),因?yàn)檫@塊對(duì)于開(kāi)發(fā)來(lái)講,我這塊主要從貼吧角度來(lái)講,它是服務(wù)其邏輯數(shù)據(jù)還是用一些比較快的,還是以前那套老東西,只不過(guò)把UI這一塊做到PHP,當(dāng)然其他系統(tǒng)不是這樣。 這個(gè)時(shí)候后臺(tái)像Web Services等等提供這種數(shù)據(jù),給PHP腳本,這是一個(gè)現(xiàn)在這樣一個(gè),應(yīng)該說(shuō)比較經(jīng)典PHP開(kāi)發(fā)模式,或者在我們百度來(lái)說(shuō),主要還是以這種方式,PHP只是做展現(xiàn)。這樣的情況下有一個(gè)問(wèn)題,什么問(wèn)題?比方說(shuō)你是一個(gè)PHP工程師,你的上級(jí)交給你一個(gè)任務(wù),你去寫(xiě)一個(gè)什么樣的系統(tǒng),你把它部署下去。你剛來(lái)很有信心,沒(méi)問(wèn)題我去做,你用了一周時(shí)間寫(xiě)出來(lái),寫(xiě)完之后你用一天時(shí)間把環(huán)境搭起來(lái),把代碼放上去,四臺(tái)服務(wù)器需要共享,把這些東西都用完你可能用一周半時(shí)間,沒(méi)有問(wèn)題你這個(gè)做的很好,你這個(gè)東西也很正常,架構(gòu)也設(shè)計(jì)很好。 現(xiàn)在這樣的問(wèn)題還有100個(gè)你怎么辦?難道你再去部署100次,這不行吧。另外你做的東西放上去之后,你可能出去玩了,下班回家了,那怎么監(jiān)控呢?誰(shuí)去監(jiān)控呢?這也是現(xiàn)在單個(gè)產(chǎn)品線都要遇到的問(wèn)題。還有一個(gè)問(wèn)題資源流量陡增,比方說(shuō)你這個(gè)產(chǎn)品挺好的,日均PV10萬(wàn),突然一天漲到100萬(wàn),大家都知道去年的時(shí)候69圣戰(zhàn),貼吧經(jīng)過(guò)一次所謂69圣戰(zhàn),流量爆增了多少不知道,但把服務(wù)器給壓死了。 那么遇到流量陡增怎么辦,不能說(shuō)現(xiàn)在這個(gè)產(chǎn)品10萬(wàn),前臺(tái)上了100臺(tái)前臺(tái)機(jī),我告訴老大,我這個(gè)流量某一天陡增10誰(shuí)信啊,成本也受不了這也是一個(gè)問(wèn)題。規(guī)范和標(biāo)準(zhǔn),這是最頭疼的,我到百度以后參與了很多規(guī)范制定,也會(huì)提很多意見(jiàn),我每次做這些事情的時(shí)候我都是信心慢慢的,我覺(jué)得做完之后大家看了之后會(huì)去用,會(huì)去學(xué),可能咱們普遍共同語(yǔ)言就會(huì)多一點(diǎn)。但是發(fā)現(xiàn)你標(biāo)準(zhǔn)規(guī)范制定出來(lái)沒(méi)人理,這就是規(guī)范一個(gè)怎么去執(zhí)行,當(dāng)然這個(gè)問(wèn)題很難了,另外一個(gè)問(wèn)題,這也是我們現(xiàn)在遇到的問(wèn)題,我們有編碼規(guī)范,有部署規(guī)范,有目錄規(guī)范,但是沒(méi)有辦法推卸,沒(méi)有一個(gè)東西去強(qiáng)制讓他們這么去做。 還有防攻擊容災(zāi),你有4臺(tái)前端機(jī),僅僅4臺(tái),某個(gè)不知名相關(guān)組織弄了100多臺(tái)僵尸肉雞去壓你,你有什么辦法,沒(méi)有辦法,你只能被攻擊。還有一個(gè)問(wèn)題,我們現(xiàn)在產(chǎn)品線這么多,每個(gè)產(chǎn)品線使用的框架各不相同,開(kāi)發(fā)模式各不相同,這就造成他們都是異構(gòu)的,異構(gòu)會(huì)有什么問(wèn)題,OP會(huì)很郁悶。OP遇到每個(gè)產(chǎn)品線,有的配置文件在這放,有的配置文件在那放,就像我們UC就得為各種各樣框架命名規(guī)則開(kāi)發(fā)一個(gè)不同類(lèi)庫(kù)??焖匍_(kāi)發(fā)我就要求我的基礎(chǔ)設(shè)施足夠豐富,我基礎(chǔ)設(shè)施足夠豐富的情況下才能做到快速開(kāi)發(fā),我框架功能要很強(qiáng),這樣開(kāi)發(fā)才會(huì)快。 但是你框架功能很強(qiáng)就帶來(lái)一個(gè)問(wèn)題,你代碼多,就慢,PHP就這樣,怎么辦,這也是一個(gè)根本矛盾。這些問(wèn)題有沒(méi)有解決方案呢?當(dāng)然是有的,要不然我也不會(huì)拿出來(lái)講了。在百度現(xiàn)在對(duì)于前面的問(wèn)題,比方說(shuō)運(yùn)維,部署和容災(zāi),一些流量陡增這些問(wèn)題怎么辦呢?看最右邊一個(gè)Bae,就是百度應(yīng)用開(kāi)發(fā)平臺(tái),在這個(gè)上面會(huì)做一些類(lèi)似于Gae,Sae這樣的東西,目前來(lái)說(shuō)只是百度內(nèi)部用。這樣的話當(dāng)我用了這個(gè)東西之后,我們開(kāi)發(fā)者不再要求需要關(guān)心資源,也不需要關(guān)心被攻擊,或者流量陡增,這個(gè)我待會(huì)還會(huì)講。 我們?cè)赑HP這層加了一個(gè)小螃蟹,它的名字叫做AP,我待會(huì)會(huì)介紹AP是什么樣?xùn)|西。然后在腳本和PHP之間又加了一層Odp,又是什么東西?這三個(gè)就是解決我剛才提到哪些問(wèn)題。Bae,我剛才提到是來(lái)解決我們剛才說(shuō)的那些問(wèn)題,比方說(shuō)我資源怎么管理,流量陡增沒(méi)法應(yīng)付了怎么辦。Bae把所有資源統(tǒng)一調(diào)度起來(lái),提供一個(gè)很大平臺(tái)給你,你其中只用一部分,他會(huì)把冗余資源調(diào)配節(jié)給你,滿(mǎn)足你陡增的資源需求。 集群化還有一個(gè)問(wèn)題是防攻擊,我現(xiàn)在是三大服務(wù)器有人來(lái)壓我了,他拿100臺(tái)肉雞來(lái)壓我,沒(méi)有關(guān)系,我們百度后面還有1千臺(tái)服務(wù)器呢,上,你再來(lái)壓。如果他真的強(qiáng)大到拿1萬(wàn)臺(tái),1千萬(wàn)臺(tái)來(lái)壓你,這樣成本在國(guó)內(nèi)很難做到。所以,這樣情況下能解決我們剛才所說(shuō)小規(guī)模攻擊,因?yàn)槟愎粑揖涂梢赃w移,我可以自動(dòng)遷移。 流量陡增也是一樣道理,太多。接下來(lái)就是今天我要介紹的重點(diǎn),就是怎么解決沉重的框架問(wèn)題。我們現(xiàn)在用的很多框架,各個(gè)公司開(kāi)發(fā)都會(huì)有用框架,也有自己開(kāi)發(fā)框架。在做開(kāi)發(fā)框架的時(shí)候大家都會(huì)遇到一個(gè)問(wèn)題,這個(gè)框架要不要做的這么重,為什么要做的重呢?因?yàn)槟愎ぷ饕峁┑亩?,要提供路由,提供搜索引擎,還有ORM等等這樣?xùn)|西。我提供這么多東西,必須有這么多的代碼,我有那么多代碼,就那么多邏輯,就有一個(gè)結(jié)果慢了下來(lái),怎么取舍呢? 對(duì)于百度來(lái)說(shuō),我們現(xiàn)在解決方案出來(lái)之前流行兩種開(kāi)發(fā)模式,一種比較成熟E框架,或者ZF框架,還有性能要求比較高的,會(huì)使用我們百度自己開(kāi)發(fā)的B-Gou框架,只做路由,是一個(gè)輕量級(jí)框架,是一個(gè)非常非常輕量框架,來(lái)滿(mǎn)足性能問(wèn)題。有沒(méi)有一個(gè)解決方案做他們倆的取舍呢,下面有一個(gè)擴(kuò)展化。 什么是擴(kuò)展化?在座都知道PHP擴(kuò)展,如果關(guān)心這個(gè)肯定會(huì)知道,可能也有不知道同學(xué),我就提一下什么是PHP的擴(kuò)展。PHP本身是用C語(yǔ)言寫(xiě)的,你所編寫(xiě)的PHP腳本到最后都是通過(guò)C代碼執(zhí)行的,這時(shí)候PHP還提供一種方式可以直接寫(xiě)用C來(lái)寫(xiě)一個(gè)共享庫(kù),動(dòng)態(tài)的共享庫(kù),把它加載到PHP中,通過(guò)這種方式讓你業(yè)務(wù)模式以C模式存在在PHP當(dāng)中,這個(gè)模式就叫擴(kuò)展,PHP提供一個(gè)很強(qiáng)大模塊來(lái)支持你自己PHP擴(kuò)展。 我剛才提到了其實(shí)問(wèn)題也就很明顯了,我們需要用一個(gè)PHP擴(kuò)展去做一個(gè)很重的PHP框架。還有一個(gè)要提的,什么樣的情況下我們應(yīng)該使用擴(kuò)展,還有一個(gè)問(wèn)題擴(kuò)展為什么會(huì)快,這兩個(gè)問(wèn)題,有些看似很簡(jiǎn)單問(wèn)題,其實(shí)要想起來(lái)還是挺難的。第一什么樣的情況下我們可以使用擴(kuò)展,我們有兩種方式是需要擴(kuò)展,第一種方式我們有一些,比方說(shuō)已經(jīng)成熟的C庫(kù),我們PHP許多辦法直接用,我必須用一個(gè)擴(kuò)展把它橋接過(guò)來(lái),這種情況下需要使用PHP擴(kuò)展。 還有一種情況我對(duì)CPU密集型的東西,比方說(shuō)我有一個(gè)算法,或者我有一個(gè)很復(fù)雜,很復(fù)雜的加密算法。這個(gè)算法如果我用PHP寫(xiě)的話非常慢,對(duì)于這種CPU密集型的東西,我是可以把它擴(kuò)展化用C來(lái)實(shí)現(xiàn),這樣的話能提高性能,就這兩種方式要去使用PHP擴(kuò)展。PHP擴(kuò)展為什么會(huì)快呢?這里我要提一下FaceBook極致,去年11月份極致把一個(gè)應(yīng)用性能提高到4倍,他是怎么做到的呢?我們大家聽(tīng)各種各樣報(bào)告,是把PHP編譯成C++,他這個(gè)編譯其實(shí)不是說(shuō)我根據(jù)你的邏輯找到對(duì)應(yīng)的C代碼進(jìn)行編輯,他做的更多是把這個(gè)符號(hào)解析給拿掉了。我們?cè)赑HP里面,我們的變量,我們的函數(shù)都是存儲(chǔ)在一個(gè)一個(gè)關(guān)聯(lián)數(shù)字結(jié)構(gòu)里面,他這個(gè)結(jié)構(gòu)設(shè)計(jì)足夠精妙,確實(shí)也花很大心思去設(shè)計(jì),但是當(dāng)我們使用一個(gè)變量,或者一個(gè)方式的時(shí)候,都需要從這個(gè)表里面去查的,這個(gè)過(guò)程是非常耗時(shí)的。 所以,PHP性能絕大部分低也是這個(gè)關(guān)鍵。PHP就把能在編譯期間確定的符號(hào)就把它直接替換掉,相當(dāng)于我們C程序編譯的時(shí)候把符號(hào)直接換成二進(jìn)制地址的一樣,就是一個(gè)符號(hào)回天。這只是一方面,還有一方面為什么擴(kuò)展會(huì)比PHP快?這個(gè)我們拋開(kāi)一切問(wèn)題,一切IO,拋開(kāi)一切內(nèi)存存儲(chǔ)我們來(lái)算一個(gè)簡(jiǎn)單算術(shù)題,一個(gè)1G赫茲CPU能編織多少,這也是PHP比較慢一個(gè)原因。 比方說(shuō)一個(gè)簡(jiǎn)單ICOU(音譯),如果你用C代碼來(lái)寫(xiě),直接寫(xiě)ICOU2也可以,如果PHPICOU2先編譯,第二部分先分析這個(gè)PHP,找到對(duì)應(yīng)PHP調(diào)用,這個(gè)時(shí)候有三種情況,這時(shí)候拿到一個(gè)指令進(jìn)行執(zhí)行,當(dāng)執(zhí)行這次指令的時(shí)候可能會(huì)發(fā)生多次調(diào)用。我一個(gè)簡(jiǎn)單的ICOU可能在PHP最后執(zhí)行的時(shí)候,可能有5次以上函數(shù)調(diào)用,這個(gè)就慢了,擴(kuò)展化就可以避免這些問(wèn)題。 我們Ap就是一個(gè)全功能MVC框架,是用擴(kuò)展來(lái)實(shí)現(xiàn),也就是利用C語(yǔ)言去寫(xiě)的一個(gè)PHP擴(kuò)展。這個(gè)地方又有一個(gè)問(wèn)題,我們擴(kuò)展一般也兩種理由去寫(xiě)擴(kuò)展,擴(kuò)展還分兩類(lèi),第一類(lèi)就是說(shuō)一個(gè)簡(jiǎn)單我的業(yè)務(wù)邏輯都是用C代碼去做的,我只是簡(jiǎn)單從PHP腳本拿到數(shù)據(jù),把處理結(jié)果反給PHP,我基本上不怎么使用Ap。第二個(gè)擴(kuò)展就是負(fù)載PHP擴(kuò)展,就是Ap,用了大量API,提供相應(yīng)存量,或者是一些資源給PHP腳本讓用戶(hù)去進(jìn)行使用。對(duì)于用戶(hù)來(lái)看,他可能覺(jué)得這跟PHP腳本使用起來(lái)一樣,他用Ap框架,如果我用PHP腳本使用一個(gè)類(lèi)似框架,把這個(gè)替代掉,PHP寫(xiě)的這個(gè)框架換上去對(duì)他是透明的。第二類(lèi)框架復(fù)雜性要遠(yuǎn)遠(yuǎn)高于第一類(lèi)型,他要遵循PHP引用技術(shù),要遵循PHP一些比較特殊約定。 當(dāng)然,這些不是說(shuō)PHP的問(wèn)題,可能有一些歷史原因。種種這些你都是要去遵循的,這個(gè)復(fù)雜度確實(shí)比第一種高一些。 |
|