C++結合的無限種可能

探索嵌入式PHP與C/C++結合的無限種可能

內容來源:2018 年 5 月 20 日,騰訊企點開放平臺技術負責人熊月在“PHPCon China 2018 技術峰會”進行《嵌入式PHP的探索實踐》演講分享。IT 大咖說作為獨家視頻合作方,經主辦方和講者審閱授權發佈。

閱讀字數:2410 | 7分鐘閱讀

獲取嘉賓演講視頻及PPT,請複製:http://t.cn/RDsTba0,粘貼至瀏覽器即可。

探索嵌入式PHP與C/C++結合的無限種可能

摘要

對於擁有很多複雜業務場景的tob領域,“開發效率”和“性能”常常是我們考慮的兩個主要問題,PHP作為腳本語言,本身適用於快速開發業務邏輯,同時為了解決PHP特定的性能瓶頸,一般將C++/PHP結合,在PHP代碼裡調用C/C++擴展。 這次我們帶來了不同思路的探索:將php嵌入到高性能C/C++框架運行,將C/C++框架作為容器,完美結合php快速開發優勢和C/C++高性能特點。Zend Engine提供了一種嵌入式開發模式,我們利用這一特性使它可以在C/C++的環境中單獨執行PHP腳本,並且支持多實例運行,可以在C/C++協程框架中運行。嵌入式PHP也為在任意C/C++協程框架結合帶來無限可能,包括在C++的客戶端上運行PHP。

嵌入式PHP

作為一門後臺開發語言PHP有著不同的發展階段。最開始是大家都比較熟悉的LAMP,接著是PHP-fpm和fastcgi,再往後是swoole,之後在swoole的基礎上又新增了協程。

為了便於理解,在介紹嵌入式PHP之前要先講下SAPI的概念。SAPI即後臺應用程序編程接口,是PHP與其他應用程序交互的接口。常見的SAPI有cgi、fpm、cli、Apace2 hander,而嵌入式PHP(embed)也是其中一類。

業務場景

探索嵌入式PHP與C/C++結合的無限種可能

我們最初的業務框架是基於TSF2.0,底層為Zend Engine和擴展,擴展最核心的部分是基於swoole。在此之上是TSF PHP層,包含協程調度器、微服務框架、監控管理進程、MVC模式。最上層才是真正的執行邏輯的PHP腳本。

這樣一套框架存在幾個問題。PHP原生的Generator協程需要配合yield使用,對開發來說不怎麼友好,因為yield的使用時機不太好確定,尤其是對於新手。由於協程調度器是用原生PHP實現的,因此相對其他語言在性能上會差些,特別是在高併發場景下。還有就是低版本swoole不夠穩定,問題最多的就是在內存洩露這塊。大家都知道騰訊內部有很多公用組件,這些組件接口大多是用C++實現的,為此我們需要做的是用擴展對接PHP與其他組件,而問題就在於擴展無法使用上層的PHP協程。

方案:SPP+PHP

為什麼選擇嵌入式PHP

SNG中有個非常有名的C++後臺框架SPP,它是一個高性能的網絡框架,起始於2008年,被廣泛的應用於SNG的各個業務線。眾所周知開發效率一直是PHP的長處,性能方面則是短板。所以我們就在想能不能將SPP和PHP結合起來兼顧高性能和開發效率,嵌入式PHP無疑是很好的結合方案。

探索嵌入式PHP與C/C++結合的無限種可能

SPP主要有5個模塊。proxy用來處理新請求,內存隊列是proxy和workgroup交互的內存區域,workgroup是和後臺邏輯腳本交互的模塊,controller作為控制核心來控制proxy和workgroup的運行狀態,最後是最重要的協程模塊。

如何將SPP和Zend結合

SPP其實是基於協程的框架,協程是一個用戶態的多線程概念。在協程切換的時候會涉及內存管理的機制,而Zend沒有這種切換內存資源的機制,只有全局變量和多線程資源隔離的方式。這樣的話要想將SPP和Zend結合起來,就要對Zend進行改造。

Zend的源碼大概有60萬行,如果直接改動核心源碼,不光實施起來很麻煩,對之後的升級也會造成問題。最好的辦法是藉助Zend本身的機制對入口進行改造,而不侵入內核。

Zend改造

Zend有多進程和多線程兩種方式,在多線程模式下有一個線程安全的機制ZTS。ZTS本質其實是對每個線程的全局資源進行了隔離,與SPP協程的結合就需要用到ZTS,下面是具體步驟。

第一步當然是打開Zend內核ZTS開關,第二步為了滿足協程上下文切換,需要將ZTS中的線程私有變量轉化為全局數據元素,第三步增加資源入口切換API。做完這三步就完成了Zend和SPP的結合,雖然步驟不多但實際上在做的過程中還是會有很多挑戰。

PHP執行流調度器

探索嵌入式PHP與C/C++結合的無限種可能

解決了結合問題之後,接下來為了將整個流程串起來需要有一個執行流程調度器。上圖是整個執行流程,首先SPP通過SAPI進入到Zend中,然後Zend執行PHP腳本,先編譯成OpCode,之後如果有網路IO就會用到協程。協程也可以基於SPP提供的API來運作,通過Tsrm的全局資源table可以進行協程切換。

探索嵌入式PHP與C/C++結合的無限種可能

在有這樣一套執行流的情況下,擴展也可以依賴SPP的API實現協程調度。

探索嵌入式PHP與C/C++結合的無限種可能

上圖是SPP結合PHP之後的整體架構。最底層是SPP,往上是PHP執行流調度器,中間是PHP內核和擴展,最上層是PHP腳本。這一整套架構以嵌入式的方式結合了SPP和PHP,讓開發者既可以利用SPP提供的高性能網絡框架,同時也能應用到上層PHP快速開發的特點。

探索嵌入式PHP與C/C++結合的無限種可能

這裡展示的是壓測時候的環境數據,包括機型、壓測工具、壓測方法以及框架的版本等。

探索嵌入式PHP與C/C++結合的無限種可能

這是壓測後獲得的實際數據對比,可以看到SPP-PHP框架相對舊的框架性能上大概有3倍的提升。

以上為今天的分享內容,謝謝大家!


分享到:


相關文章: