¿Cómo ajustar un motor de reglas en una arquitectura de microservicio cuando requiere muchos datos de entrada?


12

Situación actual

Estamos implementando (y ahora manteniendo) una aplicación web de compras en línea en una arquitectura de microservicio.

Uno de los requisitos es que la empresa debe poder aplicar reglas sobre lo que nuestros clientes agregan a su carrito, a fin de personalizar su experiencia y el pedido final. Obviamente, se tuvo que establecer un motor de reglas de negocio e implementamos un "microservicio" específico para esto (si aún pudiéramos llamarlo así).

A lo largo de un año, este motor de reglas se ha vuelto cada vez más complejo, requiriendo más y más datos (por ejemplo, contenido del carrito pero también información del usuario, su función, sus servicios existentes, cierta información de facturación, etc.) para poder calcular esas reglas

Por el momento, nuestro shopping-cartmicroservicio está recopilando todos estos datos de otros microservicios. Aunque parte de esta información es utilizada por shopping-cart, la mayoría de las veces se usa principalmente para alimentar el motor de reglas.

Nuevos requisitos

Ahora llega la necesidad de otras aplicaciones / microservicios para reutilizar el motor de reglas para requisitos similares. En la situación actual, tendrían que transmitir el mismo tipo de datos, llamar a los mismos microservicios y construir (casi) los mismos recursos para poder llamar al motor de reglas.

Continuando como está, enfrentaremos varios problemas:

  • todos (llamando al motor de reglas) tienen que reimplementar la obtención de datos, incluso si no los necesitan para sí mismos;
  • las solicitudes al motor de reglas son complejas;
  • continuando en esta dirección, tendremos que transportar estos datos por toda la red para muchas solicitudes (piense en μs A llamando a μs B llamando al motor de reglas, pero A ya tiene algunos de los datos que necesita el motor de reglas);
  • shopping-cart se ha vuelto enorme debido a la obtención de todos los datos;
  • Probablemente olvide muchos ...

¿Qué podemos hacer para evitar estos problemas?

Idealmente, evitaríamos agregar más complejidad al motor de reglas. También debemos asegurarnos de que no se convierta en un cuello de botella; por ejemplo, algunos datos son bastante lentos para recuperar (10 segundos o incluso más), por lo que implementamos la recuperación previa de shopping-cartmanera que es más probable que los datos estén allí antes de llamar a las reglas motor y mantener una experiencia de usuario aceptable.

Algunas ideas

  1. Deje que el motor de reglas obtenga los datos que necesita. Esto agregaría aún más complejidad, violando el principio de responsabilidad única ( aún más ... );
  2. Implemente un proxy μs antes del motor de reglas para obtener los datos;
  3. Implemente un "captador de datos" μs que el motor de reglas llama para obtener todos los datos que necesita a la vez (consulta compuesta).

Permítanme resumir esto (con preguntas): tiene varios microservicios implementados para una tienda. Uno de ellos es un carrito de compras . Incorporado en el carrito hay un motor de reglas (ya sea homebrew o algún producto), ¿verdad? Cuando un usuario agrega un artículo al carrito, el motor de reglas se activa como parte de la lógica de negocios y modifica el carrito de alguna manera (por ejemplo, descuento o productos combinados), ¿verdad? Ahora, otro microservicio también quiere usar reglas que pueden estar basadas en datos de entrada similares, ¿verdad? Y los datos de entrada son proporcionados por otros microservicios, ¿verdad? ¿Por qué la obtención de datos es tan compleja?
Andy

3
Su mejor apuesta para evitar esos problemas es deshacerse del motor de reglas.
whatsisname

@Andy El motor de reglas es un microservicio separado. Su API está un poco adaptada shopping-cart, pero podríamos adaptarla fácilmente a las necesidades de los otros microservicios (todavía están relacionados con los usuarios, los productos y los pedidos). Tal como lo vemos, que se necesitan los mismos datos de entrada, sobre todo porque el negocio es capaz de elegir los predicados de aplicar. Todos los datos son proporcionados por otros microservicios, excepto el contenido del carrito. Obtener los datos no es complejo per se, pero se vuelve complejo cuando tiene que llamar a ~ 10 otros microservicios y mantener la estructura esperada por el motor de reglas.
Didier L

@whatsisname No soy un gran admirador de tener un motor de reglas en general tampoco, pero en este momento tenemos que lidiar con eso y de todos modos, y el negocio está cambiando su configuración día a día. Incluso si nos deshiciéramos de él, aún necesitaríamos algún componente configurable para hacer lo mismo, requiriendo los mismos datos de entrada ... Seguiría siendo un motor de reglas, solo con otro nombre, y aún enfrentaríamos los mismos problemas.
Didier L

Respuestas:


8

Retrocedamos un segundo y evaluemos nuestro punto de partida antes de escribir esta respuesta que probablemente sea novedosa. Tienes:

  • Un gran monolito (el motor de reglas)
  • Una gran cantidad de datos no modularizados que se envían de forma masiva
  • Es difícil obtener datos hacia y desde el motor de reglas
  • No puedes eliminar el motor de reglas

Ok, esto no es tan bueno para microservicios. Un problema evidente es que ustedes parecen estar malinterpretando qué son los microservicios.

todos (llamando al motor de reglas) tienen que reimplementar la obtención de datos, incluso si no los necesitan para sí mismos;

Debe definir algún tipo de API o método de comunicación que utilicen sus microservicios y que sea común. Esta podría ser una biblioteca que todos ellos pueden importar. Podría estar definiendo un protocolo de mensaje. Podría estar utilizando una herramienta existente ( busque buses de mensajes de microservicio como un buen punto de partida).

La cuestión de la comunicación entre servicios no es un problema "resuelto" per se, pero tampoco es un problema de "rodar su propio" en este momento. Muchas herramientas y estrategias existentes pueden hacer que su vida sea mucho más fácil.

Independientemente de lo que haga, elija un solo sistema e intente adaptar sus API de comunicación para usarlo. Sin una forma definida para que sus servicios interactúen, tendrá todas las desventajas de los microservicios y los servicios monolíticos y ninguna de las ventajas de ninguno.

La mayoría de sus problemas se derivan de esto.

las solicitudes al motor de reglas son complejas;

Hazlos menos complejos.

Encuentre maneras de hacerlos menos complejos. Seriamente. Modelos de datos comunes, divida su motor de reglas individuales en otros más pequeños, o algo así. Haga que su motor de reglas funcione mejor. No tome el enfoque de "atascar todo en la consulta y siga haciéndolos complicados": considere seriamente lo que está haciendo y por qué.

Defina algún tipo de protocolo para sus datos. Mi conjetura es que ustedes no se han definido plan de API (según lo anterior) y han comenzado a escribir RESTO llama ad hoc cuando sea necesario. Esto se vuelve cada vez más complejo ya que ahora tiene que mantener cada microservicio cada vez que se actualiza algo.

Mejor aún, no eres exactamente la primera compañía en implementar una herramienta de compra en línea. Ve a buscar otras compañías.

Ahora que...

Después de esto, al menos probó algunos de los problemas más importantes.

El siguiente problema es esta pregunta de su motor de reglas. Espero que esto sea razonablemente apátrida, de modo que pueda escalarlo. Si es así, si bien no es óptimo, al menos no morirás en un resplandor de gloria o crearás soluciones alternativas.

Desea que su motor de reglas no tenga estado. Hágalo de manera que solo procese datos. Si lo encuentra como un cuello de botella, hágalo para que pueda ejecutar varios detrás de un proxy / equilibrador de carga. No es ideal, pero sigue siendo viable.

Dedique algo de tiempo a considerar si alguno de sus microservicios realmente debería incluirse en su motor de reglas. Si está aumentando la sobrecarga de su sistema de manera tan significativa solo para lograr una "arquitectura de microservicios", necesita pasar más tiempo planeando esto.

Alternativamente, ¿puede dividirse su motor de reglas en pedazos? Puede obtener ganancias simplemente haciendo que partes de sus reglas generen servicios específicos.

También debemos asegurarnos de que no se convierta en un cuello de botella; por ejemplo, algunos datos son bastante lentos para obtener (10 segundos o incluso más)

Suponiendo que este problema existe después de resolver los problemas anteriores, debe investigar seriamente por qué sucede esto. Se está desarrollando una pesadilla, pero en lugar de averiguar por qué (¿10 segundos? ¿Para enviar datos del portal de compras ? Llámame cínico, pero esto parece un poco absurdo) parece que estás reparando los síntomas en lugar de mirar el problema que causa los síntomas en El primer lugar.

Has utilizado la frase "recuperación de datos" una y otra vez. ¿Están estos datos en una base de datos? De lo contrario, considere hacer esto: si pasa tanto tiempo "manualmente" buscando datos, parece que usar una base de datos real sería una buena idea.

Es posible que pueda tener un diseño con una base de datos para los datos que obtiene (dependiendo de lo que sea, lo ha mencionado muchas veces), algunos motores de reglas y sus clientes.

Una última nota es que desea asegurarse de utilizar el control de versiones adecuado de sus API y servicios. Una versión menor no debe romper la compatibilidad con versiones anteriores. Si te encuentras liberando todos tus servicios al mismo tiempo para que funcionen, no tienes una arquitectura de microservicio, tienes una arquitectura monolítica distribuida.

Y, en última instancia, los microservicios no son una solución única para todos. Por el bien de todo lo que es sagrado, no lo hagas solo porque es lo nuevo de la moda.


Gracias por tu respuesta, @enderland. De hecho, la arquitectura de microservicios todavía es relativamente nueva para nosotros, de ahí esta pregunta. Este motor de reglas ha evolucionado un poco orgánicamente para guiarnos hasta aquí, por lo que ahora necesitamos instrucciones de manejo para solucionarlo. Es (afortunadamente) completamente sin estado, de ahí la cantidad de datos que toma como entrada. Y esto es lo que nos gustaría abordar primero para que sea un componente reutilizable. Pero, ¿cómo reducir la cantidad de datos de entrada sin reducir el número de predicados disponibles? Supongo que necesitamos una API que sea capaz de obtener los datos por sí misma, pero ¿cómo diseñarlos correctamente?
Didier L

Con respecto a los problemas de rendimiento, estos provienen de microservicios que en realidad están llamando a servicios lentos JMS y SOAP implementados por back-end. Tienen sus propias bases de datos, pero el rendimiento no es realmente su primer objetivo (siempre que maneje la carga). Y hay demasiados para considerar replicar sus datos y mantenerlos (aunque para algunos lo hacemos). Lo mejor que podemos hacer es almacenar en caché y buscar previamente.
Didier L

Entonces, cuando mencionas " pocos motores de reglas ", entiendo que te refieres a motores de reglas especializados que solo evalúan predicados con 1 tipo de entrada, ¿verdad? ¿Sugeriría que busquen los datos que necesitan o que deberían obtener por adelantado? También necesitaríamos algún componente para orquestar la combinación de predicados, ¿no? Y preste atención a no agregar demasiada sobrecarga de red debido a esta orquestación.
Didier L

1

Con la cantidad de información presentada sobre el motor de reglas y sus entradas y salidas, creo que su sugerencia no. 2 está en el camino correcto.

Los consumidores actuales del motor de reglas podrían externalizar el proceso de recopilación de la información requerida a un componente de propósito más especial.

Ejemplo: Actualmente está utilizando el motor de reglas para calcular los descuentos que deben aplicarse al contenido del carrito de compras. Las compras anteriores, la geografía y las ofertas actuales tienen en cuenta.

El nuevo requisito es utilizar gran parte de esta misma información para enviar por correo electrónico ofertas a clientes anteriores en función de las próximas ofertas especiales y compras anteriores. Las compras anteriores, las ofertas actuales y futuras tienen en cuenta.

Tendría dos servicios separados para esto. Cada uno confiaría en el servicio del motor de reglas para algunos de sus trabajos pesados. Cada uno de ellos recopilaría los datos necesarios necesarios para su solicitud al motor de reglas.

El motor de reglas solo aplica las reglas, los consumidores no necesitan preocuparse por los datos exactos que necesita el motor de reglas para el contexto particular, y estos nuevos servicios intermediarios solo hacen una cosa: reunir el contexto y pasar la solicitud al motor de reglas y devuelve la respuesta sin modificar.


0

La agregación de los datos necesarios para la decisión debe hacerse fuera del motor de reglas. Esto se debe a que están mejor diseñados como servicios apátridas como sea posible. La obtención de datos implica necesariamente el procesamiento asincrónico y la retención del estado. No importa mucho si la búsqueda se realiza mediante un proxy al frente del servicio de decisiones, las personas que llaman o un proceso de negocios.

Como cuestión práctica para la implementación, mencionaré que IBM Operational Decision Manager está comenzando a documentar y ya admite el uso del producto dentro de los contenedores de acopladores . Estoy seguro de que otros productos también brindan este soporte y que se convertirá en la corriente principal.


0

Supongo que, en mi pensamiento simple, ayudará a buscar previamente todos los datos necesarios haciendo un conjunto de llamadas asíncronas a los servicios de recuperación de datos tan pronto como el cliente comience a comprar y almacenar en caché los datos. Entonces, cuando tiene que llamar al servicio de reglas, los datos ya están allí. Y continúe estando disponible para otros servicios también durante la sesión.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.