摘要:當(dāng)某種網(wǎng)絡(luò)事件發(fā)生時(shí),會(huì)回調(diào)用戶設(shè)置的指定回調(diào)函數(shù)。承擔(dān)了底層網(wǎng)絡(luò)事件的監(jiān)聽及各種底層事件處理,當(dāng)收到請(qǐng)求時(shí),會(huì)觸發(fā)事件提醒,然后將控制權(quán)轉(zhuǎn)交預(yù)先注冊的事件回調(diào)函數(shù),來進(jìn)行后續(xù)的處理。請(qǐng)求到來時(shí)創(chuàng)建,請(qǐng)求結(jié)束后銷毀。
運(yùn)行流程圖
當(dāng)啟動(dòng)一個(gè)Swoole應(yīng)用時(shí),一共會(huì)創(chuàng)建2+n+m個(gè)進(jìn)程,2為一個(gè)Master進(jìn)程和一個(gè)Manager進(jìn)程,其中n為Worker進(jìn)程數(shù),m為TaskWorker進(jìn)程數(shù)。名詞解釋 Master進(jìn)程
主進(jìn)程,該進(jìn)程會(huì)創(chuàng)建Manager進(jìn)程、Reactor線程,UDP收包線程,心跳檢測線程等線程Manger進(jìn)程
管理進(jìn)程,該進(jìn)程的作用是創(chuàng)建、管理所有的Worker進(jìn)程和TaskWorker進(jìn)程。
子進(jìn)程結(jié)束運(yùn)行時(shí),manager進(jìn)程負(fù)責(zé)回收此子進(jìn)程,避免成為僵尸進(jìn)程。并創(chuàng)建新的子進(jìn)程
服務(wù)器關(guān)閉時(shí),manager進(jìn)程將發(fā)送信號(hào)給所有子進(jìn)程,通知子進(jìn)程關(guān)閉服務(wù)
服務(wù)器reload時(shí),manager進(jìn)程會(huì)逐個(gè)關(guān)閉/重啟子進(jìn)程
Worker進(jìn)程工作進(jìn)程,所有的業(yè)務(wù)邏輯代碼均在此進(jìn)程上運(yùn)行。當(dāng)Reactor線程接收到來自客戶端的數(shù)據(jù)后,會(huì)將數(shù)據(jù)打包通過管道發(fā)送給某個(gè)Worker進(jìn)程。
接受由Reactor線程投遞的請(qǐng)求數(shù)據(jù)包,并執(zhí)行PHP回調(diào)函數(shù)處理數(shù)據(jù)
生成響應(yīng)數(shù)據(jù)并發(fā)給Reactor線程,由Reactor線程發(fā)送給TCP客戶端
可以是異步非阻塞模式,也可以是同步阻塞模式
Worker以多進(jìn)程的方式運(yùn)行
TaskWorker進(jìn)程一種特殊的工作進(jìn)程,該進(jìn)程的作用是處理一些耗時(shí)較長的任務(wù),以達(dá)到釋放Worker進(jìn)程的目的。
接受由Worker進(jìn)程通過swoole_server->task/taskwait方法投遞的任務(wù)
處理任務(wù),并將結(jié)果數(shù)據(jù)返回(使用swoole_server->finish)給Worker進(jìn)程
完全是同步阻塞模式
TaskWorker以多進(jìn)程的方式運(yùn)行
Reactor線程實(shí)際運(yùn)行Linux中是epoll實(shí)例,MacOS中為Kqueue實(shí)例,用于accept客戶端連接以及接收客戶端數(shù)據(jù)。 Swoole的主進(jìn)程是一個(gè)多線程的程序。其中有一組很重要的線程,稱之為Reactor線程。它就是真正處理TCP連接,收發(fā)數(shù)據(jù)的線程。 Swoole的主線程在Accept新的連接后,會(huì)將這個(gè)連接分配給一個(gè)固定的Reactor線程,并由這個(gè)線程負(fù)責(zé)監(jiān)聽此socket。 在socket可讀時(shí)讀取數(shù)據(jù),并進(jìn)行協(xié)議解析,將請(qǐng)求投遞到Worker進(jìn)程。在socket可寫時(shí)將數(shù)據(jù)發(fā)送給TCP客戶端。
負(fù)責(zé)維護(hù)客戶端TCP連接、處理網(wǎng)絡(luò)IO、處理協(xié)議、收發(fā)數(shù)據(jù)
完全是異步非阻塞的模式
全部為C代碼,除Start/Shudown事件回調(diào)外,不執(zhí)行任何PHP代碼
將TCP客戶端發(fā)來的數(shù)據(jù)緩沖、拼接、拆分成完整的一個(gè)請(qǐng)求數(shù)據(jù)包
Reactor以多線程的方式運(yùn)行
運(yùn)行機(jī)制Swoole是php的擴(kuò)展,一旦運(yùn)行后就會(huì)接管PHP的控制權(quán),進(jìn)入事件循環(huán)。 當(dāng)某種IO(網(wǎng)絡(luò)IO)事件發(fā)生時(shí),Swoole 會(huì)回調(diào)用戶設(shè)置的指定回調(diào)函數(shù)。 Swoole承擔(dān)了底層網(wǎng)絡(luò)事件的監(jiān)聽及各種底層事件處理,當(dāng)收到請(qǐng)求時(shí),會(huì)觸發(fā)事件提醒,然后將控制權(quán)轉(zhuǎn)交預(yù)先注冊的事件回調(diào)函數(shù),來進(jìn)行后續(xù)的處理。 可以理解為Reactor就是nginx,Worker就是php-fpm。Reactor線程異步并行地處理網(wǎng)絡(luò)請(qǐng)求,然后再轉(zhuǎn)發(fā)給Worker進(jìn)程中去處理。Reactor和Worker間通過UnixSocket進(jìn)行通信。 Swoole提供的TaskWorker是一套更完整的方案,將任務(wù)的投遞、隊(duì)列、php任務(wù)處理進(jìn)程管理合為一體。通過底層提供的API可以非常簡單地實(shí)現(xiàn)異步任務(wù)的處理。 另外TaskWorker還可以在任務(wù)執(zhí)行完成后,再返回一個(gè)結(jié)果反饋到Worker。 Swoole的Reactor、Worker、TaskWorker之間可以緊密的結(jié)合起來,提供更高級(jí)的使用方式。 一個(gè)更通俗的比喻,假設(shè)Server就是一個(gè)工廠,Master是董事長,Manager是CEO,那Reactor就是銷售經(jīng)理,接受客戶訂單。而Worker就是工人,當(dāng)銷售接到訂單后,Worker去工作生產(chǎn)出客戶要的東西。 而TaskWorker可以理解為行政人員,可以幫助Worker干些雜事,讓W(xué)orker專心工作。
所謂的回調(diào)函數(shù)(CallBack) 就好比是張開了夾子的捕鼠器,我們設(shè)定當(dāng)有老鼠踩到捕鼠器的時(shí)候,他會(huì)關(guān)閉夾子然后捉住老鼠,我們放置捕鼠器的時(shí)候,捕鼠器并沒有真的抓老鼠。這個(gè)設(shè)定就是回調(diào),他不立刻執(zhí)行,會(huì)在遇到觸發(fā)條件(事件)時(shí)執(zhí)行,在上面的示例當(dāng)中我們放置了3個(gè)捕鼠器(回調(diào)函數(shù)),我們只需要知道他會(huì)在特定老鼠(事件)踩到的時(shí)候(發(fā)生的時(shí)候)去執(zhí)行我們期望的功能就好。
底層會(huì)為Worker進(jìn)程、TaskWorker進(jìn)程分配一個(gè)唯一的ID
不同的Worker和TaskWorker進(jìn)程之間可以通過sendMessage接口進(jìn)行通信
運(yùn)行周期 程序全局期在swoole_server->start之前就創(chuàng)建好的對(duì)象,我們稱之為程序全局生命周期。 這些變量在程序啟動(dòng)后就會(huì)一直存在,直到整個(gè)程序結(jié)束運(yùn)行才會(huì)銷毀。 有一些服務(wù)器程序可能會(huì)連續(xù)運(yùn)行數(shù)月甚至數(shù)年才會(huì)關(guān)閉/重啟,那么程序全局期的對(duì)象在這段時(shí)間持續(xù)駐留在內(nèi)存中的。 程序全局對(duì)象所占用的內(nèi)存是Worker進(jìn)程間共享的,不會(huì)額外占用內(nèi)存。 這部分內(nèi)存會(huì)在寫時(shí)分離(COW),在Worker進(jìn)程內(nèi)對(duì)這些對(duì)象進(jìn)行寫操作時(shí),會(huì)自動(dòng)從共享內(nèi)存中分離,變?yōu)檫M(jìn)程全局對(duì)象。 程序全局期include/require的代碼,必須在整個(gè)程序shutdown時(shí)才會(huì)釋放,reload無效。進(jìn)程全局期
swoole擁有進(jìn)程生命周期控制的機(jī)制,一個(gè)Worker子進(jìn)程處理的請(qǐng)求數(shù)超過max_request配置后,就會(huì)自動(dòng)銷毀。 Worker進(jìn)程啟動(dòng)后創(chuàng)建的對(duì)象(onWorkerStart中創(chuàng)建的對(duì)象),在這個(gè)子進(jìn)程存活周期之內(nèi),是常駐內(nèi)存的。 onConnect/onReceive/onClose 中都可以去訪問它。 進(jìn)程全局對(duì)象所占用的內(nèi)存是在當(dāng)前子進(jìn)程內(nèi)存堆的,并非共享內(nèi)存。對(duì)此對(duì)象的修改僅在當(dāng)前Worker進(jìn)程中有效。 進(jìn)程期include/require的文件,在reload后就會(huì)重新加載。會(huì)話期
會(huì)話期是在onConnect后創(chuàng)建,或者在第一次onReceive時(shí)創(chuàng)建,onClose時(shí)銷毀。一個(gè)客戶端連接進(jìn)入后,創(chuàng)建的對(duì)象會(huì)常駐內(nèi)存,直到此客戶端離開才會(huì)銷毀。 swoole中會(huì)話期的對(duì)象直接是常駐內(nèi)存,不需要session_start之類操作。 可以直接訪問對(duì)象,并執(zhí)行對(duì)象的方法。請(qǐng)求期
請(qǐng)求期就是指一個(gè)完整的請(qǐng)求發(fā)來,也就是onReceive收到請(qǐng)求開始處理,直到返回結(jié)果發(fā)送response。 這個(gè)周期所創(chuàng)建的對(duì)象,會(huì)在請(qǐng)求完成后銷毀。 swoole中請(qǐng)求期對(duì)象與普通PHP程序中的對(duì)象就是一樣的。 請(qǐng)求到來時(shí)創(chuàng)建,請(qǐng)求結(jié)束后銷毀。4種PHP回調(diào)函數(shù)風(fēng)格 匿名函數(shù)
$server->on("Request", function ($req, $resp) use ($a, $b, $c) { echo "hello world"; });
可使用use向匿名函數(shù)傳遞參數(shù)類靜態(tài)方法
class A { static function test($req, $resp) { echo "hello world"; } } $server->on("Request", "A::Test"); $server->on("Request", array("A", "Test"));對(duì)象方法
class A { function test($req, $resp) { echo "hello world"; } } $object = new A(); $server->on("Request", array($object, "test"));函數(shù)
function my_onRequest($req, $resp) { echo "hello world"; } $server->on("Request", "my_onRequest");編程須知 注意事項(xiàng)
不要在代碼中執(zhí)行sleep以及其他睡眠函數(shù),這樣會(huì)導(dǎo)致整個(gè)進(jìn)程阻塞
在swoole程序中禁止使用exit/die,如果PHP代碼中有exit/die,當(dāng)前工作的Worker進(jìn)程、Task進(jìn)程、User進(jìn)程、以及swoole_process進(jìn)程會(huì)立即退出。使用exit/die后Worker進(jìn)程會(huì)因?yàn)楫惓M顺? 被master進(jìn)程再次拉起, 最終造成進(jìn)程不斷退出又不斷啟動(dòng)和產(chǎn)生大量警報(bào)日志。
mt_rand隨機(jī)數(shù),在Swoole中如果在父進(jìn)程內(nèi)調(diào)用了mt_rand,不同的子進(jìn)程內(nèi)再調(diào)用mt_rand返回的結(jié)果會(huì)是相同的。所以必須在每個(gè)子進(jìn)程內(nèi)調(diào)用mt_srand重新播種。
while循環(huán)的影響,異步程序如果遇到死循環(huán),事件將無法觸發(fā)。異步IO程序使用Reactor模型,運(yùn)行過程中必須在reactor->wait處輪詢。如果遇到死循環(huán),那么程序的控制權(quán)就在while中了,reactor無法得到控制權(quán),無法檢測事件,所以IO事件回調(diào)函數(shù)也將無法觸發(fā)。
可通過register_shutdown_function來捕獲致命錯(cuò)誤,在進(jìn)程異常退出時(shí)做一些清理工作
PHP代碼中如果有異常拋出,必須在回調(diào)函數(shù)中進(jìn)行try/catch捕獲異常,否則會(huì)導(dǎo)致工作進(jìn)程退出
不支持set_exception_handler,必須使用try/catch方式處理異常
Worker進(jìn)程不得共用同一個(gè)Redis或MySQL等網(wǎng)絡(luò)服務(wù)客戶端,Redis/MySQL創(chuàng)建連接的相關(guān)代碼可以放到onWorkerStart回調(diào)函數(shù)中。
異步編程異步程序要求代碼中不得包含任何同步阻塞操作
異步與同步代碼不能混用,一旦應(yīng)用程序使用了任何同步阻塞的代碼,程序即退化為同步模式
類/函數(shù)重復(fù)定義新手非常容易犯這個(gè)錯(cuò)誤,由于Swoole是常駐內(nèi)存的,所以加載類/函數(shù)定義的文件后不會(huì)釋放。因此引入類/函數(shù)的php文件時(shí)必須要使用include_once或require_once,否會(huì)發(fā)生cannot redeclare function/class 的致命錯(cuò)誤。進(jìn)程隔離
進(jìn)程隔離也是很多新手經(jīng)常遇到的問題。修改了全局變量的值,為什么不生效,原因就是全局變量在不同的進(jìn)程,內(nèi)存空間是隔離的,所以無效。所以使用Swoole開發(fā)Server程序需要了解進(jìn)程隔離問題。
不同的進(jìn)程中PHP變量不是共享,即使是全局變量,在A進(jìn)程內(nèi)修改了它的值,在B進(jìn)程內(nèi)是無效的
如果需要在不同的Worker進(jìn)程內(nèi)共享數(shù)據(jù),可以用Redis、MySQL、文件、SwooleTable、APCu、shmget等工具實(shí)現(xiàn)
不同進(jìn)程的文件句柄是隔離的,所以在A進(jìn)程創(chuàng)建的Socket連接或打開的文件,在B進(jìn)程內(nèi)是無效,即使是將它的fd發(fā)送到B進(jìn)程也是不可用的
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/29731.html
摘要:前言都是為了生存有收獲的話請(qǐng)加顆小星星,沒有收獲的話可以反對(duì)沒有幫助舉報(bào)三連代碼倉庫初始上一什么是面向生產(chǎn)環(huán)境的異步網(wǎng)絡(luò)通信引擎使開發(fā)人員可以編寫高性能的異步并發(fā),服務(wù)。 前言:都是為了生存 有收獲的話請(qǐng)加顆小星星,沒有收獲的話可以 反對(duì) 沒有幫助 舉報(bào)三連 代碼倉庫 初始swoole【上】 一、什么是swoole Swoole:面向生產(chǎn)環(huán)境的 PHP 異步網(wǎng)絡(luò)通信引擎 使 PHP...
摘要:目錄初識(shí)創(chuàng)建服務(wù)器上創(chuàng)建服務(wù)器下異步任務(wù)持續(xù)更新中。。。參加工作有一段時(shí)間了,偶爾會(huì)聽到,對(duì)我這種小白粗略看下文檔都會(huì)覺得很牛逼。個(gè)人理解就是解決這樣應(yīng)用場景的。 目錄 初識(shí)Swoole 創(chuàng)建服務(wù)器(上) 創(chuàng)建服務(wù)器(下) 異步任務(wù)task 持續(xù)更新中。。。 參加工作有一段時(shí)間了,偶爾會(huì)聽到swoole,對(duì)我這種PHP小白粗略看下文檔都會(huì)覺得很牛逼。由于學(xué)習(xí)成本比較高,自身對(duì)網(wǎng)絡(luò)異...
摘要:前言接初識(shí)上,這篇主要是異步問題有收獲的話請(qǐng)加顆小星星,沒有收獲的話可以反對(duì)沒有幫助舉報(bào)三連代碼倉庫初識(shí)下異步任務(wù)設(shè)置異步任務(wù)的工作進(jìn)程數(shù)量連接連接歡迎大山驢回調(diào)投遞異步任務(wù)觸發(fā)異步任務(wù)服務(wù)端回復(fù)說處理異步任務(wù)新的異步任務(wù) 前言:接初識(shí)swoole【上】,這篇主要是異步問題 有收獲的話請(qǐng)加顆小星星,沒有收獲的話可以 反對(duì) 沒有幫助 舉報(bào)三連 代碼倉庫 初識(shí)swoole【下】 6、異...
摘要:是一個(gè)請(qǐng)求對(duì)象,包含了客戶端發(fā)來的握手請(qǐng)求信息事件函數(shù)中可以調(diào)用向客戶端發(fā)送數(shù)據(jù)或者調(diào)用關(guān)閉連接事件回調(diào)是可選的當(dāng)服務(wù)器收到來自客戶端的數(shù)據(jù)幀時(shí)會(huì)回調(diào)此函數(shù)。 前言:了解概念之后就應(yīng)該練練手啦,不然就是巨嬰 有收獲的話請(qǐng)加顆小星星,沒有收獲的話可以 反對(duì) 沒有幫助 舉報(bào)三連 代碼倉庫 實(shí)戰(zhàn)swoole【聊天室】 在線體驗(yàn) 準(zhǔn)備工作 需要先看初識(shí)swoole【上】,了解基本的服務(wù)端...
摘要:安裝命令環(huán)境下必須關(guān)閉選項(xiàng)需要修改關(guān)閉在下開發(fā)可以使用來方便的開發(fā)應(yīng)用,安裝好后再里的選項(xiàng)里共享代碼所在磁盤。為源碼所在路徑為容器內(nèi)路徑在里執(zhí)行編譯安裝擴(kuò)展是按照標(biāo)準(zhǔn)擴(kuò)展構(gòu)建的。 環(huán)境依賴 僅支持 Linux、FreeBSD、MacOS 三種操作系統(tǒng) 在Windows平臺(tái),可使用CygWin或WSL(Windows Subsystem for Linux) Linux 內(nèi)核版本 2....
閱讀 3578·2021-09-24 09:48
閱讀 1105·2021-09-10 10:51
閱讀 3283·2019-08-30 13:03
閱讀 3331·2019-08-30 12:51
閱讀 1399·2019-08-30 11:22
閱讀 1074·2019-08-29 18:38
閱讀 2045·2019-08-29 16:41
閱讀 3216·2019-08-29 15:32