Archive for Swoole

使用 xdebug 在 phpStorm 进行 php 本地和远程 swoole 调试设置

其实类似 xdebug 在 phpStorm 的调试文件一搜一大把,这里简单的总结下,主要是适合使用 swoole 开发的人。

本地调试的设置方法

第1步

在 Run 菜单中点击 Edit Configurations,然后点击最左侧 + 按钮,选择 PHP Script。

第2步

Configuration 的 File 参数就选择 swoole 的启动文件,Arguments 输入你这个启动文件的参数,没有的话就留空,名字自己设定

完成

然后点击保存,如果 phpStorm 提示找不到php命令的话你设置下路径就好了。

这个时候在窗口的右上角就会有一个可以调试的按钮,这个时候在要断点的位置打上打断,启动调试就可以了。


远程调试设置

当脚本在服务器上运行时,就需要用到远程调试了(也适用于本机调试)远程调试设置方法如下:

第1步

打开设置面板,找到 Languages & Frameworks -> PHP -> Servers。点击 + 号添加,Host 填需要调试的服务器的ip,端口填 xdebug 的 remote_port (ini中默认为 9000,这个值远程服务器启动命令上是可以设置的)

如果服务器上代码路径和本地路径不一致的话,需要勾选 “Use path mappings”,然后主项目路径后的 Absolute path on the server 填一下对应服务器的路径,设置好后保存。

第2步

设置时候继续设置,同本地是设置,在 Run 菜单中点击 Edit Configurations 点击添加按钮,选择 php remote debug。servers 就选择刚刚添加的那个。网上文档都有说 ide key 要填个 PHPSTORM 什么的,其实可以不用填,因为 swoole 起的服务器并不是传统的 web 服务器。

第3步

设置好了后,记得在swoole的启动命令上加上参数:

-dxdebug.remote_autostart=1 -dxdebug.remote_host=192.168.1.2 -dxdebug.remote_port=9100 -dxdebug.remote_enable=1

, 例如:

php -dxdebug.remote_autostart=1 -dxdebug.remote_host=192.168.1.2 -dxdebug.remote_port=9100 -dxdebug.remote_enable=1 server.php -vvv

其中 remote_host 是服务器 ip,remote_port 是 xdebug 的调试端口,千万别暴露给外网。当然,这些参数是可以在 php.ini 中直接设置的,如果设置好了,可以不带这些参数直接启动的。


参阅

开源了一个好用又简单的大数据日志数据实时统计服务功能 Easy Total

因为我们公司游戏的日志越来越多,普通的数据光插入数据就会让数据库挂掉,后来我们用 Hadoop 集群来处理日志,但是问题是需要越来越多的服务器,为了解决这个问题,用了半年时间开发了一个简单好用的实时统计服务器:EasyTotal。此服务还在测试,感兴趣的同学可以去点赞或贡献代码,项目地址 https://github.com/xindong/easy-total。在我们线上测试环境(监听了20多条统计的SQL语句)单机每分钟处理300万+的日志量cpu负载在 3 – 5之间,可持续处理1000万/分钟的日志量,峰值可达1300万/分钟,这样的性能堪称无敌,因为这样的数据光插入 10 台机器组成的 Elasticsearch 集群用不了多久集群就要挂了。

下面是项目介绍:

EasyTotal 是一个通过监听预先添加好的SQL统计查询语句,对汇入的数据进行实时统计处理后不间断的将统计结果导出的服务解决方案,它解决了日志数据量非常巨大的情况下,数据库无法承载巨大的插入和查询请求的问题,并且可以满足业务统计的需求。程序的网络层是采用c写的swoole扩展进行处理,具有极高的性能,网络处理能力和 nginx 相当,处理数据模块采用 php 开发则可以方便团队根据自己的需求进行二次开发。

支持常用的运算统计功能,比如 count, sum, max, min, avg, first, last, dist,支持 group by、where 等,后续将会增加 join 的功能。

特点:

  • 实时处理,定时汇出统计结果;
  • 对巨大的日志量进行清洗汇总成1条或多条输出,可以成万倍的缩小数据体量,可在汇总结果中进行二次统计;
  • 特别适用于对大量log的汇入统计,免去了先入库再统计这种传统方式对系统造成的负担;
  • 分布式水平扩展,支持随时增删统计服务器;
  • 不需要特别的技术、使用简单;
  • 可以二次开发;

使用场景

当需要对业务数据进行统计分析时,传统的做法是把数据或日志导入到数据库后进行统计,但是随着数据量的增长,数据库压力越来越大甚至插入数据都成问题更不用说是进行数据统计了,此时只能对数据进行分库、分片等处理或者是用 hadoop、spark 等离线统计,然后就需要分布式架构,这在技术角度上来说是可行的做法,但这带来的问题就是:

  • 需要很多服务器,增加巨额托管费用;
  • 需要能够hold住这些服务器和技术的高级开发及运维人员;
  • 架构调整导致的研发难度和周期增加;

EasyTotal 正是为了解决这些问题而诞生,可以用极少的服务器以及简单的技术就能处理巨大的数据并满足业务统计的需求,对你来说一切都是那么的easy。

上两张管理界面:

admin01

admin02

swoole_process 正常退出却 zm_deactivate_swoole: worker process is terminated by exit()/die().

不废话,先上一段代码

<?php

error_reporting(7);

$serv = new swoole_server("0.0.0.0", 9500, SWOOLE_PROCESS);
$serv->set([
    'worker_num' => 1,
    'task_worker_num' => 1,
]);

$serv->on('Receive', function(swoole_server $server, $fd, $from_id, $data)
{
    $server->task('a');
});


$serv->on('workerstart', function(swoole_server $server, $id)
{
});

//$serv->set([]);

$serv->on('Task', function($serv, $task_id, $from_id, $data)
{
    $arr = ['a','b','c','d'];
    $processes = [];
    foreach ($arr as $v)
    {
        echo "-------". (microtime(1))."\n";

        $process = new swoole_process(function(swoole_process $worker) use ($v)
        {
            echo $v."======". ($t = microtime(1))."\n";
            sleep(3);
            echo $v."++++++". (microtime(1) - $t)."\n";
            // $worker->daemon(true);
        }, false);
        $process->start();
        $processes[] = $process;
    }

    while(true)
    {
        # 等待回收,如果不回收进程会变成僵死进程,很可怕的
       if (false === swoole_process::wait())
        {
            break;
        }
    }

    echo "done\n";
});

$serv->on('Finish', function()
{
});


$serv->start();

(TO小白:保存成test.php文件,然后php test.php这样运行,再telnet 127.0.0.1 9500 上,随便输入个内容回车就可以执行了)

这个代码成功执行后,在控制台上会输出4个WARN的错误,类似

zm_deactivate_swoole: worker process is terminated by exit()/die().

经过测试发现,如果 new swoole_process 时第二个参数设置成 true(定向子进程的标准输入和输出),则不会报这样的错误。
但是我的程序就是需要接受输出那么怎么办呢?

在测试代码里有一个注释了的代码

// $worker->daemon(true);

,把注释去掉这样就解决了,不再报那个错误了。
daemon 方法可见文档,它是把子进程蜕变成一个守护进程用的。

最后,再强调一下,一定要:

    while(true)
    {
        # 等待回收,如果不回收进程会变成僵死进程,很可怕的
       if (false === swoole_process::wait())
        {
            break;
        }
    }

这样进行回收,因为测试代码里开了4个子进程,如果只回收1次,还会有3个进程得不到回收,变成僵死进程的。