搜尋
首頁後端開發php教程享受PHP與Go的強大合體【RoadRunner】的樂趣!

#享有它的樂趣!


在過去的十年中,我們一直在為 財富 500 強公司 以及用戶人數不超過 500 人的企業開發應用程式。一直以來,我們的工程師主要使用 PHP 來開發後端。但是兩年前,出現了一些問題不僅嚴重影響了我們的產品性能,還影響了它們的可擴展性——因此我們將 Golang (Go) 引入了我們的技術堆疊。

幾乎同時,我們發現 Go 不僅允許我們創建更大的應用程序,並且能夠將效能提高多達 40 倍。有了它,我們能夠擴展使用 PHP 編寫的現有產品,並透過結合兩種語言的優勢來改進它們。

我們將透過大量的 Go 和 PHP 經驗告訴你,如何用它來解決實際的開發問題,以及我們如何把它變成一個工具,來消除與  PHP 死亡模型 相關的一些問題。

推薦學習:《PHP影片教學

#常規PHP 開發環境

在講述Go 如何改善PHP 死亡模型前,先了解常規PHP 開發環境。

通常,應用程式運行於 nginx 和 PHP-FPM 上。 nginx 處理靜態請求,而動態請求則被重新導向給 PHP-FPM,並由其執行 PHP 程式碼。也許你用的是 Apache 和 mod_php,但是他們原理相同,運作起來只有細微的差別。

看看 PHP-FPM 是如何執行程式碼的。當收到請求,PHP-FPM 初始化 PHP 子程序,並將請求的詳細資訊轉送給它,作為其狀態的一部分(_GET, _POST, _SERVER 等)。

在 PHP 腳本執行期間,狀態將無法更改,因此只能透過一種方式取得一組新的輸入資料:清除進程記憶體並再次初始化它。

這種效能模型有許多優點。你不需要太擔心記憶體消耗,所有進程都是完全隔離的,如果其中一個進程「死亡」,它將自動重新創建,並且不會影響其他進程。但是,當你嘗試擴展應用程式時,這種方式會有缺點產生。

典型PHP 環境的缺點和低效性

如果你從事PHP 的專業開發,那麼你就知道從哪裡開始創建一個新專案——選擇框架。它是一個用於依賴注入、ORM、轉換和模板方法的函式庫。當然,所有使用者輸入的資料都可以方便地放在一個物件中(Symfony / HttpFoundation 或 PSR-7)。這些框架很棒!

但一切都有它的代價。在任何企業框架中,為了處理一個簡單的使用者請求或存取資料庫,您必須載入至少幾十個文件,建立許多類,並解析多個配置。但最糟糕的是,在每個任務完成後,您需要重置所有內容並重新啟動:您剛剛啟動的所有程式碼都將變得無用,在它的幫助下,您將無法處理另一個請求。把這件事告訴任何用其他語言寫的程式設計師——你會看到他臉上的困惑。

多年來,PHP工程師一直在尋找解決此問題的方法,他們使用了延遲載入技術、微幀、最佳化程式庫、快取等。但最終,您仍然必須放棄整個應用程序,重新開始*(譯者註:隨著PHP7.4中預先加載的出現,這個問題將得到部分解決)

##一個PHP進程能處理多個請求嗎?

您可以編寫持續時間超過幾分鐘的PHP腳本(最多幾小時或幾天):例如Cron任務、CSV解析器、佇列處理程序。所有這些工作遵循一個模式:他們取得一條任務,處理完它,然後取得下一個任務。程式碼常駐在記憶體中,因此避免了額外的操作來載入框架和應用程序,節約了寶貴時間。

但是開發長時間運行的腳本並不是那麼容易。任何錯誤都會殺死進程,記憶體溢位會導致崩潰,而且不能用F5來調試程式了。

自PHP 7後情況有所改善:可靠的垃圾收集器出現了,它變得更容易處理錯誤,內核的擴展可以避免記憶體洩漏。是的,工程師仍然需要仔細處理記憶體並記住程式碼中的狀態的問題(有哪種語言能讓你可以不關注這些事情呢?)當然,在PHP 7中,驚喜並不多。

是否可以採用一種 常駐 PHP 腳本的模型,將其用於處理 HTTP 請求等更瑣碎的任務,從而消除對每個請求都從頭開始下載所有內容的需要?

要解決這個問題,首先需要實作一個伺服器應用程序,該應用程式可以接收 HTTP 請求並將它們逐個重定向到 PHP worker,而不是每次都殺死它。

我們知道我們可以用純 PHP(PHP-PM)或 C 擴充(Swoole)來寫 web 伺服器。儘管每種方法都有其優點,但這兩種選擇都不適合我們 —— 我想要更多的東西。我們需要的不僅僅是一個 web 伺服器 —— 我們希望得到一個解決方案,可以使我們避免與 PHP 中的「重啟動」相關的問題,同時可以輕鬆地為特定的應用程式進行調整和擴展。也就是說,我們需要一個應用程式伺服器。

Go 可以幫助解決這個問題嗎?我們知道它可以,因為這種語言將應用程式編譯成單一的二進位檔案; 它是跨平台的; 使用自己的平行處理模型(並發)和用於處理HTTP 的函式庫; 最後,我們可以把更多的開源庫整合到我們的程式中。

合併兩種程式語言遇到的困難

首先,有必要確定兩個或多個應用程式之間如何相互溝通。

例如,使用 Alex Palaestras 的 go-php 函式庫, 可以實作 PHP 和 Go 行程 (如 Apache 中的 mod_php) 之間的記憶體共用。但是這個函式庫的功能限制了我們使用它來解決問題。

我們決定使用另一種更常見的方法:透過使用 sockets / pipelines 來建立進程之間的互動。這種方法在過去十年中已經證明了其可靠性,並且在作業系統層級得到了很好的優化。

首先,我們創建了一個簡單的二進位協議,用於在進程之間交換資料和處理傳輸錯誤。在最簡單的形式中, 這種類型的協定類似於 一個具有固定大小的packet 頭 (在我們的範例中為17 個位元組) 的netstring ,其中包含的資訊有packet 的類型,其大小和二進制掩碼的訊息,用來檢查資料的完整性。

在 PHP 端,我們使用了 pack 函數 ,在 Go 端,使用了 編碼 / 二進位 函式庫。

有一個協定對我們來說有點過時,我們加入了直接 從 PHP 呼叫 net / rpc Go 服務 的功能。這個功能在後面的開發中對我們有很大的幫助,因為我們可以輕鬆地將 Go 庫整合到 PHP 應用程式中。這項工作的結果可以在我們的另一個開源產品 Goridge 中看到。

在多個 PHP Worker 之間分配任務

在互動機制實作之後,我們開始思考如何更好地將任務轉移到 PHP 進程中。當任務到達時,應用程式伺服器必須選擇一個空閒的 worker 來執行它。如果 worker 程序因錯誤而終止或“死亡”,我們將清除它並創建一個新的。如果 worker 程序成功執行,我們會將它返回到可用於執行任務的 worker 池中。

享受PHP與Go的強大合體【RoadRunner】的樂趣!

為了儲存活躍的worker 進程池,我們使用了一個 緩衝通道 , 為了從池中清除意外「死亡」的工作進程,我們新增了一個追蹤錯誤和worker 進程狀態的機制。

最終,我們得到了一個可以運行的 PHP 伺服器,它能夠處理任何以二進位形式呈現的請求。

為了讓我們的應用程式作為 web 伺服器開始運作,我們必須選擇一個可靠的 PHP 標準來處理任何傳入的 HTTP 請求。在我們的例子中,我們只需將簡單的 net / http 請求從 Go  轉換 為 PSR-7 格式,這樣它就可以與目前大多數可用的 PHP 框架相容。

由於 PSR-7 被認為是不可變的(有人會說在技術上不是),開發人員必須編寫那些在原則上不將請求視為全域實體的應用程式。這完全符合 PHP 常駐進程的概念。我們的最終實作(尚未收到名稱)如下所示:

享受PHP與Go的強大合體【RoadRunner】的樂趣!

RoadRunner - 高 - 效能PHP 應用伺服器

#我們的第一個測試任務是一個API 後端,在該後端上,會週期性地出現不可預測的突發請求(比平常更頻繁)。雖然在大多數情況下 nginx capabilities 是足夠的,但是我們經常因為無法在預期的負載增加下快速平衡系統而遇到 502 錯誤。

為解決此問題,我們在 2018 年初部署了第一台 PHP / Go 應用伺服器。並立即取得了驚人的效果!我們不僅完全消除了 502 錯誤,並且還將伺服器的數量減少了三分之二,節省了大量資金並解決了令工程師和產品經理頭痛的問題。

在年中的時候,我們改進了我們的方案,在 MIT 許可下將其發佈在 GitHub 上,並命名為 RoadRunner, 從而強調了它驚人的速度和效率。

RoadRunner 是如何改進你的開發堆疊的

#RoadRunner 的使用允許我們在Go 端使用中間件net/http ,甚至在請求進入PHP 之前進行JWT驗證,以及在Prometheus 中處理WebSocket 和全域聚合狀態。

由於內建的 RPC,你可以在不寫擴充的情況下,在 PHP 中開啟任何 Go 函式庫的 API。更重要的是,使用 RoadRunner,你可以部署不同於 HTTP 的新伺服器。範例包括在 PHP 中執行 AWS Lambda 處理器 , 建立強大的佇列 選擇器, 甚至將  gRPC 新增至我們的應用程式。

同時使用PHP 和Go ,對解決方案有了穩定的提升,在一些測試中將應用程式效能提高了40 倍,改進了調試工具,實現了與Symfony 框架的集成,並添加了對HTTPS、HTTP/2、插件和PSR-17 的支援。

結論

有些人仍然被過時的 PHP 概念所束縛,認為 PHP 是一種緩慢、繁瑣的語言,只適合在 WordPress 下編寫外掛。這些人甚至還說 PHP 有一個限制:當應用程式變得足夠大時,你必須選擇更「成熟」的語言,並重寫多年累積的程式碼庫。

對於這些問題,我的回答是:再想想。我們相信只是你自己為 PHP 設定了一些限制。你可以用一輩子的時間從一種語言遷移到另一種語言,試圖找到與你的需求完美結合的語言,或者你可以將語言視為工具。像 PHP 這樣的語言,它的假想缺陷可能是其成功的真正原因。如果你將它與另一種語言(如 Go)結合,那麼你將創造出比只使用一種語言更強大的產品。

在交替使用過Go和PHP之後,我們可以說我們很喜歡它們。我們不打算犧牲其中一個來換取另一個,相反,我們會想辦法從這個雙重架構中獲得更多利益。

原文網址:https://sudonull.com/post/6470-RoadRunne...

翻譯網址:https://learnku.com/php/t/61733

以上是享受PHP與Go的強大合體【RoadRunner】的樂趣!的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述
本文轉載於:learnku。如有侵權,請聯絡admin@php.cn刪除
使用數據庫存儲會話的優點是什麼?使用數據庫存儲會話的優點是什麼?Apr 24, 2025 am 12:16 AM

使用數據庫存儲會話的主要優勢包括持久性、可擴展性和安全性。 1.持久性:即使服務器重啟,會話數據也能保持不變。 2.可擴展性:適用於分佈式系統,確保會話數據在多服務器間同步。 3.安全性:數據庫提供加密存儲,保護敏感信息。

您如何在PHP中實現自定義會話處理?您如何在PHP中實現自定義會話處理?Apr 24, 2025 am 12:16 AM

在PHP中實現自定義會話處理可以通過實現SessionHandlerInterface接口來完成。具體步驟包括:1)創建實現SessionHandlerInterface的類,如CustomSessionHandler;2)重寫接口中的方法(如open,close,read,write,destroy,gc)來定義會話數據的生命週期和存儲方式;3)在PHP腳本中註冊自定義會話處理器並啟動會話。這樣可以將數據存儲在MySQL、Redis等介質中,提升性能、安全性和可擴展性。

什麼是會話ID?什麼是會話ID?Apr 24, 2025 am 12:13 AM

SessionID是網絡應用程序中用來跟踪用戶會話狀態的機制。 1.它是一個隨機生成的字符串,用於在用戶與服務器之間的多次交互中保持用戶的身份信息。 2.服務器生成並通過cookie或URL參數發送給客戶端,幫助在用戶的多次請求中識別和關聯這些請求。 3.生成通常使用隨機算法保證唯一性和不可預測性。 4.在實際開發中,可以使用內存數據庫如Redis來存儲session數據,提升性能和安全性。

您如何在無狀態環境(例如API)中處理會議?您如何在無狀態環境(例如API)中處理會議?Apr 24, 2025 am 12:12 AM

在無狀態環境如API中管理會話可以通過使用JWT或cookies來實現。 1.JWT適合無狀態和可擴展性,但大數據時體積大。 2.Cookies更傳統且易實現,但需謹慎配置以確保安全性。

您如何防止與會議有關的跨站點腳本(XSS)攻擊?您如何防止與會議有關的跨站點腳本(XSS)攻擊?Apr 23, 2025 am 12:16 AM

要保護應用免受與會話相關的XSS攻擊,需採取以下措施:1.設置HttpOnly和Secure標誌保護會話cookie。 2.對所有用戶輸入進行輸出編碼。 3.實施內容安全策略(CSP)限制腳本來源。通過這些策略,可以有效防護會話相關的XSS攻擊,確保用戶數據安全。

您如何優化PHP會話性能?您如何優化PHP會話性能?Apr 23, 2025 am 12:13 AM

优化PHP会话性能的方法包括:1.延迟会话启动,2.使用数据库存储会话,3.压缩会话数据,4.管理会话生命周期,5.实现会话共享。这些策略能显著提升应用在高并发环境下的效率。

什麼是session.gc_maxlifetime配置設置?什麼是session.gc_maxlifetime配置設置?Apr 23, 2025 am 12:10 AM

theSession.gc_maxlifetimesettinginphpdeterminesthelifespanofsessiondata,setInSeconds.1)它'sconfiguredinphp.iniorviaini_set().2)abalanceisesneededeededeedeedeededto toavoidperformance andunununununexpectedLogOgouts.3)

您如何在PHP中配置會話名?您如何在PHP中配置會話名?Apr 23, 2025 am 12:08 AM

在PHP中,可以使用session_name()函數配置會話名稱。具體步驟如下:1.使用session_name()函數設置會話名稱,例如session_name("my_session")。 2.在設置會話名稱後,調用session_start()啟動會話。配置會話名稱可以避免多應用間的會話數據衝突,並增強安全性,但需注意會話名稱的唯一性、安全性、長度和設置時機。

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

EditPlus 中文破解版

EditPlus 中文破解版

體積小,語法高亮,不支援程式碼提示功能

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

Dreamweaver Mac版

Dreamweaver Mac版

視覺化網頁開發工具

MinGW - Minimalist GNU for Windows

MinGW - Minimalist GNU for Windows

這個專案正在遷移到osdn.net/projects/mingw的過程中,你可以繼續在那裡關注我們。 MinGW:GNU編譯器集合(GCC)的本機Windows移植版本,可自由分發的導入函式庫和用於建置本機Windows應用程式的頭檔;包括對MSVC執行時間的擴展,以支援C99功能。 MinGW的所有軟體都可以在64位元Windows平台上運作。