×
Swoole 简介Swoole 包含模块Swoole 环境依赖Swoole 编译安装Swoole 基本实例创建Swoole 编程须知Swoole 优化内核参数调整Swoole server配置选项Swoole server事件回调函数Swoole server函数列表

Swoole实例

Swoole Server实例Swoole Client实例Swoole HttpServer实例Swoole WebSocket实例Swoole Redis Server实例Swoole MySQL实例Swoole AsyncIO实例Swoole Task实例Swoole 2.0 正式版发布,协程特性支持 PHP 7Swoole Coroutine协程支持

Swoole MySQL实例


Swoole异步MySQL介绍

MySQL异步是指将MySQL连接事件驱动化,这样就编程了非阻塞IO。使用Swoole可以实现mysql异步链接,Mysql连接池等。
  • 异步MySQL客户端依赖PHP的 mysqlnd 和 mysqli 2个扩展,请使用php -mphpinfo确认PHP是否有这2个扩展。
  • 另外需要在编译swoole时制定--enable-async-mysql

1.8.6版本已移除对mysqlimysqlnd扩展的依赖,并改为内置,无需额外的编译参数开启

简单实例:

$db = new SwooleMySQL;
$server = array(
    'host' => '127.0.0.1',
    'user' => 'test',
    'password' => 'test',
    'database' => 'test',
);

$db->connect($server, function ($db, $result) {
    $db->query("show tables", function (SwooleMySQL $db, $result) {
        if ($result === false) {
            var_dump($db->error, $db->errno);
        } elseif ($result === true) {
            var_dump($db->affected_rows, $db->insert_id);
        } else {
            var_dump($result);
            $db->close();
        }
    });
});

MySQL长连接

MySQL短连接每次请求操作数据库都需要建立与MySQL服务器建立TCP连接,这是需要时间开销的。TCP连接需要3次网络通信。这样就增加了一定的延时和额外的IO消耗。请求结束后会关闭MySQL连接,还会发生3/4次网络通信。

close操作不会增加响应延时,原因是close后是由操作系统自动进行通信的,应用程序感知不到

长连接就可以避免每次请求都创建连接的开销,节省了时间和IO消耗。提升了PHP程序的性能。

断线重连

在cli环境下,PHP程序需要长时间运行,客户端与MySQL服务器之间的TCP连接是不稳定的。

  • MySQL-Server会在一定时间内自动切断连接
  • PHP程序遇到空闲期时长时间没有MySQL查询,MySQL-Server也会切断连接回收资源
  • 其他情况,在MySQL服务器中执行kill process杀掉某个连接,MySQL服务器重启

这时PHP程序中的MySQL连接就失效了。如果仍然执行mysql_query,就会报一个“MySQL server has gone away”的错误。程序处理不到就直接遇到致命错误并退出了。所以PHP程序中需要断线重连。

有很多人提出了mysql_ping的方案,每次mysql_query进行连接检测或者定时连接检测。这个方案不是最好的。原因是

  • mysql_ping需要主动侦测连接,带来了额外的消耗
  • 定时执行mysql_ping不能解决问题,如刚刚执行过mysql_ping检测之后,连接就关闭了

最佳的方案是,进行断线重连 。它的原理是:

  1. mysql_query执行后检测返回值
  2. 如果mysql_query返回失败,检测错误码发现为2006/2013(这2个错误表示连接失败),再执行一次mysql_connect
  3. 执行mysql_connect后,重新执行mysql_query,这时必然会成功,因为已经重新建立了连接
  4. 如果mysql_query返回成功,那么连接是有效的,这是一次正常的调用

可参考swoole_framework中的代码

MySQL异步

MySQL异步是指将MySQL连接事件驱动化,这样就编程了非阻塞IO。数据库操作并不会阻塞进程,在MySQL-Server返回结果时再执行对应的逻辑。

有几个点需要注意一下:

  • 异步MySQL并没有节省SQL执行的时间
  • 一个MySQL连接同时只能执行1个SQL,如果异步MySQL存在并发那么必须创建多个MySQL连接

异步回调程序中,异步MySQL并没有提升性能。异步最大的好处是可以高并发,如果并发1万个请求,那么就需要建立1万个MySQL连接,这会给MySQL-Server带来巨大的压力。

MySQL是根据连接数分配资源的,一个连接需要开启一个线程。1000连接那么需要维持1000线程才可以。线程数量增加后,线程间切换会占用大量CPU资源
MySQL短连接反而不会出现此问题,因为短连接在使用完后就释放了。不会占用MySQL-Server的连接资源

虽然应用层代码使用异步回调避免了自身的阻塞,实际上真正的瓶颈是数据库服务器。异步MySQL还带来了额外的编程复杂度,所以除非是特殊场景的需求,否则不建议使用异步MySQL。

如果程序中坚持要使用异步,那么必须是异步MySQL+连接池的形式。超过规定的MySQL最大连接后,应当对SQL请求进行排队,而不是创建新连接,避免大量并发请求导致MySQL服务器崩溃。

MySQL连接池

连接池是可以有效降低MySQL-Server负载的。原理是 连接池使用一个共享资源的模式,如并发100个请求,实际上并不是每个请求的所有时间都在执行SQL查询。这样100个请求,共享20个MySQL连接就可以满足需求了。当一个请求操作完数据库后,开始进入模板渲染等流程,这时就会释放数据库连接给其他的请求使用。

连接池仅在超大型应用中才有价值。普通的应用采用MySQL长连接方案,每个php-fpm创建一个MySQL连接,每台机器开启100个php-fpm进程。如果有10台机器,每台机器并发的请求为100。实际上只需要创建1000个MySQL连接就能满足需求,数据库的压力并不大。即使有100台机器,硬件配置好的存储服务器依然可以承受。

达到数百或者数千台应用服务器时,MySQL服务器就需要维持十万级的连接。这时数据库的压力就会非常大了。连接池技术就可以派上用场了,可以大大降低数据库连接数。

基于swoole的AsyncTask模块实现的连接池是完美方案,编程简单,没有数据同步和锁的问题。甚至可以多个服务共享连接池。缺点是1, 灵活性不如多线程连接池,无法动态增减连接。2, 有一次进程间通信的开销。
node.js/ngx_lua等在多进程的模式下,无法开发出真正的连接池,除非也像swoole_task这样来实现



分类导航

关注微信下载离线手册

bootwiki移动版 bootwiki
(群号:472910771)