Compartir vía


Mejorar el rendimiento y la confiabilidad de Azure Functions

En este artículo se proporcionan instrucciones para mejorar el rendimiento y la confiabilidad de las aplicaciones de funciones sin servidor . Para obtener un conjunto más general de procedimientos recomendados de Azure Functions, consulte Azure Functions procedimientos recomendados.

A continuación se muestran los procedimientos recomendados para crear y diseñar soluciones sin servidor mediante Azure Functions.

Evitar funciones de larga duración

Las funciones grandes y de ejecución prolongada pueden provocar problemas de tiempo de espera inesperados. Para más información sobre los tiempos de espera de un plan de hospedaje determinado, consulte Duración del tiempo de espera de la aplicación de funciones.

Una función puede ser grande debido a muchas Node.js dependencias. La importación de dependencias también puede provocar un aumento de los tiempos de carga que dan lugar a interrupciones por tiempo de espera inesperadas. Las dependencias se cargan de forma explícita e implícita. Un único módulo cargado por el código puede cargar sus propios módulos adicionales.

Siempre que sea posible, refactorice las funciones grandes en conjuntos de funciones más pequeños que funcionan juntos y devuelven respuestas rápidamente. Por ejemplo, un webhook o una función de desencadenador HTTP podría requerir una respuesta de confirmación dentro de un límite de tiempo determinado; Es habitual que los webhooks requieran una respuesta inmediata. Puede pasar la carga útil del desencadenador HTTP a una cola para que sea procesada por una función de desencadenador de cola. Este enfoque le permite aplazar el trabajo real y devolver una respuesta inmediata.

Asegúrese de que las tareas en segundo plano se completen

Cuando tu función inicia cualquier tarea, devolución de llamada, subproceso o proceso, deben completarse antes de que el código de tu función regrese. Dado que Functions no realiza un seguimiento de estos subprocesos en segundo plano, el apagado del sitio puede producirse independientemente del estado del subproceso en segundo plano, lo que puede provocar un comportamiento no deseado en las funciones.

Por ejemplo, si una función inicia una tarea en segundo plano y devuelve una respuesta correcta antes de que se complete la tarea, el tiempo de ejecución de Functions considera que la ejecución se ha completado correctamente, independientemente del resultado de la tarea en segundo plano. Si esta tarea en segundo plano realiza un trabajo esencial, es posible que el cierre del sitio pueda interrumpirla, dejando ese trabajo en un estado desconocido.

Comunicación entre funciones

Durable Functions y Azure Logic Apps se crean para administrar las transiciones de estado y la comunicación entre varias funciones.

Si no usa Durable Functions o Logic Apps para integrarse con varias funciones, es mejor usar colas de almacenamiento para la comunicación entre funciones. La razón principal es que las colas de almacenamiento son más baratas y mucho más fáciles de aprovisionar que otras opciones de almacenamiento.

Los mensajes individuales de una cola de almacenamiento tienen un tamaño limitado a 64 KB. Si necesita pasar mensajes más grandes entre funciones, se podría usar una cola de Azure Service Bus para admitir tamaños de mensaje de hasta 256 KB en el nivel Estándar y hasta 100 MB en el nivel Premium.

Service Bus tópicos son útiles si necesita un filtrado de mensajes antes de su procesamiento.

Los centros de eventos son útiles para admitir comunicaciones de gran volumen.

Escriba funciones sin estado

Las funciones deben carecer de estado e idempotentes si es posible. Asocie cualquier información de estado necesaria a los datos. Por ejemplo, un pedido que se está procesando probablemente tenga un miembro asociado. Una función podría procesar un orden basado en ese estado mientras la propia función permanece sin estado.

Las funciones idempotentes se recomiendan especialmente con disparadores de temporizador. Por ejemplo, si tiene algo que absolutamente debe ejecutarse una vez al día, escríbalo para que pueda ejecutarse en cualquier momento durante el día con los mismos resultados. La función puede salir cuando no hay trabajo durante un día determinado. Además, si una ejecución anterior no se pudo completar, la siguiente ejecución debe continuar desde donde se quedó. Esto es especialmente importante para los enlaces basados en mensajes que se reintentan en caso de error. Para obtener más información, consulte Diseñar funciones de Azure para entradas idénticas.

Escribe funciones defensivas

Supongamos que la función podría encontrar una excepción en cualquier momento. Diseñe las funciones con la capacidad de continuar desde un punto de error anterior durante la siguiente ejecución. Considere un escenario que requiera las siguientes acciones:

  1. Consulta de 10 000 filas en una base de datos.
  2. Cree un mensaje de cola para cada una de esas filas para su posterior procesamiento.

Dependiendo de la complejidad de su sistema, es posible que tenga: los servicios aguas abajo implicados que se comportan mal, interrupciones de red o límites de uso alcanzados, etc. Cualquiera de estos puede afectar a su función en cualquier momento. Debe diseñar sus funciones para que estén preparadas.

¿Cómo reacciona el código si se produce un error después de insertar 5000 de esos elementos en una cola para su procesamiento? Realice un seguimiento de los elementos de un conjunto que haya completado. De lo contrario, puede volver a insertarlos la próxima vez. Esta inserción doble puede tener un impacto grave en el flujo de trabajo, por eso asegúrate de que tus funciones sean idempotentes.

Si ya se procesó un elemento de cola, configure la función para que sea una operación nula.

Aproveche las medidas defensivas ya proporcionadas para los componentes que use en la plataforma Azure Functions. Por ejemplo, consulte Handling poison queue messages en la documentación de Azure Storage Queue triggers and bindings.

Para las funciones basadas en HTTP, considere utilizar estrategias de control de versiones de API con Azure API Management. Por ejemplo, si tiene que actualizar la aplicación de funciones basada en HTTP, implemente la nueva actualización en una aplicación de función independiente y use revisiones o versiones de API Management para dirigir a los clientes a la nueva versión o revisión. Una vez que todos los clientes usan la versión o revisión y no quedan más ejecuciones en la aplicación de funciones anterior, puede desaprovisionar la aplicación de funciones anterior.

Procedimientos recomendados de la organización de funciones

Como parte de la solución, puede desarrollar y publicar varias funciones. Estas funciones suelen combinarse en una única aplicación de funciones, pero también se pueden ejecutar en aplicaciones de funciones independientes. En los planes de hospedaje Premium y dedicados (App Service), varias aplicaciones de funciones también pueden compartir los mismos recursos mediante la ejecución en el mismo plan. La forma de agrupar las funciones y las aplicaciones de funciones puede afectar al rendimiento, el escalado, la configuración, la implementación y la seguridad de la solución general. No hay reglas que se apliquen a todos los escenarios, por lo que debe tener en cuenta la información de esta sección al planear y desarrollar las funciones.

Organización de funciones para el rendimiento y el escalado

Cada función que crea tiene una huella de memoria. Aunque esta superficie suele ser pequeña, tener demasiadas funciones dentro de una aplicación de funciones puede provocar un inicio más lento de la aplicación en nuevas instancias. También significa que el uso general de memoria de la aplicación de funciones puede ser mayor. Es difícil decir cuántas funciones deben estar en una sola aplicación, que depende de la carga de trabajo determinada. Sin embargo, si la función almacena una gran cantidad de datos en memoria, considere la posibilidad de tener menos funciones en una sola aplicación.

Si ejecuta varias aplicaciones de funciones en un único plan Premium o un plan dedicado (App Service), estas aplicaciones comparten todos los mismos recursos asignados al plan. Si tiene una aplicación de función que tiene un requisito de memoria mucho mayor que los demás, usa una cantidad desproporcionada de recursos de memoria en cada instancia en la que se implementa la aplicación. Dado que esto podría dejar menos memoria disponible para las otras aplicaciones de cada instancia, es posible que quiera ejecutar una aplicación de funciones con memoria alta, como esta en su propio plan de hospedaje independiente.

Nota:

Al usar el plan de consumo, se recomienda colocar siempre cada aplicación en su propio plan, ya que las aplicaciones se escalan de forma independiente de todos modos. Para obtener más información, consulte Varias aplicaciones en el mismo plan.

Tenga en cuenta si desea agrupar funciones con perfiles de carga diferentes. Por ejemplo, si tiene una función que procesa muchos miles de mensajes de cola y otra a la que solo se llama ocasionalmente, pero tiene requisitos de memoria elevados, es posible que quiera implementarlos en aplicaciones de funciones independientes para que obtengan sus propios conjuntos de recursos y se escalen independientemente entre sí.

Organización de funciones para la configuración y la implementación

Las aplicaciones de funciones tienen un archivo />

Todas las funciones del proyecto local se implementan juntas como un conjunto de archivos en la aplicación de funciones en Azure. Es posible que tenga que implementar funciones individuales por separado o usar características como ranuras de implementación para algunas funciones y no otras. En tales casos, debe implementar estas funciones (en proyectos de código independientes) en diferentes aplicaciones de funciones.

Organización de funciones por privilegio

Las cadenas de conexión y otras credenciales almacenadas en la configuración de la aplicación proporcionan a todas las funciones de la aplicación de funciones el mismo conjunto de permisos en el recurso asociado. Considere la posibilidad de minimizar el número de funciones con acceso a credenciales específicas moviendo las funciones que no las utilizan a una aplicación de funciones independiente. Siempre puede usar técnicas como el encadenamiento de funciones para pasar datos entre funciones de diferentes aplicaciones de funciones.

Procedimientos recomendados de escalabilidad

Hay varios factores que afectan a cómo se realiza la escalabilidad de las instancias de tu aplicación de funciones. Los detalles se proporcionan en la documentación para el escalado de funciones. A continuación se muestran algunos procedimientos recomendados para garantizar una escalabilidad óptima de una aplicación de funciones.

Uso compartido y administración de conexiones

Vuelva a usar conexiones a recursos externos siempre que sea posible. Consulte cómo administrar conexiones en Azure Functions.

Evitar el uso compartido de cuentas de almacenamiento

Al crear una aplicación de funciones, debe asociarla a una cuenta de almacenamiento. La conexión de la cuenta de almacenamiento se mantiene en la configuración de la aplicación AzureWebJobsStorage.

Para maximizar el rendimiento, use una cuenta de almacenamiento independiente para cada aplicación de función. Este enfoque es especialmente importante cuando tiene funciones desencadenadas Durable Functions o Event Hubs, que generan un gran volumen de transacciones de almacenamiento. Cuando la lógica de la aplicación interactúa con Azure Storage, ya sea directamente (mediante el SDK de Storage) o a través de uno de los enlaces de almacenamiento, debe usar una cuenta de almacenamiento dedicada. Por ejemplo, si tiene una función desencadenada por el centro de eventos que escribe algunos datos en Blob Storage, use dos cuentas de almacenamiento: una para la aplicación de funciones y otra para los blobs que almacena la función.

No mezclar código de prueba y producción en la misma aplicación de funciones

Funciones dentro de una aplicación de funciones comparten recursos. Por ejemplo, la memoria se comparte. Si usa una aplicación de funciones en producción, no agregue a ella funciones y recursos relacionados con pruebas. Puede provocar una sobrecarga inesperada durante la ejecución del código de producción.

Tenga cuidado de lo que cargue en las aplicaciones de funciones de producción. La memoria se calcula en promedio en cada función de la aplicación.

Si tiene un ensamblado compartido al que se hace referencia en varias funciones de .NET, colóquelo en una carpeta compartida común. De lo contrario, podría implementar accidentalmente varias versiones del mismo binario que se comportan de forma diferente entre las funciones.

No use un registro detallado en el código de producción, ya que tiene un impacto negativo en el rendimiento.

Usar código asincrónico, pero evitar el bloqueo de llamadas

La programación asincrónica es un procedimiento recomendado, especialmente cuando se bloquean las operaciones de E/S.

En C#, evite siempre hacer referencia a la propiedad o llamar al método en una instancia. Este enfoque puede provocar el agotamiento de subprocesos.

Sugerencia

Si planea usar los enlaces HTTP o WebHook, debe evitar el agotamiento de puertos que puede deberse a la creación incorrecta de instancias de . Para obtener más información, consulte Cómo administrar conexiones en Azure Functions.

Usar múltiples procesos de trabajo

De forma predeterminada, cualquier instancia de host para Functions usa un único proceso de trabajo. Para mejorar el rendimiento, especialmente con entornos de ejecución de un solo subproceso como Python, use el FUNCTIONS_WORKER_PROCESS_COUNT para aumentar el número de procesos de trabajo por host (hasta 10). Azure Functions luego intenta distribuir uniformemente simultáneas invocaciones de funciones entre estos trabajadores.

El FUNCTIONS_WORKER_PROCESS_COUNT se aplica a cada host que Functions crea al distribuir la carga de la aplicación para satisfacer la demanda.

Recibir mensajes por lotes siempre que sea posible

Algunos desencadenadores como Event Hubs permiten recibir un lote de mensajes en una sola invocación. Los mensajes de procesamiento por lotes tienen un rendimiento mucho mejor. Puede configurar el tamaño máximo del lote en el archivo, tal como se detalla en la documentación de referencia dehost.json.

Para funciones en C#, puede cambiar el tipo a una matriz fuertemente tipada. Por ejemplo, en lugar de la firma del método podría ser . Para otras lenguas, deberá establecer explícitamente la propiedad de cardinalidad de function.json a many para habilitar el procesamiento por lotes como se muestra aquí.

Configuración de comportamientos de host para controlar mejor la simultaneidad

El archivo de la aplicación de funciones permite la configuración del tiempo de ejecución del host y los comportamientos de desencadenador. Además de los comportamientos de procesamiento por lotes, puede administrar la simultaneidad de varios desencadenadores. Frecuentemente, el ajustar los valores de estas opciones puede hacer que cada instancia se escale adecuadamente para satisfacer la demanda de las funciones que se invocan.

La configuración del archivo host.json se aplica en todas las funciones de la aplicación, dentro de una sola instancia de la función. Por ejemplo, si tuviera una aplicación de funciones con dos funciones HTTP y solicitudes establecidas en 25, una solicitud a cualquiera de los desencadenadores HTTP contaría para las 25 solicitudes simultáneas compartidas. Cuando esa aplicación de funciones se escala a 10 instancias, las diez funciones permiten eficazmente 250 solicitudes simultáneas (10 instancias * 25 solicitudes simultáneas por instancia).

Otras opciones de configuración de host se encuentran en el artículo de configuración del archivo host.json.

Pasos siguientes

Para obtener más información, consulte los siguientes recursos: