Connexion master/slave avec Doctrine

Cet article a été publié depuis plus de 6 mois, cela signifie que le contenu peut ne plus être d'actualité.

Pour optimiser les performances d'une application, il arrive que l'on mette en place une architecture type master/slave. Ce type de fonctionnement consiste à mettre en place un serveur maître, répliqué sur un serveur esclave. Les accès à la base de données sont ensuite séparées: les opérations de lecture s'effectuent sur l'instance répliquée alors que les écritures se font sur le serveur maître.

Mettre en place ce type de fonctionnement en PHP lorsque l'on utilise Doctrine est très simple puisque la bibliothèque a prévu ce mode de fonctionnement. Pour cela, il est nécessaire de spécifier le type de connexion à utiliser au travers du paramètre wrapperClass et de décrire comment se connecter aux différents serveurs.

$connection = Doctrine\DBAL\DriverManager::getConnection([
    'wrapperClass' => 'Doctrine\DBAL\Connections\MasterSlaveConnection',
    'driver' => 'pdo_mysql',
    'master' => ['user' => '', 'password' => '', 'host' => '', 'dbname' => ''],
    'slaves' => [
        ['user' => 'slave1', 'password', 'host' => '', 'dbname' => ''],
        ['user' => 'slave2', 'password', 'host' => '', 'dbname' => ''],
    ]
]);

La configuration de la connexion s'effectue au sein de DBAL (la couche d'abstraction d'accès à la base de données du projet). Cette configuration est donc également possible au niveau de Doctrine ORM ainsi que son implémentation dans les frameworks Zend et Symfony.

Par exemple, pour utiliser ce mode de connexion à la base de données dans un projet Symfony, il suffira d'ajouter la configuration suivante :

# app/config/config.yml
doctrine:
    dbal:
        driver:   %database_driver%
        host:     %database_host%
        port:     %database_port%
        dbname:   %database_name%
        user:     %database_user%
        password: %database_password%
        slaves:
            slave1:
                host:     %database_host_slave1%
                port:     %database_port_slave1%
                dbname:   %database_name_slave1%
                user:     %database_user_slave1%
                password: %database_password_slave1%


            slave2:
                host:     %database_host_slave2%
                port:     %database_port_slave2%
                dbname:   %database_name_slave2%
                user:     %database_user_slave2%
                password: %database_password_slave2%

Lors de l'utilisation de la connexion MasterSlaveConnection, il est important de noter les opérations qui seront effectuées sur la base maître et sur la base esclave. Par exemple, l'appel aux méthodes exec, executeUpdate, insert, delete, update, createSavepoint, releaseSavepoint, beginTransaction, rollback, commit, query et prepare s'exécuteront sur la base maître.

Pour lire des données depuis les connexions secondaires, il sera nécessaire d'utiliser la méthode executeQuery. Lors de cette action, un serveur "esclave" sera choisi aléatoirement.

Il est également important de noter qu'il est possible de faire une opération d'écriture sur les serveurs esclaves si la requête effectuée n'ouvre pas de transaction. Il est tout à fait possible d'écrire le code suivant : $connection->executeQuery("DELETE FROM table");.