¿Estás visitando desde Argentina?
Ingresá a Linware Argentina ⯈
Continuar en Linware Argentina ⯈
×
¿Qué estás buscando?
BUSCAR!
BLOG
Optimización de los recursos y costos de la nube con metadatos APM en Elastic Observability
Publicada el 13/12/2023

La supervisión del rendimiento de las aplicaciones (APM) es mucho más que capturar y rastrear errores y seguimientos de pila. Las empresas actuales basadas en la nube implementan aplicaciones en varias regiones e incluso en proveedores de la nube. Por lo tanto, aprovechar el poder de los metadatos proporcionados por los agentes de Elastic APM se vuelve más crítico. Aprovechar los metadatos, incluida información crucial como la región de la nube, el proveedor y el tipo de máquina, nos permite realizar un seguimiento de los costos en toda la pila de aplicaciones. En esta publicación de blog, analizamos cómo podemos utilizar los metadatos de la nube para capacitar a las empresas para que tomen decisiones más inteligentes y rentables, al mismo tiempo que mejoramos la utilización de los recursos y la experiencia del usuario.

Primero, necesitamos una aplicación de ejemplo que nos permita monitorear los cambios de infraestructura de manera efectiva. Usamos una aplicación Python Flask con el agente APM de Elastic Python. La aplicación es una calculadora sencilla que toma los números como una solicitud REST. Utilizamos Locust, una sencilla herramienta de prueba de carga para evaluar el rendimiento bajo diferentes cargas de trabajo.

El siguiente paso incluye obtener la información de precios asociada con los servicios en la nube. Cada proveedor de nube es diferente. La mayoría de ellos ofrecen una opción para recuperar precios a través de una API. Pero hoy nos centraremos en Google Cloud y aprovecharemos su calculadora de precios para recuperar información de costos relevante.

 

La calculadora y los precios de Google Cloud

Para realizar un análisis de costos, necesitamos conocer el costo de las máquinas en uso. Google proporciona una API de facturación y una biblioteca de cliente para recuperar los datos necesarios mediante programación. En este blog, no cubrimos el enfoque API. En cambio, la Calculadora de precios de Google Cloud es suficiente. Seleccione el tipo de máquina y la región en la calculadora y establezca el recuento en 1 instancia. Luego informará el costo total estimado para esta máquina. Hacer esto para un tipo de máquina e2-estándar-4 da como resultado 107,7071784 dólares estadounidenses por un tiempo de ejecución de 730 horas.

Ahora, vayamos a nuestro Kibana ® donde crearemos un nuevo índice dentro de Dev Tools. Como no queremos analizar texto, le diremos a Elasticsearch ® que trate cada texto como una palabra clave. El nombre del índice es facturación en la nube . Quizás quiera hacer lo mismo para Azure y AWS, luego puedo agregarlo al mismo índice.

 
PUT cloud-billingn{n  "mappings": {n    "dynamic_templates": [n      {n        "stringsaskeywords": {n          "match": "*",n          "match_mapping_type": "string",n          "mapping": {n            "type": "keyword"n          }n        }n      }n    ]n  }n}
 
 

El siguiente paso es elaborar nuestro documento de facturación:

 
POST cloud-billing/_doc/e2-standard-4_europe-west4n{n  "machine": {n    "enrichment": "e2-standard-4_europe-west4"n  },n  "cloud": {n    "machine": {n       "type": "e2-standard-4"n    },n    "region": "europe-west4",n    "provider": "google"n  },n  "stats": {n    "cpu": 4,n    "memory": 8n  },n  "price": {n    "minute": 0.002459068,n    "hour": 0.14754408,n    "month": 107.7071784n  }n}
 
 

Creamos un documento y establecemos una identificación personalizada. Este ID coincide con el nombre de la instancia y la región, ya que los costos de las máquinas pueden diferir en cada región. Las identificaciones automáticas podrían ser problemáticas porque es posible que desee actualizar periódicamente el costo de una máquina. Podría usar un índice con marca de tiempo para eso y solo usar la última coincidencia de documentos. Pero de esta manera puedo actualizar y no tengo que preocuparme por eso. También calculé el precio en minutos y horas. Lo más importante es el campo machine.enrichment , que es el mismo que el ID. El mismo tipo de instancia puede existir en varias regiones, pero nuestro procesador de enriquecimiento está limitado a coincidencias o rangos. Creamos un nombre coincidente que pueda coincidir explícitamente como en e2-standard-4_europe-west4 . Depende de usted decidir si desea que el proveedor de la nube esté allí y convertirlo en google_e2-standard-4_europ-west-4 .

 

Calculando el costo

Hay varias formas de lograr esto en Elastic Stack. En este caso, utilizaremos una política de enriquecimiento, incorporaremos la canalización y la transformaremos.

 

La política de enriquecimiento es bastante fácil de configurar:

 
PUT _enrich/policy/cloud-billingn{n  "match": {n    "indices": "cloud-billing",n    "match_field": "machine.enrichment",n    "enrich_fields": ["price.minute", "price.hour", "price.month"]n  }n}nnPOST _enrich/policy/cloud-billing/_execute
 
 

No olvide ejecutar _execute al final. Esto es necesario para elaborar los índices internos utilizados por el enriquecimiento en la tubería de ingesta. La canalización de ingesta es bastante minimalista: llama al enriquecimiento y cambia el nombre de un campo. Aquí es donde entra en juego nuestro campo machine.enrichment . Una advertencia sobre el enriquecimiento es que cuando agrega nuevos documentos al índice de facturación en la nube, debe volver a ejecutar la instrucción _execute . El último bit calcula el costo total con el recuento de máquinas únicas vistas.

 
PUT _ingest/pipeline/cloud-billingn{n  "processors": [n    {n      "set": {n        "field": "_temp.machine_type",n        "value": "{{cloud.machine.type}}_{{cloud.region}}"n      }n    },n    {n      "enrich": {n        "policy_name": "cloud-billing",n        "field": "_temp.machine_type",n        "target_field": "enrichment"n      }n    },n    {n      "rename": {n        "field": "enrichment.price",n        "target_field": "price"n      }n    },n    {n      "remove": {n        "field": [n          "_temp",n          "enrichment"n        ]n      }n    },n    {n      "script": {n        "source": "ctx.total_price=ctx.count_machines*ctx.price.hour"n      }n    }n  ]n}
 
 

Como todo esto ya está configurado, estamos listos para nuestra Transformación. Para esto, necesitamos una vista de datos que coincida con los flujos de datos de APM. Esto es traces-apm* , metrics-apm.* , logs-apm.* . Para Transform, vaya a la interfaz de usuario de Transform en Kibana y configúrela de la siguiente manera:

 
 
 
 

Estamos haciendo un desglose por horas, por lo tanto, obtengo un documento por servicio, por hora, por tipo de máquina. Lo interesante son las agregaciones. Quiero ver el uso promedio de la CPU y el percentil 75,95,99, para ver el uso de la CPU cada hora. Permitiéndome identificar el uso de la CPU durante una hora. En la parte inferior, asigne un nombre a la transformación, seleccione un índice de costos de nube y seleccione la canalización de ingesta de facturación  en la nube .

 

Aquí está la transformación completa como documento JSON:

 
PUT _transform/cloud-billingn{n  "source": {n    "index": [n      "traces-apm*",n      "metrics-apm.*",n      "logs-apm.*"n    ],n    "query": {n      "bool": {n        "filter": [n          {n            "bool": {n              "should": [n                {n                  "exists": {n                    "field": "cloud.provider"n                  }n                }n              ],n              "minimum_should_match": 1n            }n          }n        ]n      }n    }n  },n  "pivot": {n    "group_by": {n      "@timestamp": {n        "date_histogram": {n          "field": "@timestamp",n          "calendar_interval": "1h"n        }n      },n      "cloud.provider": {n        "terms": {n          "field": "cloud.provider"n        }n      },n      "cloud.region": {n        "terms": {n          "field": "cloud.region"n        }n      },n      "cloud.machine.type": {n        "terms": {n          "field": "cloud.machine.type"n        }n      },n      "service.name": {n        "terms": {n          "field": "service.name"n        }n      }n    },n    "aggregations": {n      "avg_cpu": {n        "avg": {n          "field": "system.cpu.total.norm.pct"n        }n      },n      "percentiles_cpu": {n        "percentiles": {n          "field": "system.cpu.total.norm.pct",n          "percents": [n            75,n            95,n            99n          ]n        }n      },n      "avg_transaction_duration": {n        "avg": {n          "field": "transaction.duration.us"n        }n      },n      "percentiles_transaction_duration": {n        "percentiles": {n          "field": "transaction.duration.us",n          "percents": [n            75,n            95,n            99n          ]n        }n      },n      "count_machines": {n        "cardinality": {n          "field": "cloud.instance.id"n        }n      }n    }n  },n  "dest": {n    "index": "cloud-costs",n    "pipeline": "cloud-costs"n  },n  "sync": {n    "time": {n      "delay": "120s",n      "field": "@timestamp"n    }n  },n  "settings": {n    "max_page_search_size": 1000n  }n}
 
 

Una vez creada y ejecutada la transformación, necesitamos una vista de datos de Kibana para el índice: costos de nube . Para la transacción, utilice el formateador personalizado dentro de Kibana y establezca su formato en "Duración" en "microsegundos".

 
Con eso, todo está arreglado y listo para funcionar.
 

Observando cambios de infraestructura

A continuación creé un panel que nos permite identificar:

  • ¿Cuánto cuesta un determinado servicio?
  • uso de CPU
  • Uso de memoria
  • Duración de la transacción
  • Identificar el potencial de ahorro de costos
 

De izquierda a derecha, queremos centrarnos en el primer gráfico. Tenemos las barras que representan la CPU como promedio en verde y el percentil 95 en azul en la parte superior. Va de 0 a 100 % y está normalizado, lo que significa que incluso con 8 núcleos de CPU, seguirá leyendo el 100 % de uso y no el 800 %. El gráfico de líneas representa la duración de la transacción, el promedio está en rojo y el percentil 95 en morado. Por último, tenemos el área naranja en la parte inferior, que es el uso promedio de memoria en ese host.

Inmediatamente nos damos cuenta de que nuestra calculadora no necesita mucha memoria. Al pasar el cursor sobre el gráfico se muestra un uso de memoria del 2,89%. La máquina e2-standard-8 que estamos usando tiene 32 GB de memoria. Ocasionalmente alcanzamos un nivel de CPU del 100% en el percentil 95. Cuando esto sucede, vemos que la duración promedio de la transacción aumenta a 2,5 milisegundos. Sin embargo, cada hora esta máquina nos cuesta unos 30 céntimos. Con esta información, ahora podemos reducir el tamaño para adaptarlo mejor. El uso promedio de CPU es de alrededor del 11-13% y el percentil 95 no está tan lejos. 

Debido a que utilizamos 8 CPU, ahora se podría decir que el 12,5% representa un núcleo completo, pero eso es sólo una suposición en una hoja de papel. No obstante, sabemos que hay mucho margen de maniobra y podemos reducir bastante la escala. En este caso, decidí pasarme a 2 CPU y 2 GB de RAM, lo que se conoce como e2-highcpu2 . Esto debería adaptarse mejor a mi aplicación de calculadora. Apenas tocamos la RAM, el 2,89% de los 32 GB son aproximadamente 1 GB de uso. Después del cambio y reinicio de la máquina calculadora, comencé la misma prueba Locust para identificar el uso de mi CPU y, lo que es más importante, si mis transacciones se vuelven más lentas y, de ser así, en qué medida. En última instancia, quiero decidir si 1 milisegundo más de latencia vale 10 centavos más por hora. Agregué el cambio como una anotación en Lens.

Después de dejarlo funcionar por un momento, ahora podemos identificar el impacto de los hosts más pequeños. En este caso podemos ver que el promedio no cambió. Sin embargo, el percentil 95 (el 95% de todas las transacciones están por debajo de este valor) se disparó. Nuevamente, se ve mal al principio, pero al comprobarlo, pasó de ~1,5 milisegundos a ~2,10 milisegundos, un aumento de ~0,6 milisegundos. Ahora, puedes decidir si vale la pena pagar ~180$ más al mes por ese aumento de 0,6 milisegundos o si la latencia actual es lo suficientemente buena.

 

Conclusión

La observabilidad es más que simplemente recopilar registros, métricas y seguimientos. Vincular la experiencia del usuario con los costos de la nube le permite a su empresa identificar áreas en las que puede ahorrar dinero. Tener las herramientas adecuadas a su disposición le ayudará a generar esos conocimientos rápidamente. El objetivo final es tomar decisiones informadas sobre cómo optimizar el costo de la nube y, en última instancia, mejorar la experiencia del usuario.

El panel y la vista de datos se pueden encontrar en mi repositorio de GitHub . Puede descargar el archivo .ndjson e importarlo usando Objetos guardados dentro de Stack Management en Kibana.

 

Advertencias

El precio es solo para máquinas base sin información de disco, direcciones IP públicas estáticas y cualquier otro costo adicional, como licencias para sistemas operativos. Además, excluye precios al contado, descuentos o créditos gratuitos. Además, tampoco se incluyen los costes de transferencia de datos entre servicios. Solo lo calculamos en función de la tarifa por minuto del servicio en ejecución; no verificamos los intervalos de facturación de Google Cloud. En nuestro caso facturaríamos por minuto, independientemente de lo que tenga Google Cloud. El uso del recuento para instancias únicas.ids funciona según lo previsto. Sin embargo, si una máquina sólo funciona durante un minuto, lo calculamos en función de la tarifa por hora. Por lo tanto, una máquina funcionando durante un minuto costará lo mismo que funcionando durante 50 minutos, al menos como lo calculamos. La transformación utiliza intervalos de horas calendario; por lo tanto, son de 8 a.m. a 9 a.m., de 9 a.m. a 10 a.m., y así sucesivamente.

Ir al Blog