Swoole引擎原理(swoole為什么能提升PHP的速度)


首先,在網上找的信息說PHP代碼執行的順序是這樣的,第一步是詞法分析,第二步是語法分析,第三步是轉化為opcode,第四部也就是順序執行這些opcode了。

聰明如各位看到這里,再返回上面看一下這張圖片,肯定就會有不一樣的感覺了。咱們借用一句話來闡述這幾個步驟:當PHP拿到一段代碼后,經過詞法解析、語法解析等階段后,源程序會被翻譯成一個個指令(opcodes),然后ZEND虛擬機順次執行這些指令完成操作。

我們都知道,PHP本身是用C實現的,因此最終調用的也是C的函數,實際上,我們可以把PHP看做一個C開發的軟件。既然如此,那么PHP的代碼執行的核心也就是翻譯出來的一條一條指令,在這里就是opcode。

那么,我們就可以把opcode看成是PHP代碼執行的最基本單位。所以PHP代碼執行的本質也就可以理解為,我們的代碼最終被翻譯為一組opcode處理函數,完事之后再順序執行。

有了這些認知之后,我們就來看下這個opcode究竟是什么鬼。本質上一個opcode由兩個參數(op1,op2)、返回值和處理函數組成。它的官方解釋就是PHP腳本編譯后的中間語言,類似於java中的bytecode或者是.net中的MSL。

它的作用就是如下:

1、編譯原理的中間過程會產生一種中間代碼(語言),PHP由Zend引擎(C語言編寫)編譯后的中間代碼為Opcode然后再交由Zend引擎處理,如同C語言編譯后匯編代碼然后再交由匯編。

2、生成的Opcode作為一種中間語言,可以幫助實現PHP源程序代碼的不開源,如果你不想別人知道你的PHP代碼是怎么寫的,那你可以直接使用APC截取生成Opcode緩存文件,然后使用自己的PHP擴展加密程序對Opcode文件進行加密和解密,在Zend引擎對Opcode進行解析前進行解密然后再執行。

 

1、php-fpm 是如何處理web請求的?有什么問題?
我們用的 PHP 主要用於 web 開發,通過 nginx、apache 等服務端程序調用 php-fpm 處理服務端的業務邏輯,處理完后 php 撤消內存並返回結果。一個 web 請求就要加載一次 php 的全部文件,需要的系統資源開銷很大,這是目前 php-fpm 的缺點之一;並且因為 php-fpm 在一次請求結束就釋放內存,無法做連接池,也不合適 service 端的開發。我們用的 PHP 主要用於 web 開發,通過 nginx、apache 等服務端程序調用 php-fpm 處理服務端的業務邏輯,處理完后 php 撤消內存並返回結果。一個 web 請求就要加載一次 php 的全部文件,需要的系統資源開銷很大,這是目前 php-fpm 的缺點之一;並且因為 php-fpm 在一次請求結束就釋放內存,無法做連接池,也不合適 service 端的開發。

下面是 php-fpm 的運行流程,各位可以參考一下:

 1 http://www.test.cc
 2         |
 3       Nginx
 4         |
 5 路由到 http://www.test.cc/index.php
 6         |
 7 加載nginx的fast-cgi模塊
 8         |
 9 fast-cgi監聽127.0.0.1:9000地址
10         |
11 www.test.com/index.php請求到達127.0.0.1:9000
12         |
13 php-fpm 監聽127.0.0.1:9000
14         |
15 php-fpm 接收到請求,啟用worker進程處理請求
16         |
17 php-fpm 處理完請求並撤消內存,返回給nginx
18         |
19 nginx 將結果通過http返回給瀏覽器

 

2.swoole是如何解決php-fpm遇到的問題的?

swoole如何避免文件的反復加載:
swoole是完全的長駐內存的,長駐內存一個最大的好處就是可以性能加速。在fpm模式下,我們處理一個請求,通常會有一些空消耗,比如框架共用文件加載,配置文件加載,那么在swoole中,可以在onworkerstart的時候提前一次性把一些必要的文件和配置加載好,不必每次receive重復加載一遍,這樣能提升不小的性能。

常駐內存
常駐內存。傳統 PHP框架或者單文件,在處理每個請求之前,都要做一遍加載框架文件、配置的操作,請求完成之后會釋放所有資源和內存,無須擔心內存泄漏。但是如果請求數量上升,並發很高的時候,快速創建資源,又馬上釋放,會導致 PHP 程序運行效率急劇下降。而使用 Swoole 則沒有這個問題:PHP的代碼加載到內存后,擁有更長的生命周期,這樣建立的數據庫連接和其他大的對象,不被釋放。每次請求只需要處理很少的代碼,而這些代碼只在第一次運行時,被 PHP 解析器編譯,駐留內存。以后都是直接載入 OPCODE ,讓 Zend 引擎直接運行。另外,之前PHP不能實現的,如數據庫連接池,緩存連接池都可以在Swoole引擎下實現。系統的運行效率會大大提高。

swoole如何實現高並發

 1 請求到達 Main Reactor
 2         |
 3 Main Reactor 根據 Reactor 的情況,將請求注冊給對應的 Reactor
 4 (每個 Reactor 都有 epoll,用來監聽客戶端的變化)
 5         |
 6 客戶端有變化時,交給 worker 來處理
 7         |
 8 worker 處理完畢,通過進程間通信(比如管道、共享內存、消息隊列)發給對應的 reactor
 9         |
10 reactor 將響應結果發給相應的連接
11         |
12 請求處理完成
 

因為reactor基於epoll,所以每個reactor可以處理很多個連接請求。 如此,swoole就輕松的處理了高並發。

swoole如何實現異步I/O
swoole的worker進程有2種類型:一種是普通的worker進程,一種是task worker進程。
worker進程是用來處理普通的耗時不是太長的請求;task worker進程用來處理耗時較長的請求,比如數據庫的I/O操作。

我們以異步Mysql舉例:

 1 耗時較長的Mysql查詢進入worker
 2             |
 3 worker通過管道將這個請求交給taskworker來處理
 4             |
 5 worker再去處理其他請求
 6             |
 7 task worker處理完畢后,處理結果通過管道返回給worker
 8             |
 9 worker 將結果返回給reactor
10             |
11 reactor將結果返回給請求方

 

如此,通過worker、task worker結合的方式,我們就實現了異步I/O。

總結一下 swoole 的技術特點:

1 常駐內存,避免重復加載帶來的性能損耗,提升海量性能;
2 基於epoll,輕松支持高並發;
3 協程異步I/O,提高對I/O密集型場景並發處理能力;
4 支持多種通信協議,方便地開發 Http、WebSocket、TCP、UDP 等應用

3.swoole與php-fpm對比有哪些優缺點?

優點

1 常駐內存的 cli 運行模式,不用每次請求加載一次項目代碼
2 大大提高了對連接請求的並發能力
3 協程異步I/O,提高對I/O密集型場景並發處理能力
4 支持多種通信協議,能搭建 TCP/UDP/UnixSocket 服務器
5 原生支持毫秒定時器

缺點

1 相關文檔較少
2 不支持 xdebug,不支持手動 dump,不熟悉相關工具的話,不太方便調試
3 入門難度高,多數 phper 不了解 TCP/IP 網絡協議、多進程 / 多線程、異步 io 等

3.進程的基本知識

對於一個進程來說,它的核心內容分為兩個部分,一個是它的內存,這個內存是這進程創建之初從系統分配的,它所有創建的變量都會存儲在這一片內存環境當中

一個是它的上下文環境我們知道進程是運行在操作系統的,那么對於程序來說,它的運行依賴操作系統分配給它的資源,操作系統的一些狀態。

在這里插入圖片描述
Swoole的進程結構

Swoole的高效不僅僅於底層使用c編寫,他的進程結構模型也使其可以高效的處理業務,我們想要深入學習,並且在實際的場景當中使用必須了解,下面我們先看一下結構圖
在這里插入圖片描述
首先先介紹下swoole的這幾種進程分別是干什么的:

1)Master進程:主進程

第一層,Master進程,這個是swoole的主進程,這個進程是用於處理swoole的核心事件驅動的,那么在這個進程當中可以看到它擁有一個MainReactor[線程]以及若干個Reactor[線程],swoole所有對於事件的監聽都會在這些線程中實現,比如來自客戶端的連接,信號處理等。

在這里插入圖片描述
MainReactor(主線程)

1 主線程會負責監聽server socket,如果有新的連接accept,
2 主線程會評估每個Reactor線程的連接數量。
3 將此連接分配給連接數最少的reactor線程,做一個負載均衡。

 

Reactor線程組

1 Reactor線程負責維護客戶端機器的TCP連接、處理網絡IO、收發數據
2 完全是異步非阻塞的模式。
3 swoole的主線程在Accept新的連接后,會將這個連接分配給一個固定的Reactor線程,
4 在socket可讀時讀取數據,並進行協議解析,將請求投遞到Worker進程。在socket可寫時將數據發送給TCP客戶端。
 

心跳包檢測線程(HeartbeatCheck)

1 Swoole配置了心跳檢測之后,心跳包線程會在固定時間內對所有之前在線的連接
2 發送檢測數據包

 

UDP收包線程(UdpRecv)

1 接收並且處理客戶端udp數據包

2)Manger進程:管理進程

Swoole在運行中會創建一個單獨的管理進程,所有的worker進程和task進程都是從管理進程Fork出來的。管理進程會監視所有子進程的退出事件,當worker進程發生致命錯誤或者運行生命周期結束時,管理進程會回收此進程,並創建新的進程。換句話也就是說,對於worker、task進程的創建、回收等操作全權有“保姆”Manager進程進行管理。

再來一張圖梳理下Manager進程和Worker/Task進程的關系。
在這里插入圖片描述
3)Worker進程:工作進程

worker 進程屬於swoole的主邏輯進程,用戶處理客戶端的一系列請求,接受由Reactor線程投遞的請求數據包,並執行PHP回調函數處理數據生成響應數據並發給Reactor線程,由Reactor線程發送給TCP客戶端可以是異步非阻塞模式,也可以是同步阻塞模式。

4)Task進程:異步任務工作進程

taskWorker進程這一進程是swoole提供的異步工作進程,這些進程主要用於處理一些耗時較長的同步任務,在worker進程當中投遞過來。

進程查看及流程梳理
當啟動一個Swoole應用時,一共會創建2 + n + m個進程,2為一個Master進程和一個Manager進程,其中n為Worker進程數。m為TaskWorker進程數。

默認如果不設置,swoole底層會根據當前機器有多少CPU核數,啟動對應數量的Reactor線程和Worker進程。我機器為1核的。Worker為1。

所以現在默認我啟動了1個Master進程,1個Manager進程,和1個worker進程,TaskWorker沒有設置也就是為0,當前server會產生3個進程。

在啟動了server之后,在命令行執行ps -ajft|grep server.php查看當前產生的進程
在這里插入圖片描述
這三個進程中,所有進程的根進程,也就是例子中的21915進程,就是所謂的Master進程;而21917進程,則是Manager進程;最后的21919進程,是Worker進程。

swoole事件處理流程
在這里插入圖片描述
swoole使用的是reactor事件處理模式,一個請求經歷的步驟如下

1 服務器主線程等待客戶端連接。
2 Reactor線程處理接連socket,讀取socket上的請求數據(Receive),將請求封裝好后投遞給work進程。
3 Work進程就是邏輯單元,處理業務數據。
4 Work進程結果返回給Reactor線程。
5 Reactor線程將結果寫回socket(Send)。

 

轉載 http://wangzhenkai.com/article/16
參考 https://juejin.im/entry/6844903842404892680


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM