gpt4 book ai didi

php - 为 SilverStripe 网站添加只读副本

转载 作者:搜寻专家 更新时间:2023-10-31 21:22:51 24 4
gpt4 key购买 nike

我已经设法获得了一个稳定的负载平衡前端服务器,它可以很好地水平扩展,但下一个瓶颈将是数据库。有一个 blog post讨论水平扩展数据库,但很少详细说明。我目前正在使用 PostgreSQL,所以唯一的 plugin我发现行不通了。

我唯一的选择是创建自己的 HAProxy 还是重写 PostgreSQL 插件以允许与只读副本的连接?

我的所有托管都使用 AWS

最佳答案

首先 - 我很乐意得到纠正!

仅快速浏览了 SilverStripe 3.5 站点中的一些 ORM 类,看起来 ORM 确实支持多个数据库连接(参见 DB::get_conn with argument for name) 它是为特定的用例而设计的。也就是说,您可能有一个模块需要写入特定的数据库,所以这将允许它。

您想要的是在框架内对此提供 native 和自动支持,以便所有读取都转到您的奴隶,而写入则转到您的主人。不幸的是,这看起来并不是开箱即用的。您可以通过使用注入(inject)器重载几个核心 SQL 类来实现它。

如果您要尝试this answer概述了如何将 select 语句与其余语句分开并通过不同的数据库连接器运行它们。

作为您如何使用 SQLSelect 实现此目的的快速示例,您会注意到它是可注入(inject)的,这意味着您可以轻松地重载它。

文件: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(),否则你最终会得到一些仍然命中的查询主服务器,因为它会通过不使用注入(inject)器来绕过你的类。

SQLConditionalExpression 中还有一个实例,您也应该替换它 (::toSelect),但这可能会影响该类的其他子实现的查询转换,并且如果不 (A) 对框架进行 PR 修复或 (B) 重载所有其他 SQL* 类,您将无能为力。

此时,您应该拥有将选择查询路由到您的 default_read 连接所需的一切。

基础设施

在基础架构方面,您应该能够通过 RDS 控制台设置只读副本。当您这样做时,它将为您的副本节点提供一个 DNS 端点,您可以在 _config.php 中使用它来配置与只读副本数据库的连接。


如果这对你有用,你应该为它创建一个模块并将它放在 GitHub 上——这肯定对将来的其他人有用!

您还可以考虑向框架发出拉取请求,以向方法添加额外的参数,例如 DB::prepared_query 以接受连接名称。

另外值得注意的是,如果您使用的是 mysqlnd 数据库适配器,您可以利用 read/write splitting ,通过某种注入(inject)器重载实现,但都在低于应用程序层的级别处理。

关于php - 为 SilverStripe 网站添加只读副本,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42756756/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com