-
背景介紹
公司內部基礎服務,基本上每一個業務,每一個頁面都會調用的接口。隨着業務的增長,在rpc服務提供以前,http接口天天的調用量有1億次。原先有4臺阿里雲服務器(8C+32G),3臺nginx+1臺crontab,後來增長到5臺nginx。業務高峯時負載較高,時常超過運維規定的報警峯值。
http接口:php 5.6.7 + yaf 2.3.5 + redis + MySQLphp
以其中標籤業務爲例: |
- |
最短響應(ms) |
<10ms |
<50ms |
讀 |
2.5 |
99.9% |
0.1% |
寫 |
7.5 |
73% |
27% |
- RPC接口
php 7.1.9 + swoole 2.0.8 + zookeeper + redis + MySQL等
基於Swoole,實現dubbo的主要功能:服務註冊+服務發現+監控+服務提供+服務消費,大體結構以下:
數據流:
-
效果mysql
服務器 |
配置 |
數量 |
http |
8C+32G |
5 |
rpc |
8C+32G |
2 |
注:redis與mysql資源都是同樣的。nginx
使用rpc接口後數據與效果對比: |
- |
數據量 |
最短響應(ms) |
<1ms |
<10ms |
<50ms |
http讀 |
n |
2.5 |
0% |
99.9% |
0.1% |
http寫 |
m |
4.0 |
0% |
74% |
26% |
rpc讀 |
40n |
0.3 |
98% |
1.9% |
0.1% |
rpc寫 |
m |
0.9 |
28% |
62.5% |
9.5% |
rpc讀接口詳細詳細時間分佈
git
服務器負載均降到1之內,業務高峯期不超過2redis
線上運行狀況:
sql
- 踩過的坑
4.1. 請求丟失(萬分之幾,週期性)
這個在開發初期,模擬線上業務長期壓測的過程當中出現。老是有周期性的丟包。聯繫過swoole做者,想讓韓大幫忙看看解決,後來本身解決了。由於在worker進程中加了SwooleTimer::tick(),想作心跳,檢查worker狀態+維護tcp鏈接,去掉了就沒有丟過包。
4.2. 心跳如何保持
worker進程里加心跳貌似會影響swoole的運行機制,經過對單起註冊進程,按期對worker發送消息,worker收到消息後檢查維護。
4.3. 變量如何傳遞($_SERVER,調用鏈追溯)
專門設置一個環境變量的參數,傳遞到下一級請求。
4.4. 鏈接數增長(worker_num*數據庫數量)
這是個大問題。咱們的php-fpm調用mysql採用的短鏈接,每次請求完了會釋放。rpc使用的是swoole常駐進程,鏈接mysql使用的是長鏈接,鏈接數=worker_num*數據庫數量,結果mysql服務器的鏈接數暴增,後經過mycat解決。
4.5. 狀態監控(worker_num, active_worker_num)
經過對單起註冊進程,按期對worker發送消息維護。
- 對比與探索
如今比較流行的PHP運行模式是LNMP, 其中PHP以PHP-FPM模式運行。PHP-FPM是多進程模式,master進程管理worker進程,worker進行實際運行代碼處理請求。
5.1. PHP-FPM模式的幾個問題:
5.1.1. 沒有鏈接池:PHP-FPM模式下,註定一個請求的生命週期只有1次。也就是說,從FPM請求到請求,解析PHP腳本,FPM的Zend虛擬機分配資源執行,到最後的處理結束,PHP-FPM會回收此次請求的全部資源。因此高併發業務下,網絡的處理會有劣勢。
5.1.2. 對單個進程沒有多線程的程序來講,若是頻繁的有http接口的請求,服務容易被block。
5.2. 基於swoole的RPC方案,能夠有效避免FPM模式的兩個缺陷。
5.2.1. 維護鏈接池: worker常駐進程,能夠保持對資源鏈接的鏈接池,並經過按期心跳維護鏈接保持。
5.2.2. 進程內使用協程,對每一個資源的鏈接保存在SwooleChannel(高性能內存隊列)內,沒必要考慮對資源的過多鏈接,協程處理請求又不相互影響。不一樣的資源鏈接在不一樣的資源池,不會相互影響,其中一個請求到IO時,底層會將IO事件註冊到EventLoop,並讓出執行權。接口請求並不會在進程裏佔用timeout時間。
5.2.3. 常駐進程,配置文件及程序初始化加載都可以在初始化階段(onWorkerStart)完成,省去了請求開始的腳本初始化及請求結束的資源釋放,能更快的響應請求。
5.3. swoole協程解決的問題:
5.3.1. 若是碰見FPM模式下接口A響應時間超時,不影響下一個請求的處理,不影響worker的處理能力;
5.3.2. 資源類的IO都是經過協程出讓worker的主動權,能提升總體的QPS能力;
- 總結
基於swoole的tcp/rpc接口對短平快的接口有更好的表現。http接口調用php-fpm初始化消耗一些時間,使用swoole常駐進程能夠節省。http接口請求頻繁打開關閉的鏈接,對服務器形成壓力,也能夠經過swoole常駐進程解決。
- TODO
7.1 swoole協程對資源調用的IO操做有更好的處理,下一步在項目中驗證。
7.2 使用協程搶佔式調度器,解決單次請求響應時間過長/超時問題。
(剛看了一眼git tag記錄,第一次上線時間是2018年5月22日,至今上線已有一年有餘,至今穩定運行。 )數據庫
最後,歡迎路過的各路大神指點指正,互相交流。服務器