Episodio 1 · día 1, 9:00

El día de cobro

lectura · 12 mindominio · BCPS Bankoperación · lecturas del día de cobro

Todo el mundo mira su saldo a la vez

Es día 1 y son las nueve de la mañana. Las empresas han mandado las nóminas y, en BCPS Bank, miles de personas abren la app a la vez para comprobar si ya ha llegado la suya. Cada una mira su saldo, baja por los movimientos y, por si acaso, vuelve a mirar.

Todas esas consultas acaban en el mismo sitio: la base de datos de Cuentasver en el mapa, la que guarda el libro de movimientos y los saldos. Es la misma base de datos en la que, en ese momento, se están apuntando las nóminas que entran y los pagos que autoriza Tarjetasver en el mapa, porque la gente, en cuanto cobra, paga.

La base de datos no distingue entre una consulta curiosa y un abono de 1.800 €: atiende lo que le llega por orden. Y esta mañana le llegan, por cada escritura, más de diez lecturas. Esta serie trata de sacar esas lecturas de ahí: primero a una copia idéntica, y al final a un sistema con otro modelo. Cada paso alivia a la base de datos principal y cada paso lee un dato más viejo. La tira de arriba es el mapa del camino.

Repartir las lecturas

La app, Tarjetas y la entrada de nóminas piden cosas a Cuentas, y Cuentas decide a qué base de datos va cada una. El primario es la base de datos que acepta escrituras: tiene 8 trabajadores (las casillas), y cada uno hace una cosa a la vez. A la izquierda, todo va al primario. A la derecha, Cuentas tiene réplicas, copias que el primario mantiene al día, y manda allí las consultas de la app.

Debajo de cada diagrama, dos cifras que verás en toda la serie: la carga del primario y la edad del dato que lee la app. Pulsa Arrancar y compáralas. Luego sube y baja el número de réplicas, prueba el lote de nóminas y, con Tarjetas leyendo de una réplica, haz que Ana pague dos veces.

Qué ha pasado

Las lecturas se comen al primario

El día de cobro, la app manda 170 consultas por segundo y entran unas 24 escrituras: las nóminas y los cargos de los pagos.probar en el laboratorio Una lectura es más barata que una escritura, pero hay tantas que, a la izquierda, se quedan con todos los trabajadores del primario. Lo que llega después hace cola, y la cola no distingue: la nómina de alguien espera detrás de la décima consulta de saldo de otro. La barra de carga se pone roja y la espera de las escrituras pasa de 0,3 s a varios segundos, y sigue creciendo mientras dure el pico. Si una petición espera más de cinco segundos, quien la mandó se rinde: son las fallidas.

Lo curioso es que casi nada de ese trabajo necesita al primario. Quien mira su saldo en la app no va a notar si el dato tiene medio segundo. Solo hace falta el primario para escribir, y para las pocas lecturas con las que se decide algo.

Read/write splitting

A la derecha, Cuentas separa: las escrituras van al primario y las consultas de la app, a las réplicas. Es el read/write splitting. Cada réplica recibe los cambios del primario a través de su WAL, el registro donde el primario apunta cada cambio antes de hacerlo, y los aplica en el mismo orden. Tiene los mismos datos, con el mismo esquema, y puede contestar las mismas consultas.

Con dos réplicas, cada una atiende la mitad de las consultas y va holgada, y el primario baja a una cuarta parte de su capacidad: las escrituras vuelven a tardar lo de siempre. Con una sola réplica, la réplica va justa. Con tres, sobra. Quien reparte las consultas entre réplicas es un balanceador: aquí, el propio código de Cuentas, que las manda por turnos.

El precio se lee en la otra cifra del marcador. A la izquierda, cada lectura sale del primario: está al día. A la derecha, la app lee lo que la réplica tenga en ese momento. La réplica 1 va 0,2 s por detrás del primario, casi nada. La réplica 2 va 2,5 s por detrás, porque está en otra sala con la red más cargada, y hoy nadie lo ha notado. Quien lee de ella ve el saldo de hace dos segundos y medio. Volveremos a ella en el episodio 3.

El giro: las réplicas no escriben

A media mañana, una gran empresa manda de golpe las nóminas de toda su plantilla: 90 escrituras por segundo.probar en el laboratorio Ahora los dos paneles se saturan, aunque la derecha tenga tres réplicas. Cada escritura tiene que hacerse en el primario, porque es el único que acepta escrituras, y además hay que copiarla a cada réplica. Añadir réplicas multiplica la capacidad de leer, no la de escribir.

Contra un pico de escrituras hacen falta otras cosas: agrupar escrituras, encolarlas para hacerlas a su ritmo (el colchón de la cola de la serie de eventos) o repartir los datos entre varios primarios, cada uno con sus cuentas, que es el sharding. Es otra historia, la del bloque de datos a escala del catálogo.

Cuándo hace daño: el saldo con el que se decide

Viendo lo bien que va, alguien propone que Tarjetas también lea el saldo de las réplicas: al fin y al cabo, autorizar un pago empieza por leer un saldo.probar en el laboratorio Ana tiene 60 € en la cuenta de gastos. Paga 50 € en el súper y, un segundo después, 40 € en la gasolinera. A la izquierda, el segundo pago se deniega: quedan 10 €. A la derecha, la segunda lectura cae en la réplica 2, que todavía no se ha enterado del primer pago, ve 60 € y autoriza. La cuenta queda en −30 €.

Hay una diferencia más, y no es de edad. Cuando Tarjetas lee del primario, puede leer el saldo y apuntar el cargo en la misma transacción: nadie más puede gastar ese dinero entre medias (la serie de consistencia cuenta cómo). Cuando lee de una réplica, son dos operaciones en dos bases de datos distintas, y entre una y otra pasa el tiempo que la réplica vaya por detrás. Por eso la regla es sencilla: las lecturas que deciden algo van al primario. Son pocas, así que caben.

Criterio

No se elige entre primario y réplicas: se elige para cada lectura. La pregunta es qué pasa si el dato llega con unos segundos de retraso.

LecturaDe dóndePor qué
Saldo para autorizar un pago o una retiradaPrimario, en la misma transacción que el cargoDecide algo que no se puede deshacer; un dato viejo es un descubierto
Saldo y últimos movimientos en la appRéplicaSon la mayoría de las lecturas; medio segundo no cambia nada… salvo justo después de que escribas tú (episodio 3)
Informes y extractosNi una ni otra (episodio 5)Leen muchísimo y se pueden quedar con una réplica entera
Cualquier escrituraPrimarioEs el único que las acepta; las réplicas no ayudan a escribir
  1. ¿Con lo que lees se va a decidir algo (autorizar, rechazar, mover dinero)?El saldo de Ana antes de la gasolinera.
    primario
  2. ¿El primario va holgado incluso en el peor momento?Un día normal, al 26 %; el día de cobro, saturado.
    primario: aún no hacen falta réplicas
  3. ¿Lo que satura son las escrituras?El lote de nóminas.
    las réplicas no ayudan
  4. Réplicas de lectura, sabiendo que la app leerá un dato de hace un momento (y con cuidado justo después de que escribas, episodio 3).

Tener réplicas no es gratis: cada una es una base de datos más que mantener y vigilar, y el código tiene que saber a dónde manda cada cosa. Si el primario va holgado todo el año salvo un rato el día 1, una caché delante de las consultas más repetidas puede bastar (el bloque de caché del catálogo). Y si lo que satura son las escrituras, las réplicas no son la respuesta.

En el mundo real

Casi todas las bases de datos relacionales traen réplicas de lectura. En PostgreSQL es la streaming replication con réplicas en modo hot standby, que aceptan consultas mientras aplican el WAL; en MySQL, la replicación desde el binlog. Los servicios gestionados lo reducen a un botón: Amazon RDS permite hasta quince réplicas de lectura por instancia, y Aurora da un reader endpoint que reparte las conexiones entre ellas.

El reparto se hace en dos sitios. En la aplicación: Rails tiene desde la versión 6 roles writing y reading y cambia de conexión según la petición, y Django permite escribir un database router que decide a qué base de datos va cada consulta. O en un proxy entre la aplicación y la base de datos: ProxySQL para MySQL y Pgpool-II para PostgreSQL separan lecturas y escrituras mirando cada sentencia. El proxy no conoce el negocio, así que no sabe qué lectura decide algo: suele hacer falta marcarlas.

La regla de leer del primario lo que decide la aplica cualquier sistema con dinero de por medio. Y lo de la réplica 2 que va por detrás sin que nadie lo note pasa a menudo: por eso se vigila el replication lag de cada réplica y se saca del reparto la que se queda atrás. GitHub, por ejemplo, frena las escrituras masivas cuando sus réplicas de MySQL empiezan a retrasarse, con una herramienta que publicó como código abierto, freno.

Siguiente episodio

Las réplicas sirven para algo más que para leer: son el repuesto del primario. Si el primario se cae, una de ellas pasa a ocupar su sitio. Pero una réplica va siempre un poco por detrás, y lo que el primario confirmó y la réplica no tenía, ¿dónde está?

Episodio 2 Si cae el primario Replicación asíncrona, semi-síncrona y síncrona: cuándo dice «hecho» el primario y qué se pierde si se cae justo después.

← Todos los episodios · Cuentas en el mapa de BCPS Bank