繁体   English   中英

为SilverStripe网站添加只读副本

[英]Add read replicas for SilverStripe website

我已经设法得到一个稳定的负载平衡前端服务器,可以水平扩展,但下一个瓶颈将是数据库。 有一篇博客文章讨论水平缩放dbs,但很少有细节。 我目前正在使用PostgreSQL,因此我发现的唯一插件无效。

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

我正在使用AWS进行所有托管

首先 - 我很想在此纠正!

只是快速浏览了SilverStripe 3.5站点中的一些ORM类,看起来ORM 确实支持多个数据库连接(请参阅带有参数的DB::get_conn ),它是针对特定用例而设计的。 也就是说,您可能有一个需要写入特定数据库的模块,因此这将允许它。

您想要的是在框架内对此进行原生和自动支持,以便所有读取都转到您的从属设备并写入您的主设备。 不幸的是,它看起来并不像是开箱即用。 您可以通过使用注入器重载几个核心SQL类来实现它。

如果你要尝试它, 这个答案概述了如何将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 ),但这可能会影响该类的其他子实现的查询转换,如果没有(A)PRing,您将无法做很多事情。修复框架或(B)重载所有其他SQL *类。

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

基础设施

在基础结构方面,您应该能够通过RDS控制台设置只读副本。 执行此操作时,它将为您的副本节点提供DNS端点,您可以在_config.php使用该端点来配置与只读副本数据库的连接。


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

您还可以考虑向框架发出pull请求,以向DB::prepared_query等方法添加其他参数以接受连接名称。

另外值得注意的是,如果您正在使用mysqlnd数据库适配器,您可以利用读/写拆分 ,通过某种类型的注入器重载实现,但所有处理都在比应用层更低的级别处理。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM