swoole基礎(chǔ)+easyswoole實(shí)踐

一央拖、涉及的計(jì)算機(jī)基礎(chǔ)知識

通信網(wǎng)絡(luò)

  • 全雙工/單工/半雙工:
    1祭阀、單工:數(shù)據(jù)只在一個方向上傳輸,不能實(shí)現(xiàn)雙方通信爬泥。如:閉路電視柬讨、廣播。
    2袍啡、半雙工:允許數(shù)據(jù)在兩個方向上傳輸踩官,但是同一時間數(shù)據(jù)只能在一個方向上傳輸,其實(shí)際上是切換的單工境输。如:對講機(jī)
    3蔗牡、全雙工:允許數(shù)據(jù)在兩個方向上同時傳輸。如:手機(jī)通話

  • IP/TCP/UDP:
    1嗅剖、ip協(xié)議(網(wǎng)絡(luò)層):IP的責(zé)任就是把數(shù)據(jù)從源傳送到目的地辩越。它不負(fù)責(zé)保證傳送可靠性,流控制信粮,包順序和其它對于主機(jī)到主機(jī)協(xié)議來說很普通的服務(wù)黔攒。
    2、tcp(傳輸層):是一種面向連接的强缘、可靠的督惰、基于字節(jié)流的傳輸層通信協(xié)議,TCP為了保證不發(fā)生丟包旅掂,就給每個包一個序號赏胚,同時序號也保證了傳送到接收端實(shí)體的包的按序接收。然后接收端實(shí)體對已成功收到的包發(fā)回一個相應(yīng)的確認(rèn)(ACK)商虐;TCP用一個校驗(yàn)和函數(shù)來檢驗(yàn)數(shù)據(jù)是否有錯誤觉阅;在發(fā)送和接收時都要計(jì)算校驗(yàn)和崖疤。
    3、udp(傳輸層):一種無連接的傳輸層協(xié)議典勇,提供面向事務(wù)的簡單不可靠信息傳送服務(wù)劫哼,UDP有不提供數(shù)據(jù)包分組、組裝和不能對數(shù)據(jù)包進(jìn)行排序的缺點(diǎn)割笙,也就是說沦偎,當(dāng)報(bào)文發(fā)送之后,是無法得知其是否安全完整到達(dá)的咳蔚。

  • socket:
    socket本質(zhì)是編程接口(API),對TCP/IP的封裝搔驼,TCP/IP也要提供可供程序員做網(wǎng)絡(luò)開發(fā)所用的接口谈火,這就是Socket編程接口。在設(shè)計(jì)模式中舌涨,Socket其實(shí)就是一個門面模式糯耍,它把復(fù)雜的TCP/IP協(xié)議族隱藏在Socket接口后面,對用戶來說囊嘉,一組簡單的接口就是全部温技,讓Socket去組織數(shù)據(jù),以符合指定的協(xié)議扭粱。

  • websocket:
    WebSocket協(xié)議是基于TCP的一種新的網(wǎng)絡(luò)協(xié)議舵鳞。它實(shí)現(xiàn)了瀏覽器與服務(wù)器全雙工(full-duplex)通信,它只需要一次http握手,就可以保持一個長連接,使得服務(wù)器可以主動發(fā)送消息給客戶端,大大減少了輪詢機(jī)制的消耗

  • 參考文章:計(jì)算機(jī)通信網(wǎng)絡(luò)系列文章

操作系統(tǒng)

  • 進(jìn)程:進(jìn)程是一個具有一定獨(dú)立功能的程序關(guān)于某個數(shù)據(jù)集合的一次運(yùn)行活動琢蛤。它是操作系統(tǒng)動態(tài)執(zhí)行的基本單元蜓堕,在傳統(tǒng)的操作系統(tǒng)中,進(jìn)程既是基本的分配單元博其,也是基本的執(zhí)行單元套才。進(jìn)程是一個實(shí)體。每一個進(jìn)程都有它自己的地址空間慕淡,一般情況下背伴,包括文本區(qū)域(text region)、數(shù)據(jù)區(qū)域(data region)和堆棧(stack region)峰髓。

  • 線程:通常在一個進(jìn)程中可以包含若干個線程傻寂,當(dāng)然一個進(jìn)程中至少有一個線程,不然沒有存在的意義儿普。線程可以利用進(jìn)程所擁有的資源崎逃,在引入線程的操作系統(tǒng)中,通常都是把進(jìn)程作為分配資源的基本單位,而把線程作為獨(dú)立運(yùn)行和獨(dú)立調(diào)度的基本單位苹熏,由于線程比進(jìn)程更小,基本上不擁有系統(tǒng)資源惰拱,故對它的調(diào)度所付出的開銷就會小得多巴柿,能更高效的提高系統(tǒng)多個程序間并發(fā)執(zhí)行的程度凛虽。

  • 協(xié)程:你可能看的最多的就是這樣一句話“協(xié)程就是用戶態(tài)的線程”,用戶態(tài)的線程不是由操作系統(tǒng)來調(diào)度的广恢,而是由程序員來調(diào)度的凯旋。PHP程序中,yield這個關(guān)鍵字就是用來產(chǎn)生中斷, 并保存當(dāng)前的上下文的, 比如說程序的一段代碼是訪問遠(yuǎn)程服務(wù)器钉迷,那這個時候CPU就是空閑的至非,就用yield讓出CPU,接著執(zhí)行下一段的代碼糠聪,如果下一段代碼還是訪問除CPU以外的其它資源荒椭,還可以調(diào)用yield讓出CPU. 繼續(xù)往下執(zhí)行,這樣就可以用同步的方式寫異步的代碼了舰蟆。

  • 上下文:上下文切換(有時也稱做進(jìn)程切換或任務(wù)切換)是指CPU從一個進(jìn)程或線程切換到另一個進(jìn)程或線程趣惠。上下文是指某一時間點(diǎn) CPU 寄存器和程序計(jì)數(shù)器的內(nèi)容。寄存器是 CPU 內(nèi)部的數(shù)量較少但是速度很快的內(nèi)存(與之對應(yīng)的是 CPU 外部相對較慢的 RAM 主內(nèi)存)身害。寄存器通過對常用值(通常是運(yùn)算的中間值)的快速訪問來提高計(jì)算機(jī)程序運(yùn)行的速度味悄。程序計(jì)數(shù)器是一個專用的寄存器,用于表明指令序列中 CPU 正在執(zhí)行的位置塌鸯,存的值為正在執(zhí)行的指令的位置或者下一個將要被執(zhí)行的指令的位置侍瑟,具體依賴于特定的系統(tǒng)。

  • 參考文章:計(jì)算機(jī)操作系統(tǒng)系列文章

二界赔、涉及的PHP基礎(chǔ)知識

五種常見運(yùn)行模式

  • cgi 協(xié)議模式
  • fast-cgi 協(xié)議模式丢习,一個常駐內(nèi)存型的cgi。
  • 模塊模式淮悼,如php作為apache的模塊隨apache啟動而啟動
  • php-cli模式咐低,屬于命令行模式
  • 其他,如SwooleServer

fast-cgicgi都是一種協(xié)議,開啟的進(jìn)程是單獨(dú)實(shí)現(xiàn)該協(xié)議的進(jìn)程袜腥,php-fpm是fastcgi進(jìn)程管理器见擦。
php-fpm啟動->生成n個fast-cgi協(xié)議處理進(jìn)程->監(jiān)聽一個端口等待任務(wù)->用戶請求->web服務(wù)器接收請求->請求轉(zhuǎn)發(fā)給php-fpm->php-fpm交給一個空閑進(jìn)程處理->進(jìn)程處理完成->php-fpm返回給web服務(wù)器->web服務(wù)器接收數(shù)據(jù)->返回給用戶。更詳細(xì)內(nèi)容可參考FastCGI相關(guān)文章
SwooleServer 則是相當(dāng)于取代了 php-fpm 作為管理器的位置羹令, 由于Swoole 是運(yùn)行在 CLI 模式下鲤屡, 所以可以常駐運(yùn)行和以守護(hù)進(jìn)程運(yùn)行, 但也正因?yàn)槿绱烁3蓿残枰_發(fā)者自行處理變量的銷毀及各種異常和超時的處理酒来。

pcntl_fork多進(jìn)程使用

  • pcntl是php官方的多進(jìn)程擴(kuò)展,只能在linux環(huán)境使用
  • 當(dāng)pcntl_fork()創(chuàng)建子進(jìn)程成功時,在父進(jìn)程執(zhí)行線程內(nèi)返回產(chǎn)生的子進(jìn)程的PID肪凛,在子進(jìn)程執(zhí)行線程內(nèi)返回0堰汉。失敗時辽社,在 父進(jìn)程上下文返回-1,不會創(chuàng)建子進(jìn)程翘鸭,并且會引發(fā)一個PHP錯誤滴铅。
  • 子進(jìn)程會復(fù)制父進(jìn)程的狀態(tài),如果在第五行執(zhí)行了pcntl_fork就乓,那么創(chuàng)建出的子進(jìn)程汉匙,代碼也是從第五行開始執(zhí)行的。又子進(jìn)程復(fù)制了數(shù)據(jù)生蚁,代碼噩翠。
    具體可參考php中pcntl_fork詳解 / PHP多進(jìn)程編之pcntl_fork
swoole涉及的其他PHP知識

三、swoole基礎(chǔ)

應(yīng)用場景

Swoole是一個為PHP用C和C++編寫的基于事件的高性能異步&協(xié)程并行網(wǎng)絡(luò)通信引擎尼摹。使 PHP 開發(fā)人員可以編寫高性能的異步并發(fā) TCP、UDP剂娄、Unix Socket蠢涝、HTTP,WebSocket 服務(wù)阅懦。Swoole 可以廣泛應(yīng)用于互聯(lián)網(wǎng)和二、移動通信、企業(yè)軟件耳胎、云計(jì)算惯吕、網(wǎng)絡(luò)游戲、物聯(lián)網(wǎng)(IOT)怕午、車聯(lián)網(wǎng)废登、智能家居等領(lǐng)域。 使用 PHP + Swoole 作為網(wǎng)絡(luò)通信框架郁惜,可以使企業(yè) IT 研發(fā)團(tuán)隊(duì)的效率大大提升堡距,更加專注于開發(fā)創(chuàng)新產(chǎn)品。
Swoole高并發(fā)高性能保證:IO復(fù)用兆蕉、常駐內(nèi)存型羽戒、協(xié)程、異步虎韵、進(jìn)程池易稠、耗時任務(wù)處理、高性能數(shù)據(jù)結(jié)構(gòu)(hashTable)等包蓝。

swoole服務(wù)運(yùn)行結(jié)構(gòu)圖

運(yùn)行流程圖

進(jìn)程/線程結(jié)構(gòu)圖1

進(jìn)程/線程結(jié)構(gòu)圖2
Reactor驶社、Worker企量、TaskWorker的關(guān)系

三種角色分別的職責(zé)是:

Reactor線程
  • 負(fù)責(zé)維護(hù)客戶端TCP連接、處理網(wǎng)絡(luò)IO衬吆、處理協(xié)議梁钾、收發(fā)數(shù)據(jù)
  • 完全是異步非阻塞的模式
  • 全部為C代碼,除Start/Shudown事件回調(diào)外逊抡,不執(zhí)行任何PHP代碼
  • 將TCP客戶端發(fā)來的數(shù)據(jù)緩沖姆泻、拼接、拆分成完整的一個請求數(shù)據(jù)包
  • Reactor以多線程的方式運(yùn)行
Worker進(jìn)程
  • 接受由Reactor線程投遞的請求數(shù)據(jù)包和處理冒嫡,包括協(xié)議解析和響應(yīng)請求拇勃,并執(zhí)行PHP回調(diào)函數(shù)處理數(shù)據(jù)
  • 生成響應(yīng)數(shù)據(jù)并發(fā)給Reactor線程,由Reactor線程發(fā)送給TCP客戶端
  • 可以是異步非阻塞模式孝凌,也可以是同步阻塞模式
  • Worker以多進(jìn)程的方式運(yùn)行
  • 未設(shè)置worker_num方咆,底層會啟動與CPU數(shù)量一致的Worker進(jìn)程。
TaskWorker進(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)行
三者關(guān)系

可以理解為Reactor就是nginx瓣赂,Worker就是php-fpm。Reactor線程異步并行地處理網(wǎng)絡(luò)請求片拍,然后再轉(zhuǎn)發(fā)給Worker進(jìn)程中去處理煌集。Reactor和Worker間通過UnixSocket進(jìn)行通信。swoole與nginx有很多原理相似之處捌省,具體可參考 swoole原理和nginx原理對比苫纤。

在php-fpm的應(yīng)用中,經(jīng)常會將一個任務(wù)異步投遞到Redis等隊(duì)列中纲缓,并在后臺啟動一些php進(jìn)程異步地處理這些任務(wù)卷拘。Swoole提供的TaskWorker是一套更完整的方案,將任務(wù)的投遞祝高、隊(duì)列栗弟、php任務(wù)處理進(jìn)程管理合為一體。通過底層提供的API可以非常簡單地實(shí)現(xiàn)異步任務(wù)的處理工闺。另外TaskWorker還可以在任務(wù)執(zhí)行完成后横腿,再返回一個結(jié)果反饋到Worker。

Swoole的Reactor斤寂、Worker耿焊、TaskWorker之間可以緊密的結(jié)合起來,提供更高級的使用方式遍搞。
一個更通俗的比喻罗侯,假設(shè)Server就是一個工廠,那Reactor就是銷售溪猿,接受客戶訂單钩杰。而Worker是管理層及行政人員纫塌,執(zhí)行小任務(wù)或派發(fā)耗時任務(wù)。當(dāng)銷售接到訂單后讲弄,Worker就去處理一些簡單的雜事措左,而TaskWorker可以理解工人,專門處理worker派發(fā)下來的一些耗時比較長的任務(wù)避除。

底層會為Worker進(jìn)程怎披、TaskWorker進(jìn)程分配一個唯一的ID,不同的Worker和TaskWorker進(jìn)程之間可以通過sendMessage接口進(jìn)行通信

Master 主進(jìn)程瓶摆、Manager 進(jìn)程

Master 主進(jìn)程:主進(jìn)程內(nèi)有多個Reactor線程凉逛,基于epoll/kqueue進(jìn)行網(wǎng)絡(luò)事件輪詢。收到數(shù)據(jù)后轉(zhuǎn)發(fā)到Worker進(jìn)程去處理

Manager 進(jìn)程:對所有Worker進(jìn)程進(jìn)行管理群井,Worker進(jìn)程生命周期結(jié)束或者發(fā)生異常時自動回收状飞,并創(chuàng)建新的Worker進(jìn)程

swoole常見功能

Swoole 使用純 C 語言編寫,提供了 PHP 語言的異步多線程服務(wù)器书斜,異步 TCP/UDP 網(wǎng)絡(luò)客戶端诬辈,異步 MySQL,異步 Redis荐吉,數(shù)據(jù)庫連接池自晰,AsyncTask,消息隊(duì)列稍坯,毫秒定時器,異步文件讀寫搓劫,異步DNS查詢瞧哟。 Swoole內(nèi)置了Http/WebSocket服務(wù)器端/客戶端、Http2.0服務(wù)器端枪向∏诳基礎(chǔ)入門可參考快速起步
除了異步 IO 的支持之外,Swoole 為 PHP 多進(jìn)程的模式設(shè)計(jì)了多個并發(fā)數(shù)據(jù)結(jié)構(gòu)和IPC(進(jìn)程間通信)通信機(jī)制秘蛔,可以大大簡化多進(jìn)程并發(fā)編程的工作陨亡。其中包括了并發(fā)原子計(jì)數(shù)器,并發(fā) HashTable深员,Channel负蠕,Lock,進(jìn)程間通信IPC等豐富的功能特性倦畅。
Swoole2.0 支持了類似 Go 語言的協(xié)程遮糖,可以使用完全同步的代碼實(shí)現(xiàn)異步程序。PHP 代碼無需額外增加任何關(guān)鍵詞叠赐,底層自動進(jìn)行協(xié)程調(diào)度欲账,實(shí)現(xiàn)異步屡江。

常見服務(wù)類型

  • Swoole\Server
    創(chuàng)建一個異步服務(wù)器程序,支持TCP赛不、UDP惩嘉、UnixSocket 3種協(xié)議,支持IPv4和IPv6踢故,支持SSL/TLS單向雙向證書的隧道加密文黎。使用者無需關(guān)注底層實(shí)現(xiàn)細(xì)節(jié),僅需要設(shè)置網(wǎng)絡(luò)事件的回調(diào)函數(shù)即可畴椰。
    請勿在使用Server創(chuàng)建之前調(diào)用其他異步IO的API臊诊,否則將會創(chuàng)建失敗⌒敝可以在Server啟動后onWorkerStart回調(diào)函數(shù)中使用抓艳。
    Server只能用于php-cli環(huán)境,在其他環(huán)境下會拋出致命錯誤

  • Swoole\Http\Server
    Http\Server繼承自Server帚戳,是一個的Http服務(wù)器實(shí)現(xiàn)玷或。Http\Server支持同步和異步2種模式。
    無論是同步模式還是異步模式片任,Http\Server都可以維持大量TCP客戶端連接偏友。同步/異步僅僅體現(xiàn)在對請求的處理方式上。
    swoole_http_server是swoole_server的子類对供,內(nèi)置了Http的支持位他。當(dāng)然不單單只有http,如swoole_redis_server也是swoole_server的子類产场,內(nèi)置了Redis服務(wù)器端協(xié)議的支持鹅髓。
    http\Server對Http協(xié)議的支持并不完整,建議僅作為應(yīng)用服務(wù)器京景。并且在前端增加Nginx作為代理

  • Swoole\WebSocket\Server
    swoole內(nèi)置的WebSocket服務(wù)器支持窿冯,通過幾行PHP代碼就可以寫出一個異步非阻塞多進(jìn)程的WebSocket服務(wù)器。
    swoole_websocket_server是swoole_http_server的子類确徙,內(nèi)置了WebSocket的支持

自定義進(jìn)程Process:1.7.2版本增加了一個進(jìn)程管理模塊醒串,用來替代PHP的pcntl,Swoole\Process提供了如下特性:

  • 基于Unix Socket和sysvmsg消息隊(duì)列的進(jìn)程間通信鄙皇,只需調(diào)用write/read或者push/pop即可
  • 支持重定向標(biāo)準(zhǔn)輸入和輸出芜赌,在子進(jìn)程內(nèi)echo不會打印屏幕,而是寫入管道伴逸,讀鍵盤輸入可以重定向?yàn)楣艿雷x取數(shù)據(jù)
  • 配合Event模塊较鼓,創(chuàng)建的PHP子進(jìn)程可以異步的事件驅(qū)動模式
  • 提供了exec接口,創(chuàng)建的進(jìn)程可以執(zhí)行其他程序,與原PHP父進(jìn)程之間可以方便的通信

協(xié)程模式:Swoole2/4版本支持了協(xié)程博烂,使用協(xié)程后事件回調(diào)函數(shù)將會并發(fā)地執(zhí)行香椎。協(xié)程是一種用戶態(tài)線程實(shí)現(xiàn),沒有額外的調(diào)度消耗禽篱,僅占用內(nèi)存畜伐。使用協(xié)程模式,可以理解為“每次事件回調(diào)函數(shù)都會創(chuàng)建一個新的線程去執(zhí)行躺率,事件回調(diào)函數(shù)執(zhí)行完成后玛界,線程退出”。
當(dāng)協(xié)程執(zhí)行完后悼吱,底層會恢復(fù)協(xié)程上下文慎框,代碼邏輯繼續(xù)從切換點(diǎn)開始恢復(fù)執(zhí)行。開發(fā)者整個過程不需要關(guān)心整個切換過程后添”靠荩可查看實(shí)現(xiàn)原理Coroutine進(jìn)行調(diào)用

并發(fā)HashTable:swoole_table一個基于共享內(nèi)存和鎖實(shí)現(xiàn)的超高性能,并發(fā)數(shù)據(jù)結(jié)構(gòu)遇西。用于解決多進(jìn)程/多線程數(shù)據(jù)共享和同步加鎖問題馅精。詳細(xì)可參考swoole_table

  • 性能強(qiáng)悍,單線程每秒可讀寫200萬次
  • 應(yīng)用代碼無需加鎖粱檀,swoole_table內(nèi)置行鎖自旋鎖洲敢,所有操作均是多線程/多進(jìn)程安全。用戶層完全不需要考慮數(shù)據(jù)同步問題茄蚯。
  • 支持多進(jìn)程压彭,swoole_table可以用于多進(jìn)程之間共享數(shù)據(jù)
  • 使用行鎖,而不是全局鎖渗常,僅當(dāng)2個進(jìn)程在同一CPU時間壮不,并發(fā)讀取同一條數(shù)據(jù)才會進(jìn)行發(fā)生搶鎖

進(jìn)程間通信IPC:此函數(shù)可以向任意Worker進(jìn)程或者Task進(jìn)程發(fā)送消息。在非主進(jìn)程和管理進(jìn)程中可調(diào)用凳谦。收到消息的進(jìn)程會觸發(fā)onPipeMessage事件『馕矗可查看Server->sendMessage進(jìn)行調(diào)用

Swoole\Server配置參數(shù)

示例:
$serv->set(array(
   'reactor_num' => 2, //reactor thread num
   'worker_num' => 4,    //worker process num
   'backlog' => 128,   //listen backlog
   'max_request' => 50,
   'dispatch_mode' => 1,
));

最大連接:max_conn => 10000, 此參數(shù)用來設(shè)置Server最大允許維持多少個tcp連接尸执。超過此數(shù)量后,新進(jìn)入的連接將被拒絕
守護(hù)進(jìn)程化:daemonize => 1缓醋,加入此參數(shù)后如失,執(zhí)行php server.php將轉(zhuǎn)入后臺作為守護(hù)進(jìn)程運(yùn)行
reactor線程數(shù):reactor_num => 2,通過此參數(shù)來調(diào)節(jié)Reactor線程的數(shù)量送粱,以充分利用多核褪贵,reactor_num和默認(rèn)設(shè)置為CPU核數(shù)
worker進(jìn)程數(shù):worker_num => 4,設(shè)置啟動的Worker進(jìn)程數(shù)量。Swoole采用固定Worker進(jìn)程的模式脆丁。
全異步非阻塞服務(wù)器 worker_num配置為CPU核數(shù)的1-4倍即可世舰。
同步阻塞服務(wù)器,worker_num配置為100或者更高槽卫,具體要看每次請求處理的耗時和操作系統(tǒng)負(fù)載狀況
設(shè)定的Worker進(jìn)程數(shù)小于reactor線程數(shù)時跟压,會自動調(diào)低reactor線程的數(shù)量
max_request:max_request => 2000,此參數(shù)表示worker進(jìn)程在處理完n次請求后結(jié)束運(yùn)行歼培。manager會重新創(chuàng)建一個worker進(jìn)程震蒋。此選項(xiàng)用來防止worker進(jìn)程內(nèi)存溢出。
worker進(jìn)程數(shù)據(jù)包分配模式:dispatch_mode = 1 //1平均分配躲庄,2按FD取模固定分配查剖,3搶占式分配,默認(rèn)為取模(dispatch=2)
更多配置可參考Server->set配置信息

Swoole\Server事件回調(diào)函數(shù)

Swoole\Server是事件驅(qū)動模式噪窘,所有的業(yè)務(wù)邏輯代碼必須寫在事件回調(diào)函數(shù)中笋庄。當(dāng)特定的網(wǎng)絡(luò)事件發(fā)生后,底層會主動回調(diào)指定的PHP函數(shù)效览。共支持13種事件无切。更詳細(xì)的內(nèi)容可參考:事件回調(diào)函數(shù)
事件執(zhí)行順序:

  • 所有事件回調(diào)均在$server->start后發(fā)生
  • 服務(wù)器關(guān)閉程序終止時最后一次事件是onShutdown
  • 服務(wù)器啟動成功后,onStart/onManagerStart/onWorkerStart會在不同的進(jìn)程內(nèi)并發(fā)執(zhí)行
  • onReceive/onConnect/onClose在Worker進(jìn)程中觸發(fā)
  • Worker/Task進(jìn)程啟動/結(jié)束時會分別調(diào)用一次onWorkerStart/onWorkerStop
  • onTask事件僅在task進(jìn)程中發(fā)生
  • onFinish事件僅在worker進(jìn)程中發(fā)生
  • onStart/onManagerStart/onWorkerStart 3個事件的執(zhí)行順序是不確定的
參考文章

四丐枉、easyswoole框架

easyswoole框架生命周期

具體可參考核心代碼文件:vendor/easyswoole/easyswoole/src/Core.php


框架生命周期
服務(wù)類型

  • EASYSWOOLE_SERVER (對應(yīng)Swoole\Server)
  • EASYSWOOLE_WEB_SERVER (對應(yīng)Swoole\Http\Server)
  • EASYSWOOLE_WEB_SOCKET_SERVER (對應(yīng)Swoole\WebSocket\Server)
easyswoole案例演示

  • tcp請求:

EasySwoole Tcp服務(wù) / tcp demo

#在CliExample目錄下執(zhí)行 php TCPClient3.php
服務(wù)端回復(fù): 1557998515 
服務(wù)端回復(fù): your args is:{"name":"\u4ed9\u58eb\u53ef"}

#服務(wù)端內(nèi)容響應(yīng):
已連接
tcp服務(wù)3  fd:3 發(fā)送消息:M{"controller":"Index","action":"index","param":{"name":"\u4ed9\u58eb\u53ef"}}
tcp服務(wù)3  fd:3 發(fā)送消息:L{"controller":"Index","action":"args","param":{"name":"\u4ed9\u58eb\u53ef"}}
tcp服務(wù)3  fd:3 已關(guān)閉

服務(wù)端通過addListener開啟9504端口監(jiān)聽哆键,客戶端通過$client->connect('127.0.0.1', 9504, 0.5)發(fā)起鏈接后發(fā)送數(shù)據(jù)。服務(wù)端通過\EasySwoole\Socket\Dispatcher->dispatch進(jìn)行路由解析瘦锹,并執(zhí)行具體動作后將數(shù)據(jù)返回給客戶端籍嘹。

  • http請求:

http教程 / http demo

#按照demo案例添加App/HttpController/Test.php,并訪問以下函數(shù)
function index()
{
    $this->response()->write('test index');
}

# 訪問 http://mytest.easyswoole.com/Test/index
輸出:test index
  • 壓力測試:
#硬件信息
CPU:1核 Intel(R) Xeon(R) Gold 6148 CPU @ 2.40GHz
內(nèi)存:1GB
操作系統(tǒng): Ubuntu / 16.04 LTS amd64 (64bit) 

# ab長連接壓測swoole頁面(ab -c 100 -n 100000 -k http://127.0.0.1:9501/Test/index)返回:
Concurrency Level:      100
Time taken for tests:   18.085 seconds
Complete requests:      100000
Failed requests:        0
Keep-Alive requests:    100000
Total transferred:      15500000 bytes
HTML transferred:       1000000 bytes
Requests per second:    5529.44 [#/sec] (mean)
Time per request:       18.085 [ms] (mean)
Time per request:       0.181 [ms] (mean, across all concurrent requests)
Transfer rate:          836.98 [Kbytes/sec] receive

#ab非長連接壓測swoole頁面(ab -c 100 -n 100000 http://127.0.0.1:9501/Test/index)返回:
Concurrency Level:      100
Time taken for tests:   46.141 seconds
Complete requests:      100000
Failed requests:        0
Total transferred:      15000000 bytes
HTML transferred:       1000000 bytes
Requests per second:    2167.29 [#/sec] (mean)
Time per request:       46.141 [ms] (mean)
Time per request:       0.461 [ms] (mean, across all concurrent requests)
Transfer rate:          317.47 [Kbytes/sec] received

#ab長連接壓測nginx頁面(ab -c 100 -n 100000 -k http://127.0.0.1/test.php)返回:
Concurrency Level:      100
Time taken for tests:   36.257 seconds
Complete requests:      100000
Failed requests:        0
Keep-Alive requests:    0
Total transferred:      14700000 bytes
HTML transferred:       1000000 bytes
Requests per second:    2758.12 [#/sec] (mean)
Time per request:       36.257 [ms] (mean)
Time per request:       0.363 [ms] (mean, across all concurrent requests)
Transfer rate:          395.94 [Kbytes/sec] received

swoole頁面的長連接比非長連接qps高出一半弯院,nginx非長連接壓測的qps比swoole非長連接壓測的qps要高

  • 自定義進(jìn)程

Process教程 / 多進(jìn)程 / swoole_process實(shí)現(xiàn)多進(jìn)程 / Process自定義進(jìn)程demo

#按照demo部署代碼辱士,并稍微調(diào)整EasySwooleEvent.php下函數(shù)mainServerCreate代碼
public static function mainServerCreate(EventRegister $register)
{
       /**
        * 除了進(jìn)程名,其余參數(shù)非必須
        */
       for($i=0;$i<3;$i++){
          $myProcess = new ProcessOne("processName".$i,$i,false,2,true);
          ServerManager::getInstance()->getSwooleServer()->addProcess($myProcess->getProcess());
       }
}

#稍微調(diào)整App/Process/ProcessOne.php代碼
public function run($arg)
{
       Logger::getInstance()->console($this->getProcessName().'-'.$arg." start");
       while (1){
           \co::sleep(4-$arg);
           Logger::getInstance()->console($this->getProcessName().'-'.$arg." run");
       }
}

#查詢執(zhí)行的進(jìn)程:
root@instance-wjbdyzhe:/data/web/mytest.easyswoole.com# ps -aux|grep processName
root     10288  0.0  0.0  14688   908 pts/0    S+   20:53   0:00 grep --color=auto processName
root     24261  0.0  1.2 232932 12308 pts/2    S+   20:04   0:00 processName0
root     24262  0.0  1.2 232932 12308 pts/2    S+   20:04   0:00 processName1
root     24263  0.0  1.2 232932 12308 pts/2    S+   20:04   0:00 processName2

#三個進(jìn)程的執(zhí)行結(jié)果:
[2019-04-28 08:56:37][default]processName0-0 start
[2019-04-28 08:56:37][default]processName2-2 start
[2019-04-28 08:56:37][default]processName1-1 start
[2019-04-28 08:56:39][default]processName2-2 run
[2019-04-28 08:56:40][default]processName1-1 run
[2019-04-28 08:56:41][default]processName0-0 run
[2019-04-28 08:56:41][default]processName2-2 run
[2019-04-28 08:56:43][default]processName1-1 run
[2019-04-28 08:56:43][default]processName2-2 run

可以看到以上代碼及執(zhí)行結(jié)果:執(zhí)行程序后听绳,創(chuàng)建了三個自定義進(jìn)程颂碘,并且進(jìn)程是并行執(zhí)行的

  • 異步任務(wù):

異步任務(wù)教程 / 異步任務(wù)demo

#按照demo部署代碼,并調(diào)整以下函數(shù)
function multiTaskConcurrency(){
       // 多任務(wù)并發(fā)
       $tasks[] = function () { sleep(1);return 'this is 1'; }; // 任務(wù)1
       $tasks[] = function () { sleep(5);return 'this is 2'; }; // 任務(wù)2
       $tasks[] = function () { sleep(3);return 'this is 3'; }; // 任務(wù)3

       $results = \EasySwoole\EasySwoole\Swoole\Task\TaskManager::barrier($tasks, 6);

       var_dump($results);
       $this->response()->write('執(zhí)行并發(fā)任務(wù)成功');
   }

# 訪問 http://mytest.easyswoole.com/index/multiTaskConcurrency
輸出:
array(3) {
 [0]=>
 string(9) "this is 1"
 [2]=>
 string(9) "this is 3"
 [1]=>
 string(9) "this is 2"
}

由代碼和打印來看椅挣,雖然任務(wù)2排在第二位头岔,但由于執(zhí)行時間長,執(zhí)行結(jié)果排在最后鼠证,由此可知三個任務(wù)并非串行執(zhí)行峡竣,而是并行執(zhí)行

  • 連接池

Mysql協(xié)程連接池 / Redis協(xié)程連接池 / 連接池demo

#最大進(jìn)程配置數(shù)8個
'SETTING' => [
      'worker_num'       => 8,
      'max_request'      => 5000,
      'task_worker_num'  => 8,
     'task_max_request' => 1000,
],
#每個進(jìn)程連接池最大連接個數(shù)5個
'REDIS' => [
       'host'          => '127.0.0.1',
       'port'          => '6379',
       'auth'          => 'test',
       'POOL_MAX_NUM'  => '5',
       'POOL_TIME_OUT' => 'utf8mb4',
   ],

#jmeter壓測配置
線程數(shù):100;ramp-up時間:10量九;循環(huán)次數(shù):30

#通過redis客戶端查看鏈接信息:
127.0.0.1:6379> info clients
# Clients
connected_clients:41
client_recent_max_input_buffer:4
client_recent_max_output_buffer:0
blocked_clients:0

理論最大redis鏈接數(shù) = worker_num*POOL_MAX_NUM = 8*5 = 40
并發(fā)壓測客戶端顯示 = 41-1 = 40(多一個1實(shí)際為手動鏈接)
只要不終止swoole/server服務(wù)客戶端連接适掰,顯示一直為41颂碧,表示鏈接一直處于鏈接可用狀態(tài)。

#最大進(jìn)程配置數(shù)8個
'SETTING' => [
      'worker_num'       => 8,
      'max_request'      => 5000,
      'task_worker_num'  => 8,
     'task_max_request' => 1000,
],
#匿名連接池最大配置10個鏈接
'MYSQL3'  => [
       'host'          => '127.0.0.1',//防止報(bào)錯,就不切換數(shù)據(jù)庫了
       'port'          => '3306',
       'user'          => 'root',
       'timeout'       => '5',
       'charset'       => 'utf8mb4',
       'password'      => '123456',
       'database'      => 'test',//防止報(bào)錯,就不切換數(shù)據(jù)庫了
       'POOL_MAX_NUM'  => '10',
       'POOL_TIME_OUT' => '0.1'
   ],

#jmeter壓測配置
線程數(shù):100类浪;ramp-up時間:10载城;循環(huán)次數(shù):30

#通過mysql查看鏈接個數(shù)
mysql> show processlist;
……
| 306155 | root | 172.17.0.1:48704 | test | Sleep   |   30 |          | NULL             |
| 306156 | root | 172.17.0.1:48840 | test | Sleep   |   36 |          | NULL             |
| 306157 | root | 172.17.0.1:48846 | test | Sleep   |   29 |          | NULL             |
+--------+------+------------------+------+---------+------+----------+------------------+
81 rows in set (0.00 sec)

理論最大mysql鏈接數(shù) = worker_num*POOL_MAX_NUM = 8*10 = 80
并發(fā)壓測客戶端顯示 = 81-1 = 80(多一個1實(shí)際為手動鏈接)
過一段再show processlist發(fā)現(xiàn)已無鏈接,可能mysql主動超時中斷,有興趣的同學(xué)可主動排查

  • 更多參考

EasySwoole教程
EasySwoole代碼案例
easyswoole入門經(jīng)典

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末戚宦,一起剝皮案震驚了整個濱河市个曙,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌受楼,老刑警劉巖垦搬,帶你破解...
    沈念sama閱讀 218,941評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異艳汽,居然都是意外死亡猴贰,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評論 3 395
  • 文/潘曉璐 我一進(jìn)店門河狐,熙熙樓的掌柜王于貴愁眉苦臉地迎上來米绕,“玉大人,你說我怎么就攤上這事馋艺≌じ桑” “怎么了?”我有些...
    開封第一講書人閱讀 165,345評論 0 356
  • 文/不壞的土叔 我叫張陵捐祠,是天一觀的道長碱鳞。 經(jīng)常有香客問我,道長踱蛀,這世上最難降的妖魔是什么窿给? 我笑而不...
    開封第一講書人閱讀 58,851評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮率拒,結(jié)果婚禮上崩泡,老公的妹妹穿的比我還像新娘。我一直安慰自己猬膨,他們只是感情好角撞,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,868評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著勃痴,像睡著了一般谒所。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上召耘,一...
    開封第一講書人閱讀 51,688評論 1 305
  • 那天百炬,我揣著相機(jī)與錄音褐隆,去河邊找鬼污它。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的衫贬。 我是一名探鬼主播德澈,決...
    沈念sama閱讀 40,414評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼固惯!你這毒婦竟也來了梆造?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,319評論 0 276
  • 序言:老撾萬榮一對情侶失蹤葬毫,失蹤者是張志新(化名)和其女友劉穎镇辉,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體贴捡,經(jīng)...
    沈念sama閱讀 45,775評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡忽肛,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了烂斋。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片屹逛。...
    茶點(diǎn)故事閱讀 40,096評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖汛骂,靈堂內(nèi)的尸體忽然破棺而出罕模,到底是詐尸還是另有隱情,我是刑警寧澤帘瞭,帶...
    沈念sama閱讀 35,789評論 5 346
  • 正文 年R本政府宣布淑掌,位于F島的核電站,受9級特大地震影響图张,放射性物質(zhì)發(fā)生泄漏锋拖。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,437評論 3 331
  • 文/蒙蒙 一祸轮、第九天 我趴在偏房一處隱蔽的房頂上張望兽埃。 院中可真熱鬧,春花似錦适袜、人聲如沸柄错。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,993評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽售貌。三九已至,卻和暖如春疫萤,著一層夾襖步出監(jiān)牢的瞬間颂跨,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,107評論 1 271
  • 我被黑心中介騙來泰國打工扯饶, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留恒削,地道東北人池颈。 一個月前我還...
    沈念sama閱讀 48,308評論 3 372
  • 正文 我出身青樓,卻偏偏與公主長得像钓丰,于是被迫代替她去往敵國和親躯砰。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,037評論 2 355