使用PhalconPHP / PDO进行ND连接故障转移的MySQL

时间:2016-01-07 14:26:50

标签: php mysql pdo phalcon mysqlnd

在Mysql-nd手册的this部分中描述了如何在失去与从属MySQL服务器的连接时实现推荐的故障转移方式。

我愿意在PhalconPHP中实施它。由于我有几个使用Phalcon和Mysql-nd的重要项目,因此在正确的位置进行此操作非常重要。

试图找到一些文档,但无法找到任何开头的例子。试图找到EventManager方法,查看Phalcon文档herehere,但无法透明地找到方法。

最有吸引力的方法是使用event manager来捕获错误事件,并在连接错误时再次查询错误事件。

1更新

在阅读了一些Phalcon来源后,我发现,可能无法以标准方式第二次运行相同的查询 - 我的意思是通过某种PDO参数或使用Phalcons' EventManager附加db服务。我发现的一种可能的尝试是在db:afterConnection事件后实际运行任何查询,但它不是解决方案。

2更新

db:afterConnection几乎无法访问,而是可以在db:beforeQuery期间收集所有内容。问题是,PDO由Phalcon运行PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,所以当与奴隶的连接死亡时,它无法到达db:afterConnection事件。可以在db:beforeQuery期间获取PDO实例,并通过EventManager更改此属性,但它不会提供任何内容,因为即使我能够第二次发送相同的查询,我也无法找到在适当的位置返回的方式(db:afterQuery期间无法覆盖查询结果)because obtained statement is not a part of event send, and Eventmanager result is not being used at all

    if typeof statement == "object" {
        if typeof eventsManager == "object" {
            eventsManager->fire("db:afterQuery", this, bindParams);
        }
        return new ResultPdo(this, statement, sqlStatement, bindParams, bindTypes);
    }

1 个答案:

答案 0 :(得分:0)

目前看起来配置似乎已修复:

{
    "db-cluster": {
        "master": {
            "master": {
                "host": "master.local",
                "port": 3306
            }
        },
        "slave": {
            "slave-1": {
                "host": "slave-1.local",
                "port": 3306
            },
            "slave-2": {
                "host": "slave-2.local",
                "port": 3306
            },
            "slave-3": {
                "host": "slave-3.local",
                "port": 3306
            }
        },
        "filters": {
            "roundrobin": []
        },
        "failover": {
            "strategy": "loop_before_master",
            "remember_failed": true,
            "max_retries": 1
        },
        "server_charset": "utf8"
    }
}

如果服务器无法访问,则会回退到其他服务器,问题是它尝试连接到无法访问的服务器至少3秒钟。解决方法是:

$eventsManager = new EventsManager();
$connection->setEventsManager($eventsManager);

$eventsManager->attach('db:beforeQuery', function($event, $connection) {

    // fix: if slave does not respond, without this it goes over 3 seconds before trying next one
    !defined('DST') && define('DST', ini_get('default_socket_timeout'));
    ini_set("default_socket_timeout", 1);

});

$eventsManager->attach('db:afterQuery', function($event, $connection) {
    ini_set('default_socket_timeout', defined('DST') ? DST : 60);
});

即使现在可以正常工作(当奴隶无法访问时,它会挂起最多1秒钟 - 这仍然是很多时间),它仍然不允许我从PHP源连接到写入一个recommended solution

更新

可以通过扩展executePrepared类来覆盖Phalcon\Db\Adapter\Pdo类的Phalcon\Db\Adapter\Pdo\Mysql方法:

namespace Application;

use \PDOException;

class Mysql extends \Phalcon\Db\Adapter\Pdo\Mysql {

    public function executePrepared(statement, placeholders, dataTypes) {

        try {
            !defined('DST') && define('DST', ini_set('default_socket_timeout', 1));
            $stmt = parent::executePrepared(statement, placeholders, dataTypes);
            ini_set('default_socket_timeout', DST ?: 60);
            return $stmt;
        } catch(PDOException $e) {

            if(/* logic to find [2002, 2003, 2005] sql errors */) {
                return $this->executePrepared(statement, placeholders, dataTypes);
            }

            throw $e;
        }
    }
}

并使用它构建db服务。