PHP 的性能猛獸 - Swoole

前言

PHP 自 1995 年發展至今已將近 30 年,經過不斷發展迭代的 PHP 語言儼然與大家古老中刻板印象的概念大相逕庭。現今的 PHP 8 除了具備許多現代化的語法與特性外,在近 10 年中 Symfony 與 Laravel 等開發社群的持續蓬勃的發展加持下,Laravel 更是成為了在跨語言的 Web 框架中人氣居高不下的開源專案,加上原本的 Wordpress、Drupal、WooCommerce 等生態也使得 PHP 一直在現今 Web 系統中始終保持很高的使用占比。

由於 PHP 先天上程式運行模型的設計與 Blocking I/O 的特性,加上許多現代的熱門 Web 框架都內建了許多功能,使得 PHP 的效能問題常常變成大家的討論議題。事實上在 PHP 7 後以同樣為解釋型語言的 Ruby 與 Python 為例,PHP 的執行性能相比之下其實已經相當優秀,下面為 Benchmarks Game 網站上性能測試的結果(執行時間,數值越小越好):

但 PHP 在傳統上 Stateless 的運行模式,再加上內建全部的 I/O 請求都是以 Blocking I/O 的方式運作,所以使得 PHP 在併發量較高的系統中往往只能以多開機器資源的方式來擴充處理能力,而 Swoole 正是在這種背景情境下所誕生的一大 PHP 性能利器。

Swoole 簡介

Swoole 這個命名源自於作者偶然間創造出來的概念:sword-server,意即希望為廣大的 PHP 開發者創造出一把鋒利的劍,後來又參考 google 的字將 sword-server做變形變成了 Swoole 這個名字。

Swoole 的創始人為韓天峰(Rango),為 PHP 官方 PECL 開發組的成員,曾任職於於騰訊、阿里巴巴、虎牙直播等,現任為好未來集團的首席架構師,為中國 PHP 領域中除了鳥哥(惠新宸)外相當具有影響力的 PHP 技術專家。

開發團隊中較活躍的另一位開發者 twosee 也同時為 PHP 内核開發團隊的成員。

Swoole 最早於 2012 年左右開始密集開發,於 2014 年開始有 1.7 stable 版本的 release,在這十年期間官方的開發團隊對於該專案一直保持積極的維護,目前為止 Swoole 專案在 GitHub 上發展概況如下:

  • 18.1 k 的 starts
  • 3.2 k 的 forks 數量
  • 234 次的版本發布
  • 140 個 contributors

Swoole 的版本迭代基本上與 PHP 官方的支援一致,除了在 PHP 版本更新時 Swoole 會同步支援外,官方對於舊版的 EOF 維護週期基本上也是同步的。

Swoole 為 PHP 提供了許多原生不支援的強大特性,包含:

  • TCP / UDP / HTTP(1.1/2) / Websocket / Redis / Unix Socket 的 Asynchornouns / Coroutine Server
  • 除了上述支援協議外,還有 MySQL / PostgreSQL / Fast CGI 的 Coroutine Client
  • Event Loop
  • Asynchronous Task Worker
  • 底層直接替換 PHP 原生中基於 Blocking I/O 原生函數的 Runtime Hook
  • Connection Pool
  • 比起 pcntl 更強大易用的 Process / Process Pool / Process Manager
  • 支援毫秒精度的 Timer
  • 跨 Process 共享的 Swoole Table (Shared Memory)
  • 跨 Process 溝通的 Atomic 與 Lock

這些強大的特性除了使 PHP 能以 Non-Blocking I/O 的能力來大幅提高併發處理能力外,Swoole 更使 PHP 不只局限在 HTTP 的使用情境,還能開發所有 TCP / UDP 協議的相關 Server,為 PHP 拓展了許多新的應用領域。

在 PHP 社群中除了 Swoole 能為 PHP 提供 Asynchronous I/O 的能力外,其他較知名的專案包含:ReactPHP、AMPHP,他們不像 Swoole 是以 C extension 來開發,而是完全以 PHP 開發的專案,使用時可以不需要額外安裝 extension。

在這些 Asynchronous I/O 的解決方案中目前只有 Swoole 提供了能在底層直接替換 PHP 原生中基於 Blocking I/O 原生函數的 Runtime Hook,這意味著 PHP 開發者能夠更好將傳統 PHP 程式中的 Blocking I/O 方法自動協程化(這一點類似 Python 中 Coroutine 的發展方向)。

在 2021 年 Laravel 官方也同時發佈了 Octane Package,他使 Laravel 透過 Swoole 或 RoadRunner 來當作 HTTP Server 達成常駐化執行的加速效果,可見 Swoole 的影響力已經逐漸擴大到主流社群當中。

但 Octane 至今仍不支援 Swoole 的 Coroutine 特性,所以在併發能力的提升在 I/O 密集的情境上還是有一定限制。

性能評測

下面為 Swoole 和 Golang 的 HTTP Server 做簡單回傳值的 benchmark 對比:

測試環境為 Macbook Pro M1 2021 的機器

Golang

package main

import (
    "fmt"
    "io"
    "net/http"
)

func main() {
    fmt.Println("Server is starting...")
    http.HandleFunc("/", handle)
    http.ListenAndServe("0.0.0.0:9501", nil)
}

func handle(rw http.ResponseWriter, r *http.Request) {
    rw.Header().Set("Content-Type", "text/html")
    io.WriteString(rw, "Hello Go!")
}
wrk -t4 -c100 http://127.0.0.1:9501
Running 10s test @ http://127.0.0.1:9501
  4 threads and 100 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     1.35ms    3.24ms  63.00ms   92.21%
    Req/Sec    31.27k    20.62k  148.72k    81.06%
  1245879 requests in 10.06s, 129.51MB read
Requests/sec: 123822.65
Transfer/sec:     12.87MB

Swoole

<?php

$server = new Swoole\HTTP\Server('0.0.0.0', 9501);

$server->on('request', function ($request, $response) {
    $response->end('Hello Swoole!');
});

echo "Server is starting...\n";
$server->start();
wrk -t4 -c100 http://127.0.0.1:9501
Running 10s test @ http://127.0.0.1:9501
  4 threads and 100 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     0.90ms  542.35us  17.96ms   95.74%
    Req/Sec    28.61k     3.47k   34.05k    79.21%
  1150119 requests in 10.10s, 182.08MB read
Requests/sec: 113850.41
Transfer/sec:     18.02MB

從上面結果來看 Swoole 的測試結果和 Golang 相比其實差距已經不大,相比傳統的 PHP 來說,Swoole 確實為 PHP 提供了非常優秀的併發性能。

但上面的測試結果並不代表 PHP 的性能接近 Golang,畢竟直譯式語言和編譯式語言的運行模式在天生上就不一樣,在實際較複雜的商務邏輯或 CPU 密集的程式中 Golang 絕對佔有更大的優勢。

結論

總結來說 Swoole 確實為 PHP 提供了非常優異的性能還有許多以往傳統 PHP 不具備的新特性,但由於這些新特性在過往 PHP 中並不存在,若開發者對於作業系統、網路協議、Asynchronous I/O、Coroutine 等概念較不熟悉,那在使用 Swoole 上可能會存在一些門檻。

在此筆者推薦由 Bruce Dou 所編寫的 Mastering Swoole PHP 這本書,其中對於相關的基礎知識都有涵蓋到,能補足以往 PHP 開發者較欠缺的相關能力。

書本網站:https://swoolebook.com