Logo de la Universdad de Valencia Logo Máster Universitario en Tecnologías Web, Computación en la Nube y Aplicaciones Móviles Logo del portal

Desarrollo de servicios REST al estilo devops

8 de mayo de 2019

Contenidos

  1. Introducción
  2. Documentar el API
  3. Añadir métricas (capa de observabilidad)
  4. Añadir tolerancia a fallos (capa de escalabilidad)
  5. Conclusiones
  6. Enlaces

 

1 Introducción

Supongamos que vamos a desarrollar un servicio en un contexto devops. Tendremos que pensar tanto en la lógica de negocio que ofrece el servicio (la parte dev) como en la ejecución del servicio (la parte ops). En esta segunda parte intervienen, entre otros elementos, la escalabilidad y la observabilidad.

Para la parte dev, desde el lenguaje Java, podemos usar por ejemplo Spring Boot o el Eclipse MicroProfile. Este último ofrece un subconjunto del API de Java EE orientado al desarrollo de servicios que ofrecen un API REST.

Para la parte ops hay que añadir servicios adicionales orientados al plano de control. Para esto tenemos diferentes aproximaciones:

  • Proporcionarlos desde fuera del código como por ejemplo ocurre con Istio sobre Kubernetes.
  • Proporcionarlos desde el código si disponemos de un API que nos permita especificar de forma declarativa el comportamiento deseado, por ejemplo frente ante un error, y el contenedor que gestiona nuestro servicio se encarga de realizar el trabajo especificado.

El MicroProfile es un ejemplo de esta segunda aproximación y ofrece un conjunto de APIs que permiten:

  • Desarrollar el servicio
  • Facilitar el escalado de los servicios
  • Facilitar la observabilidad de los servicios

Figure 1: Capas del API microprofile

La capa inferior es un subconjunto de las APIs de Java EE. La segunda capa de APIs está orientada a la escalabilidad y la capa superior permite observar el estado de los servicios y recoger información que puede ayudar a optimizarlos o a corregir errores.

Vamos a revisar brevemente tres de las APIs que ofrece.

 

2 Documentar el API

Cuando se está desarrollando una arquitectura basada en servicios es necesario documentar las APIs. Esto se puede realizar desde el propio código mediante el uso de anotaciones.

A partir de estas anotaciones se crea un nuevo endpoint en la URL http://HOST:PORT/openapi/ui que contiene la documentación del API. Esto nos permite obtener una visión general del API que ofrece el servicio, o los detalles de las operaciones desde donde podemos enviar peticiones tal y como se muestra en las dos figuras siguientes:

openapi_ui1.png

Figure 2: Vista general del API que ofrece el servicio

openapi_ui2.png

Figure 3: Descripción detallada de una operación desde donde podemos realizar peticiones.

 

3 Añadir métricas (capa de observabilidad)

Es importante poder obtener métricas que permitan observar el estado del servicio y de la máquina virtual. Para ello se puede utilizar el API MicroProfile Metrics. Usando esta API, el servicio proporcionará un API REST para la consulta de las métricas.

Este API nos proporciona anotaciones como: @Counted que permite contar el número de veces que se llama a un determinado método; @Timed que permite medir el tiempo que tarda en ejecutarse un método; o @Gauge que permite mostrar un valor cualquiera.

Las métricas están disponibles en las URLs http://HOST:PORT/metrics o http://HOST:PORT/metrics/application para visualizar únicamente las métricas que ofrece la aplicación.

metrics1.png

Figure 4: Ejemplo de métricas antes de realizar peticiones.

metrics2.png

Figure 5: Ejemplo de métricas tras realizar diferentes peticiones.

Podríamos configurar un servicio como Prometheus para que consulte periódicamente esta información y obtener gráficas de aquellas métricas que nos interesen.

prometheus-metrics.png

Figure 6: Prometheus: ejemplo de la gráfica de una métrica proporcionada por la aplicación.

 

4 Añadir tolerancia a fallos (capa de escalabilidad)

Hay diferentes patrones que ayudan a hacer más robusta una aplicación:

  • fail fast que sirve para notificar lo antes posible al cliente que realiza la llamada de que la ejecución tarda más de lo aceptable,
  • retry que sirve para realizar un número de reintentos cuando se produce un error antes de devolver un fallo al cliente,
  • circuit breaker que sirve para no realizar llamadas a los servicios que están fallando, o
  • bulkhead para limitar el número de peticiones que pueden ejecutar concurrentemente un servicio.

El API MicroProfile Fault Tolerance ofrece un conjunto de anotaciones que permiten configurar cómo se debe comportar el servicio ante fallos.

Se puede configurar un tiempo de espera máximo mediante la anotación @Timeout de tal forma que si la ejecución del método no finaliza en el tiempo especificado se detendrá la ejecución del método, que finalizará con una excepción del tipo TimeoutException.

Para especificar un número de reintentos se usa la anotación @Retry. Si se supera el número de intentos entonces la ejecución finalizará con una excepción.

 

5 Conclusiones

En un contexto devops hay que centrarse en el desarrollo, en cómo conseguir la funcionalidad que debe ofrecer el servicio, y también en su comportamiento en ejecución, en cómo se debe comportar en caso de fallo propio o de otros servicios con los que interacciona. Hemos mostrado que el API que ofrece Eclipse MicroProfile incorpora algunos de estos elementos del plano de control y nos ofrece una serie de anotaciones para informar al contenedor que ejecuta el servicio sobre qué debe hacer en caso de fallos. En dos talleres de la asignatura Computación en la Nube se ha desarrollado el servicio, se ha encapsulado en una imagen y se ha generado un servicio con docker-compose que integra también el contenedor Prometheus.

 

6 Enlaces

Etiquetas