1

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

我愿意在 PhalconPHP 中实现它。因为我有几个使用 Phalcon 和 Mysql-nd 的重要项目,所以在正确的地方做这件事对我来说非常重要。

试图找到一些文档,但找不到任何可以开始的示例。试图找到 EventManager 方法,在这里查看 Phalcon 文档和此处查看 Phalcon 文档,但找不到透明的方法。

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

1 更新

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

2 更新

db:afterConnection几乎无法到达,而是可以在db:beforeQuery. 问题是,PDO 由 Phalcon 运行PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,因此当与从属设备的连接断开时,它无法到达db:afterConnection事件。可以通过 获取 PDO 实例db:beforeQuery并更改此属性EventManager,但它什么也没提供,因为即使我能够第二次发送相同的查询,我也找不到将其返回到适当位置的方法(无法覆盖查询结果during db:afterQuery)因为获取的语句不是事件发送的一部分,并且 Eventmanager 结果根本没有被使用

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

1 回答 1

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 源连接到编写推荐的解决方案.

更新

可以通过扩展类覆盖类中的executePrepared方法:Phalcon\Db\Adapter\PdoPhalcon\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服务。

于 2016-01-11T11:23:52.093 回答