MySQL с аварийным переключением соединения ND с PhalconPHP/PDO

В это в части руководства Mysql-nd описывается, как реализовать рекомендуемый способ аварийного переключения при потере соединения с подчиненным сервером MySQL.

Я готов реализовать это в PhalconPHP. Поскольку у меня есть несколько важных проектов, использующих Phalcon и Mysql-nd, для меня очень важно сделать это в нужном месте.

Пытаюсь найти документацию, но не могу найти ни одного примера, с которого можно было бы даже начать. Пытался найти подход EventManager, просматривая документацию Phalcon здесь и здесь, но не могу найти способ сделать это прозрачно.

Наиболее привлекательным способом было бы использование менеджера событий для захвата события ошибки и запросите то же самое снова, если ошибка соединения.

1 ОБНОВЛЕНИЕ

Прочитав некоторые источники Phalcon, я обнаружил, что может быть невозможно запустить один и тот же запрос во второй раз стандартным способом - я имею в виду здесь через какой-то параметр PDO или с помощью Phalcons EventManager, прикрепленного к db сервису. Одна возможная попытка, которую я нашел, - фактически запустить любой запрос после события db:afterConnection, но это не решение.

2 ОБНОВЛЕНИЕ

db:afterConnection труднодоступен, зато можно собрать все во время db:beforeQuery. Проблема в том, что PDO запускается Phalcon с PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, поэтому, когда соединение с подчиненным обрывается, он не может достичь события db:afterConnection. Можно получить экземпляр PDO во время db:beforeQuery и изменить этот атрибут через EventManager, но это ничего не даст, потому что даже если я смогу отправить тот же запрос во второй раз, я не могу найти способ вернуть его в нужном месте (не могу переопределить результат запроса во время 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);
    }

person yergo    schedule 07.01.2016    source источник


Ответы (1)


На данный момент это кажется исправленным с конфигурацией:

{
    "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\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.

person yergo    schedule 11.01.2016