在Mysql-nd手册的this部分中描述了如何在失去与从属MySQL服务器的连接时实现推荐的故障转移方式。
我愿意在PhalconPHP中实施它。由于我有几个使用Phalcon和Mysql-nd的重要项目,因此在正确的位置进行此操作非常重要。
试图找到一些文档,但无法找到任何开头的例子。试图找到EventManager方法,查看Phalcon文档here和here,但无法透明地找到方法。
最有吸引力的方法是使用event manager来捕获错误事件,并在连接错误时再次查询错误事件。
在阅读了一些Phalcon来源后,我发现,可能无法以标准方式第二次运行相同的查询 - 我的意思是通过某种PDO参数或使用Phalcons' EventManager
附加db
服务。我发现的一种可能的尝试是在db:afterConnection
事件后实际运行任何查询,但它不是解决方案。
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);
}
答案 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
服务。