Saltar al contenido

Cuando tu aplicación Laravel crece y comienza a manejar más usuarios, una de las primeras optimizaciones que debes considerar es distribuir la carga de tu base de datos. Laravel ofrece una funcionalidad nativa elegante para separar operaciones de lectura y escritura: las conexiones Read/Write.

En este artículo te explico cómo configurar y aprovechar esta funcionalidad para escalar tu aplicación de manera efectiva.

¿Por qué separar lecturas y escrituras?

En la mayoría de aplicaciones web, el 80% del tráfico son operaciones de lectura (SELECT) y solo el 20% son escrituras (INSERT, UPDATE, DELETE). Esta distribución desigual crea oportunidades de optimización:

  • Mejor rendimiento: Las lecturas pueden distribuirse entre múltiples servidores

  • Escalabilidad horizontal: Puedes agregar más servidores de lectura según crezcas

  • Menos contención: Las escrituras no compiten con lecturas por recursos

Configurando Read/Write en Laravel

Laravel hace increíblemente fácil implementar esta separación. Solo necesitas configurar tu conexión de base de datos con hosts específicos para lectura y escritura:

<?php

// config/database.php
'mysql' => [
    'read' => [
        'host' => [
            '192.168.1.10', // Servidor de lectura principal
            '192.168.1.11', // Servidor de lectura secundario
        ],
    ],
    'write' => [
        'host' => [
            '192.168.1.5', // Servidor de escritura (Master)
        ],
    ],
    'sticky' => true,
    
    // Configuración compartida
    'driver' => 'mysql',
    'port' => '3306',
    'database' => env('DB_DATABASE', 'laravel'),
    'username' => env('DB_USERNAME', 'forge'),
    'password' => env('DB_PASSWORD', ''),
    'charset' => 'utf8mb4',
    'collation' => 'utf8mb4_unicode_ci',
    'prefix' => '',
    'strict' => true,
    'engine' => null,
],

Cómo funciona automáticamente

Una vez configurado, Laravel maneja toda la lógica automáticamente:

<?php

// Estas operaciones van automáticamente al servidor WRITE
User::create(['name' => 'Juan', 'email' => '[email protected]']);
Post::where('id', 1)->update(['title' => 'Nuevo título']);
Comment::destroy(5);

// Estas operaciones van automáticamente al servidor READ
$users = User::all();
$posts = Post::where('published', true)->get();
$comments = Comment::with('user')->paginate(15);

No necesitas cambiar tu código existente. Laravel detecta automáticamente el tipo de operación y usa la conexión apropiada.

La opción Sticky: ¿Qué es y cuándo usarla?

La opción sticky es crucial para evitar problemas de consistencia:

<?php

'sticky' => true,

Sin sticky (false):

<?php

// Usuario crea un post
$post = Post::create(['title' => 'Mi nuevo post']); // Va a WRITE

// Inmediatamente intenta verlo
$post = Post::find($post->id); // Va a READ (¡podría no estar sincronizado aún!)

Con sticky (true):

<?php

// Usuario crea un post
$post = Post::create(['title' => 'Mi nuevo post']); // Va a WRITE

// Inmediatamente intenta verlo
$post = Post::find($post->id); // Sigue usando WRITE en esta request

Recomendación: Siempre usa sticky => true en producción.

Implementación en tu Service Layer

Para tener máximo control, puedes manejar las conexiones explícitamente en tu Service Layer:

<?php

class PostService
{
    public function createPost(array $data): Post
    {
        // Escrituras explícitas al Master
        return DB::connection('mysql')->transaction(function () use ($data) {
            return Post::create($data);
        });
    }
    
    public function getPublishedPosts(): Collection
    {
        // Lecturas pueden ir a cualquier READ server
        return Post::where('published', true)
                   ->latest()
                   ->get();
    }
    
    public function getPostStats(): array
    {
        // Queries pesadas van a READ servers
        return [
            'total' => Post::count(),
            'published' => Post::where('published', true)->count(),
            'avg_comments' => Post::withCount('comments')->avg('comments_count'),
        ];
    }
}

Variables de entorno para diferentes entornos

Para manejar múltiples entornos fácilmente:

# .env.production
DB_READ_HOST_1=replica1.myapp.com
DB_READ_HOST_2=replica2.myapp.com
DB_WRITE_HOST=master.myapp.com

# .env.local
DB_READ_HOST_1=127.0.0.1
DB_WRITE_HOST=127.0.0.1
<?php

'read' => [
    'host' => array_filter([
        env('DB_READ_HOST_1'),
        env('DB_READ_HOST_2'),
        env('DB_READ_HOST_3'),
    ]),
],
'write' => [
    'host' => [env('DB_WRITE_HOST', '127.0.0.1')],
],

Monitoreo y debugging

Para verificar que todo funciona correctamente, puedes usar eventos de Laravel:

<?php

use Illuminate\Support\Facades\DB;
use Illuminate\Database\Events\QueryExecuted;

public function boot()
{
    DB::listen(function (QueryExecuted $query) {
        if (app()->environment('local')) {
            $connection = $query->connection->getName();
            Log::info("Query on {$connection}: {$query->sql}");
        }
    });
}

El requisito previo: Replicación MySQL

Aquí está el detalle importante que muchos developers pasan por alto: para que las conexiones Read/Write funcionen correctamente, necesitas tener configurada previamente la replicación MySQL entre tus servidores.

Laravel maneja el enrutamiento de consultas, pero no configura la sincronización de datos. Necesitas:

  • Un servidor Master configurado para replicación

  • Uno o más servidores Replica sincronizados automáticamente

  • Usuarios de base de datos con permisos apropiados

  • Monitoreo de la sincronización

Si nunca has configurado replicación MySQL desde cero, puede parecer intimidante. Involucra configuración de archivos my.cnf, binary logs, usuarios de replicación, y comandos específicos de MySQL.

Para developers que quieren aprender este proceso completo, desde la configuración de MySQL Master-Replica hasta su integración con Laravel, he creado un curso práctico: Master-Replica MySQL con Laravel y Docker. En una hora cubrimos todo el setup usando Docker, verificaciones de funcionamiento, y mejores prácticas para producción.

Conclusión

Las conexiones Read/Write de Laravel son una herramienta poderosa para escalar aplicaciones, pero son solo una pieza del puzzle. Combinadas con una infraestructura de replicación MySQL bien configurada, pueden mejorar significativamente el rendimiento de tu aplicación.

Lo mejor de esta funcionalidad de Laravel es su transparencia: una vez configurada, tu código existente funcionará automáticamente con la nueva arquitectura, sin necesidad de refactoring masivo.


Recursos adicionales:

school Curso completo

Curso Laravel 12
Completo 2026

El único curso 100% actualizado que incluye Laravel 12, Livewire 3, Vue 3, React 19 e Inertia 2. Aprende con proyectos reales y las últimas funcionalidades.

access_time 8 horas de contenido
layers 4 tecnologías en 1
update 100% actualizado
code Proyectos prácticos
Ver Curso Laravel 12 arrow_forward

star Incluido en cualquier suscripción

Rutas de aprendizaje