WG Contract API: zool贸gico de servicios



Con el aumento en el n煤mero de componentes en un sistema de software, el n煤mero de personas que participan en su desarrollo generalmente tambi茅n crece. Como resultado, para mantener el ritmo de desarrollo y la facilidad de mantenimiento, los enfoques para la organizaci贸n de la API deben ser objeto de especial atenci贸n.

Si desea ver m谩s de cerca c贸mo el equipo de Wargaming Platform hace frente a la complejidad de un sistema de m谩s de cien servicios web que interact煤an entre s铆, entonces bienvenido a cat.

Hola a todos! Mi nombre es Valentine y soy ingeniero en la Plataforma de Wargaming. Para aquellos que no saben qu茅 es la plataforma y qu茅 hace, les dejo aqu铆 un enlace a la publicaci贸n reciente de uno de mis colegas: max_posedon

En este momento, llevo m谩s de cinco a帽os trabajando en la empresa y descubr铆 parcialmente el per铆odo de crecimiento activo de World of Tanks. Para descubrir los problemas planteados en este art铆culo, necesito comenzar con una breve digresi贸n sobre la historia de la Plataforma Wargaming.

Un poco de historia


La creciente popularidad de los "tanques" result贸 ser una avalancha, y como suele ser el caso en tales casos, la infraestructura alrededor del juego comenz贸 a desarrollarse r谩pidamente. Como resultado, el juego se superpuso r谩pidamente con varios servicios web, y cuando me un铆 al equipo, su puntaje ya estaba llegando a decenas (ahora, por cierto, m谩s de 100 componentes de la plataforma funcionan y benefician a la empresa).

A medida que pasaba el tiempo, aparecieron nuevos juegos, y entender las complejidades de las integraciones entre los servicios web ya no era f谩cil. La situaci贸n solo empeor贸 cuando los equipos de otras oficinas de Wargaming se unieron al desarrollo de la plataforma. El desarrollo se ha distribuido, con todas las consecuencias en forma de distancia, zonas horarias y barrera del idioma. Y hay m谩s servicios. Encontrar una persona que entienda c贸mo funciona la plataforma en su conjunto no es tan f谩cil. La informaci贸n a menudo tuvo que ser recopilada en partes de diferentes fuentes.

Las interfaces de varios servicios web pueden diferir enormemente en el rendimiento estil铆stico, lo que dificulta a煤n m谩s el proceso de integraci贸n con la plataforma. Y las dependencias directas entre componentes redujeron la flexibilidad de desarrollo al complicar la descomposici贸n de la funcionalidad dentro de la plataforma. Para empeorar las cosas, los juegos, clientes de la plataforma, conoc铆an bien nuestra topolog铆a, ya que ten铆an que integrarse directamente con cada servicio de la plataforma. Esto les dio la oportunidad, mediante conexiones horizontales, de presionar para la implementaci贸n de ciertas mejoras directamente en el componente con el que se integran. Esto condujo a la aparici贸n de funciones duplicadas en varios componentes de la plataforma, as铆 como a la incapacidad de extender la funcionalidad existente a otros juegos. Se hizo obvio que continuar construyendo una plataforma alrededor de cada juego espec铆fico es una rama de desarrollo sin salida. Necesit谩bamos cambios t茅cnicos y organizativos, como resultado de lo cual pudimos tomar el control de la creciente complejidad de un sistema en r谩pido crecimiento y hacer que toda la funcionalidad de la plataforma sea adecuada para su uso en cualquier juego.

Con esto quiero terminar la excursi贸n hist贸rica y, finalmente, hablar sobre una de nuestras soluciones t茅cnicas, que ayuda a mantener bajo control la complejidad causada por el n煤mero cada vez mayor de servicios. Adem谩s, reduce el costo de desarrollar nuevas funciones y simplifica enormemente la integraci贸n con la plataforma.

Conoce la API del contrato


Dentro de la plataforma, la llamamos API de contrato. En esencia, es un marco de integraci贸n representado por un conjunto de documentaci贸n y bibliotecas de clientes para cada tecnolog铆a de nuestra pila (Erlang / Elixir, Java / Scala, Python). Se est谩 desarrollando, en primer lugar, para simplificar la integraci贸n de los componentes de la plataforma entre s铆. Segundo, para ayudarnos a resolver varios de los siguientes problemas:

  • diferencias estil铆sticas de las interfaces del programa
  • la presencia de dependencias directas entre componentes
  • mantener la documentaci贸n actualizada
  • introspecci贸n y depuraci贸n de funcionalidad de extremo a extremo

Entonces, lo primero es lo primero.

Diferencias estil铆sticas en las interfaces de software.


En mi opini贸n, este problema surgi贸 como resultado de una combinaci贸n de varios factores:

  • Falta de un est谩ndar estricto de c贸mo deber铆a ser la API. El conjunto de recomendaciones a menudo no tiene el efecto deseado, la API sigue siendo diferente. Especialmente si el desarrollo se lleva a cabo por equipos de diferentes oficinas de la empresa. Cada equipo tiene sus propios h谩bitos y pr谩cticas. Colectivamente, tales API a menudo no parecen partes de un todo.
  • Falta de un solo directorio con los nombres y formatos de entidades espec铆ficas del negocio. Como regla general, no puede tomar una entidad del resultado de una API y pasarla a la API de otro servicio. Esto requiere transformaci贸n.
  • Falta de un sistema de revisi贸n centralizado obligatorio para la API. Siempre hay fechas l铆mite y no hay tiempo para recopilar actualizaciones y, adem谩s, hacer cambios en la API, que de hecho a menudo resulta estar ya a medias.

Lo primero que hicimos al dise帽ar la API de contrato fue decir que a partir de ahora la API pertenece a la plataforma, y 鈥嬧媙o a un solo componente. Esto llev贸 al hecho de que el desarrollo de una nueva funcionalidad comienza con una solicitud de extracci贸n a una API de almacenamiento centralizado. Actualmente, utilizamos el repositorio GIT como almacenamiento. Por conveniencia, dividimos la API completa en funciones comerciales separadas, formalizamos la estructura de esta funci贸n y la llamamos Contrato.

Desde entonces, cada nueva funci贸n comercial en nuestra API de contrato debe describirse en un formato especial y pasar por la solicitud de extracci贸n con una revisi贸n obligatoria. No hay otra forma de publicar una nueva API en la API del contrato. En el mismo repositorio, definimos un directorio de entidades espec铆ficas del negocio y sugerimos que los desarrolladores de contratos los reutilicen en lugar de describir estas entidades por s铆 mismos.

Por lo tanto, obtuvimos una API de plataforma conceptualmente integrada que parec铆a un solo producto, a pesar del hecho de que en realidad se implement贸 en muchos componentes de la plataforma utilizando varias pilas tecnol贸gicas.

La presencia de dependencias directas entre componentes.


Este problema nuestro se manifest贸 en el hecho de que se requer铆a que cada componente de la plataforma supiera qui茅n atiende espec铆ficamente la funcionalidad que necesita.

Y ni siquiera fue la dificultad de mantener este directorio actualizado, sino el hecho de que las dependencias directas complicaron significativamente la migraci贸n de la funcionalidad empresarial de un componente de la plataforma a otro. El problema fue especialmente agudo cuando comenzamos la descomposici贸n de nuestros monolitos en componentes m谩s peque帽os. Result贸 que convencer al cliente para que reemplace la integraci贸n de trabajo con cualquier funcionalidad con la misma desde el punto de vista del negocio, pero otra desde el punto de vista t茅cnico, no es una tarea de administraci贸n trivial. El cliente simplemente no ve el punto en esto, ya que todo funciona bien para 茅l. Como resultado, se escribieron capas malolientes de compatibilidad con versiones anteriores que solo complicaron el soporte de la plataforma y tuvieron un efecto negativo en la calidad del servicio. Y como ya 铆bamos a estandarizar la API de la plataforma, era necesario resolver este problema simult谩neamente.

Nos enfrentamos a una elecci贸n de varias opciones. De estos, consideramos especialmente cuidadosamente:

  • Implementaci贸n de protocolos de descubrimiento de servicios en cada uno de los componentes.
  • Usar un mediador para redirigir las solicitudes de los clientes al componente de plataforma correcto.
  • Usar un agente de mensajes como un bus de mensajer铆a.

Como resultado de algunas reflexiones y experimentos, la elecci贸n recay贸 en el intermediario de mensajes, a pesar del hecho de que nos ve铆a como un posible punto 煤nico de falla y aument贸 la sobrecarga de operar la plataforma. El hecho de que la plataforma en ese momento ya ten铆a experiencia en trabajar con RabbitMQ desempe帽贸 un papel importante en la selecci贸n. Y el corredor en s铆 mismo escalaba bien y ten铆a mecanismos incorporados para garantizar la tolerancia a fallas. Como beneficio adicional, tuvimos la oportunidad de implementar una arquitectura basada en eventos ( arquitectura dirigida por eventos o EDA ) "bajo el cap贸". Lo que posteriormente abri贸 ante nosotros posibilidades m谩s amplias de interacci贸n entre servicios, en comparaci贸n con la interacci贸n punto a punto.

Entonces, topol贸gicamente, la plataforma comenz贸 a pasar de un gr谩fico con conectividad aleatoria a una estrella. Y los componentes de la plataforma invirtieron sus dependencias y tuvieron la oportunidad de interactuar entre ellos exclusivamente a trav茅s de contratos registrados en un repositorio centralizado, sin la necesidad de saber qui茅n implementa espec铆ficamente un contrato en particular. En otras palabras, todos los componentes dentro de la plataforma pudieron interactuar entre s铆 utilizando un 煤nico punto de integraci贸n, lo que simplific贸 enormemente la vida de los desarrolladores.

Mantener la documentaci贸n actualizada


Los problemas asociados con la falta de documentaci贸n o la p茅rdida de su relevancia casi siempre se encuentran. Y cuanto mayor es el ritmo de desarrollo, m谩s a menudo se manifiesta. Y despu茅s del hecho, reunir todas las especificaciones API en un solo lugar y formato para m谩s de cien servicios en un equipo distribuido y multinacional es una tarea dif铆cil.

Al desarrollar la API de contrato, tambi茅n nos fijamos el objetivo de resolver este problema. Y lo hicimos Un formato estrictamente definido para la descripci贸n del contrato nos permiti贸 construir un proceso de acuerdo con el cual, inmediatamente despu茅s de la aparici贸n de un nuevo contrato, se inicia el montaje autom谩tico de la documentaci贸n. Esto nos da la confianza de que nuestra documentaci贸n de la API siempre est谩 actualizada. Este proceso est谩 totalmente automatizado y no requiere ning煤n esfuerzo de desarrollo o gesti贸n.

Introspecci贸n y depuraci贸n de funcionalidad de extremo a extremo


A medida que dividimos nuestros monolitos en componentes m谩s peque帽os, naturalmente, comenzaron a surgir dificultades para depurar la funcionalidad de extremo a extremo. Si el servicio de una funci贸n comercial se distribu铆a entre varios componentes de la plataforma, a menudo para localizar y depurar el problema, uno ten铆a que buscar representantes de cada uno de los componentes. Lo que a veces se pod铆a lograr con dificultad, dada la diferencia horaria de 11 horas con algunos de nuestros colegas.

Con el advenimiento de la API de contrato, y en particular gracias al intermediario de mensajes subyacente, tuvimos la oportunidad de recibir copias de mensajes involucrados en la ejecuci贸n de una funci贸n comercial, sin efectos secundarios en la interacci贸n de los participantes. Para hacer esto, ni siquiera es necesario saber cu谩l de los componentes de la plataforma es responsable de procesar un contrato en particular. Y despu茅s de la localizaci贸n del problema, podemos obtener el identificador del componente roto a partir de los metadatos del mensaje del problema.

驴Qu茅 m谩s desarrollamos sobre la API del contrato?


Adem谩s de su prop贸sito principal y de resolver los problemas anteriores, la API de Contrato nos permiti贸 implementar una serie de servicios 煤tiles.

Pasarela para acceder a la funcionalidad de la plataforma


La estandarizaci贸n de la API en forma de contratos nos permiti贸 desarrollar un 煤nico punto de acceso a la funcionalidad de la plataforma a trav茅s de HTTP. Adem谩s, con la llegada de nuevas funcionalidades (contratos), no necesitamos modificar este punto de acceso de ninguna manera. Es compatible con todos los contratos futuros. Esto le permite trabajar con la plataforma como un solo producto utilizando la interfaz HTTP habitual.

Servicio de operaciones masivas


Cualquier contrato puede iniciarse como parte de una operaci贸n masiva, con la capacidad de rastrear su estado y luego recibir un informe sobre los resultados de esta operaci贸n. Este servicio, al igual que el anterior, es compatible con todos los contratos futuros por adelantado.

Manejo unificado de errores de plataforma


El protocolo Contract API tambi茅n estandariza los errores. Esto nos permiti贸 implementar un interceptor de errores, que analiza su gravedad y notifica al sistema de monitoreo de posibles problemas en los componentes de la plataforma. Y en el futuro, podr谩 decidir independientemente el descubrimiento de un error en el componente de la plataforma. El interceptor de errores los atrapa directamente del agente de mensajes y no sabe nada sobre el prop贸sito de un contrato o error, actuando solo sobre la base de metainformaci贸n. Esto le permite, al igual que todos los servicios descritos en esta secci贸n, ser compatible con todos los contratos futuros.

Generar autom谩ticamente interfaces de usuario


Los contratos estrictamente formalizados le permiten crear autom谩ticamente componentes de interfaz de usuario. Hemos desarrollado un servicio que le permite generar una interfaz administrativa basada en una colecci贸n de contratos y luego integrar esta interfaz en cualquiera de nuestras herramientas de plataforma. Por lo tanto, los administradores que anteriormente escribimos con nuestras manos ahora se pueden generar (aunque solo parcialmente hasta ahora) en modo autom谩tico.

Registro de plataforma


Este componente a煤n no se ha implementado y est谩 en desarrollo. Pero en el futuro, permitir谩 "sobre la marcha" activar y desactivar el registro de cualquier funci贸n comercial en la plataforma, extrayendo esta informaci贸n directamente del agente de mensajes, sin ning煤n efecto secundario que afecte negativamente a los componentes que interact煤an.

El objetivo principal de la API de contrato


Pero a煤n as铆, el objetivo principal de la API de contrato es reducir el costo de integrar componentes de la plataforma.

Los desarrolladores se abstraen del nivel de transporte por las bibliotecas que desarrollamos para cada una de nuestras pilas de tecnolog铆a. Esto nos da margen de maniobra en caso de que tengamos que cambiar el intermediario de mensajes o incluso cambiar a la interacci贸n punto a punto. La interfaz externa de la biblioteca permanecer谩 sin cambios.

La biblioteca debajo del cap贸 genera un mensaje de acuerdo con ciertas reglas y lo env铆a al agente, despu茅s de lo cual, despu茅s de esperar un mensaje de respuesta, devuelve el resultado al desarrollador. En el exterior, parece una solicitud s铆ncrona regular (o as铆ncrona, dependiente de la implementaci贸n). Como demostraci贸n, dar茅 algunos ejemplos.

Ejemplo de llamada de contrato de Python
from platform_client import Client client = Client(contracts_path=CONTRACTS_PATH, url=AMQP_URL, app_id='client') client.call("ban-management.create-ban.v1", { "wgid": 1234567890, "reason": "Fraudulent activity", "title": "ru.wot", "component": "game", "bantype": "access_denied", "author_id": "v_nikonovich", "expires_at": "2038-01-19 03:14:07Z" }) { u'ban_id': 31415926, u'wgid': 1234567890, u'title': u'ru.wot', u'component': u'game', u'reason': u'Fraudulent activity', u'bantype': u'access_denied', u'status': u"active", u'started_at': u"2019-02-15T15:15:15Z", u'expires_at': u"2038-01-19 03:14:07Z" } 

La misma llamada de contrato, pero usando Elixir
 :platform_client.call("ban-management.create-ban.v1", %{ "wgid" => 1234567890, "reason" => "Fraudulent activity", "title" => "ru.wot", "component" => "game", "bantype" => "access_denied", "author_id" => "v_nikonovich", "expires_at" => "2038-01-19 03:14:07Z" }) {:ok, %{ "ban_id" => 31415926, "wgid" => 1234567890, "title" => "ru.wot", "conponent" => "game", "reason" => "Fraudulent activity", "bantype" => "access_denied", "status" => "active", "started_at" => "2019-02-15T15:15:15Z", "expires_at" => "2038-01-19 03:14:07Z" }} 

En lugar del contrato "ban-management.create-ban.v1" puede haber cualquier otra funcionalidad de plataforma, por ejemplo: "account-management.rename-account.v1" o "notify-center.create-sms-notify.v1". Y todo estar谩 disponible a trav茅s de este 煤nico punto de integraci贸n con la plataforma.

La descripci贸n general estar谩 incompleta si no demuestra la API del contrato desde el punto de vista del desarrollador del servidor. Considere una situaci贸n en la que un desarrollador necesita implementar un controlador para el mismo contrato ban-management.create-ban.v1.

 from platform_server import BlockingServer, handler class CustomServer(BlockingServer): @handler('ban-management.create-ban.v1') def handle_create_ban(self, params, context): response = do_some_usefull_job(params) return response d = CustomServer(app_id="server", amqp_url=AMQP_URL, contracts_path=CONTRACTS_PATH) d.serve() 

Este c贸digo ser谩 suficiente para comenzar a cumplir un contrato determinado. La biblioteca del servidor desempaquetar谩 y verificar谩 que los par谩metros de la solicitud sean correctos, y luego llamar谩 al manejador del contrato con los par谩metros de la solicitud listos para su procesamiento. Por lo tanto, el desarrollador del servidor est谩 protegido por una biblioteca que, en caso de recibir par谩metros de solicitud incorrectos, enviar谩 un error de validaci贸n al cliente y registrar谩 el hecho de un problema.

Debido al hecho de que, bajo el cap贸, la API de contrato se implementa en funci贸n de los eventos, tenemos la oportunidad de ir m谩s all谩 del alcance del script de Solicitud / Respuesta e implementar una gama m谩s amplia de interacciones entre servicios.

Por ejemplo:

  • haga una solicitud y olvide (sin esperar una respuesta)
  • realizar solicitudes a varios contratos simult谩neamente (incluso sin usar un bucle de eventos)
  • haga una solicitud y reciba respuestas de varios manejadores a la vez (si lo proporciona el script de integraci贸n)
  • registrar un manejador de respuestas (se activa si el manejador de contratos inform贸 la finalizaci贸n, acepta el resultado del trabajo del manejador de contratos, es decir, su respuesta)

Y esta no es una lista completa de escenarios que se pueden expresar a trav茅s de un modelo de interacci贸n de eventos. Esta es una lista de los que estamos usando actualmente.

En lugar de una conclusi贸n


Hemos estado utilizando la API de contrato durante varios a帽os. Por lo tanto, no es posible hablar sobre todos los escenarios de su uso en el marco de un art铆culo de revisi贸n. Por la misma raz贸n, no sobrecargu茅 el art铆culo con detalles t茅cnicos. Ella ya result贸 bastante voluminosa. Haga preguntas y tratar茅 de responderlas directamente en los comentarios. Si un tema es particularmente interesante, ser谩 posible revelarlo con m谩s detalle en un art铆culo separado.

Source: https://habr.com/ru/post/441708/


All Articles