摘要:修復添加超過萬個以上定時器時發生崩潰的問題增加模塊,下高性能序列化庫修復監聽端口設置無效的問題等。線程來處理網絡事件輪詢,讀取數據。當的三次握手成功了以后,由這個線程將連接成功的消息告訴進程,再由進程轉交給進程。此時進程觸發事件。
本文示例代碼詳見:https://github.com/52fhy/swoo...。
簡介Swoole是一個PHP擴展,提供了PHP語言的異步多線程服務器,異步TCP/UDP網絡客戶端,異步MySQL,異步Redis,數據庫連接池,AsyncTask,消息隊列,毫秒定時器,異步文件讀寫,異步DNS查詢。 Swoole內置了Http/WebSocket服務器端/客戶端、Http2.0服務器端。
Swoole: PHP的異步、并行、高性能網絡通信引擎
http://www.swoole.com/
Github:
https://github.com/swoole
https://github.com/matyhtf
Swoole需要使用源碼安裝。暫無Windows版擴展。
源碼安裝wget -O swoole.zip https://github.com/swoole/swoole-src/archive/v1.9.11.zip unzip swoole.zip cd swoole phpize ./configure make && make installpecl安裝
由于pecl是需要編譯的,所以需要先安裝編譯器(已安裝編譯器可以忽略):
yum install -y gcc gcc-c++ make cmake bison autoconf
然后:
pecl install swoole pecl install redis
pecl安裝擴展完成后會提示添加so文件到php.ini。示例:
Build process completed successfully Installing "/usr/lib64/php/modules/swoole.so" install ok: channel://pecl.php.net/swoole-1.9.11 configuration option "php_ini" is not set to php.ini location You should add "extension=swoole.so" to php.ini
添加示例:
[swoole] extension = /usr/lib64/php/modules/swoole.so版本選擇
建議使用的版本(截止時間2017-6-3)
穩定版:v1.9.9 預覽版:v2.0.7
1.9.x 分支已進入特性鎖定期,不再開發新功能,僅修復BUG。
最低版本:
建議1.8.6+。PHP7建議使用1.9.2+。
建議使用的PHP版本
PHP5.5或更高版本 PHP7.0.13或更高版本
使用TP3.1+框架的朋友升級到PHP7.1.0可能會出現rewrite失效問題。建議PHP7.0.x系列。
快速查看當前swoole的版本:
php --ri swoole
1.8.6~1.8.13 都是小范圍BUG修復及功能新增。其中 1.8.11 增加SIGRTMIN信號處理函數,用于重新打開日志文件。
1.8.6 版本是一個重要的BUG修復版本,主要修復了PHP7環境下HttpServer、TCPClient、HttpClient、Redis等客戶端存在的內存泄漏、崩潰問題。
1.9.0 版本增加了多項新特性,修復了多個已知問題。1.9版本是100%向下兼容1.8的,用戶可無縫升級。
1.9.1 修復PHP7下啟用opcache導致崩潰的問題;重構reopen log file特性,收到SIGRTMIN信號后重新打開日志文件并重定向標準輸出 等。
1.9.2 修復PHP7下發生zend_mm_heap corrupted的問題 等。
1.9.4 修復WebSocket服務器默認onRequest方法內存泄漏問題 等。
1.9.5 增加pid_file選項,在Server啟動時將主進程ID寫入指定的文件 等。
1.9.6 修復添加超過1萬個以上定時器時發生崩潰的問題;增加swoole_serialize模塊,PHP7下高性能序列化庫;修復監聽UDP端口設置onPacket無效的問題 等。
1.9.9 修復Http2客戶端POST數據時協議錯誤問題 等。
1.9.11 修復WebSocket服務器onOpen回調函數存在內存泄漏的問題;修復Http服務器文件上傳在5.6版本發生崩潰的問題;優化添加Task和Timer的定時器性能,提升分支預測成功率 等。
Swoole的進程模型 運行模式Swoole目前總共有三種運行模式,默認為多進程模式(SWOOLE_PROCESS)。
# Base模式(SWOOLE_BASE) 傳統的異步非阻塞Server,reactor和worker是同一個角色。TCP連接是在worker進程中維持的。 如果客戶端連接之間不需要交互,可以使用BASE模式。如Memcache、Http服務器等。 # 線程模式 多線程Worker模式,Reactor線程來處理網絡事件輪詢,讀取數據。得到的請求交給Worker線程去處理。 缺點:一個線程發生內存錯誤,整個進程會全部結束。 由于PHP的ZendVM在多線程模式存在內存錯誤,多線程模式在v1.6.0版本后已關閉。 # 進程模式 與多線程Worker模式不同的是,線程換成了進程。Reactor線程來處理網絡事件輪詢,讀取數據。得到的請求交給Worker進程去處理。適合業務邏輯非常復雜的場景。如WebSocket服務器等。
$serv = new swoole_server(string $host, int $port, int $mode = SWOOLE_PROCESS, int $sock_type = SWOOLE_SOCK_TCP);實例分析
我們來使用實例進行分析:
on("connect", function ($serv, $fd){ }); $server->on("receive", function ($serv, $fd, $from_id, $data){ }); $server->on("close", function ($serv, $fd){ }); $server -> start();
繼續在Shell中輸入以下命令:
php swoole_tcp_server.php pstree -ap|grep swoole_tcp_server | | `-php,2454 swoole_tcp_server.php | | |-php,2456 swoole_tcp_server.php | | | `-php,2458 swoole_tcp_server.php
從系統的輸出中,我們可以很容看出server其實有3個進程,進程的pid分別是2454、2456、2458,其中2454是2456的父進程,而2456又是2458的父進程。
所以,其實我們雖然看起來只是啟動了一個Server,其實最后產生的是三個進程。
這三個進程中,所有進程的根進程(2454),就是所謂的Master進程;而2456進程,則是Manager進程;最后的2458進程,是Worker進程。
基于此,我們簡單梳理一下,當執行的start方法之后,發生了什么:
守護進程模式下,當前進程fork出Master進程,然后退出,Master進程觸發OnMasterStart事件。
Master進程啟動成功之后,fork出Manager進程,并觸發OnManagerStart事件。
Manager進程啟動成功時候,fork出Worker進程,并觸發OnWorkerStart事件。
非守護進程模式下,則當前進程直接作為Master進程工作。
所以,一個最基礎的Swoole Server,至少需要有3個進程,分別是Master進程、Manager進程和Worker進程。
事實上,一個多進程模式下的Swoole Server中,有且只有一個Master進程;有且只有一個Manager進程;卻可以有n個Worker進程。
進程模型Master進程是一個多線程進程,其中有一組非常重要的線程,叫做Reactor線程(組),每當一個客戶端連接上服務器的時候,都會由Master進程從已有的Reactor線程中,根據一定規則挑選一個,專門負責向這個客戶端提供維持鏈接、處理網絡IO與收發數據等服務。分包拆包等功能也是在這里完成。
Manager進程,某種意義上可以看做一個代理層,它本身并不直接處理業務,其主要工作是將Master進程中收到的數據轉交給Worker進程,或者將Worker進程中希望發給客戶端的數據轉交給Master進程進行發送。
Manager進程還負責監控Worker進程,如果Worker進程因為某些意外掛了,Manager進程會重新拉起新的Worker進程,有點像Supervisor的工作。而這個特性,也是最終實現熱重載的核心機制。
Worker進程其實就是處理各種業務工作的進程,Manager將數據包轉交給Worker進程,然后Worker進程進行具體的處理,并根據實際情況將結果反饋給客戶端。
我們可以總結出來上面簡單的Server,當客戶端連接的時候這個過程中,三種進程之間是怎么協作的:
Client主動Connect的時候,Client實際上是與Master進程中的某個Reactor線程發生了連接。
當TCP的三次握手成功了以后,由這個Reactor線程將連接成功的消息告訴Manager進程,再由Manager進程轉交給Worker進程。
在這個Worker進程中觸發了OnConnect的方法。
當Client向Server發送了一個數據包的時候,首先收到數據包的是Reactor線程,同時Reactor線程會完成組包,再將組好的包交給Manager進程,由Manager進程轉交給Worker。
此時Worker進程觸發OnReceive事件。
如果在Worker進程中做了什么處理,然后再用Send方法將數據發回給客戶端時,數據則會沿著這個路徑逆流而上。
Swoole進程/線程結構圖:
現在,我們基于上面的例子修改代碼,來看看一個簡單的多進程Swoole Server的幾個基本配置:
set(array( "demonize" => false,//是否后臺運行 "reactor_num" => 2, "worker_num" => 4 )); $server -> start();
reactor_num:表示Master進程中,Reactor線程總共開多少個,注意,這個可不是越多越好,因為計算機的CPU是有限的,所以一般設置為與CPU核心數量相同,或者兩倍即可。
worker_num:表示啟動多少個Worker進程,同樣,Worker進程數量不是越多越好,仍然設置為與CPU核心數量相同,或者兩倍即可。
我們可以在Shell里運行,使用pstree查看進程模型結構:
php swoole_tcp_server.php pstree -ap|grep swoole_tcp | | `-php,2505 swoole_tcp_server.php | | |-php,2507 swoole_tcp_server.php | | | |-php,2510 swoole_tcp_server.php | | | |-php,2511 swoole_tcp_server.php | | | |-php,2512 swoole_tcp_server.php | | | `-php,2513 swoole_tcp_server.php回調函數
Swoole作為Server時,回調函數有很多。但可以簡單分個類:
1) 進程啟動時執行的:onStart、onManagerStart、onWorkerStart;onWorkerStop、onManagerStop、onShutdown;onWorkerError
2) 客戶端交互時觸發的:onReceive/onRequest/onPacket/onMessage、onOpen/onConnect、onClose
3) Task:onTask、onFinish
4) Timer:onTimer
事件執行順序:
所有事件回調均在$server->start后發生
服務器關閉程序終止時最后一次事件是onShutdown
服務器啟動成功后,onStart/onManagerStart/onWorkerStart會在不同的進程內并發執行。
onReceive/onConnect/onClose/onTimer在worker進程(包括task進程)中各自觸發
worker/task進程啟動/結束時會分別調用onWorkerStart/onWorkerStop
onTask事件僅在task進程中發生
onFinish事件僅在worker進程中發生
onStart/onManagerStart/onWorkerStart 3個事件的執行順序是不確定的
UDP協議下只有onReceive事件,沒有onConnect/onClose事件
如果未設置onPacket回調函數,收到UDP數據包默認會回調onReceive函數
onOpen事件回調是可選的:當WebSocket客戶端與服務器建立連接并完成握手后會回調此函數
實際使用的時候不是所有回調都可以使用的,例如UDP服務器沒有onConnect/onClose;例如接收數據,在WebSocket里使用onReceive,在HttpServer使用onRequest,在UDPServer使用onPacket。
示例:
set(array( "daemonize" => false, "reactor_num" => 2, "worker_num" => 4 )); $server->on("connect", function ($serv, $fd){ echo "client connect. fd is {$fd} "; }); $server->on("receive", function ($serv, $fd, $from_id, $data){ echo "client connect. fd is {$fd} "; }); $server->on("close", function ($serv, $fd){ echo "client close. fd is {$fd} "; }); // 以下回調發生在Master進程 $server->on("start", function (swoole_server $server){ echo "On master start. "; }); $server->on("shutdown", function (swoole_server $server){ echo "On master shutdown. "; }); // 以下回調發生在Manager進程 $server->on("ManagerStart", function (swoole_server $server){ echo "On manager start. "; }); $server->on("ManagerStop", function (swoole_server $server){ echo "On manager stop. "; }); // 以下回調也發生在Worker進程 $server->on("WorkerStart", function (swoole_server $server, $worker_id){ echo "Worker start "; }); $server->on("WorkerStop", function(swoole_server $server, $worker_id){ echo "Worker stop "; }); $server->on("WorkerError", function(swoole_server $server, $worker_id, $worker_pid, $exit_code){ echo "Worker error "; }); $server -> start();編程須知
不要在代碼中執行sleep以及其他睡眠函數,這樣會導致整個進程阻塞
exit/die是危險的,會導致worker進程退出
可通過register_shutdown_function來捕獲致命錯誤,在進程異常退出時做一些請求工作,具體參看/wiki/page/305.html
PHP代碼中如果有異常拋出,必須在回調函數中進行try/catch捕獲異常,否則會導致工作進程退出
swoole不支持set_exception_handler,必須使用try/catch方式處理異常
Worker進程不得共用同一個Redis或MySQL等網絡服務客戶端,Redis/MySQL創建連接的相關代碼可以放到onWorkerStart回調函數中。原因是如果共用1個連接,那么返回的結果無法保證被哪個進程處理。持有連接的進程理論上都可以對這個連接進行讀寫,這樣數據就發生錯亂了。具體參考/wiki/page/325.html
不能使用類的屬性保存客戶端連接信息,因為一個worker進程可以處理多個客戶端連接,導致類屬性數據錯亂。常量則是可以的。
歡迎關注公眾號及時獲取最新文章推送!
推薦!每月僅需$2.5,即可擁有配置SSD的VPS!
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/23065.html
摘要:所以,我感覺學習,需要一個引導。學習參考鏈接喵星球特別厲害的一個官網的幾個框架文檔優勢先看一下的結構設計的應用場景的設計項目中引入一個簡易的具體參考一篇文章,集合和的簡易實例項目中引入結合致敬 前期學完了操作系統,特別是知道了進程,線程 調度的問題。回來看,發現了很多細節。第三次看文檔,最初經一個高手朋友的介紹,看swoole,說文檔寫的賊好。但是看的時候,也是很一頭霧水,只知道把de...
摘要:消息隊列更常見的用途是主進程分配任務,子進程消費執行。子進程前面加了個,這是為了防止父進程還未往消息隊列中加入內容直接退出。 前面幾節都是講解pcntl擴展實現的多進程程序。本節給大家介紹swoole擴展的swoole_process模塊。 swoole多進程 swoole_process 是swoole提供的進程管理模塊,用來替代PHP的pcntl擴展。 首先,確保安裝的swoole...
摘要:安裝準備或更高版本或更高版本安裝擴展配置支持編輯在其中加入擴展支持服務端代碼服務端客戶端代碼測試代碼在命令模式下輸入重新再開一個窗口可以用檢測如服務端客戶端如上,表示服務端啟動,客戶端連接服務端返回消息,一個閉環形成開發者頭條 1.安裝準備 php-5.3.10 // 或更高版本 gcc-4.4 //或更高版本 make autoconf 2.安裝swoole擴展 w...
摘要:配置了參數后將會啟用功能,務必要注冊個事件回調函數。周期性定時器一次性定時器清除定時器定時器回調函數注意最大不得超過。進程中不能添加定時器。建議在回調里寫定時器。定時器示例防止重復每隔觸發一次后執行此函數 本文示例代碼詳見:https://github.com/52fhy/swoo...。 重新打開日志 在1.8.11及之后版本支持重新打開日志:向Server主進程發送SIGRTMIN...
摘要:超過此數量后,新進入的連接將被拒絕。表示連接最大允許空閑的時間。當出錯時底層會認為是惡意連接,丟棄數據并強制關閉連接。在啟動時自動將進程的寫入到文件,在關閉時自動刪除文件。 配置說明 $server->set(array( daemonize => true, log_file => /www/log/swoole.log, reactor_num => 2, ...
閱讀 3546·2019-08-30 12:58
閱讀 927·2019-08-29 16:37
閱讀 2801·2019-08-29 16:29
閱讀 3107·2019-08-26 12:18
閱讀 2368·2019-08-26 11:59
閱讀 3414·2019-08-23 18:27
閱讀 2788·2019-08-23 16:43
閱讀 3305·2019-08-23 15:23