swoole之代码热更新实现

From: http://www.th7.cn/Program/php/201405/211057.shtml

持续的思考:

 本人参与的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进程。
简单原理: 调用$server->reload()的时候:

  第一步: 向manager进程发送USR1信号,
  第二步: manager捕获到USR1信号,会向worker进程发送 TERM信号。
  第三步:worker进程捕获这个TERM信息,做把一个running的标识设置0
  第四步:woker的事件循环发现running标识为0,处理完当前逻辑就会自杀(自杀前会回调onWorkerStop函数),
  第五步:manager再拉起一个新的worker (拉起后会回调onWorkerStart函数)
 我们会发现,onWorkerStart 和 onWorkerStop非常像 sapi里的 RINT, RSHUTDOWN.
  所以到了这里,reload的方案就呼之欲出了:
  我们把业务逻辑的脚本代码载入放到onWorkerStart里来。就行了。
示例:

 function onWorkerStart($serv,$worker_id) {

     include"hot_update_class.php";

     $class=newHotUpdate();  

 }


如果修改了hot_update_class.php里的相关文件,再执行$serv->reload(),就可以实现热更新了。
如果你使用了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


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Swoole直播的实现代码比较复杂,这里提供一个简单的示例代码,仅供参考: ```php // 创建swoole服务器 $server = new Swoole\WebSocket\Server("0.0.0.0", 9501); // 监听WebSocket连接事件 $server->on('open', function (Swoole\WebSocket\Server $server, $request) { echo "WebSocket连接成功\n"; }); // 监听WebSocket消息事件 $server->on('message', function (Swoole\WebSocket\Server $server, $frame) { // 接收客户端发送的消息 $data = json_decode($frame->data, true); $type = isset($data['type']) ? $data['type'] : ''; $content = isset($data['content']) ? $data['content'] : ''; switch ($type) { case 'login': // 用户登录信息处理 break; case 'message': // 消息处理 break; case 'heartbeat': // 心跳处理 break; default: // 其他处理 break; } }); // 监听WebSocket关闭事件 $server->on('close', function (Swoole\WebSocket\Server $server, $fd) { echo "WebSocket关闭连接\n"; }); // 启动swoole服务器 $server->start(); ``` 上述代码中,我们创建了一个WebSocket服务器,并监听了三个事件:连接事件、消息事件和关闭事件。当有客户端连接到服务器时,会触发`open`事件;当有客户端发送消息时,会触发`message`事件;当有客户端关闭连接时,会触发`close`事件。 在消息事件中,我们可以根据客户端发送的消息类型进行不同的处理。例如,当客户端发送登录消息时,我们可以将用户信息保存到服务器中,以便后续使用;当客户端发送聊天消息时,我们可以将消息广播给所有在线用户。 需要注意的是,在实际的直播应用中,还需要考虑到视频流的推拉流、音视频混流等问题,这些问题需要使用专门的直播技术来解决。本示例代码仅提供了WebSocket服务器的基本实现,实际应用中还需要根据具体需求进行更加详细的开发。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值