swoole之代码热更新实现 转自https://blog.csdn.net/nep_tune/article/details/81329918
随着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()的时候:
第一步: 向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方法里。
示例:
function onWorkerStart($serv,$worker_id) {
include"hot_update_class.php";
$class=newHotUpdate();
}
function onWorkerStop($serv, $worker_id) {
opcache_reset(); //zend_opcache的opcache清理函数
}
这时如果我们修改了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
swoole之代码热更新实现 转自https://blog.csdn.net/nep_tune/article/details/81329918的更多相关文章
- 码云私人代码 SSH 设置----https://blog.csdn.net/kkaazz/article/details/78667573
码云私人代码 SSH 设置 https://blog.csdn.net/kkaazz/article/details/78667573
- 基于eclipse的mybatis映射代码自动生成的插件http://blog.csdn.net/fu9958/article/details/7521681
基于eclipse的mybatis映射代码自动生成的插件 分类: JAVA 数据库 工具相关2012-04-29 00:15 2157人阅读 评论(9) 收藏 举报 eclipsegeneratori ...
- <转载> 22种代码味道(Martin Fowler与Kent Beck) http://blog.csdn.net/lovelion/article/details/9301691
Martin Fowler在Refactoring: Improving the Design of Existing Code(中译名:<重构——改善既有代码的设计>)一书中与Kent ...
- Cordova 代码热更新 - 简书
原文:Cordova 代码热更新 - 简书 Cordova 代码热更新 [图片上传失败...(image-a19be7-1521624289049)] 基于 Cordova 框架能将网页应用 (js, ...
- Unity3D热更新之LuaFramework篇[09]--资源热更新与代码热更新的具体实现
前言 在上一篇文章 Unity3D热更新之LuaFramework篇[08]--热更新原理及热更服务器搭建 中,我介绍了热更新的基本原理,并且着手搭建一台服务器. 本篇就做一个实战练习,真正的来实现热 ...
- Unity代码热更新方案 JSBinding + SharpKit 首页
目前Unity的代码更新方案有很多,主要以lua为主. JSBinding + SharpKit 是一种新的技术,他做了两件事情: JSBinding将C#导出到 JavaScript (引擎是 Mo ...
- nodeJs 代码热更新
在开发node过程中,每次修改代码都需要重新启动服务,是一件很抓狂的事情 使用nodemon热加载可以帮我们很好的解决这一问题 1. 安装 npm install nodemon -g 2. 修改np ...
- idea内置tomcat中java代码热更新
按照上图设置后,然后修改代码后按shift+F9快捷键,即可实现代码更新,这时在debug模式下会看到代码变更后的输出
- node.js之nodemon 代码热更新 修改代码后服务器自动重启
1.安装nodemon: npm install -g nodemon //全局安装 npm install nodemon --save //局部安装 2.在项目根目录下创建 nodemon.jso ...
随机推荐
- npm run dev 报错 run `npm audit fix` to fix them, or `npm audit` for details
前几天写的直接运行npm run dev还是ok的,突然不行了,前面报错是css-loader没有,删除style标签上的lang='scss'就好了,先不需要这个依赖.这个先不管. 只是后面的 ru ...
- 使用EFCore,手动创建SQLLite数据库
有时候我们需要在代码中动态生成一个sqllite数据库文件,可以按照以下代码完成, static void Main(string[] args) { MyContext context = new ...
- n个骰子的点数之和
题目:把n个骰子扔在地上,所有骰子朝上一面的点数之和为S.输入n,打印出S的所有可能的值出现的概率. 解题思路:动态规划 第一步,确定问题解的表达式.可将f(n, s) 表示n个骰子点数的和为s的排列 ...
- UML 类图口诀
UML类图口诀: (10G:实线继承)空三角实线指向被继承, (虚实:虚线实现)空三角虚线指向被实现, (恐惧:空棱形聚合)空棱形实线(棱形)指向聚合整体.部分作为成员变量. (十足:实棱形组合)实棱 ...
- Python 进程池的回调函数
import os from multiprocessing import Pool,Process def f1(n): print('进程池里面的进程id',os.getpid()) print( ...
- iframe嵌套vue页面打开新窗口
iframe嵌套vue页面时目录结构为下图: 此时出口文件指向index.html, 所以只需要用a标签动态拼接href, 并设置属性 target="_blank" ,即可在if ...
- 【Spring】文件上传
一:引入所需jar包 // https://mvnrepository.com/artifact/commons-fileupload/commons-fileuploadcompile group: ...
- silverlight中 设置 头像(添加图片)
参考文章: http://www.cnblogs.com/wsdj-ITtech/archive/2009/08/26/1554056.html 1. ChainManager.xaml 前台 < ...
- 在虚拟机上利用宿主机共享目录编译linux程序
#前提条件: 宿主机:windows7 虚拟机:REDHAT 开发环境 qt4.7.4 +vs2010 . 代码在windows7 上编译成功 ,运行正常 在linux下编译需要的第三方库已经编译成功 ...
- 把一个给定的值存储到一个整数中指定的几个位《C与指针5.8.5》
编写一个函数,把一个给定的值存储到一个整数中指定的几个位.它的原型如下: int store_bit_field(int original_value, int value_to_store, uns ...