我设法获得了一个稳定的负载平衡前端服务器,可以水平扩展,但下一个瓶颈将是数据库。有一个blog post在水平方向上讨论dbs,但是它的细节很少。我目前正在使用PostgreSQL,因此我发现的唯一plugin无效。
我唯一的选择是创建自己的HAProxy还是重写PostgreSQL插件以允许与只读副本连接?
我使用AWS进行所有托管
答案 0 :(得分:1)
首先 - 我很乐意纠正这个问题!
只快速查看SilverStripe 3.5站点中的某些ORM类,看起来好像ORM 支持多个数据库连接(请参阅DB::get_conn
,其中包含名称参数)它是专为特定用例而设计的。也就是说,您可能有一个需要写入特定数据库的模块,因此可以使用它。
您想要的是在框架内对此进行原生和自动支持,以便所有读取都转到您的从属设备并写入到您的主设备。不幸的是,它看起来并不像是开箱即用。您可以通过使用注入器重载几个核心SQL类来实现它。
如果你尝试它,this answer概述了如何将select语句与其余语句分开,并通过不同的数据库连接器运行它们。
作为如何使用SQLSelect
实现此目标的简单示例,您会注意到它是可注射的,这意味着您可以轻松地使其超载。
文件:mysite / _config / injector.yml
Injector:
SQLSelect:
class: ReadOnlySQLSelect
您需要使用DB类注册新的数据库连接:
文件:mysite / _config.php
$readDatabaseConfig = array(/** define your DB credentials here, as with the default $databaseConfig **/);
if (!DB::connect($readDatabaseConfig, 'default_read')) {
user_error('Failed to connect to read replica DB!', E_USER_ERROR);
}
现在,重载SQLSelect
类并替换调用DB类方法的部分。此类继承自SQLExpression
,该类包含您在此实例中实际关注的方法:
文件:mysite / code / ReadOnlySQLSelect.php
class ReadOnlySQLSelect extends SQLSelect
{
public function sql(&$parameters = array())
{
// Changed from SQLExpression: third parameter passed as connection name
$sql = DB::build_sql($this, $parameters, 'default_read');
if (empty($sql)) {
return null;
}
if ($this->replacementsOld) {
$sql = str_replace($this->replacementsOld, $this->replacementsNew, $sql);
}
return $sql;
}
public function execute()
{
$sql = $this->sql($parameters);
// Changed from SQLExpression: skip DB::prepared_query since it doesn't allow
// you to provide the connection name - replace it with its contents instead.
$conn = DB::get_conn('default_read');
return $conn->preparedQuery($sql, $parameters);
}
}
注意: SQLSelect::unlimitedRowCount
在技术上应该在它调用DB::prepared_query
的地方被替换,因为准备好的查询方法调用DB::get_conn
没有参数,因此将始终返回默认连接。您可以将DB::prepared_query
行替换为与上面使用的相同:
$conn = DB::get_conn('default_read');
$result = $conn->preparedQuery($sql, $innerParameters);
如果您实施上述方法,也请将new SQLSelect()
更改为SQLSelect::create()
,否则您最终会遇到仍然遇到主服务器的一些查询,因为它会绕过您的班级不使用注射器。
SQLConditionalExpression
中还有一个你应该替换的实例(::toSelect
),但这可能会影响该类的其他子实现的查询转换,并且你赢了#39在没有(A)修复框架修复或(B)重载所有其他SQL *类的情况下,能够做很多事情。
此时,您应该拥有将选择查询路由到default_read
连接所需的一切。
在基础结构方面,您应该能够通过RDS控制台设置只读副本。执行此操作时,它将为您的副本节点提供DNS端点,您可以在_config.php
中使用该端点配置与只读副本数据库的连接。
如果这对您有用,您应该为它创建一个模块并将其放在GitHub上 - 这对其他人来说肯定会有用!
您还可以考虑向框架发出拉取请求,以便为DB::prepared_query
等方法添加其他参数以接受连接名称。
另外值得注意的是,如果您正在使用mysqlnd数据库适配器,您可以利用read/write splitting,通过某种注入器重载实现,但所有处理都低于应用程序层