swoole之代碼熱更新實現

本人蔘與的swoole項目有幸被不少朋友使用,我也大力向周邊的一些朋友推薦,隨着swoole的版本迭代更新,已經足夠穩定了,在阿里,騰訊,yy等各大公司都有着使用,也有不少遊戲圈裏的朋友也在使用,這些朋友常常會提到一個問題,每次代碼更新還須要中止服務,而後從新啓動,來達到更新代碼,然而這種作法,是比較粗暴的。其實swoole裏提供reload的特性,徹底支持代碼的熱更新。

在介紹swoole的reload以前,先簡要的講講web方式是如何改了文件就當即生效的:

  幾個概念: 
  1) sapi:能夠簡單的理解爲php引擎對外的一個統一接口,使得php能夠和外部程序進行交互
  2) php的生命週期中關鍵四個調用:MINT -> RINT -> RSHUTDOWN -> MSHUTDOWN

  3)  fpm : fastcgi進程管理器

  那麼fpm方式的流程就是: fpm經過sapi接口與php進程交互,
  在fpm啓動的時候,
第一步: 會調用各擴展的MINT方法,進行一些數據初始化(長駐內存),
第二步: 每一個請求過來,先會執行RINT對單個請求行一個初始化,
第三步: 執行php腳本,
第四步: 執行RSHUTDOWN方法,
第五步: 若是你要中止fpm了,纔會執行MSHUTDOWN。

  fpm對每一個請求的處理都是一直在在重複執行 2~4步 。

 在第三步中, php的腳本是動態執行的,因爲每次都要執行一次php腳本,而每次php腳本都要有一個把php文件翻譯成opcode的流程(比較耗時), 因而就產生的opcache工具。

 opcache:  直接把php翻譯後的opcode代碼樹保存到共享內存中,以便直接使用,從而減小每次都把php翻譯成opcode的開銷。

opcache的問題:按照他的描述,修改了php文件,並不能當即被更新,

opcache的解決方案:有一個配置來設置隔多長時間檢測文件是否更新了,從而有機會在第二步從新來reload相關的文件.

  固然,你也能夠直接reload fpm,從而達到php熱更新的效果(opcache擴展能夠在第四步把相關的opcode cache給清空)。

  
  swoole的問題:

swoole是以cli運行的,而後長駐內存的。整個生命週期只有在啓動的時間能夠一次執行RINT過程, 以後全部的請求都在第三步之內完成。(這也是swoole更快的緣由之一),這樣的話,相關的php腳本若是被執行了一次,就永久性的長駐內存了,更新代碼就沒有效果了。

  swoole的解決方案:內置方法 $serv->reload()

前提:swoole是一個三層架構: master->manager->worker, master和manager是啓動以後,就長駐內存的,因此這裏reload的是worker進程,(而咱們的業務邏輯正好都在worker進程)。

簡單原理: 調用$server->reload()的時候:php

  第一步: 向manager進程發送USR1信號,
  第二步: manager捕獲到USR1信號,會向worker進程發送 TERM信號。
  第三步:worker進程捕獲這個TERM信號,作把一個running的標識設置0
  第四步:woker的事件循環發現running標識爲0,處理完當前邏輯就會自殺(自殺前會回調onWorkerStop函數),
  第五步:manager再拉起一個新的worker (拉起後會回調onWorkerStart函數)

 從這個流程中咱們會發現,onWorkerStart 和 onWorkerStop很是像 sapi裏的 RINT, RSHUTDOWN.

  因此到了這裏,實現代碼熱更新的的方案就是:

  把業務邏輯的腳本文件的載入放到onWorkerStart方法裏,若是用了opcache,那麼把一些opcache的清理邏輯放到onWorkerStop方法裏。

示例:git

 function onWorkerStart($serv,$worker_id) {github

     include"hot_update_class.php";web

     $class=newHotUpdate();  api

 }swoole

 

 function onWorkerStop($serv, $worker_id) {架構

      opcache_reset(); //zend_opcache的opcache清理函數框架

 }curl


這時若是咱們修改了hot_update_class.php裏的相關文件,再執行$serv->reload(),就能夠實現熱更新了。

ps: 因此,咱們能夠把onWorkerStart當成個人業務邏輯的入口。


   若是你使用了autoloader, 那麼你把autoloader的註冊放到onWorkerStart裏來。
   若是你使用了框架,那麼你能夠把框架的入口文件放到onWorkerStart裏來。異步



若是你開啓了opcache,那麼,你能夠在onWorkerStop的時候,執行相關的opcache清理工做。
(zend_opcache,直接調用opcache_reset()方法便可)

示例:

 function onWorkerStop($serv,$worker_id) {

     opcache_reset(); //zend_opcache的      

     //apc, xcache, eacc等其餘方式,請調用相關函數  

 }

 

最後但願這篇博客能給你帶來一些幫助。(注:若是你的worker裏掛了異步事件,好比把某個curl掛到swoole_event_add裏,那麼worker的reload會把這些都清理掉,可能致使一些邏輯錯誤,解決方案正在醞釀中)

swoole官方交流羣:321637118

相關文章
相關標籤/搜索