基於 Swoft 協程框架的 PHP 微服務治理

基於 Swoft 協程框架的 PHP 微服務治理

內容來源:2018 年 05 月 27 日,Swoole開源項目創始人韓天峰在“【上海】OSC源創會第75期”進行《基於 Swoft 協程框架的 PHP 微服務治理》演講分享。IT 大咖說作為獨家視頻合作方,經主辦方和講者審閱授權發佈。

閱讀字數:2928 | 8分鐘閱讀

獲取嘉賓演講視頻回放及PPT,請複製鏈接:http://t.cn/ReH3YJo,即可觀看。

基於 Swoft 協程框架的 PHP 微服務治理

摘要

本次演講將介紹 Swoole 3.0 全新的 PHP 協程編程模式,以及 Swoft 協程框架的使用,基於 Swoft Cloud 提供的各類組件實現 PHP 微服務架構。

基於swoole 4.0全新的PHP編程模式

基於 Swoft 協程框架的 PHP 微服務治理

上面是一段PHP代碼,其中2個函數的執行時間都是1秒,整段代碼執行完成需要2秒。要想將這種串行執行方式轉換為並行執行,在PHP中可以通過創建多進程來執行每個函數,單個進程執行單個函數,這樣在1秒鐘能就能執行完上面的代碼。雖然在Java中多線程應用很普遍,但是很可惜PHP並不支持多線程。

基於 Swoft 協程框架的 PHP 微服務治理

除開多線程和多進程,還有一種方式也能實現並行編程,那就是協程(Coroutine),這也是GO語言的重要特性。協程的併發量相對多線程和多進程要高出很多,同一個進程內可以創建幾十萬甚至上百萬個協程,且只佔用少量的內存空間。線程和進程由操作系統調度,是非常昂貴的系統資源,創建過多的話,在上下文保存和進行切換的開銷上會很大。

基於 Swoft 協程框架的 PHP 微服務治理

這裡將前面的代碼以協程的形式進行了重寫,執行的時候會創建兩個協程,執行時間為1秒。雖然執行效果和多進程或多線程一樣,但實現原理有所不同。協程中這兩個函數的執行基於一種自動讓出的機制,一旦執行函數遇到IO操作,就會自動讓出當前執行棧交由下一個函數執行,在IO完成之後再恢復協程棧。

PHP由於自身的天然缺陷無法支持多線程,所以我們繞開了它直接在swoft 4.0中實現了協程。但由於針對CPU密集操作只能利用到一個核,所以在使用協程的時候還是會利用多進程的方式來複用CPU的多核操作。

協程最大的好處在於能夠提供極大的併發,因為它僅佔用內存,不存在進程/線程切換開銷,單個進程就可開啟50w個協程。

我們在swoft 1.0的時候採用的技術方案和node.js的異步回調一樣,在2.0的時候開始嘗試實現協程,但是存在一些缺陷——協程不能用在所有的函數上,只能用在一些已經預定好的函數上。這是由於PHP有一些動態的特性,比如將URL映射到一個類方法上,這種場景下執行2.0的協程程序就會崩潰。4.0的時候我們對此做了一些優化,基於微信開源的庫重新實現了協程方案,這時的協程就達到了在Go語言中的效果。

基於 Swoft 協程框架的 PHP 微服務治理

上面展示的就是PHP中使用協程的三種方式。左上的代碼通過循環的方式創建了10個協程,下面這段則是在協程中執行讀文件的操作,且內部還嵌套了兩個協程,它們之間是相互依賴的關係。右邊的代碼直接創建了3個協程,每個協程的執行邏輯都不一樣。

有了協程之後,就會涉及到如何管理協程或數據通信的問題。在Java多線程中,線程之間的通信可能會使用鎖或者數據結構的方式解決,在協程編程中一般使用的chan的方式管理。

協程是一個用戶態的線程,同一時間執行的協程只有一個。這一點和多線程不同,創建出來的多個線程都會並行執行。

基於 Swoft 協程框架的 PHP 微服務治理

左邊這段代碼是協程編程,它會讀取一個全局的數組,當協程1讀取數組的時候,協程2其實沒有運行,直到協程1遇到IO操作釋放了控制權,協程2才會恢復再去讀全局變量,這樣就完全不用加鎖了。

右邊是線程編程,可以看到如果程序要讀取全局臨界資源就一定要加鎖,要不斷的lock、unlock。

Chan有點類似隊列,不過它自帶了協程調度能力。

多線程讀取隊列時,會有生產者和消費者。在隊列內存佔用過多無法再寫入的情況下,生產者還是會持續寫入,一般的解決方案是進行盲等,比如讓生產者sleep一段時間然後再去寫入。在隊列無數據可返回的情況下,一種方案是讓消費者盲等,CPU死循環去等待,不過這樣會佔滿CPU。一般的方案是在發現無數據返回的時候sleep一段時間,之後再嘗試讀取。

協程編程中可以通過chan來完成協程調度。當生產者發現容量不足的時候會展示掛起當前協程,直到有消費者拿走一些數據之後才會喚醒這個協程。消費者的讀取機制也是一樣的,無可用數據時就掛起,一旦生產者push數據後再喚醒。

由於PHP的動態語言特性,所以可以向chan中push任意的PHP變量,無論是對象還是數組。Chan的底層基於引用計數管理,完全沒有內存拷貝,除了標量類型是直接複製之外,包括數組、對象這些複雜的數據結構都是用的引用計數管理。像Go語言一樣,我們也提供了chan::select用來對多個chan進行讀寫判讀。

基於 Swoft 協程框架的 PHP 微服務治理

協程框架swoft的介紹

Swoft是基於協程實現的web開發框架。它借鑑了spring Cloud做了完全組件化的實現,裡面很多功能都是一個小的組件,當然也可以用自定義的組件替換內置的組件。該框架也提供了依賴注入、容器、連接池、AOP,除了應用在web領域之外,還能夠用在微服務上。

基於 Swoft 協程框架的 PHP 微服務治理

上面兩行命令分別是用來創建swoft工程和引入相關組件。

目前swoft支持3種服務器,swoft-http-srever 、swoft-websocket-server swoft-rpc-server。 第一個用來做主流的web應用程序,第二個是長連接通信服務,最後是微服務領域的RPC服務。

基於 Swoft 協程框架的 PHP 微服務治理

通過命令行腳本能夠直接啟用以上3種服務,這裡也提供了一些常用的腳本工具。

基於 Swoft 協程框架的 PHP 微服務治理

Swoft參考Java的Spring框架,用了很多註解編程的方式。對於Web開發中的URL映射,可以直接通過註解的方式寫Route。能夠自動將URL映射到當前Controller方法中,URL中的參數也會自動帶入類方法中。

基於swoft協程框架進行PHP微服務治理

Swoft自帶了一些微服務常用的組件,包括服務註冊、熔斷、降級、負載均衡、接口多版本等。

基於 Swoft 協程框架的 PHP 微服務治理

Swoft的服務註冊與發現是基於Google開源的consul,要使用consul需要添加一些配置,定義服務提供方和接入方的key。然後在前面提到的命令行腳本調用RPC start就會自動將我們的服務器節點註冊到consul服務器中。

基於 Swoft 協程框架的 PHP 微服務治理

Swoft的接口聲明也是基於註解的方式,如上圖所示通過註解定義了service指向的服務以及調用的接口,調用的時候會映射到對應的方法。

swoft的熔斷機制中失敗超過一定次數,服務就關閉,成功的話,服務重新連接。

基於 Swoft 協程框架的 PHP 微服務治理

這段代碼是關於熔斷器的調用,首先確定熔斷器的名詞,正常情況下調用handler,失敗的話就調用fallback進行一些處理。

這裡關於微服務的介紹可能比較簡要,其實是因為做服務治理更多的還是要用成熟的框架。PHP方面我們推薦使用Tars,這是騰訊開源的微服務治理框架,基於WUP結構定義文件,可以自動生成接口骨架代碼,有著完整的服務治理方案,自帶發佈、運維、監控、彈性伸縮體系。

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


分享到:


相關文章: