使用 Async、Swoole 和 Parallel 加速 Tarantool 的 PHP 連接器

使用 Async、Swoole 和 Parallel 加速 Tarantool 的 PHP 連接器

在 PHP 生態系統中,目前有兩個連接器可與 Tarantool 伺服器配合使用 - 這是官方的 PECL 擴展 tarantool/tarantool-php,用 C 語言編寫,並且 tarantool-php/客戶端,用 PHP 寫。 我是後者的作者。

在本文中,我想分享這兩個庫的效能測試結果,並展示如何透過對程式碼進行最小的更改,實現 3-5 的效能提升(在綜合測試中!).

我們將測試什麼?

我們將測試上面提到的那些 同步 非同步、並行和非同步並行運行的連接器。 🙂 我們也不想觸及連接器本身的程式碼。 目前有幾個擴充功能可以實現您想要的:

  • 斯沃爾 ― PHP 的高效能非同步框架。 被阿里巴巴、百度等網路巨頭使用。 從4.1.0版本開始出現了一個神奇的方法 SwooleRuntime::enableCoroutine(),它允許您「用一行程式碼將同步 PHP 網路庫轉換為非同步網路庫」。
  • 直到最近,Async 仍然是 PHP 中非同步工作的一個非常有前途的擴展。 為什麼直到最近? 不幸的是,由於我不知道的原因,作者刪除了儲存庫,並且該專案的未來命運尚不清楚。 我得用它 來自叉子。 與 Swoole 一樣,此擴充功能可讓您輕彈手腕即可輕鬆打開褲子,透過以非同步版本取代 TCP 和 TLS 串流的標準實作來實現非同步。 這是透過選項“異步 TCP = 1“。
  • 平行 ——來自著名的 Joe Watkins 的相當新的擴展,他是 phpdbg、apcu、pthreads、pcov、uopz 等庫的作者。 該擴充功能為 PHP 中的多執行緒提供了 API,並定位為 pthread 的替代品。 該程式庫的一個重要限制是它僅適用於 ZTS(Zend Thread Safe)版本的 PHP。

我們將如何測試?

讓我們啟動一個禁用預寫日誌記錄的 Tarantool 實例(wal_mode = 無)和增加的網路緩衝區(預讀 = 1 * 1024 * 1024)。 第一個選項將消除對磁碟的工作,第二個選項將可以從作業系統緩衝區讀取更多請求,從而最大限度地減少系統呼叫的數量。

對於處理資料(插入、刪除、讀取等)的基準測試,在啟動基準測試之前,將(重新)建立一個 memtx 空間,其中主索引值由有序整數值產生器建立(序列)。
空間 DDL 如下圖所示:

space = box.schema.space.create(config.space_name, {id = config.space_id, temporary = true})
space:create_index('primary', {type = 'tree', parts = {1, 'unsigned'}, sequence = true})
space:format({{name = 'id', type = 'unsigned'}, {name = 'name', type = 'string', is_nullable = false}})

如有必要,在運行基準測試之前,用 10,000 個以下形式的元組填充該空間

{id, "tuplе_<id>"}

使用隨機鍵值存取元組。

基準測試本身是對伺服器的單一請求,該請求執行 10,000 次(循環),而這些請求又以迭代方式執行。 重複迭代,直到 5 次迭代之間的所有時間偏差都在 3%* 的可接受誤差範圍內。 此後,取平均結果。 迭代之間有 1 秒的暫停,以防止處理器限流。 Lua 的垃圾收集器在每次迭代之前都已停用,並在完成後強制啟動。 僅使用基準測試所需的擴充功能啟動 PHP 進程,並啟用輸出緩衝並停用垃圾收集器。

* 轉數、迭代次數和誤差閾值可以在基準設定中變更。

測試環境

以下發布的結果是在 MacBookPro (2015)、作業系統 - Fedora 30(核心版本 5.3.8-200.fc30.x86_64)上得出的。 Tarantool 在 docker 中啟動,參數為“--network host".

封裝版本:

Tarantool: 2.3.0-115-g5ba5ed37e
Docker:19.03.3,建置 a872fc2f86
PHP:7.3.11(cli)(建置時間:22 年 2019 月 08 日 11:04:XNUMX)
塔蘭工具/客戶端:0.6.0
rybakit/msgpack:0.6.1
ext-tarantool:0.3.2(+ 7.3 的補丁)*
外部訊息包:2.0.3
外部非同步:0.3.0-8c1da46
ext-swoole:4.4.12
外部並行:1.1.3

* 不幸的是,官方連接器不適用於 PHP 版本 > 7.2。 要在 PHP 7.3 上編譯並執行擴展,我必須使用 修補.

Результаты

同步模式

Tarantool協定使用二進位格式 消息包 序列化訊息。 在PECL連接器中,序列化隱藏在庫的深處,並影響使用者層級程式碼的編碼過程 似乎不可能。 相反,純 PHP 連接器提供了透過擴展標準編碼器或使用您自己的實現來自訂編碼過程的能力。 有兩種開箱即用的編碼器,一種基於 msgpack/msgpack-php (官方MessagePack PECL擴充),另一個是on rybakit/msgpack (純 PHP)。

在比較連接器之前,我們將測量 PHP 連接器的 MessagePack 編碼器的效能,在進一步的測試中,我們將使用顯示最佳結果的編碼器:

使用 Async、Swoole 和 Parallel 加速 Tarantool 的 PHP 連接器
雖然PHP版本(Pure)在速度上不如PECL擴展,但在實際專案中我仍然推薦使用它 rybakit/msgpack,因為在官方 MessagePack 擴充功能中,格式規範僅部分實現(例如,不支援自訂資料類型,否則您將無法使用 Decimal - Tarantool 2.3 中引入的新資料類型)並且具有其他人數 проблем (包括與 PHP 7.4 的兼容性問題)。 嗯,總的來說,這個項目看起來被遺棄了。

那麼,讓我們在同步模式下測量連接器的性能:

使用 Async、Swoole 和 Parallel 加速 Tarantool 的 PHP 連接器
從圖中可以看出,與 PHP 連接器(Client)相比,PECL 連接器(Tarantool)顯示出更好的效能。 但這並不奇怪,因為後者除了以較慢的語言實現之外,實際上還做了更多的工作:每次呼叫都會創建一個新對象 要求 и 響應 (在選擇的情況下 - 也 標準,並且在更新/更新插入的情況下 ― 操作),單獨的實體 連線設定, 帕克 и 處理程序 它們還增加了開銷。 顯然,靈活性是有代價的。 不過,總的來說,PHP 解釋器表現出了良好的性能,儘管存在差異,但差異不大,而且在PHP 7.4 中使用預加載時,性能可能會更差,更不用說PHP 8 中的JIT了。

讓我們繼續。 Tarantool 2.0 引入了 SQL 支援。 讓我們嘗試使用 SQL 協定執行選擇、插入、更新和刪除操作,並將結果與 noSQL(二進位)等效項進行比較:

使用 Async、Swoole 和 Parallel 加速 Tarantool 的 PHP 連接器
SQL 結果不是很令人印象深刻(讓我提醒您,我們仍在測試同步模式)。 不過,我不會提前對此感到不安;SQL 支援仍在積極開發中(例如,最近添加了支援) 準備好的報表)並且,從列表來看 問題未來SQL引擎還會進行多項優化。

異步

好吧,現在讓我們看看 Async 擴充功能如何幫助我們改進上面的結果。 為了編寫非同步程序,該擴充功能提供了一個基於協程的 API,我們將使用它。 我們根據經驗發現,我們環境的最佳協程數量是 25:

使用 Async、Swoole 和 Parallel 加速 Tarantool 的 PHP 連接器
在 10,000 個協程中「分散」25 個操作,看看會發生什麼:

使用 Async、Swoole 和 Parallel 加速 Tarantool 的 PHP 連接器
每秒操作次數增加3倍以上 tarantool-php/客戶端!

可惜的是,PECL 連接器並未以 ext-async 啟動。

那麼 SQL 呢?

使用 Async、Swoole 和 Parallel 加速 Tarantool 的 PHP 連接器
正如您所看到的,在非同步模式下,二進位協定和 SQL 之間的差異已在誤差範圍內。

斯沃爾

我們再次找出最佳協程數量,這次是 Swoole:
使用 Async、Swoole 和 Parallel 加速 Tarantool 的 PHP 連接器
讓我們在 25 處停止。讓我們重複與非同步擴展相同的技巧 - 在 10,000 個協程之間分配 25 個操作。 此外,我們將新增另一個測試,其中我們將所有工作分為 2 個兩個進程(即每個進程將在 5,000 個協程中執行 25 個操作)。 流程將使用以下方式創建 Swoole進程.

結果:

使用 Async、Swoole 和 Parallel 加速 Tarantool 的 PHP 連接器
在一個進程中運行時,與Async 相比,Swole 顯示的結果稍低,但如果有2 個進程,情況會發生巨大變化(數字2 不是偶然選擇的;在我的機器上,是2 個進程顯示了最佳結果)。

順便說一句,非同步擴展也有一個用於處理進程的 API,但我沒有註意到在一個或多個進程中運行基準測試有任何區別(我可能在某個地方搞砸了)。

SQL 與二進位協定:

使用 Async、Swoole 和 Parallel 加速 Tarantool 的 PHP 連接器
與非同步一樣,非同步模式下消除了二進位操作和 SQL 操作之間的差異。

平行

由於並行擴展不是關於協程,而是關於線程,讓我們測量並行線程的最佳數量:

使用 Async、Swoole 和 Parallel 加速 Tarantool 的 PHP 連接器
在我的機器上它等於 16。 讓我們在 16 個平行執行緒上執行連接器基準測試:

使用 Async、Swoole 和 Parallel 加速 Tarantool 的 PHP 連接器
正如您所看到的,結果甚至比非同步擴展更好(不包括在 2 個進程上運行的 Swoole)。 請注意,對於 PECL 連接器,更新和更新插入操作為空。 這是因為這些操作因錯誤而失敗 - 我不知道這是 ext-parallel、ext-tarantool 的錯誤,還是兩者兼而有之。

現在我們來比較一下 SQL 效能:

使用 Async、Swoole 和 Parallel 加速 Tarantool 的 PHP 連接器
注意到與同步運行連接器的圖表相似嗎?

一起

最後,讓我們將所有結果總結在一張圖表中,以查看測試擴展的整體情況。 讓我們在圖表中新增一項尚未完成的新測試 - 讓我們使用 Parallel* 並行運行非同步協程。 整合以上擴展的想法已經 被討論了 作者,但沒有共識,你必須自己做。

* 無法使用 Parallel 啟動 Swoole 協程;看來這些擴充不相容。

所以,最終結果:

使用 Async、Swoole 和 Parallel 加速 Tarantool 的 PHP 連接器

取而代之的是結論

在我看來,結果是相當值得的,而且出於某種原因,我確信這不是極限! 無論您是否需要在實際專案中為自己做出決定,我只會說,對我來說,這是一個有趣的實驗,它允許您評估可以以最小的努力從同步TCP 連接器中“擠出”多少內容。 如果您有改進基準的想法,我將很樂意考慮您的拉取要求。 所有包含啟動說明和結果的程式碼均發佈在單獨的 儲存庫.

來源: www.habr.com

添加評論