Las pruebas de rendimiento son fundamentales para garantizar que una aplicación pueda soportar escenarios de uso del mundo real, especialmente cuando se enfrenta a una alta carga de tráfico. Mediante la implementación y ejecución sistemática de pruebas de rendimiento, el análisis de los resultados y la optimización basada en estos hallazgos, es posible mejorar significativamente la capacidad de respuesta, estabilidad y escalabilidad de la aplicación. El uso de marcos de prueba como Locust facilita este proceso y permite evaluar el comportamiento de la aplicación frente a diversos escenarios de tráfico.
Para comenzar a realizar pruebas de rendimiento, es necesario contar con una aplicación funcional y un marco de pruebas adecuado. En este caso, usaremos Locust, que es un marco basado en Python, ideal para simular cargas de usuarios y medir el rendimiento de una aplicación web. A continuación, se describen los pasos para configurar y ejecutar una prueba de rendimiento básica utilizando Locust.
Preparación
Antes de comenzar, debes asegurarte de que tu aplicación esté funcionando correctamente. Para los fines de esta demostración, utilizaremos una aplicación prototipo basada en FastAPI, llamada protoapp. También necesitarás instalar Locust en tu entorno virtual. Si aún no lo has hecho, puedes instalarlo ejecutando el siguiente comando:
Una vez que tengas Locust instalado, puedes proceder a configurar el archivo de pruebas, locustfile.py, en la raíz de tu proyecto. Este archivo define cómo los usuarios simularán la interacción con tu aplicación bajo prueba. Un ejemplo mínimo de configuración para un archivo locustfile.py sería el siguiente:
Ejecución de la prueba
Para ejecutar la prueba, primero asegúrate de que el servidor de FastAPI esté en funcionamiento. Puedes iniciar el servidor con el siguiente comando:
Luego, abre otra ventana de terminal y ejecuta Locust:
A continuación, abre tu navegador y navega a la URL http://localhost:8089, donde se encuentra la interfaz web de Locust. Desde allí podrás configurar los parámetros de la prueba:
-
Usuarios concurrentes: Define el número máximo de usuarios que accederán al servicio simultáneamente.
-
Tasa de incremento de usuarios: Especifica la cantidad de nuevos usuarios que se añadirán por segundo para simular un aumento en el tráfico.
Una vez que hayas configurado estos parámetros, haz clic en el botón "Start" para iniciar la simulación de tráfico a tu aplicación a través del endpoint /home definido en el archivo locustfile.py.
También puedes simular tráfico sin necesidad de la interfaz web, utilizando el siguiente comando desde la terminal:
Este comando ejecutará Locust en modo sin cabeza (sin interfaz gráfica), simulando 10 usuarios concurrentes con una tasa de generación de un usuario por segundo.
Integración en un pipeline CI/CD
Puedes llevar aún más lejos tus pruebas de rendimiento integrándolas en un pipeline de Integración Continua/Entrega Continua (CI/CD). Esto te permitirá realizar pruebas de rendimiento automáticamente antes de desplegar tu aplicación o incluso incluirlas en una rutina de pruebas más amplia. La documentación oficial de Locust ofrece una guía detallada sobre cómo probar cada aspecto del tráfico de tu aplicación.
Ampliación del alcance de las pruebas
Las pruebas de rendimiento no deben limitarse solo a medir cuántos usuarios puede soportar tu aplicación. Es importante analizar cómo se comporta la aplicación bajo diferentes condiciones, como:
-
Pruebas de escalabilidad: ¿Cómo responde la aplicación cuando aumentas el número de usuarios?
-
Pruebas de estrés: ¿Hasta qué punto tu aplicación puede manejar tráfico excesivo antes de fallar?
-
Pruebas de resistencia: ¿Cómo se comporta la aplicación durante periodos prolongados de carga constante?
-
Pruebas de recuperación: ¿Es capaz tu aplicación de recuperarse de fallos o caídas?
Estas pruebas deben realizarse en condiciones que imiten escenarios de uso realistas. Cuanto más se acerquen estas condiciones a lo que experimentarán los usuarios reales, más precisos serán los resultados. Además, es clave que las pruebas se repitan periódicamente para detectar problemas que puedan surgir tras actualizaciones o cambios en la infraestructura.
Optimización posterior a las pruebas
Una vez obtenidos los resultados de las pruebas, el siguiente paso es la optimización. Con base en los datos recolectados durante las pruebas de rendimiento, puedes identificar los cuellos de botella de la aplicación y trabajar en su mejora. Esto puede incluir:
-
Optimización de consultas SQL: Revisar y ajustar las consultas a la base de datos para que sean más eficientes.
-
Mejora del uso de recursos: Revisar el uso de memoria y CPU para asegurarte de que los recursos no se sobrecarguen.
-
Caché: Implementar mecanismos de caché para reducir la carga en el servidor y mejorar los tiempos de respuesta.
Recuerda que las pruebas de rendimiento son una parte esencial del ciclo de vida del desarrollo de software, y es fundamental realizarlas antes de realizar despliegues en producción.
¿Cómo integrar MongoDB con FastAPI para operaciones CRUD?
Para desarrollar aplicaciones eficientes y escalables, las operaciones CRUD (Crear, Leer, Actualizar y Eliminar) son fundamentales. En el contexto de FastAPI, utilizar bases de datos NoSQL como MongoDB ofrece flexibilidad en el manejo de datos sin necesidad de esquemas estrictos. A continuación, se describe cómo integrar MongoDB con FastAPI, configurando una conexión y creando endpoints para realizar operaciones CRUD en una aplicación de ejemplo.
Para comenzar, se debe tener Python y el paquete FastAPI instalados en el entorno, así como una instancia de MongoDB corriendo y accesible. Si aún no se tiene MongoDB, es posible configurar una instancia local siguiendo la documentación oficial (https://www.mongodb.com/try/download/community). Para esta receta, se utilizará una instancia de MongoDB que esté corriendo en http://localhost:27017. Si se usa otro puerto o una máquina remota, solo se debe ajustar la URL de conexión.
En primer lugar, es necesario instalar el paquete motor, el cual es el controlador asincrónico desarrollado por MongoDB para Python. Para instalarlo, se debe ejecutar el siguiente comando en la línea de comandos:
El siguiente paso es establecer la conexión con MongoDB. Esto se hace en un módulo llamado db_connection.py, donde se define un cliente de MongoDB. El código básico para la conexión es el siguiente:
Cada vez que se necesite interactuar con la instancia de MongoDB, se utilizará el objeto mongo_client. Para asegurar que la conexión esté activa, se puede crear una función que haga un "ping" al servidor de MongoDB y verificar si responde correctamente:
Esta función intentará hacer un ping al servidor. Si no se recibe respuesta, se lanzará un error y el código dejará de ejecutarse.
Una vez que la conexión esté configurada, es necesario gestionar el ciclo de vida del servidor FastAPI. Esto se hace mediante un contexto asincrónico llamado lifespan, el cual se encarga de verificar la conexión a MongoDB cuando se inicia el servidor:
Al iniciar el servidor con el siguiente comando:
Se verá un mensaje de log que confirmará la conexión exitosa con MongoDB.
Con la conexión lista, ahora se puede proceder a implementar las operaciones CRUD en FastAPI. Primero, se debe crear una base de datos en MongoDB. En este caso, se usará una base de datos llamada beat_streaming:
No es necesario realizar ninguna acción adicional en el lado del servidor de MongoDB, ya que la librería motor se encargará de verificar si la base de datos y las colecciones existen y las creará automáticamente si no lo están.
Luego, se debe definir una función que devuelva esta base de datos como dependencia en las rutas de FastAPI, lo cual ayudará a mantener el código organizado y reutilizable:
Ahora se puede proceder a crear los endpoints para las operaciones CRUD. El primero es para agregar una canción a la colección songs en MongoDB. Este endpoint recibirá un objeto JSON con los detalles de la canción y lo almacenará en la base de datos:
Este endpoint permitirá agregar una canción a la colección de MongoDB, devolviendo el ID del documento insertado.
Para leer una canción desde la base de datos, se crea un endpoint de tipo GET que reciba el song_id y devuelva los datos correspondientes:
Si la canción con el ID proporcionado no existe, se devolverá un error 404.
Para actualizar una canción, el endpoint utilizará el método PUT. Recibirá un song_id y los nuevos datos para la canción, y actualizará el documento correspondiente:
Este endpoint actualizará la canción correspondiente, o devolverá un error si no se encuentra el documento o si no se realizó ninguna modificación.
Estas son las bases de las operaciones CRUD con MongoDB en FastAPI, pero se pueden añadir muchas más funcionalidades como filtros avanzados, validación de datos o paginación. Es importante tener en cuenta que, al trabajar con MongoDB, se tiene la ventaja de no estar atado a un esquema rígido como en las bases de datos SQL. Esto facilita el trabajo con datos no estructurados o de estructuras flexibles, lo cual es particularmente útil en aplicaciones modernas como plataformas de streaming, donde los tipos de datos pueden cambiar rápidamente.
¿Cómo implementar la internacionalización y optimizar el rendimiento de una aplicación FastAPI?
La implementación de la internacionalización (i18n) y la localización (l10n) en una aplicación web no solo permite que el contenido se adapte a distintos idiomas, sino que también facilita la entrega de contenido personalizado, como la moneda o la fecha, según la región del usuario. Estos conceptos se han vuelto imprescindibles en el desarrollo de plataformas globales, como en el caso de aplicaciones que desean ofrecer una experiencia fluida a usuarios de todo el mundo. En este sentido, el uso de FastAPI, un framework eficiente y flexible para la creación de APIs, es una excelente opción para lograr estos objetivos de manera óptima.
Al desarrollar la funcionalidad de internacionalización, uno de los primeros pasos consiste en crear una función que maneje el encabezado Accept-Language, utilizado por los navegadores para enviar al servidor la preferencia de idioma del usuario. Para lograrlo, podemos implementar una función como resolve_accept_language, que procesa este encabezado para devolver un valor adecuado de localización.
La implementación de la función comienza importando el módulo babel y creando una instancia de la clase Locale. La función toma el valor del encabezado Accept-Language y lo divide en una lista de preferencias de idioma, utilizando el parámetro q que indica la prioridad del idioma preferido. Luego, esta lista se ordena según la prioridad del valor q, asegurando que el idioma preferido sea el primero en la lista. Para determinar cuál es el idioma más adecuado para la aplicación, utilizamos la función negotiate_locale de Babel. Si no hay un idioma que coincida con los valores disponibles en la configuración, se retorna por defecto el idioma inglés (en_US).
Además, en una implementación real, los contenidos traducidos no se deben almacenar directamente en el código como un diccionario estático, sino que deben ser recuperados desde una base de datos, lo que permite una mayor escalabilidad y flexibilidad. Por ejemplo, para un endpoint /homepage, el contenido de la página de inicio se puede almacenar en diferentes idiomas (como "Welcome to Trip Platform" para inglés y "Bienvenue sur Trip Platform" para francés). A través del uso de la dependencia resolve_accept_language, FastAPI selecciona el contenido adecuado para el usuario.
En un escenario similar, es posible que se necesite adaptar la moneda en función del idioma o la región. Para ello, un endpoint como /show/currency podría devolver la moneda correcta para cada usuario, utilizando un patrón similar al de la página de inicio. En este caso, los valores de las monedas, como "USD" para Estados Unidos y "EUR" para Francia, se gestionan también con la ayuda del encabezado Accept-Language.
Es importante tener en cuenta que la localización y la internacionalización no solo se limitan a la traducción de cadenas de texto. Factores como el formato de fecha y hora, el tipo de moneda, y el uso de unidades de medida son esenciales para ofrecer una experiencia de usuario verdaderamente local. Por ejemplo, la visualización de la fecha en formato "dd/mm/yyyy" en lugar de "mm/dd/yyyy" o la adaptación de las unidades métricas según la región del usuario (kilómetros frente a millas) son detalles fundamentales para que la aplicación se sienta auténtica y relevante para cada región.
En paralelo con la internacionalización, la optimización del rendimiento de la aplicación es otro aspecto clave en el desarrollo de plataformas escalables y rápidas. FastAPI, aunque es conocido por su alta eficiencia, puede beneficiarse de técnicas adicionales para detectar cuellos de botella en el código y mejorar su desempeño general. Una estrategia comúnmente utilizada para este fin es la instrumentación de código, que permite medir el tiempo de ejecución de las funciones y detectar posibles áreas problemáticas.
El uso de herramientas como pyinstrument permite crear perfiles de rendimiento del código, lo que facilita la identificación de secciones del código que consumen más recursos. Para implementar un profiler en FastAPI, primero es necesario configurar el paquete pyinstrument, activando el modo asíncrono para asegurarse de que se registren los tiempos de ejecución de las funciones que usan await. Luego, se puede crear un middleware que se encargue de iniciar y detener el profiler antes y después de cada solicitud, lo que garantiza que solo se mida el tiempo de ejecución de los endpoints, evitando así el sobrecosto de la instrumentación en otras partes de la aplicación.
Este middleware se integra fácilmente en la aplicación FastAPI, y al final de cada solicitud, se genera un archivo profiler.html que muestra un desglose detallado del rendimiento de cada función llamada. Este enfoque permite a los desarrolladores detectar fácilmente las partes del código que pueden estar causando retrasos o sobrecarga, y optimizarlas según sea necesario.
En resumen, la implementación de la internacionalización y localización en una aplicación FastAPI es un proceso esencial para asegurar que la plataforma esté lista para ser utilizada por un público global. Además, es crucial implementar técnicas de optimización del rendimiento para garantizar que la aplicación pueda manejar grandes cantidades de tráfico sin perder eficiencia. Con las herramientas y métodos descritos, se puede crear una plataforma escalable, rápida y accesible para usuarios de diferentes partes del mundo.
¿Cómo ejecutar una aplicación FastAPI con múltiples trabajadores en Docker para mejorar el rendimiento?
En entornos con alto tráfico, ejecutar una aplicación FastAPI con un único trabajador puede no ser suficiente para manejar todas las solicitudes de manera eficiente. Para mejorar el rendimiento y optimizar el uso de los recursos, es posible ejecutar la aplicación FastAPI utilizando múltiples trabajadores. Esta configuración se puede lograr utilizando herramientas como Gunicorn. En este artículo, exploraremos cómo ejecutar una aplicación FastAPI con múltiples trabajadores en un contenedor Docker, y discutiremos la capacidad de Uvicorn para manejar múltiples trabajadores, así como sus limitaciones.
Preparativos previos
Es importante tener en cuenta que el paquete Gunicorn no es compatible con Windows. Para garantizar la operabilidad del sistema operativo, ejecutaremos nuestra aplicación en un contenedor Docker. Este enfoque es útil para mantener la coherencia en los entornos de desarrollo y producción, ya que Docker proporciona una plataforma independiente del sistema operativo. A continuación, abordamos los pasos para ejecutar FastAPI con Gunicorn y Docker.
Implementación de FastAPI con múltiples trabajadores
FastAPI, cuando se ejecuta con múltiples trabajadores, inicia copias de la aplicación en procesos de CPU diferentes. Esto permite distribuir la carga entre varios procesos, mejorando la escalabilidad y el rendimiento del servicio web. Para visualizar mejor esto, podemos modificar el punto de entrada de la aplicación para que devuelva el ID del proceso (PID) en cada solicitud.
En el archivo main.py, agregue las siguientes líneas de código:
A continuación, agregue Gunicorn a las dependencias del archivo requirements.txt:
Configuración de Gunicorn
En entornos Linux o macOS, basta con instalar Gunicorn en el entorno de desarrollo con el siguiente comando:
Luego, se puede ejecutar el servidor con cuatro trabajadores utilizando el siguiente comando:
Sin embargo, si está utilizando Windows, es necesario ejecutar el contenedor Docker debido a la incompatibilidad de Gunicorn con este sistema operativo. En el archivo Dockerfile.dev, agregue la instrucción CMD para especificar cómo ejecutar Gunicorn:
Ahora, construya la imagen Docker utilizando el siguiente comando:
Una vez construida la imagen, ejecute el contenedor con el siguiente comando:
El parámetro -i permite ejecutar el contenedor en modo interactivo para poder visualizar los registros.
Verificación del funcionamiento
Con el servidor en funcionamiento, puede acceder a la documentación interactiva en http://localhost:8000/docs y realizar algunas pruebas. En la salida del terminal, podrá observar diferentes PIDs que varían en cada solicitud, lo que indica que Gunicorn distribuye la carga entre varios procesos, aprovechando múltiples núcleos de CPU.
De esta manera, hemos aprendido cómo ejecutar una aplicación FastAPI con Gunicorn y múltiples trabajadores, lo que mejora el rendimiento y la escalabilidad de su servicio web. Puede experimentar con diferentes configuraciones y opciones para encontrar la mejor solución adaptada a sus necesidades.
Consideraciones adicionales
Aunque Uvicorn también puede manejar múltiples trabajadores, su gestión de procesos no es tan avanzada como la de Gunicorn en este momento. Gunicorn es más robusto para gestionar aplicaciones de alto rendimiento, especialmente cuando se utiliza con Uvicorn como su clase de trabajador.
Es importante tener en cuenta que ejecutar múltiples trabajadores tiene sus propios desafíos. Cada proceso de trabajador tiene su propio espacio de memoria y no puede compartir datos con otros procesos. Por lo tanto, es necesario utilizar un servicio centralizado o distribuido para almacenar componentes con estado, como cachés o sesiones, utilizando tecnologías como Redis o Memcached.
Además, ejecutar múltiples trabajadores puede aumentar el consumo de recursos y la posibilidad de contención en el servidor, especialmente si la aplicación es intensiva en CPU o depende mucho de las entradas y salidas. Por lo tanto, es fundamental elegir el número adecuado de trabajadores según las características de la aplicación y los recursos disponibles. Una regla general es usar la fórmula trabajadores = (2 x núcleos) + 1, donde "núcleos" es el número de núcleos de CPU en el servidor. Sin embargo, esta fórmula puede no ser adecuada para todos los casos, y será necesario realizar pruebas y ajustes finos para obtener los mejores resultados.
¿Cómo la Pandemia del Coronavirus Resalta las Oportunidades para un Proyecto Democrático Radical?
¿Cómo afectan las variaciones de proceso a la corriente de salida en un circuito CMOS?

Deutsch
Francais
Nederlands
Svenska
Norsk
Dansk
Suomi
Espanol
Italiano
Portugues
Magyar
Polski
Cestina
Русский