文档章节

swoole入门教程03-Timer定时器、心跳检测及Task进阶实例:mysql连接池

摇滚哈哈狗
 摇滚哈哈狗
发布于 2015/09/24 21:15
字数 1595
阅读 99
收藏 0

环境说明: 系统:Ubuntu14.04 (安装教程包括CentOS6.5)
PHP版本:PHP-5.5.10
swoole版本:1.7.7-stable

Github地址:https://github.com/LinkedDestiny/swoole-doc


1.Timer定时器

在实际应用中,往往会遇到需要每隔一段时间重复做一件事,比如心跳检测、订阅消息、数据库备份等工作。通常,我们会借助PHP的time()以及相关函数自己实现一个定时器,或者使用crontab工具来实现。但是,自定义的定时器容易出错,而使用crontab则需要编写额外的脚本文件,无论是迁移还是调试都比较麻烦。
因此,Swoole提供了一个内置的Timer定时器功能,通过函数addtimer即可在Swoole中添加一个定时器,该定时器会在建立之后,按照预先设定好的时间间隔,每到对应的时间就会调用一次回调函数onTimer通知Server。
简单示例如下:

$this->serv->on('Timer', array($this, 'onTimer'));

    public function onWorkerStart( $serv , $worker_id) {
        // 在Worker进程开启时绑定定时器
        // 只有当worker_id为0时才添加定时器,避免重复添加
        if( $worker_id == 0 ) {
            $serv->addtimer(500);
            $serv->addtimer(1000);
            $serv->addtimer(1500);
        }
    }

    public function onTimer($serv, $interval) {
        switch( $interval ) {
            case 500: { // 
                echo "Do Thing A at interval 500\n";
                break;
            }
            case 1000:{
                echo "Do Thing B at interval 1000\n";
                break;
            }
            case 1500:{
                echo "Do Thing C at interval 1500\n";
                break;
            }
        }
    }

可以看到,在onWorkerStart回调函数中,通过addtimer添加了三个定时器,时间间隔分别为500、1000、1500。而在onTimer回调中,正好通过间隔的不同来区分不同的定时器回调,从而执行不同的操作。
需要注意的是,在上述示例中,当1000ms的定时器被触发时,500ms的定时器同样会被触发,但是不能保证会在1000ms定时器前触发还是后触发,因此需要注意,定时器中的操作不能依赖其他定时器的执行结果。

点此查看完整示例

(PS:在Swoole-1.7.7版本,新提供了一个after函数, 这个功能的用法会在以后的教程中给出。)

2.心跳检测

上文提到过,使用Timer定时器功能可以实现发送心跳包的功能。事实上,Swoole已经内置了心跳检测功能,能自动close掉长时间没有数据来往的连接。而开启心跳检测功能,只需要设置heartbeat_check_intervalheartbeat_idle_time即可。如下:

$this->serv->set(
    array(
        'heartbeat_check_interval' => 60,
        'heartbeat_idle_time' => 600,
    )
);

其中heartbeat_idle_time的默认值是heartbeat_check_interval的两倍。 在设置这两个选项后,swoole会在内部启动一个线程,每隔heartbeat_check_interval秒后遍历一次全部连接,检查最近一次发送数据的时间和当前时间的差,如果这个差值大于heartbeat_idle_time,则会强制关闭这个连接,并通过回调onClose通知Server进程。 点此查看完整示例 小技巧: 结合之前的Timer功能,如果我们想维持连接,就设置一个略小于如果这个差值大于heartbeat_idle_time的定时器,在定时器内向所有连接发送一个心跳包。如果收到心跳回应,则判断连接正常,如果没有收到,则关闭这个连接或者再次尝试发送。

3.Task进阶:MySQL连接池

上一章中我简单讲解了如何开启和使用Task功能。这一节,我将提供一个Task的高级用法。

在PHP中,访问MySQL数据库往往是性能提升的瓶颈。而MySQL连接池我想大家都不陌生,这是一个很好的提升数据库访问性能的方式。传统的MySQL连接池,是预先申请一定数量的连接,每一个新的请求都会占用其中一个连接,请求结束后再将连接放回池中,如果所有连接都被占用,新来的连接则会进入等待状态。
知道了MySQL连接池的实现原理,那我们来看如何使用Swoole实现一个连接池。
首先,Swoole允许开启一定量的Task Worker进程,我们可以让每个进程都拥有一个MySQL连接,并保持这个连接,这样,我们就创建了一个连接池。
其次,设置swoole的dispatch_mode为抢占模式(主进程会根据Worker的忙闲状态选择投递,只会投递给处于闲置状态的Worker)。这样,每个task都会被投递给闲置的Task Worker。这样,我们保证了每个新的task都会被闲置的Task Worker处理,如果全部Task Worker都被占用,则会进入等待队列。

下面直接上关键代码:

public function onWorkerStart( $serv , $worker_id) {
    echo "onWorkerStart\n";
    // 判定是否为Task Worker进程
    if( $worker_id >= $serv->setting['worker_num'] ) {
        $this->pdo = new PDO(
            "mysql:host=localhost;port=3306;dbname=Test", 
            "root", 
            "123456", 
            array(
                PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES 'UTF8';",
                PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
                PDO::ATTR_PERSISTENT => true
            )
        );
    }
}

首先,在每个Task Worker进程中,创建一个MySQL连接。这里我选用了PDO扩展。

public function onReceive( swoole_server $serv, $fd, $from_id, $data ) {
    $sql = array(
        'sql'=>'select * from Test where pid > ?',
        'param' => array(
            0
        ),
        'fd' => $fd
    );
    $serv->task( json_encode($sql) );
}

其次,在需要的时候,通过task函数投递一个任务(也就是发起一次SQL请求)

public function onTask($serv,$task_id,$from_id, $data) {
    $sql = json_decode( $data , true );

    $statement = $this->pdo->prepare($sql['sql']);
    $statement->execute($sql['param']);     

    $result = $statement->fetchAll(PDO::FETCH_ASSOC);
    $serv->send( $sql['fd'],json_encode($result));
    return true;
}

最后,在onTask回调中,根据请求过来的SQL语句以及相应的参数,发起一次MySQL请求,并将获取到的结果通过send发送给客户端(或者通过return返回给Worker进程)。而且,这样的一次MySQL请求还不会阻塞Worker进程,Worker进程可以继续处理其他的逻辑。

可以看到,简单十几行代码,就实现了一个高效的异步MySQL连接池。
通过测试,单个客户端一共发起1W次select请求,共耗时9s;
1W次insert请求,共耗时21s。
(客户端会在每次收到前一个请求的结果后才会发起下一次请求,而不是并发)。

点此查看完整服务端代码
点此查看完整客户端代码

下章预告:Swoole多端口监听、热重启以及Timer进阶:简单crontab

版权声明:本文为博主原创文章,未经博主允许不得转载。

本文转载自:http://blog.csdn.net/ldy3243942/article/details/40596547

摇滚哈哈狗
粉丝 14
博文 226
码字总数 28445
作品 0
深圳
程序员
私信 提问
swoole实现Timer定时器、心跳检测及Task进阶实例:mysql连接池

Table of Contents 1.Timer定时器 2.心跳检测 3.Task进阶:MySQL连接池 环境说明: 系统:Ubuntu14.04 (安装教程包括CentOS6.5) PHP版本:PHP-5.5.10 swoole版本:1.7.7-stable 1.Timer定时...

太阳黑子
2016/10/28
180
0
Swoole 1.9.11 发布,心跳检测支持时间轮算法

PHP的异步、并行、高性能网络通信引擎 Swoole 已发布 1.9.11 版本。此版本优化了心跳检测算法,从轮询算法改为时间轮算法,在维持大量TCP连接时消耗的CPU资源更少。另外异步客户端在底层增加...

matyhtf
2017/05/26
3K
15
Swoole 分布式通讯框架--SwooleDistributed

SwooleDistributed 是swoole分布式系统的实现,他提供了一套基于swoole扩展的分布式通讯框架。 结构图: SwooleDistributed 不仅提供了分布式搭建的必要设施,还提供了4大组件帮助你提高编写...

白_猫
2016/07/25
7.3K
3
php异步高并发扩展 swoole-1.6.11 版发布

简介: swoole是一个php版本的异步、高并发扩展,是国人被php官方pecl包收录的力作之一。 很高兴的通知大家,1.6.11版本发布了。 内核更新: - Disable by default async_mysql (默认关闭asy...

半桶水_桶哥
2014/03/04
2.4K
14
swoole-1.8.0 发布,PHP 的异步并行 C 扩展

Swoole-1.8.0 版本已发布,此版本是一个里程碑式新版本,新增了多项新特性、多项核心功能优化以及问题修复、移除了无效的特性。更新内容如下: 客户端 增加原生异步 MySQL 客户端 增加原生异...

matyhtf
2016/01/27
3.2K
24

没有更多内容

加载失败,请刷新页面

加载更多

分页查询

一、配置 /*** @author beth* @data 2019-10-14 20:01*/@Configurationpublic class MybatisPlusConfig { @Bean public PaginationInterceptor paginationInterceptor(){ ......

一个yuanbeth
昨天
5
0
在LINQPad中使用Ignite.NET

LINQPad是进行.NET开发的一款优秀工具,非常有利于Ignite.NET API的快速入门。 入门 下载LINQPad:linqpad.net/Download.aspx,注意要选择64位操作系统的AnyCPU版本; 安装Ignite.NET的NuGet...

李玉珏
昨天
6
0
JS其他类型值转化为Boolean类型规则

本文转载于:专业的前端网站➤JS其他类型值转化为Boolean类型规则 由于最近在笔试的时候,发现好多关于其他类型转化为Boolean类型的题目,因此总结一下! 一、String类型转化为Boolean 1.转化...

前端老手
昨天
6
0
EurekaClient自动装配及启动流程解析

在上篇文章中,我们简单介绍了EurekaServer自动装配及启动流程解析,本篇文章则继续研究EurekaClient的相关代码 老规矩,先看spring.factories文件,其中引入了一个配置类EurekaDiscoveryClie...

Java学习录
昨天
10
0
析构函数是否必须为虚函数?为何?

p517 在C++中,基类指针可以指向一个派生类的对象。如果基类的析构函数不是虚函数,当需要delete这个指向派生类的基类指针时,就只会调用基类的析构函数,而派生类的析构函数无法被调用。容易...

天王盖地虎626
昨天
6
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部