Звезда не активнаЗвезда не активнаЗвезда не активнаЗвезда не активнаЗвезда не активна
 

Репликация и разделение запросов yii на чтение и запись

Репликация и разделение запросов на чтение и запись

Многие СУБД поддерживают репликацию баз данных для лучшей доступности базы данных и уменьшения времени ответа сервера. С репликацией базы данных, данные копируются из master servers на slave servers. Все вставки и обновления должны происходить на основном сервере, хотя чтение может производится и с подчинённых серверов.



Чтоб воспользоваться преимуществами репликации и достичь разделения чтения и записи, вам необходимо настроить компонент [[yii\db\Connection]] как указано ниже:

[
    'class' => 'yii\db\Connection',

    // настройки для мастера
    'dsn' => 'dsn for master server',
    'username' => 'master',
    'password' => '',

    // общие настройки для подчинённых
    'slaveConfig' => [
        'username' => 'slave',
        'password' => '',
        'attributes' => [
            // используем небольшой таймаут для соединения
            PDO::ATTR_TIMEOUT => 10,
        ],
    ],

    // список настроек для подчинённых серверов
    'slaves' => [
        ['dsn' => 'dsn for slave server 1'],
        ['dsn' => 'dsn for slave server 2'],
        ['dsn' => 'dsn for slave server 3'],
        ['dsn' => 'dsn for slave server 4'],
    ],
]

Вышеуказанная конфигурация определяет систему с одним мастером и несколькими подчинёнными. Один из подчинённых будет подключен и использован для чтения, в то время как мастер будет использоваться для запросов записи. Такое разделение чтения и записи будет осуществлено автоматически с указанной конфигурацией. Например,

// создание экземпляра соединения, использующего вышеуказанную конфигурацию
Yii::$app->db = Yii::createObject($config);

// запрос к одному из подчинённых
$rows = Yii::$app->db->createCommand('SELECT * FROM user LIMIT 10')->queryAll();

// запрос к мастеру
Yii::$app->db->createCommand("UPDATE user SET username='demo' WHERE id=1")->execute();

Info: Запросы выполненные через [[yii\db\Command::execute()]] определяются как запросы на запись, а все остальные запросы через один из "query" методов [[yii\db\Command]] воспринимаются как запросы на чтение. Вы можете получить текущий статус соединения к подчинённому серверу через $db->slave.

Компонент Connection поддерживает балансировку нагрузки и переключение при сбое для подчинённых серверов. При выполнении первого запроса на чтение, компонент Connection будет случайным образом выбирать подчинённый сервер и попытается подключиться к нему. Если сервер окажется "мёртвым", он попробует подключиться к другому. Если ни один из подчинённых серверов не будет доступен, он подключится к мастеру. Если настроить [[yii\db\Connection::serverStatusCache|кеш статуса серверов]], то недоступность серверов может быть запомнена, чтоб не использоваться в течении [[yii\db\Connection::serverRetryInterval|заданного промежутка времени]].

Info: В конфигурации выше, таймаут соединения к подчинённому серверу настроен на 10 секунд. Это означает, что если сервер не ответит за 10 секунд, он будет считаться "мёртвым". Вы можете отрегулировать этот параметр исходя из настроек вашей среды.

Вы также можете настроить несколько основных и несколько подчинённых серверов. Например,

[
    'class' => 'yii\db\Connection',

    // общая конфигурация для основных серверов
    'masterConfig' => [
        'username' => 'master',
        'password' => '',
        'attributes' => [
            // используем небольшой таймаут для соединения
            PDO::ATTR_TIMEOUT => 10,
        ],
    ],

    // список настроек для основных серверов
    'masters' => [
        ['dsn' => 'dsn for master server 1'],
        ['dsn' => 'dsn for master server 2'],
    ],

    // общие настройки для подчинённых
    'slaveConfig' => [
        'username' => 'slave',
        'password' => '',
        'attributes' => [
            // используем небольшой таймаут для соединения
            PDO::ATTR_TIMEOUT => 10,
        ],
    ],

    // список настроек для подчинённых серверов
    'slaves' => [
        ['dsn' => 'dsn for slave server 1'],
        ['dsn' => 'dsn for slave server 2'],
        ['dsn' => 'dsn for slave server 3'],
        ['dsn' => 'dsn for slave server 4'],
    ],
]

Конфигурация выше, определяет два основных и четыре подчинённых серверов. Компонент Connection поддерживает балансировку нагрузки и переключение при сбое между основными серверами, также как и между подчинёнными. Различие заключается в том, что когда ни к одному из основных серверов не удастся подключиться будет выброшено исключение.

Note: Когда вы используете свойство [[yii\db\Connection::masters|masters]] для настройки одного или нескольких основных серверов, все остальные свойства для настройки соединения с базой данных (такие как dsn, username, password) будут проигнорированы компонентом Connection.

По умолчанию, транзакции используют соединение с основным сервером. И в рамках транзакции, все операции с БД будут использовать соединение с основным сервером. Например,

$db = Yii::$app->db;
// Транзакция запускается на основном сервере
$transaction = $db->beginTransaction();

try {
    // оба запроса выполняются на основном сервере
    $rows = $db->createCommand('SELECT * FROM user LIMIT 10')->queryAll();
    $db->createCommand("UPDATE user SET username='demo' WHERE id=1")->execute();

    $transaction->commit();
} catch(\Exception $e) {
    $transaction->rollBack();
    throw $e;
} catch (\Throwable $e) {
    $innerTransaction->rollBack();
    throw $e;
}

Если вы хотите запустить транзакцию на подчинённом сервере, вы должны указать это явно, как показано ниже:

$transaction = Yii::$app->db->slave->beginTransaction();

Иногда может потребоваться выполнить запрос на чтение через подключение к основному серверу. Это может быть достигнуто с использованием метода useMaster():

$rows = Yii::$app->db->useMaster(function ($db) {
    return $db->createCommand('SELECT * FROM user LIMIT 10')->queryAll();
});

Вы также можете явно установить $db->enableSlaves в ложь, чтоб направлять все запросы к соединению с мастером.

Заберите ссылку на статью к себе, чтобы потом легко её найти ;)

Выберите, то, чем пользуетесь чаще всего:

Спасибо за внимание, оставайтесь на связи! Ниже ссылка на форум и обсуждение ; )


Обсудить эту статью

INFO: Вы отправляете сообщение как 'Гость'