平滑重啟原理
什么是平滑重啟?
平滑重啟不同于普通的重啟,平滑重啟可以做到在不影響用戶的情況下重啟服務(wù)(一般指短鏈接業(yè)務(wù)),以便重新載入PHP程序,完成業(yè)務(wù)代碼更新。
平滑重啟一般應(yīng)用于業(yè)務(wù)更新或者版本發(fā)布過程中,能夠避免因?yàn)榇a發(fā)布重啟服務(wù)導(dǎo)致的暫時性服務(wù)不可用的影響。
注意
Windows系統(tǒng)不支持reload。注意
長連接(例如websocket)業(yè)務(wù),進(jìn)程平滑重啟時連接會被斷開。解決方案是使用類似gatewayWorker的架構(gòu),一組進(jìn)程專門維持連接,并將這組進(jìn)程的reloadable屬性設(shè)置為false。業(yè)務(wù)邏輯啟動另外一組worker進(jìn)程處理,gateway與worker進(jìn)程通過tcp通訊的方式互相調(diào)用。當(dāng)業(yè)務(wù)需要變更時,只重啟worker進(jìn)程即可。
限制
注意:只有在on{...}回調(diào)中載入的文件平滑重啟后才會自動更新,啟動腳本中直接載入的文件或者寫死的代碼運(yùn)行reload不會自動更新。
以下代碼reload后不會更新
$worker = new Worker('http://0.0.0.0:1234');
$worker->onMessage = function($connection, $request) {
$connection->send('hi'); // 寫死的代碼不支持熱更新
};
$worker = new Worker('http://0.0.0.0:1234');
require_once __DIR__ . '/your/path/MessageHandler.php'; // 啟動腳本直接載入的文件不支持熱更新
$messageHandler = new MessageHandler();
$worker->onMessage = [$messageHandler, 'onMessage']; // 假設(shè)MessageHandler類里有一個onMessage方法
以下代碼reload后會自動更新
$worker = new Worker('http://0.0.0.0:1234');
$worker->onWorkerStart = function($worker) { // onWorkerStart是進(jìn)程啟動后觸發(fā)的回調(diào)
require_once __DIR__ . '/your/path/MessageHandler.php'; // 進(jìn)程啟動后載入的文件支持熱更新
$messageHandler = new MessageHandler();
$worker->onMessage = [$messageHandler, 'onMessage'];
};
MessageHandler.php改動后執(zhí)行 php start.php reload
,MessageHandler.php會重新載入內(nèi)存達(dá)到更新業(yè)務(wù)邏輯的效果。
提示
上面代碼為了方便演示,使用了require_once
語句,如果你的項(xiàng)目支持psr4自動加載,則無需調(diào)用require_once
語句。
平滑重啟原理
Workerman分為主進(jìn)程和子進(jìn)程,主進(jìn)程負(fù)責(zé)監(jiān)控子進(jìn)程,子進(jìn)程負(fù)責(zé)接收客戶端的連接和連接上發(fā)來的請求數(shù)據(jù),做相應(yīng)的處理并返回數(shù)據(jù)給客戶端。當(dāng)業(yè)務(wù)代碼更新時,其實(shí)我們只要更新子進(jìn)程,便可以達(dá)到更新代碼的目的。
當(dāng)Workerman主進(jìn)程收到平滑重啟信號時,主進(jìn)程會向其中一個子進(jìn)程發(fā)送安全退出(讓對應(yīng)進(jìn)程處理完畢當(dāng)前請求后才退出)信號,當(dāng)這個進(jìn)程退出后,主進(jìn)程會重新創(chuàng)建一個新的子進(jìn)程(這個子進(jìn)程載入了新的PHP代碼),然后主進(jìn)程再次向另外一個舊的進(jìn)程發(fā)送停止命令,這樣一個進(jìn)程一個進(jìn)程的重啟,直到所有舊的進(jìn)程全部被置換為止。
我們看到平滑重啟實(shí)際上是讓舊的業(yè)務(wù)進(jìn)程逐個退出然后并逐個創(chuàng)建新的進(jìn)程做到的。為了在平滑重啟時不影響客用戶,這就要求進(jìn)程中不要保存用戶相關(guān)的狀態(tài)信息,即業(yè)務(wù)進(jìn)程最好是無狀態(tài)的,避免由于進(jìn)程退出導(dǎo)致信息丟失。