4

我们在 Symfony 1.4/ Propel 1.4 中有一个现有项目(SNS 网站+android/Iphone 游戏)

我们在数据库服务器(比如 DB1)上遇到了额外的负载。我们正在做 DB 优化,但作为直接的解决方案,我们决定再创建一个 DB 服务器,因为 DB2 始终是 DB1 的精确副本。目前我们只有 DB1,用于读写操作。

现在我们需要将所有读取操作移至 DB2,并保持 DB1 上的写入操作(通常在事务中)与现在一样。

进行这些更改的可能方法是什么(在没有太多停机时间的生产服务器上),如果可能的话,只需最少的代码更改。

在第一条评论后编辑

基于 J0k 和其他一些链接给出的链接,我已经在本地开发环境中完成了以下操作。

  1. 创建了一个测试 symfony 1.4 项目
  2. 更新 database.yml 如下

    all:
      propel:
        class: sfPropelDatabase
        param:
          classname: PropelPDO
          dsn: 'mysql:host=localhost;dbname=wzo;'
          username: root
          password: mysql
          encoding: utf8
          persistent: true
          pooling: true
        slaves:
          slave1:
            dsn:      'mysql:host=localhost;dbname=wzoslv;'
            username: root
            password: mysql
            encoding: utf8
    

    其中数据库wzoslv是数据库的精确副本,wzo除了一个测试条目中的更改。在表格odd_play第 26 行 (PK) 列result条目是WON1WON分别。

  3. 运行 symfony 任务

    php symfony propel:build-schema
    php symfony propel:build-model
    php symfony cc
    
  4. 创建了一个模块并添加了以下代码:

    class wzoActions extends sfActions
    {
      public function executeIndex(sfWebRequest $request)
      {
        $con_write = Propel::getConnection(OddPlayPeer::DATABASE_NAME, Propel::CONNECTION_WRITE);
        $con_read = Propel::getConnection(OddPlayPeer::DATABASE_NAME, Propel::CONNECTION_READ);
        $oddPlay = OddPlayPeer::retrieveByPK(26,0,$con_write);
        echo "on write connection, result=".$oddPlay->getResult();
        $oddPlayRead = OddPlayPeer::retrieveByPK(26,0,$con_read);
        echo "<br/>on Read connection, result=".$oddPlayRead->getResult();
        exit;
        $this->setLayout('layout');
      }
    }
    

    在浏览器中运行http://local.sftest.com/index.php/wzo/index,输出是,

    on write connection, result=WON //正确的预期输出

    on Read connection, result=WON //不正确。那应该是 WON1

我想OddPlayPeer::DATABASE_NAME在创建读/写连接时通过是问题,但在线示例中是如何建议的。有人可以建议我在哪里犯错吗?

编辑:更多输入

我更新了调试回声lib\vendor\symfony\lib\plugins\sfPropelPlugin\lib\vendor\propel\Propel.php以检查它是如何返回连接的。发现它正在进入以下 if(第 544-549 行)

$slaveconfigs = isset(self::$configuration['datasources'][$name]['slaves']) ? self::$configuration['datasources'][$name]['slaves'] : null;

if (empty($slaveconfigs)) {
  echo "inelseifif<br/>";// no slaves configured for this datasource
  self::$connectionMap[$name]['slave'] = false;
  return self::getConnection($name, Propel::CONNECTION_WRITE); // Recurse to get the WRITE connection
}

哪里$slaveconfigs是空的,所以返回写连接。现在的问题是,为什么 slaveconfigs 是空的?

我还尝试按照旧论坛中的定义编辑 sfDatabaseConfigHandler.class.php,但这样做会在某处破坏 symfony,并且不会在 Web 甚至日志中显示任何内容。

4

2 回答 2

4

我确定我犯了一些错误,但无论在 Propel/symfony 的官方文件中,甚至在 stackoverflow 上,似乎都对我不起作用。可能官方文档应该更好地照顾没有很多symfony经验的程序员。

虽然我们不喜欢编辑任何框架/第三方库的核心文件,但这迫使我编辑核心文件来为我制定一个可行的解决方案。对我有用的解决方案如下:

database.yml 我的 database.yml 文件如下:

all:
  propel:
    class: sfPropelDatabase
    param:
      classname: PropelPDO
      dsn: 'mysql:host=localhost;dbname=wzo;'
      username: testuserwzo
      password: 
      encoding: utf8
      persistent: true
      pooling: true

  slave:
    class: sfPropelDatabase
    param:
      classname: PropelPDO
      dsn: 'mysql:host=localhost;dbname=wzoslv;'
      username: testuserwzoslv
      password: 
      encoding: utf8
      persistent: true
      pooling: true

之后,我编辑了 Propel.php 文件如下

对于 Propel 1.4
文件:lib/vendor/symfony/lib/plugins/sfPropelPlugin/lib/vendor/propel/Propel.php
更改行 542-543

// we've already ensured that the configuration exists, in previous if-statement
$slaveconfigs = isset(self::$configuration['datasources'][$name]['slaves']) ? self::$configuration['datasources'][$name]['slaves'] : null;

with(中间加一行)

// we've already ensured that the configuration exists, in previous if-statement
self::$configuration['datasources'][$name]['slaves'] = isset(self::$configuration['datasources']['slave']) ? self::$configuration['datasources']['slave'] : null;
$slaveconfigs = isset(self::$configuration['datasources'][$name]['slaves']) ? self::$configuration['datasources'][$name]['slaves'] : null;

然后在同一个文件中,更改了第 560 行

$con = Propel::initConnection($conparams, $name);

$con = Propel::initConnection($conparams, 'slave'); //I know its bad practive to put hard-coded value but at that moment, I was more interested in working solution without caring about best practices.

对于 propel 1.6(我们升级了 propel 只是为了使它工作,但后来又恢复到 propel 1.4,因为生产升级需要经过良好测试。)
文件:plugins/sfPropelORMPlugin/lib/vendor/propel/runtime/lib/Propel.php
已更改601行

$slaveconfigs = isset(self::$configuration['datasources'][$name]['slaves']) ? self::$configuration['datasources'][$name]['slaves'] : null;

to(之前加了一行)

self::$configuration['datasources'][$name]['slaves'] = isset(self::$configuration['datasources']['slave']) ? self::$configuration['datasources']['slave'] : null;
$slaveconfigs = isset(self::$configuration['datasources'][$name]['slaves']) ? self::$configuration['datasources'][$name]['slaves'] : null;

然后在同一个文件中,更改了第 629 行

$con = Propel::initConnection($conparams, $name);

$con = Propel::initConnection($conparams, 'slave');

然后下面的测试文件给出了预期的结果

class kapsActions extends sfActions
{
  public function executeIndex(sfWebRequest $request)
  {
      $con_write = Propel::getConnection(OddPlayPeer::DATABASE_NAME, Propel::CONNECTION_WRITE);
      $con_read = Propel::getConnection(OddPlayPeer::DATABASE_NAME, Propel::CONNECTION_READ);

      $oddPlay = OddPlayPeer::retrieveByPK(28,0,$con_write);
      echo "on write connection, result=".$oddPlay->getResult().$oddPlay->getPlayscore();

      $oddPlayRead = OddPlayPeer::retrieveByPK(27,0,$con_read);
      echo "<br/>on Read connection, result=".$oddPlayRead->getResult().$oddPlayRead->getPlayscore();
      exit;
      //$this->setLayout('layout');
  }
}

我仍然不建议编辑核心文件,但这个解决方案在紧急情况下对我们有用。如果需要,其他人可以在紧急情况下使用它。仍在寻找完美的解决方案。

于 2012-11-07T04:02:55.627 回答
1

根据文档(在 github 上) ,您应该添加一个新级别来slaves添加一个connection条目

all:
  propel:
    class: sfPropelDatabase
    param:
      classname: PropelPDO
      dsn: 'mysql:host=localhost;dbname=wzo;'
      username: root
      password: mysql
      encoding: utf8
      persistent: true
      pooling: true

      slaves:
        connection:
          slave1:
            dsn:      'mysql:host=localhost;dbname=wzoslv;'
            username: root
            password: mysql
            encoding: utf8
于 2012-11-06T10:19:37.557 回答