Coder Social home page Coder Social logo

pinguo / php-msf Goto Github PK

View Code? Open in Web Editor NEW
1.8K 142.0 318.0 3.37 MB

PHP微服务框架即Micro Service Framework For PHP

License: GNU General Public License v2.0

PHP 99.93% HTML 0.07%
php php-msf swoole mvc php-framework swoole-framework microservice microservice-framework

php-msf's Introduction

Micro Service Framework For PHP

PHP微服务框架即“Micro Service Framework For PHP”,是Camera360社区服务器端团队基于Swoole自主研发现代化的PHP协程服务框架,简称msf或者php-msf,是Swoole的工程级企业应用框架,经受了Camera360亿级用户高并发大流量的考验。php-msf由Camera360服务器团队主导研发,会持续更新与维护,也希望有更多优秀的Swoole应用实践开发者加入。php-msf核心设计**是采用协程、异步、并行的创新技术手段提高系统的单机吞吐能力,降低整体服务器成本。

主要特性

  • 精简版的MVC框架
  • IO密集性业务的单机处理能力提升5-10倍
  • 代码常驻内存
  • 支持对象池
  • 支持Redis连接池、MySQL连接池(异步与同步)
  • 内置Redis Proxy,支持分布式、master-slave集群(故障自动failover与recovery)
  • 内置MySQL Proxy,master-slave集群(读写分离、事务)
  • 支持异步、并行
  • 基于PHP Yield实现协程
  • 内建http/redis/mysql/mongodb/task等协程客户端
  • 纯异步的Http Server
  • RPC Server/Client
  • 支持命令行模式
  • 支持独立进程的定时器
  • 支持独立配置进程
  • 支持sendfile静态文件(需配置root目录)

环境要求

  • Linux,FreeBSD,MacOS(有兼容问题)
  • Linux内核版本2.3.32以上(支持epoll)
  • PHP-7.0及以上版本(生产环境建议使用PHP-7.1)
  • gcc-4.4以上版本
  • swoole-1.9.15及以上版本(暂不支持Swoole-2.0)
  • hiredis-0.13.3
  • yac
  • phpredis
  • composer

文档

框架手册(Gitbook): PHP-MSF开发手册

API Document(Rawgit): 类文档

示例DEMO项目: PHP-MSF DEMO

帮助完善文档: https://github.com/pinguo/php-msf-docs,请提交PR。

交流与反馈

PHP-MSF#1群(QQ): 614054288

快速起步

$>php -r "copy('https://raw.githubusercontent.com/pinguo/php-msf-docker/master/installer.php', 'installer.php');include('installer.php');" && source ~/.bashrc

installer.php会检查运行环境,根据你的自定义配置,自动创建项目模板,composer安装依赖,启动服务。如果cdn.rawgit.com无法访问,可以直接克隆或者下载php-msf-docker,提取installer.php,然后直接运行php installer.php

如果一切顺利,运行到最后你将看到如下的输出:

[2017-09-06 16:08:34] Run composer install success
[2017-09-06 16:08:34] Congratulations, all are installed successfully!
[2017-09-06 16:08:34] You can, visit http://127.0.0.1:8990/Welcome for test
      _______                               ____
________  / /_  ____        ____ ___  _____/ __/
___/ __ \/ __ \/ __ \______/ __ `__ \/ ___/ /_
__/ /_/ / / / / /_/ /_____/ / / / / (__  ) __/
_/ .___/_/ /_/ .___/     /_/ /_/ /_/____/_/
/_/         /_/         Camera360 Open Source TM
[2017-09-06 16:08:34] Swoole  Version: 1.9.18
[2017-09-06 16:08:34] PHP     Version: 7.1.8
[2017-09-06 16:08:34] Application ENV: docker
[2017-09-06 16:08:34] Listen     Addr: 0.0.0.0
[2017-09-06 16:08:34] Listen     Port: 8990

访问测试:

$>curl http://127.0.0.1:8990/Welcome
hello world!

注意端口,如果你不是8990,你需要修改,然后访问测试。

标准应用结构

├── app // PHP业务代码
│   ├── AppServer.php // 应用server类,可根据需求自定义
│   ├── Controllers // 控制器类目录
│   ├── Lib // 特殊逻辑处理类目录
│   ├── Models // Model类目录
│   ├── Route // 特殊路由规则类目录
│   ├── Tasks // Task类目录
│   └── Views // 视图文件目录
├── build.sh // 构建脚本(拉取docker镜像,启动容器)
├── checkstyle.sh // 代码检查脚本
├── composer.json // composer包依赖配置文件
├── config // 配置目录
├── server.php // server启动脚本
├── console.php // 命令行脚本
├── test // 单元测试目录

上述为基于php-msf的标准应用结构,一键安装程序installer.php会自动生成目录,用户可以根据需求创建一些自定义目录,只要符合psr4标准即可自动加载。

服务启动

调试模式

$>./server.php start

Daemon模式

$>./server.php start -d

停止服务

$>./server.php stop

重启服务

$>./server.php restart

Docker

我们制作了Docker镜像,方便Docker用户快速的安装环境,运行PHP-MSF DEMO工程。另外期望在开发环境修改代码实时预览效果,建议使用Docker for Mac/Windows桌面版。

如果是升级Docker,它会自动迁移原有的镜像和容器,请耐心等待,千万不能中途kill掉Docker进程,否则再想迁移就难了。

Docker Registry(阿里云):

  • 公网地址: docker pull registry.cn-hangzhou.aliyuncs.com/pinguo-ops/php-msf-docker:latest
  • 经典内网: docker pull registry-internal.cn-hangzhou.aliyuncs.com/pinguo-ops/php-msf-docker:latest
  • VPC网络: docker pull registry-vpc.cn-hangzhou.aliyuncs.com/pinguo-ops/php-msf-docker:latest
  • DockerHub(国外): docker pull pinguoops/php-msf-docker

框架定位

我们专注打造稳定高性能纯异步基于HTTP的微服务框架,作为nginx+php-fpm的替代技术栈实现架构的微服务化;而Tcp/WebSocket Server将作为插件的形势支持,或者作为其他独立的开源项目。

对于小型团队或者业务系统我们建议还是采用传统的nginx+php-fpm技术栈,对于成本和性能来说没有瓶颈,也就完全没有必要引入全新的技术栈。

对于大中型团队或者业务系统,处在服务治理或者服务化演进的重要阶段,php-msf是可选方案之一。

对于庞大的PHP应用集群,想要大幅节约服务器成本,提升服务性能,php-msf是可选方案之一。

对于聚合服务,比如大型的网站首页,想要通过服务器端聚合内容整合数据,php-msf是可选方案之一。

手工安装

推荐安装方式,通过编辑项目composer.json加入依赖pinguo/php-msf

{
    "require": {
        "pinguo/php-msf": ">=3.0.0"
    },
    "minimum-stability": "dev"
}

"minimum-stability": "dev"这个配置选项必须加上,因为日志组件依赖"monolog/monolog": "2.0.x-dev",并且monolog/monolog无2.0的release包,不过我们在生产环境已经验证其稳定性。

项目原则

稳定

php-msf经受了Camera360社区服务大流量、高并发的洗礼,稳定性得到充分验证。稳定性是我们花了大量时间、精力去解决的最重要问题,是三大原则的最重要原则。

高性能

IO密集性业务的单机处理能力提升5-10倍,这是生产环境中得出的真实数据,如Camera360社区某聚合服务在流量高峰需要40台服务器抗住流量,而采用php-msf重构之后只需要4台相同配置的服务器就可以抗住所有流量。

简单

由于Swoole复杂的进程模型,并且有同步阻塞和异步非阻塞之分,所以在运行相同代码逻辑时,可能在调用方式、传递参数都不一致,从而直线拉高了学习成本,我们为了屏蔽低层的差异,做了大量的工作,实现和传统MVC框架的唯一区别在于添加“yield”关键字。我们参考了Yii2框架的部分代码实践,我们期望无缝的从Yii2开发切换过来。

上述三大原则,是我们在新增特性、功能实现时,投票或者合并代码的依据,任何影响这些原则的PR也将会被拒绝。

关于协程

目前社区有几个PHP开源项目支持协程,它们大多采用Generator+Yield来实现,但是实现的细微差别会导致性能相差甚远,我们应该认识到协程能够以同步的代码书写方式而运行异步逻辑,故协程调度器的性能一定要足够的高,php-msf的协程调度性能是原生异步回调方式的80%,也就是说某个API采用原生异步回调写法QPS为10000,通过php-msf协程调度器调度QPS为8000。

为什么是微服务框架?

目前php-msf还在起步阶段,我们花了大量的时间和精力解决稳定性、高性能、内存问题,因为我们认为“基石”是“万丈高楼”的最基本的保障,只有基础打得牢,才能将“大楼”建设得“更高”。3.0版本是我们开源的起始版本,是我们迈出的重要一步,接下来我们重点会是分布式微服务框架的打磨。

另外,由于基于PHP常驻进程,并直接解析HTTP或者TCP请求,这是服务化最重要的支撑,基于此我们可以做很多原来不敢去实现的想法,总之想像空间很大。

感谢

php-msf最开始基于SwooleDistributed-1.7.x开发,而此次开源版本中,连接池主要采用了SD的实现。由于我们框架定位、解决的业务场景、稳定性的要求、代码风格等差异太大,因此我们决定自主研发微服务框架,每个框架都有自己的特色和优点,选择合适自己公司和业务场景的框架最重要,同时在此也感谢白猫;另外,在研发php-msf框架及生产环境应用过程中,遇到很多底层问题,不过都一一解决,而这些问题能够解决最重要就是Swoole开源项目创始人韩天峰-Rango的大力支持,在此深表感谢。

License

GNU General Public License, version 2 see https://www.gnu.org/licenses/gpl-2.0.html

php-msf's People

Contributors

kashin-j avatar pinguo-lipengcheng avatar pinguo-tonganping avatar pinguo-xiaoshiyong avatar pinguo-xudianyang avatar pinguo-zengzhiqiang avatar pinguo-zhanglu avatar shellvon avatar sunny5156 avatar syyongx avatar toxmc avatar viaweb3 avatar wiseker avatar xudianyang avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

php-msf's Issues

yield 使用临时表时出现问题

当我使用 yield 创建临时表时,返回结果应该创建成功并且有记录的,但是查询临时表时报错,提示 临时表不存在!

以下示例代码:

    {
        // 删除临时表
        $db =  yield $this->getMysqlPool('master');
        $tableName = 'tmp_user_info';

        $dropSql = 'DROP TABLE IF EXISTS ' . $tableName .';';

        yield $db->go(null,$dropSql);

        $querySql = "SELECT * FROM user_info WHERE create_at = '1514691308'";

        $createTmpTblSql = "CREATE TEMPORARY TABLE  {$tableName}  ({$querySql}) ;";

        $res1 = yield $db->go(null,$createTmpTblSql);

        dump($res1);
        /* 输出结果
         [
            'client_id' => 0
            'result' => true
            'affected_rows' => 8
            'insert_id' => 0
         ]
         */

        $res2 = yield $db->select('*')->from($tableName)->limit(1)->go();
        dump($res2);
        /*
         * [mysql]:Table 'demo_user.tmp_user_info' doesn't exist[sql]:SELECT * FROM tmp_user_info LIMIT 1
         */
        return $res2;
    }`

有个小提议。怎么调试db sql语句?

Minner.php
public $debug = false;
public function debug($debug = true){
    $this->debug = $debug;
    return $this;
}

public function go($bindId = null, $sql = null)
    {
        if ($sql == null) {
            $sql = $this->getStatement(false);
        }
        if($this->debug){
            writeln($sql);//打印sql
        }
       ..................
}

模版渲染引擎使用官方维护的repo

将目前使用的目标渲染引擎pinguo/plates 修改为官方维护的hephpleague/plates

替换为官方repo的主要原因是:

  • 目前pinguo维护的plates变更是支持多级目录做出的变更其实是多余的,因为原plates可以完成子目录渲染。
  • 为了这一点,我们不得不花费精力去维护一个fork的repo.比如当官方的plates提交了一个新的features或者bugfixed,我们fork的repo需要保持同步,于此同时需要确保官方的变更与我们的变更不要产生冲突。 与其这样,还不如花费更多的精力将msf做的更好。
  • 目前的多级视图渲染如果需要使用fetch/layout等内置函数时有BUG(无法正确找到视图文件)

另外,根据官方文档关于视图加载策略的描述:

默认情况下框架会根据请求的控制器名和方法名自动加载视图文件,比如:

http://127.0.0.1:8000/Demo/TplView

这样的URL会自动首先加载的视图文件为app/Views/Demo/TplView.php,如果失败,会继续加载php-msf/src/Views/Demo/TplView.php,如果还是失败,则会抛出异常。

即优先加载用户@app/Views目录下视图,然后尝试加载框架目录下视图。

  1. app/Views
  2. php-msf/src/Views

将视图渲染引擎修改为官方repo之后,仍然可以保证以上策略的完美执行且支持更灵活的策略配置。

为了做到这一点,框架需要修改两个地方:

  • HTTPServer增加需要加载的视图目录(为了更加灵活,可以支持配置):
/**
 * 视图文件存储路径,您可以指定多个路径以便让框架载入.
 * 数组顺序即加载顺序,当然,框架会自动将框架视图目录放在最后resolve.
 *
 * @var array
 */
public $viewResolvePaths;
/**
 * HttpServer constructor.
 */
public function __construct()
{
    parent::__construct();
    $this->viewResolvePaths = $this->config->get('http_server.view_paths', [
        APP_DIR.'/Views'
    ]);
    foreach ($this->viewResolvePaths as $path) {
      // check  dir exists and so on.
    }
    // 框架自带的视图目录.
    $this->viewResolvePaths[] = $this->MSFSrcDir;
}
  • 当有了需要遍历的视图目录时,只需要在src/Base/Output.php中将加载视图的策略代码稍微修改一下:
$responseBody = null;
$found = false;
foreach (getInstance()->viewResolvePaths as $basePath) {
    try {
       $template = getInstance()->templateEngine->setDirectory($basePath)->make($view);
       $responseBody = $template->render($data);
       $found = true;
       break;
    } catch (\Throwable $e) {
        // pass.
    }
}
if (!$found) {
    throw new Exception("A template named: {$view} was not found in any folder, please check again");
}
$this->end($responseBody);

现在即可正常使用多级渲染和多目录加载策略了。
比如$this->outputView(["data" => "someData"], "path/to/file"); 框架会自动加载

  1. app/Views/path/to/file.php 如果没有加载此文件,尝试第二步,有则渲染之。
  2. php-msf/src/Views/ path/to/file.php 如果此文件没有,则报错,有则渲染之。

Call to undefined method swoole_http_response::gzip()

/Base/Output.php;296:Call to undefined method swoole_http_response::gzip()

php --ri swoole :报以上错误
swoole

swoole support => enabled
Version => 1.9.23
Author => tianfeng.han[email: [email protected]]
epoll => enabled
eventfd => enabled
timerfd => enabled
signalfd => enabled
cpu affinity => enabled
spinlock => enabled
rwlock => enabled
async redis client => enabled
async http/websocket client => enabled
Linux Native AIO => enabled
pcre => enabled
mutex_timedlock => enabled
pthread_barrier => enabled
futex => enabled

Directive => Local Value => Master Value
swoole.aio_thread_num => 2 => 2
swoole.display_errors => On => On
swoole.use_namespace => Off => Off
swoole.fast_serialize => Off => Off
swoole.unixsock_buffer_size => 8388608 => 8388608
[root@localhost etc]#

getObject()//第二参数的传值。是怎么实现的。

Pool.php类的get()//没见到this->getObject(Class, Params);//没见到Params的传值。
$reflector = new \ReflectionClass($poolName);
$obj = $reflector->newInstanceWithoutConstructor();
$obj->__useCount = 0;
$obj->__genTime = time();
$obj->__isContruct = false;
$obj->__DSLevel = Marco::DS_PUBLIC;

要实现在启动时自动加载数据表结构。

onWorkerStart
        $poolName = 'master';
        $instnce = getInstance();
        $activePoolName = $poolName;
        $poolName       = MysqlAsynPool::ASYN_NAME . $poolName;
        $pool = $instnce->getAsynPool($poolName);
        if (!$pool) {
            $pool = new MysqlAsynPool($instnce->config, $activePoolName);
            getInstance()->addAsynPool($poolName, $pool, true);
        }
        $tables = yield $pool->go(null, 'show create table config_channel');
        print_r($tables);

没有打印print_r($tables);

同步任务返回值错乱 BUG

情景:两个同步任务,Demo1阻塞1秒,Demo2阻塞2秒。

<?php
/**
 * Demo1
 */
namespace App\Tasks;

use \PG\MSF\Tasks\Task;

class Demo1 extends Task
{
    public function test()
    {
        sleep(1);
        return 'Demo1 test';
    }
}
<?php
/**
 * DEMO2
 */
namespace App\Tasks;

use \PG\MSF\Tasks\Task;

class Demo2 extends Task
{
    public function test()
    {
        sleep(2);
        return 'Demo2 test';
    }
}
<?php
/**
 * 控制器调用
 */

namespace App\Controllers;

use PG\MSF\Controllers\Controller;

class Welcome extends Controller
{
    public function actionDemo1()
    {
        // Demo1任务使用break
        $this->getObject(\App\Tasks\Demo1::class)->test()->break();
        $this->output('demo1 run');
    }

    public function actionDemo2()
    {
        // Demo2任务使用yield
        $result = yield $this->getObject(\App\Tasks\Demo2::class)->test();
        $this->output('demo2 run,result:'.$result);
    }
}
<?php
// 测试
$a = file_get_contents("http://192.168.53.10/welcome/demo1");
$b = file_get_contents("http://192.168.53.10/welcome/demo2");
echo "demo1:".$a."<br >"."demo2:".$b;

结果:
demo1:demo1 run
demo2:demo2 run,result:Demo1 test

demo2任务返回值为Demo1的返回值。

controller yield Exception问题,严重!

class C extends Controller {
 public function actionIndex(){
          $user = $this->getObject(User::class);//User class
           $result = yield $user->login();//这里有throw new LoginFailException();的情况。
           $this->outputJson($result);
 }
public function onExceptionHandle(\Throwable $e)
    {
        if($e instanceof LoginFailException){//这里没有catch到上面的异常。
            $this->outputJson(['message'=>$e->getMessage()], 401);
            return;
        }
      parent::onExceptionHandle($e);
 }
}

当login throw LoginFailException会报如下错:
[2017-10-12 19:46:12 *29162.0] ERROR zm_deactivate_swoole (ERROR 503): Fatal error: Uncaught App\Exceptions\LoginFailException: 账号或密码错误:0,剩除次数:0 in /opt/rondaful-b2c/msf-server/app/Service/User.php:36
Stack trace:
#0 [internal function]: App\Service\User->login('admin1', 'admin', 10)
#1 /opt/rondaful-b2c/msf-server/vendor/pinguo/php-msf/src/Coroutine/Task.php(159): Generator->send(NULL)
#2 /opt/rondaful-b2c/msf-server/vendor/pinguo/php-msf/src/Coroutine/Scheduler.php(99): PG\MSF\Coroutine\Task->run()
#3 /opt/rondaful
[2017-10-12 19:46:12 $29159.0] WARNING swManager_check_exit_status: worker#0 abnormal exit, status=255, signal=0
[2017-10-12 19:46:12] 服务器进程异常退出 WORKER Error {"worker_id":0,"worker_pid":29162,"exit_code":255,"message":null}

关于对象的生命周期问题?

class Test extens Controller{
     private $server;
     public function __construct($controllerName, $methodName){
            parent::__construct($controllerName, $methodName);
            $this->server = $this->server ?? $this->getObject(Server::class);
     }
}
class Server extens Core{
    private $mode;
    public function __construct(){
          $this->model = $this->getObject(MyModel::class);
    }
   public function destroy()
    {
        parent::destroy(); // TODO: Change the autogenerated stub
        $this->model = null;
        echo "destory\n";
    }
    public function __destruct()
    {
        echo "__destruct\n";
    }
}

多worker时=4,
前4次请求会Test 调用:?? $this->getObject(Server::class);//因为每个worker都会初始一次server
这4次请求是很正常的。
第5次请求时,?? $this->getObject(Server::class);不会调用了。因为private $server被前4次设值了。

导至Server的__construct不会调用到。
那么为什么前4次明明private $server是非public的,而它的Server实例下的destroy会被调用到。
而且__destruct析构函数也调用了。

第五次没有?? $this->getObject(Server::class);,那$server中的$model就不会this->getObject(MyModel::class);//那这时的$model一直是null了。。。

layout加载完文件不继续执行代码的问题

views目录结构如下:
public
----Header.php
----- Footer.php
index
---- Index.php

Header.php具体内容如下:

<title>KoolTubeeew666666666 this is a test</title>

Index.php具体内容如下:

layout('Public/Header') ?>
Welcome to KOOLTUBE!

重启server.php后,在浏览器上显示结果如下:

<title>KoolTubeeew666666666 this is a test</title> 

Index.php中layout下面的内容没执行。

后面有没有考虑添加服务注册发现,熔断等特性?

看了下整个项目的思路:

  1. 使用swoole异步IO提升效率
  2. 使用协程提升回调效率,避免callback hell
  3. 使用对象池减少内存占用

收益良多,感谢~

但感觉目前没有服务注册发现&熔断等特性,如果直接写死ip的话,感觉不利于维护和扩展,后面有考虑加上这一块吗?

没有中间件

是否有计划在框架中集成基于PSR-15规范的中间件?目前有没有替代方案实现类似中间件的功能?

Redis 命令rpoplpush,brpoplpush第二个参数值始终为2

src/Pools/CoroutineRedisProxy.php中第194行:
$arguments[2] = $this->generateUniqueKey(2);
按照generateUniqueKey函数定义,第二个参数始终为2,导致以上命令无法正常使用。
1507708689.923708 [0 127.0.0.1:37236] "RPOPLPUSH" "sourceMQS" "2"

miner.php bug

$pool = this->getMysqlPool();
$pool->where('name', 100);
$pool->from($table);
$pool->go();

必现name = 100问题。因为
name改为group,(group为table表的字段)也会报错。

模版渲染异常时文案提示可能是错的

目前渲染的逻辑是当所有目录遍历完之后如果found=false则会抛出异常:

php-msf/src/Base/Output.php

Lines 265 to 278 in a21350e

foreach (getInstance()->viewResolvePaths as $basePath) {
try {
$template = getInstance()->templateEngine->setDirectory($basePath)->make($view);
$responseBody = $template->render($data);
$found = true;
$template = null;
break;
} catch (\Throwable $e) {
// pass.
}
}
if (!$found) {
throw new Exception(sprintf('A template named %s was not found in any folder, please check again', $view));
}

但是如果当渲染时出现一些其他的逻辑错误时,比如模版内语法错误/调用的方法不存在等情况时,会在267/268行抛出异常,从而错误的认为是模版没有找到。

解决思路:
在render之前判断模版是否存在,不存在则跳过当前目录。不再在此处捕获异常(Plates内部爆出的异常都是LogicException,无法根据异常类型区分是模版没找到还是其他错误,因此最佳方式就是把模版内的错误直接冒泡出来)。

mysql

[2017-11-17 11:33:05] 服务器发生严重错误 WORKER Error swoole_mysql::query(): mysql client is waiting response, cannot send new sql query

$mysql = $this->getMysqlPool('master');
$id = yield $mysql->goBegin();
$a = $mysql->insert('a')->set(['a'=>'a'])->go($id);
$b = $mysql->insert('a')->set(['a'=>'a'])->go($id);
$c = yield $a;
$d = yield $b;
yield $mysql->goCommit($id);

getObject通过对象池生成对象

不是很理解它的价值,因为
class BaseModel extends Model{
public function __constrance(){
echo "BaseModel";
}
}

Controller里getObject(BaseModel::class,);两次,都会打印BaseModel,也就是说,第一次生成的object,第二次还是生成object.

worker Reload时增加自定义回调机制

swoole_event_add($this->inotifyFd, function ($inotifyFd) use (&$monitorFiles) {
            $events = inotify_read($inotifyFd);
            $flag = true;
            foreach ($events as $ev) {
                if (pathinfo($ev['name'], PATHINFO_EXTENSION) != 'php') {
                    //创建目录添加监听
                    if ($ev['mask'] == 1073742080) {
                        $path = $monitorFiles[$ev['wd']] .'/'. $ev['name'];

                        $wd = inotify_add_watch($inotifyFd, $path, IN_MODIFY | IN_CREATE | IN_IGNORED | IN_DELETE);
                        $monitorFiles[$wd] = $path;
                    }
                    $flag = false;
                    continue;
                }
                writeln('RELOAD ' . $monitorFiles[$ev['wd']] .'/'. $ev['name'] . ' update');
            }
            if ($flag == true) {
                $this->MSFServer->server->reload();
            }
        }, null, SWOOLE_EVENT_READ);

改为

swoole_event_add($this->inotifyFd, function ($inotifyFd) use (&$monitorFiles) {
            $events = inotify_read($inotifyFd);
            $flag = true;
            $changes = [];//record change
            foreach ($events as $ev) {
                if (pathinfo($ev['name'], PATHINFO_EXTENSION) != 'php') {
                    //创建目录添加监听
                    if ($ev['mask'] == 1073742080) {
                        $path = $monitorFiles[$ev['wd']] .'/'. $ev['name'];

                        $wd = inotify_add_watch($inotifyFd, $path, IN_MODIFY | IN_CREATE | IN_IGNORED | IN_DELETE);
                        $monitorFiles[$wd] = $path;
                    }
                    $flag = false;
                    continue;
                }
                writeln('RELOAD ' . $monitorFiles[$ev['wd']] .'/'. $ev['name'] . ' update');
                $changes[$monitorFiles[$ev['wd']] .'/'. $ev['name']] = 'update';
            }
            if ($flag == true) {
                $callback = $this->config->get('reload.callback');//reload callback
                if($callback && is_callable($callback)){
                    $callback($changes);//call back
                }
                $this->MSFServer->server->reload();
            }
        }, null, SWOOLE_EVENT_READ);

worker 进程死掉

worker 进程死掉,查看日志,有大量如下记录

WORKER Error {"worker_id":2,"worker_pid":22443,"exit_code":0,"message":null}

貌似一直重启一直死。

根据 swoole 的文档:

$exit_code 退出的状态码,范围是 1 ~255

exit_code 为0,message 为空,咋回事呢?

docker 镜像问题

1、使用alpinelinux 进行重新打 (内核4.x了,但是无论是编译安装swoole 还是通过pcel安装swoole 都回出现找不到 libaio 事事上已经安装了)
2、使用centos7 进行制作(1.1 G )

sendfile一个大文件,会不会导致这个request请求被一直占用着?

protected function outputFile($filename, $headers = [])
    {
        $output = $this->getContext()->getOutput();
        foreach ($headers as $header=>$value){
            $output->setHeader($header, $value);
        }
        $output->response->sendfile($filename);
        $output->__isEnd = true;
    }

$filename有30m,要传1分钟,这一分钟里,会一直占用这条请求资源吗?
如果worker只有4(4个请求资源),那不就没法正常走其它业务了吗?疑问~~

类加载重复。

app/Controllers/Lists.php
   use \App\Server\Goods.php
     actionIndex(){
             this->getObject(Goods.php);//这里会报Goods.php已重复加载。
     }

app/Models/Goods.php
app/Server/Goods.php

default

Demo 项目不生成日志文件、协程无限重启

按照 运行代码 一步步来的。

supervisor> status

除了 msf:php-msf-demo RUNNING 之外,还有 nginx RUNNING,为什么还要启动 Nginx?好奇。


Demo示例项目配置了HTTP索引页,直接浏览器访问http://127.0.0.1:8000

此处展示提示:Api not found controller(Index),但 /welcome 是正常的


查看服务日志 $>cat ~/data/msf-php-msf-demo/server.log

此处 Shell 提示:open(/home/worker/data/www/runtime/demo/server.log) failed. Error: No such file or directory[2]


协程 - 示例代码:http://127.0.0.1:8000/CoroutineTest/CoroutineMode

此页面无限重启,加载的一些 .js 文件都是 404。

Mi.php context = null

/**
     * 通过对象池生成对象
     *
     * @param array $args
     * @return \stdClass|mixed
     */
    public function getObject(...$args)
    {
       //请求间隔久时,这里会出现this->context = null的情况。Miner过来的getObject(Mysql::class,...)
        return $this->context->getObjectPool()->get(...$args);
    }

通过composer 安装新的依赖和msf本身的依赖版本冲突,如何解决

msf依赖monolog的2.0dev版本,但我要安装的overtrue/wechat 依赖monolog的release 1.X的版本,通过composer安装overtrue/wechat 时候报错。请问如何解决?
Conclusion: don't install overtrue/wechat 4.0.1
- Conclusion: don't install overtrue/wechat 4.0.0
- Conclusion: don't install overtrue/wechat 4.0.0-beta.4
- Conclusion: don't install overtrue/wechat 4.0.0-beta.3
- Conclusion: don't install overtrue/wechat 4.0.0-beta.2
- Conclusion: don't install overtrue/wechat 4.0.0-beta.1
- Conclusion: don't install overtrue/wechat 4.0.0-alpha.2
- Conclusion: don't install overtrue/wechat 4.0.0-alpha.1
- Conclusion: remove monolog/monolog 2.0.x-dev
- Installation request for overtrue/wechat ~4.0 -> satisfiable by overtrue/wechat[4.0.0, 4.0.0-alpha.1, 4.0.0-alpha.2, 4.0.0-beta.1, 4.0.0-beta.2, 4.0.0-beta.3, 4.0.0-beta.4, 4.0.1, 4.0.10, 4.0.11, 4.0.12, 4.0.13, 4.0.14, 4.0.15, 4.0.16, 4.0.17, 4.0.18, 4.0.19, 4.0.2, 4.0.20, 4.0.21, 4.0.22, 4.0.3, 4.0.4, 4.0.5, 4.0.6, 4.0.7, 4.0.8, 4.0.9, 4.0.x-dev].
- Conclusion: don't install monolog/monolog 2.0.x-dev
- overtrue/wechat 4.0.x-dev requires monolog/monolog ^1.22 -> satisfiable by monolog/monolog[1.22.0, 1.22.1, 1.23.0, 1.x-dev].
- Can only install one of: monolog/monolog[1.22.0, 2.0.x-dev].
- Can only install one of: monolog/monolog[1.22.1, 2.0.x-dev].
- Can only install one of: monolog/monolog[1.23.0, 2.0.x-dev].
- Can only install one of: monolog/monolog[1.x-dev, 2.0.x-dev].
- Installation request for monolog/monolog (locked at 2.0.x-dev) -> satisfiable by monolog/monolog[2.0.x-dev].

很多常用的库都依赖monolog,并且都是release版本,现在不知道该怎么办了,求解。。

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.