Blog de Amazon Web Services (AWS)

Cómo Atresmedia Tech optimiza la utilización de instancias Spot para obtener el mejor rendimiento al ejecutar jobs de Amazon EMR

Atresmedia Tech, empresa perteneciente al grupo Atresmedia, es la encargada del desarrollo de programas informáticos relacionados con la comunicación y transformación de Atresmedia.

En su misión de proveer soluciones informáticas a los constantes desafíos planteados por la industria de medios y comunicación a elegido AWS para alojar su Data Lake. Atresmedia Tech ha implementado una arquitectura serverless altamente escalable, flexible y de bajo coste, para ejecutar procesos de ETLs, orquestada mediante el uso de AWS Step Functions, donde se realizan determinadas normalizaciones y transformaciones que sirven para procesos de generación de informes de reporting en herramientas de BI y flujos de machine learning.

Estos flujos de Machine Learning son consumidos mediante API REST para generar inferencias a clientes de ATRESplayer (servicio de transmisión de suscripción de video a la carta en streaming de vídeo bajo demanda por Internet y televisión de Atresmedia) generando recomendaciones audiovisuales de manera personalizada.

Debido a la criticidad de algunos flujos de integración, Atresmedia Tech utiliza AWS Step Functions para gestionar los reintentos en caso de fallo de ejecuciones que pueden llevar varias horas, en determinadas arquitecturas que hacen uso de jobs Spark que se ejecutan en clusters del servicio EMR efímeros (basados en instancias de Spot), debido a la criticidad de algunos flujos de integración, en caso de ejecuciones que puedan llevar varias horas en determinadas arquitecturas que hacen uso de jobs Spark que se ejecutan en clusters del servicio EMR efímeros (basados en instancias de Spot).

El reto

Con el objetivo de reducir los costes de ejecución de procesos diarios, Atresmedia Tech hace uso de clusters de Amazon EMR efímeros, mediante el uso de instancias EC2 spot, dichas instancias tienen un coste inferior, en muchos casos cercano al 80% menos, que al utilizarlas en el modelo de bajo demanda.

En determinados casos donde alguna ETL supera el tiempo medio de ejecución de 2 horas, esas instancias Spot pueden ser reclamadas, provocando que ese paso en la ejecución de AWS Step Functions quede en estado fallido, siendo necesaria su re-ejecución, hasta que ésta termine de manera exitosa.

Esto implica que un equipo de soporte 24/7 realice un monitoreo de los workflows de AWS Step Functions, y en caso de error de ejecución vuelvan a realizar reintentos hasta su correcta ejecución.

Dado que muchas de los workflows de AWS Step Functions se lanzan de manera nocturna, ello implica una automatización en el monitoreo, con la consiguiente llamada al equipo de guardia mediante una centralita.

Para resolver este problema existían 3 opciones:

  1. Realizar un switch de instancias spot a instancias On-demand, con el consiguiente incremento del coste de la arquitectura.
  2. Uso de una flota de instancias cambiando el tipo de Amazon EC2, lo que implica en algunos casos cambio en el rendimiento de los tiempos de ejecución.
  3. Automatizar los reintentos automáticos, consiguiendo de esta manera, actuar de manera proactiva ante un error, mejorando los tiempos de respuesta, sin afectar al coste. (Solución recomendada que se indicará a continuación)

Cómo crear un workflow totalmente automático para reintentos de AWS Step Functions

Atresmedia Tech hace uso de orquestación de servicios AWS mediante AWS Step Functions. Con el objetivo de dar una mayor resiliencia y tolerancia a fallos, la mayoría de sus componentes hacen uso de la gestión de excepciones, para generar reintentos para cada una de sus tareas llevando a cabo back-off de el tiempo necesario de acuerdo a la tarea en cuestión.

Ejemplo para el caso de una tarea que hace uso de una función AWS Lambda:

AWS Step Functions

Aún así, en determinadas tareas donde se realiza un trabajo asíncrono, como puede ser la creación de un cluster EMR que posteriormente ejecute un job, implicaría realizar un proceso más complejo de reintentos a medida que gestione dichos fallos y genere automáticamente la tarea. Es ahí donde se utiliza Amazon EventBridge para resolver este desafío..

Amazon EventBridge es un bus de eventos serverless que facilita la creación de aplicaciones basadas en eventos generados en la infraestructura de AWS.

Gráfica de la solución

Arquitectura

En caso de error de una tarea de AWS Step Functions, AWS generará el siguiente evento de manera interna.

{

"version": "0",

"id": "315c1398-40ff-a850-213b-158f73e60175",

"detail-type": "Step Functions Execution Status Change",

"source": "aws.states",

"account": "123456789012",

"time": "2019-02-26T19:42:21Z",

"region": "us-east-1",

"resources": ["arn:aws:states:us-east-1:123456789012:execution:state-machine-name:execution-name"],

"detail": {

"executionArn": "arn:aws:states:us-east-1:123456789012:execution:state-machine-name:execution-name",

"stateMachineArn": "arn:aws:states:us-east-1:123456789012:stateMachine:state-machine",

"name": "execution-name",

"status": "FAILED",

"startDate": 1551225146847,

"stopDate": 1551225151881,

"input": "{}",

"output": null

}

}

Teniendo esta información, se puede generar una regla en Amazon EventBridge donde en caso de error de una determinada Step Function, indicando el arn, vuelva a lanzar un reintento automático con ayuda de una función AWS Lambda como target de dicha regla.

El patrón sería el siguiente:

Patron del evento

Target de la regla de Amazon EventBridge

Target

Función

En cuanto al código de la función AWS Lambda que realiza los reintentos, este seria un ejemplo:

import json

import boto3

import os

import logging

from datetime import datetime

import pytz

from botocore.exceptions import ClientError

logger = logging.getLogger()

LOG_LEVEL = int(os.environ.get('logging_level'))

logger.setLevel(LOG_LEVEL)

def transform_input(execution_arn, input):

input_transformed = input.replace('"Timeout": 30', '"Timeout": 5')

return input_transformed

def retry_stepfunction(event, execution_arn, date):

try:

client = boto3.client('stepfunctions')

response = client.describe_execution(

executionArn=execution_arn.get("executionArn")

)

input_transformed = transform_input(execution_arn.get("stateMachineArn"), response['input'])

response = client.start_execution(

stateMachineArn=execution_arn.get("stateMachineArn"),

name='Automatic_Retry_' + date[0] + '_' + date[1],

input=input_transformed

)

return {

'statusCode': 200,

'body': json.dumps('Retry done!!')

}

except ClientError as e:

logger.error('Unexpected error creating the logs client: {}'.format(e))

except Exception as e:

logger.error('General error: {}'.format(e))

def lambda_handler(event, _):

try:

execution_arn = event['detail']

local_date = datetime.now(pytz.timezone('Europe/Berlin'))

date = local_date.strftime('%Y-%m-%d %H')

date = date.split()

retry_stepfunction(event, execution_arn, date)

logger.info('Retry in the Stepfunction: {}'.format(execution_arn))

except Exception as e:

logger.error('General error: {}'.format(e))

if __name__ == '__main__':

ev = {

'version': '0',

'id': '2805af6c-cd5f-5014-7583-5f9157db0c06',

'detail-type': 'Step Functions Execution Status Change',

'source': 'aws.states',

'account': '0123456789',

'time': '2022-04-19T14:36:03Z',

'region': 'eu-west-1',

'resources': [

'arn:aws:states:eu-west-1: '0123456789':execution:Stepfunction-analytics:c2946495-0361-9b3c-d436-b069d89b251d'],

'detail': {

'executionArn': 'arn:aws:states:eu-west-1:013791148040:execution: Stepfunction-analytics:c2946495-0361-9b3c-d436-b069d89b251d',

'stateMachineArn': 'arn:aws:states:eu-west-1:0123456789:stateMachine: Stepfunction-analytics ',

'name': 'c2946495-0361-9b3c-d436-b069d89b251d',

'status': 'FAILED',

'startDate': 1650378963518,

'stopDate': 1650378963649,

'input': '{}',

'inputDetails': {'included': True}, 'output': None, 'outputDetails': None}

}

logger.info(lambda_handler(ev, None))

El método transform_input permitirá modificar el input de la StepFunction, en caso de querer que el reintento tenga algún nuevo valor o modificación.

En cuanto a la línea de código name='Automatic_Retry_' + date[0] + '_' + date[1], permite que únicamente se ejecute un reintento por hora, evitando múltiples reintentos seguidos en caso de error de otro tipo.

reintentos

Conclusión

Atresmedia Tech usa Amazon EventBridge para mejorar la resiliencia y tolerancia a fallos en determinadas ETLs, que deben completarse en un determinado horario, para proveer la información procesada a los usuarios.

El uso de esta solución con el servicio de Amazon EventBridge genera mejores tiempos de respuesta en caso de error, además de reducir el volumen de operativa manual por parte de un equipo de guardia dedicado 24×7 a tareas de monitorización.

Agustín González Tuñón

Agustín González Tuñón

Agustín González Tuñón, director general de Atresmedia Tech, se desempeña como CIO responsable del área de Tecnología, Sistemas de Información y Seguridad del grupo Atresmedia, compañía audiovisual líder de comunicación en España, con posiciones clave en todos los sectores en los que opera: Televisión, Radio, Internet, Cine, Producción para terceros y Formación.

Alberto López Perruca

Alberto López Perruca

Alberto López Perruca es Ingeniero en Informática y Arquitecto Cloud en Atresmedia TECH, cuenta con más de 15 años de experiencia trabajando en la industria del software construyendo y escalando aplicaciones. Su pasión es diseñar sistemas que puedan aprovechar al máximo la nube, adoptando la cultura DevOps.

Juan Manuel Gomez

Juan Manuel Gomez

Juan Manuel Gomez es un Enterprise Solutions Architect en AWS. Como Enterprise SA, ayuda a diseñar e implementar los servicios de AWS en entornos de gran escala. Con más de 15 años de experiencia en la industria de TI, Juanma se especializó en servicios de gobierno en la nube y migraciones ayudando a los clientes a acelerar la adopción de la nube para lograr sus objetivos de negocio.