nginx 接收客戶端連線
——> 接收資料,判斷是否構成完整 http 訊息
—是—> 判斷是否轉交 php-fpm 處理
—是—> 有選擇地(請求行和部分訊息頭是專門給 nginx 看的,可能會剔除)將 http 訊息傳送給 php-fpm ——> php-fpm 主程式建立子程式
——> 子程式將 http 訊息更新超全域性陣列(也可能是主程式做),引入 php 入口檔案,返回 http 響應給主程式
——> php-fpm 主程式將 http 響應訊息返回給 nginx
——> nginx 將 http 響應訊息返給客戶端,並決定是否關閉連線(在響應頭 Connection 欄位通知客戶端)
nginx + php-fpm 的處理流程和 workerman 有什麼重大的區別?
- php-fpm 建立子程式處理請求,一個子程式處理一個請求,處理完關閉子程式。
workerman/hyperf/其它php伺服器,建立子程式,但是子程式是獨立的伺服器,子程式接收客戶端連線、資料、解出完整請求訊息,轉化為 request 物件,經過應用程式得到 response 物件,再轉成響應訊息,最後傳送給客戶端。 - php 伺服器沒有 php-fpm 的來一個請求建立關閉一次子程式的消耗。它的主程式只用來監聽子程式伺服器的執行與維護,發現子程式關閉後重新建立新的子程式。它的子程式,就做了 nginx + php-fpm 的事,同時沒有頻繁的更下級的子程式的建立關閉消耗。
- nginx 轉發客戶端請求給 php-fpm 主程式;php-fpm 建立子程式處理請求;子程式引入 php 入口檔案,透過業務邏輯將請求轉成響應,返給主程式並關閉自身;php-fpm 主程式將子程式處理的響應返給 nginx;nginx 響應客戶端。
- workerman 主程式建立N(可配置)個各類(tcp/http/udp/unix/https/websocket…)子程式(相當於伺服器);其中,http 子程式完成類似 nginx + php-fpm 功能
workerman 在效能上比 nginx+php-fpm 的優勢
- 不需要像 nginx 和 php-fpm 那樣本地埠通訊
- 不需要像 php-fpm 那樣建立子程式專門處理
- 資料常駐記憶體,資料單例化高,效能越來越快,不需要單獨重複性引入所謂入口檔案及對應整套邏輯,http 子程式監聽某個埠(比如 80),接收客戶端連線、資料,處理後返回資料給客戶端
那它是怎麼通訊的呢
nginx 配置裡9000 埠是 php-fpm 程式預設埠,nginx 應該和 php-fpm 保持了長連線;如果沒有,那每次請求連一次,太愚蠢了,nginx 監聽了 80 埠,它內部有連線 9000 埠的套接字(對 php-fpm 來說,nginx 是客戶端)
nginx 的主套接字監聽 80 埠,有客戶端完整請求時,它透過連線 9000 埠的套接字轉發資料給 php-fpm
主套接字監聽埠,是等別人來找你(服務端);連線其它軟體的埠的套接字,是找別人(客戶端)兩個套接字,套接字也是檔案資源控制程式碼,一個守著 80 埠等使用者發請求過來,一個把請求轉發給 php-fpm 監聽的 9000 埠
本機程式間通訊,也叫 ip 換回連線,本機程式通訊還有 unix ,就是監聽 .sock 檔案,資料傳輸在監聽檔案上表現,tcp 環回連線 效能不如 unix 連線
關於協議
-udp 和 tcp 都是基於 ip 協議,但是 udp 沒有 tcp 三次握手(建立連線);
udp 因為沒有連線,資料傳送接收速度快;但是也因為沒有連線,所以資料不知道從什麼時候開始算,只能將一次資料當作一個完整訊息,如果缺損,這次資料就報廢了,所以不安全
tcp 因為有連線,如果資料包解析錯誤,客戶端接收到相應提示,可以重新傳送,服務端可以丟棄廢資料重新接收解析,所以更安全
https 協議 基於 http 協議基於 tcp 協議 基於 ip 協議
websocket 協議(有一個額外握手,基於 http 協議格式)基於 tcp 協議
tcp的拆包粘包
拆包(接收到不完整包資料)
- 傳送的資料大於套接字緩衝區剩餘大小
- 傳送的資料大於MTU(最大傳輸單元)大小
粘包(接收到多個包資料)
- 傳送端:Nagle 演算法判斷前包資料過小,等待小段時間,同後包一起傳送
- 接收端:前包快取未讀完,後包又到,不能區分前後包
本質問題:接收端無法區分包界限
解決方案:
- 訊息資料定長,不足補空格;缺點是浪費記憶體和頻寬
- 訊息資料採用特定分隔符區分界限
- 訊息資料分頭和體,頭部帶訊息長度,接收方根據頭中長度解析資料
本作品採用《CC 協議》,轉載必須註明作者和本文連結