iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 25
1
Modern Web

成為 Modern PHPer系列 第 25

Day 25:Swoole 帶來的變革

前言

Swoole 是由中國開發者韓天峰所主導開發的 PHP Extension,不同於一般的 Extension 是為了「完成某些事」(例如連接 Redis 的 predis、大數運算的 bcmath),Swoole 為 PHP 帶來底層的一陣變革。

PHP 的基礎

PHP 構基於「快速啟動、快速銷毀」這一核心理念,每個 HTTP Request 都是會經過 RINIT(請求資源初始化)並且在處理過後經過 RSHUTDOWN(請求資源銷毀)。

這實作 HTTP 的方式有別於目前主流的程式語言,如 Golang、Nodejs、Python 或 Rust 大多都是啟動一個常駐程式去處理 Request 及 Response,這也是為什麼 PHP 通常還會再另外搭配一個 Web Server 的主要原因。

儘管 PHP 官方目前提供了 Built-in Web Server 的功能,但僅限開發時期使用,這時常讓 PHP 的微服務化產生困難。

註:事實上,像 PHP 這般類 CGI 的執行流程,算是目前流行的 Function as a Service 早期具期化,然而因為市場緣故目前沒有足夠的廠商原因投資 Zend Engine 原生的 FAAS 服務。

Swoole 的變革

Swoole 改寫 PHP 底層的運作方式,使其擁有一些額外的特性

  • TCP/UDP Server/Client
  • Coroutine

TCP/UDP Server/Client

在 Swoole 中,實現了三種非同步的 Protocol:TCP, UDP 及 UnixSocket

<?php

$server = new Swool\Server('0.0.0.0', 8000, SWOOLE_BASE, SWOOLE_SOCK_TCP)

$server->start();

可以任意更改 SWOOLE_BASE,決定將其放在哪個 Process 中執行。

可以任意更改 SWOOLE_SOCK_TCP 決定要啟動什麼樣的 Server。

也因為實現了 TCP/UDP Server,所以在往上擴展出了 HTTP 及 WebSocket,既亦可以依靠 Swoole 啟動一個原生的 HTTP/WebSocket Server。

Coroutine

Coroutine 中文通常譯為協程,類似於 Golang 的 goroutine,為的是將作業系統的 Process 資源做有效利用(Process 是個很貴昂的資源,如果一直開 Process 的話 CPU 會因為 Content Switch 的時間過多拖慢效能)

對一般的 PHP 開發者而言,幾乎沒有「Multi-Process」及「Multi-Thread」的概念,通常就覺得所有的函式都是同步化的(沒處理完這個指令之前,不會往下執行其它指令),這也是 PHP 讓初學者認為很親切容易入門的主因。

註:Process 是裝載 Thread 的容器,有關於 Process 及 Thread 的詳細說明可以參閱Program/Process/Thread 差異

Swoole 沒有為 PHP 導入 Multi-Thread 的概念,反而直接進階為 Coroutine。Coroutine 是將 Thread 資源再細分化的結果,讓 Thread 可以被充份利用。

註:pthreads extension 可以讓 PHP 實現 Multi-Thread 程式,但鮮有人使用且自 2016 年後就沒有繼續更新。

Swoole 的優劣分析

優勢

  • 效能
  • 改變 PHP 底層運作方式

Swoole 一直都以其效能優異作為賣點,從 TechEmpower Web Framework Benchmarks 的測試結果(Round 18,2019-07-09 發佈)中可以看到,Soole 基本站在 PHP 的首位,甚至僅僅略遜於少數 Rust, C/C++, Go 及 Java 而排在第 13 名(原生 PHP 排行 86 名)

且 Swoole 的出現改變 PHP 底層的運行方式,因為不再依賴 Web Server,讓它可以更容易被容器化,算是為 PHP 帶了革命性的變化

劣勢

  • 對於第三方的支援性
  • Coroutine 的概念不易讓傳統 PHP 工程師理解

儘管一直在改進諸如 Database Connection 之類的,但目前僅對於 MySQL 有比較高的支援性(甚至比 PHP 官方更快原生支援 MySQL 8.0 的 caching_sha2_password 認證方式),但是對於 PostgresQL 的支援性仍有所不足,且除了 PDO MySQL 之外基本上沒有實現其它 PDO Driver。

還有類似 XDebug 需要改為 sdebug 使用,這在讓 PHPUnit 計算 Code Coverage 時需要另外加入 sdebug 的支援。

另外就是 PHP 工程師通常都習慣於同步化程式設計,對於函式調用是同步或非同步基本上沒有概念,這也讓引入 Coroutine 時常會產生觀念上的差異。還有在 Coroutine 中通訊時需要妥善使用 Channel、Lock 等也是相對複雜的。

註:通常熟悉 Coroutine 的工程師會直接去寫 Golang,而不會繼續留在 PHP。

後記

事實上我很看好 Swoole 的發展,不過作者最近好像比較傾向於關注 Swoole Enterprise,導致 Swoole 的更新慢下來了。

Swoole 在 4.0 之後引入 Coroutine 算是嚇跑了很大一批人,因為原本的異步調用方式直接被宣告廢棄。


上一篇
Day 24:使用 Travis CI
下一篇
Day 26:Profiling 概述
系列文
成為 Modern PHPer30

尚未有邦友留言

立即登入留言