codecamp

swoole支持下的长链接和异步任务实现

遵守规则可以让你远离选择烦恼,无论是在坐车还是参加鸡尾酒会的时候。 --《选择的悖论》

写在前面的话

此PhalApi扩展类库只是初步开发完成,建议有swoole扩展经验或非保守派的同学使用,也欢迎你来丰富完善此扩展类库。

3.9.1 扩展类库:swoole支持下的长链接和异步任务实现

swoole官网请见: Swoole: PHP的异步、并行、分布式扩展

在这里,首先需要非常感谢swoole。

因为Swoole给我们提供了很多解决以往因PHP本身限制而产生的难题的灵感,但与此同时,也给我们带来了从没遇到过的挑战,特别是并发和长时间运行。

这需要我们更为小心地进行编码,因为以往可以忽略的小问题,在新的解决方案背景下都可能成为一个大问题。此扩展类库更多是作为一种尝试,并且可以作为扩展类库重要的一个转换点。因为在今后的日子里, PhalApi将会争取与其他开源项目一起,提供企业级的解决方案 

目前,此扩展类库提供了:

  • 长链接的接口调用
  • 异步计划任务的调用

3.9.2 安装

(1)安装swoole扩展类库 安装过程可以参考swoole官网,这里稍以linux系统简单说明一下编译安装。

unzip ./swoole-src-swoole-1.7.16-beta.zip
cd swoole-src-swoole-1.7.16-beta
phpize
./configure
make && make install

安装好后,添加swoole扩展:

extension=swoole.so

重启PHP后,如果看到有swoole扩展,则说明安装成功:

#php -m | grep swoole
swoole

(2)扩展包下载

从 PhalApi-Library 扩展库中下载获取 Swoole 包,如使用:

git clone https://git.oschina.net/dogstar/PhalApi-Library.git

然后把 Swoole 目录复制到 ./PhalApi/Library/ 下,即:

cp ./PhalApi-Library/Swoole/ ./PhalApi/Library/ -R

到此安装完毕!

温馨提示:
此扩展类库需要PhaApi 1.1.4及以上版本。

(3)配置

将以下配置追加到./Config/app.php:

    /**
     * Swoole扩展类库
     */
    'Swoole' => array(
        //服务
        'server' => array(
            'ip' => '127.0.0.1',
            'port' => 9501,
            'worker_num' => 1,
        ),
        //计划任务
        'task' => array(
            'ip' => '127.0.0.1',
            'port' => 9502,
            'worker_num' => 1,
        ),
    ),

3.9.3 入门使用

(1)长链接入口

在使用长链接入口对外提供接口服务后,由于不再是HTTP协议,所以入口建议放置在新的目录./Server,而不再是./Public。
入口文件的编写,如同我们以往一样,很简单:

//$ vim ./Server/run_server.php
<?php

require_once dirname(__FILE__) . '/../Public/init.php';

DI()->loader->addDirs(array('Library', 'Demo'));

$swooleLite = new Swoole_Lite();
$swooleLite->runServer();

启动、重启和关闭服务

启动可以用:

php ./Server/run_server.php

关闭可以用:

ps -ef | grep run_server | grep -v grep | awk '{print $2}'|xargs kill -9

(2)异步计划任务

异步计划任务是新型的做法,即:也通过接口服务调用的方式来完成计划任务的调度,其启动文件如同长链接入口一样简单:

//$ vim ./Server/run_task.php
<?php

require_once dirname(__FILE__) . '/../Public/init.php';

DI()->loader->addDirs(array('Library', 'Demo'));

$swooleLite = new Swoole_Lite();
$swooleLite->runTask();

启动、重启和关闭服务

启动可以用:

nohup php ./Server/run_task.php > ./Server/run_task.log 2>&1 &

(3)客户端调用

在扩展类库里有一个测试的脚本,可以用来进行PHP客户端的请求。

(1)默认接口调用

$ php ./check.php 127.0.0.1 9501 Default.Index username=swoole
Send: {"service":"Default.Index","username":"swoole"}
Received: {"ret":200,"data":{"title":"Hello World!","content":"Hi swoole, welcome to use PhalApi!","version":"1.1.3","time":1430620911},"msg":""}
Connection close

(2)带数据库的调用

$ php ./check.php 127.0.0.1 9501 User.getBaseInfo userId=1
Send: {"service":"User.getBaseInfo","userId":"1"}
Received: {"ret":200,"data":{"code":0,"msg":"","info":{"id":"1","username":"aevit","nickname":"test","password":"DE4CA99150F44B26F0D320DCA6E4B7629C43B6","salt":"wefewfew","reg_time":"0","avatar":"http:\/\/image.famillelab.com\/no_avatar.png","UUID":""}},"msg":""}
Connection close

(3)异步计划任务的调度

$ php ./check.php 127.0.0.1 9502 Default.Index username=swoole
Send: {"service":"Default.Index","username":"swoole"}
Connection close

假设Default.Index为一个计划任务的接口,但目前发现一个问题是,首次请求异步计划任务不会主动结束,而需要工作强制ctrl + c结束,再请求,则正常。

对应的log,可以看到:

2015-05-03 12:24:57|DEBUG|asynctask(0) dispath in swoole|{"service":"Default.Index","username":"swoole"}
2015-05-03 12:24:57|DEBUG|asynctask(0) start in swoole|{"service":"Default.Index","username":"swoole"}
2015-05-03 12:24:57|DEBUG|asynctask(0) finish in swoole|{"ret":200,"data":{"title":"Hello World!","content":"Hi swoole, welcome to use PhalApi!","version":"1.1.3","time":1430627097},"msg":""}
2015-05-03 12:24:57|DEBUG|asynctask(1) dispath in swoole|{"service":"Default.Index","username":"swoole"}
2015-05-03 12:24:57|DEBUG|asynctask(1) start in swoole|{"service":"Default.Index","username":"swoole"}
2015-05-03 12:24:57|DEBUG|asynctask(1) finish in swoole|{"ret":200,"data":{"title":"Hello World!","content":"Hi swoole, welcome to use PhalApi!","version":"1.1.3","time":1430627097},"msg":""}
...

3.9.4 对客户端调整

(1)调用方式的改变

改用长链接。

(2)POST参数传递方式的改变

统一使用json发送数据包。

3.9.5 对服务端的影响

(1)DI资源服务的调整

变量名称是否全局通用是否每次请求新建可否使用备注
loader可使用
config可使用
logger可使用
notorm可使用每次响应后,关闭此次全部数据库链接
cache可使用需要查看使用的链接是否支持长链接
filter可使用
crypt可使用
curl可使用
request可使用
response可使用
cookie------不可使用长链接下不应进行COOKIE的操作

(2)关于swoole扩展类库的自问自答

  • 1、数据库使用长链接吗? -- 不使用,每次响应后手动关闭数据链接
  • 2、内存问题?-- 通过类成员方法的作用域控制内存
  • 3、并发的问题?-- TODO
  • 4、代码更新后如何同步?需要重启服务器吗? -- 需要重启
  • 5、PhalApi_Response::formatResult()的访问权限,是框架的调整,还是个别自我提高? -- 扩展自我提高
  • 6、注册错误回调函数? -- 来自swoole的建议,已注册
  • 7、启动和关闭、重启脚本文件? -- 提供参考命令
  • 8、一直运行? -- TODO

    (3)特别注意!

    由于服务在启动后,已经完成了大部分的类加载、配置读取以及PHP文件的解析,所以在对项目代码(包括配置)修改后,需要重启服务,方能生效。

用户、会话和第三方登录集成
Auth 权限扩展 (由@黄苗笋提供)
温馨提示
下载编程狮App,免费阅读超1000+编程语言教程
取消
确定
目录

八、视频教程

关闭

MIP.setData({ 'pageTheme' : getCookie('pageTheme') || {'day':true, 'night':false}, 'pageFontSize' : getCookie('pageFontSize') || 20 }); MIP.watch('pageTheme', function(newValue){ setCookie('pageTheme', JSON.stringify(newValue)) }); MIP.watch('pageFontSize', function(newValue){ setCookie('pageFontSize', newValue) }); function setCookie(name, value){ var days = 1; var exp = new Date(); exp.setTime(exp.getTime() + days*24*60*60*1000); document.cookie = name + '=' + value + ';expires=' + exp.toUTCString(); } function getCookie(name){ var reg = new RegExp('(^| )' + name + '=([^;]*)(;|$)'); return document.cookie.match(reg) ? JSON.parse(document.cookie.match(reg)[2]) : null; }