¿Por qué la base de datos como cola es tan mala? [cerrado]

33

Acabo de leer este artículo y estoy confundido.

Imaginemos 1 aplicación web y 1 aplicación distinta que actúe como "trabajador", ambas compartiendo la misma base de datos .

Oh, dije "compartir" ... pero ¿de qué advierte el artículo? :

Cuarto, compartir una base de datos entre aplicaciones (o servicios) es algo malo. Es demasiado tentador poner un estado amorfo compartido allí y antes de que te des cuenta tendrás un monstruo enormemente acoplado.

=> en desacuerdo. Hay algunos casos en los que distintas aplicaciones siguen siendo parte de la misma unidad y, por lo tanto, la noción de "problema de acoplamiento" no tiene sentido en este caso.

Continuemos: la aplicación web maneja las solicitudes HTTP del cliente y puede actualizar en cualquier momento algunos agregados (término DDD), generando los eventos de dominio correspondientes.
El objetivo del trabajador sería manejar esos eventos de dominio procesando los trabajos necesarios.

La cuestión es:

¿Cómo se deben pasar los datos de eventos al trabajador?

La primera solución, como promueve el artículo leído, sería utilizar RabbitMQ, que es un gran middleware orientado a mensajes.

El flujo de trabajo sería simple:

Cada vez que la web dyno genera un evento, lo publica a través de RabbitMQ, que alimenta al trabajador.
El inconveniente sería que nada garantiza la coherencia inmediata entre la confirmación de la actualización agregada y la publicación del evento, sin tratar los posibles fallos de envío ... o problemas de hardware; Esa es otra cuestión principal.

Ejemplo: sería posible que un evento se publicara sin un éxito de la actualización agregada ... resultando en un evento que representa una representación falsa del modelo de dominio.
Se podría argumentar que existe XA global (confirmación en dos fases), pero no es una solución que se adapte a todas las bases de datos o middlewares.

Entonces, ¿cuál podría ser una buena solución para garantizar esta consistencia inmediata? :
IMO, almacenando el evento en la base de datos, en la misma transacción local que la actualización agregada.
Se crearía un planificador asíncrono simple y sería responsable de consultar los eventos actuales no publicados desde la base de datos y enviarlos a RabbitMQ, que a su vez llena al trabajador.

Pero por qué necesita un planificador adicional en el lado de la aplicación web y por cierto: ¿por qué necesita RabbitMQ en este caso?

Con esta solución, parece lógico que RabbitMQ podría ser innecesario, especialmente porque la base de datos es compartida.
De hecho, cualquiera que sea el caso, vimos que la consistencia inmediata implica un sondeo de la base de datos.
Entonces, ¿por qué el trabajador no sería responsable directamente de esta encuesta?

Por lo tanto, me pregunto por qué tantos artículos en la web critican apenas las colas de la base de datos, mientras promueven el middleware orientado a mensajes.

Extracto del artículo:

Simple, use la herramienta adecuada para el trabajo: este escenario está pidiendo un sistema de mensajería. Resuelve todos los problemas descritos anteriormente; no más sondeo, entrega eficiente de mensajes, no es necesario borrar los mensajes completos de las colas y no hay estado compartido.

Y consistencia inmediata, ¿ignorada?

En resumen, realmente parece que sea cual sea el caso, es decir, la base de datos compartida o no, necesitamos un sondeo de la base de datos .

¿Me perdí algunas nociones críticas?

Gracias

Mik378
fuente
2
El sondeo es una especie de arenque rojo, porque casi todas las bases de datos principales tienen algún mecanismo para notificar asincrónicamente algún otro proceso de que es hora de sacar algo de trabajo de una tabla.
Blrfl

Respuestas:

28

Si está creando una aplicación simple con poco tráfico, hay algo que decir acerca de mantener otro componente fuera de su sistema. Es muy probable que no usar un bus de mensajes sea la respuesta correcta para usted. Sin embargo, sugeriría construir su sistema de manera que pueda cambiar el sistema de colas basado en bases de datos por una solución de middleware. Estoy de acuerdo con el artículo. Una base de datos no es la herramienta adecuada para un sistema basado en colas, pero puede ser lo suficientemente buena para usted.

Los sistemas basados ​​en colas como RabbitMq están construidos alrededor de una escala masiva en hardware moderado. Su arquitectura es capaz de lograr esto evitando procesos que hacen que el sistema de base de datos compatible con ACID sea ​​lento por su naturaleza. Dado que un bus de mensajes solo necesita asegurarse de que un mensaje se almacena y procesa con éxito, no necesita molestarse en bloquear y escribir registros de transacciones. Ambos conceptos son absolutamente necesarios para un sistema ACID, pero a menudo son motivo de controversia.

En términos de rendimiento, todo se reduce a: usted tiene una tabla SQL. Muchas lecturas y muchas escrituras. Ambos requieren algún tipo de bloqueo para actualizar filas, páginas e índices. Su mecanismo de sondeo está constantemente bloqueando un índice para realizar búsquedas en él. Esto evita que sucedan escrituras; en el mejor de los casos están en cola. El código que realiza el procesamiento también se bloquea para actualizar el estado en la cola cuando se completan o fallan. Sí, puede hacer una optimización de consultas después de la optimización para que esto funcione, o puede usar un sistema diseñado específicamente para la carga de trabajo que está solicitando. Un RabbitMq come este tipo de carga de trabajo sin siquiera sudar; Además de eso, puede guardar su base de datos de la carga de trabajo, dándole más espacio para escalar haciendo otras cosas.

Otra cosa a tener en cuenta es que la mayoría de los sistemas de cola generalmente no usan una técnica de sondeo (algunos permiten HTTP, pero recomiendan evitar el uso para el lado de recepción). RabbitMq utiliza protocolos de red diseñados específicamente para buses de mensajes como AMPQ .

Editar: Agregar caso de uso.

La forma en que he usado Rabbit es que he tenido un punto final API que acepta un cambio que requiere una tabla de base de datos muy utilizada. Esta tabla está bajo constante discusión y, en ocasiones, no podrá guardar un cambio de manera oportuna desde la API. En cambio, lo que hago es escribir la solicitud de cambio en una cola y luego tener un servicio que maneja estos mensajes como pueden. Si se produce una contención en la base de datos, la cola simplemente crece y el procesamiento de mensajes se retrasa. Por lo general, el tiempo de procesamiento disminuye en el rango de 14 ms, pero en tiempos de alta contención obtenemos hasta 2-3 segundos.

brianfeucht
fuente
¿Cómo podría manejar la consistencia inmediata en este caso? Si la publicación se realiza pero justo después, la transacción responsable de actualizar los retrocesos del modelo de dominio ... El middleware sería totalmente inconsciente y procesaría el evento.
Mik378
Usted escribió: "no necesita molestarse con el bloqueo". Pero seguramente hay un tipo de bloqueo para garantizar el orden ascendente (en el tiempo) de los eventos enrutados (hacia el trabajador), ¿no?
Mik378
@ Mik378 Eche un vistazo a este artículo sobre idempotencia de mensajes . Sí, técnicamente pierde la promesa de coherencia, pero apuesto a que encontrará lo que gana en términos de confiabilidad del tiempo de actividad de la aplicación y el rendimiento bien vale la pena. También es bastante fácil cambiar la forma en que procesa los mensajes para que las pérdidas sean bastante indoloras.
brianfeucht
2
Sí, necesitaría un bloqueo para garantizar el pedido. Algunos sistemas de colas pueden proporcionar esto al precio del rendimiento. Si puede aceptar el hecho de que a veces las operaciones sucederán fuera de orden y encontrar una forma de manejarlo en el lado del procesador, obtendrá un beneficio exponencial desde el punto de vista del rendimiento.
brianfeucht
1
@ Mik378: agregué un caso de uso a mi respuesta. ¡Espero que ayude!
brianfeucht