La arquitectura sin servidor ofrece desafíos y oportunidades de optimización y eficiencia.
En esta publicación, aprenderá de mi experiencia sobre los desafíos que implica desarrollar un servicio sin servidor orientado al alto rendimiento. Compartiré mis conocimientos sobre la exploración de estrategias multilingües y veré cómo la adopción de la diversidad en los lenguajes de programación puede conducir a soluciones más sólidas.
Tabla de contenido
Lenguaje único de elección de AWS Lambda
Siempre he creado sin servidor con Python. He utilizado el código AWS CDK de Python para crear recursos sin servidor y he escrito mis funciones Lambda con Python.
Python es una opción natural para el desarrollo sin servidor. Cuenta con una amplia gama de bibliotecas, incluidas Powertools para AWS y bibliotecas sólidas para ingenieros de datos. Su versatilidad y excelente experiencia para desarrolladores lo convierten en la mejor opción para proyectos sin servidor, ya que ofrece una experiencia de desarrollo fluida y agradable.
Pero no te fíes solo de mis palabras. Analicemos algunos datos que respaldan la superioridad de Python en el desarrollo sin servidor.
El informe 'State of Serverless' de DataDog , un recurso confiable de la industria, ha revelado que Python y NodeJS son los campeones indiscutibles en el ámbito del desarrollo sin servidor.
Durante los últimos cinco años, Python ha sido el lenguaje que mejor se adapta a mis necesidades y es en lo que mi organización se ha centrado principalmente. Para cada nuevo servicio que creamos, Python es el lenguaje elegido.
Nuevo servicio, nuevos requisitos
Últimamente he estado trabajando en un nuevo servicio que tiene dos tipos de API:
CRUD básico.
Tiempo de ejecución corto (milisegundos de un solo dígito si es posible), cálculo algorítmico de máximo rendimiento.
Usaré API Gateway para activar funciones Lambda.
En cuanto al lenguaje de programación de funciones Lambda, Python es perfecto para el primer requisito de CRUD. La API no tiene requisitos especiales y no necesita terminar en un milisegundo de un solo dígito.
Sin embargo, en cuanto al segundo, se necesitan algunas pruebas, ya que aún no se sabe si Python logra ese rendimiento.
Mis experimentos iniciales mostraron que los números de Python no eran muy buenos desde el principio y los arranques en frío que estaba experimentando eran un fastidio. Hay formas de mitigar los arranques en frío hasta cierto punto (consulte mi publicación al respecto aquí) , pero el rendimiento de Lambda en caliente aún no era lo suficientemente bueno.
No quería rendirme todavía. Hay formas de sacarle algo de rendimiento a Python.
Aproveche al máximo el rendimiento
He visto varios enfoques. Los desarrolladores aumentarían drásticamente la memoria de función de Lambda, obteniendo así una CPU mejorada y reduciendo el tiempo de ejecución total, pero a un costo adicional.
Otro enfoque que he visto es utilizar la concurrencia en forma de funciones Lambda multiproceso para casos en los que puede resultar beneficioso, como múltiples llamadas simultáneas a API o SDK. Si bien funciona, implica una complejidad adicional. Además, los requisitos futuros pueden aumentar el tiempo de ejecución y llevar el diseño actual al límite. Debemos tener en cuenta los requisitos futuros y tener la opción de ampliar el servicio.
Todas estas soluciones son válidas, pero sólo pueden llevarte hasta cierto punto. Python tiene límites y límites de rendimiento y, para ser sincero, las soluciones parecen, en mi opinión, un parche más que un método para resolver problemas. Las soluciones pueden funcionar bien por ahora, pero dejarán de funcionar con los requisitos que se añadan en el futuro.
Cuanto más pensaba en este asunto, menos confianza tenía en mi diseño original.
Recordé una frase que escuché en la conferencia de Werner en AWS re:invent 2023:
No puedo decirte cuántas veces he escuchado esta frase de parte de desarrolladores en mi vida.
El hecho de que siempre hagamos algo de la misma manera no significa que debamos seguir haciéndolo.
Me di cuenta de que estaba haciendo lo mismo. Quería volver a utilizar Python porque así es como siempre lo hemos hecho. Sin embargo, Python no se adapta a esta API desde el punto de vista del rendimiento y cada optimización es un parche que probablemente fallará cuando se introduzcan nuevos requisitos.
Algo tenía que cambiar.
Diversidad multilingüe sin servidor
Si recuerdas mi publicación sobre arranques en frío y optimizaciones, cito el tuit de AJ sobre arranques en frío e idiomas. Los arranques en frío son un presagio de rendimiento.
Ahora bien, no voy a volver a utilizar C++; dejé ese capítulo hace años y no va a volver a hacerlo. C++ no es seguro para la memoria ni fácil de usar y requeriría un tiempo prolongado para que los desarrolladores se adapten. Rust es el nuevo chico del barrio, pero he escuchado opiniones encontradas sobre su experiencia para desarrolladores y todavía no hay muchas bibliotecas a su alrededor. LLRT es demasiado nuevo para mi gusto, pero Go me llamó la atención.
Go tiene un gran equilibrio entre la experiencia del desarrollador y el rendimiento; todos los desarrolladores que conozco me han hablado muy bien de él. Es más sencillo que Rust, ofrece un buen rendimiento, tiene recolección de basura y mi empresa tiene algo de experiencia con él. Puedes leer más sobre Go y cómo se compara con Rust y Python aquí y aquí .
Así que vamos. Tendremos que comprobar el rendimiento nosotros mismos, pero ahora tenemos una nueva y prometedora dirección. Sin embargo, tenemos que abordar dos cuestiones nuevas:
API CRUD: ¿Lo cambiamos a Go o escribimos en Python?
API de tiempo de ejecución corto: ¿Escribimos su código CDK en GO o Python?
El dilema del lenguaje de la función Lambda
La respuesta a la primera pregunta es sencilla. Usaremos Python. No hay necesidad de complicar demasiado las cosas. También puedo seguir usando Python CDK en el proyecto CRUD.
Dividiremos el servicio en dos repositorios de código que proporcionarán dos microservicios más pequeños:
API CRUD: CDK de Python y función Lambda de Python.
API de tiempo de ejecución corto: función Go Lambda.
Es posible tener las funciones Lambda de Python y las funciones Go en el mismo proyecto. Sin embargo, esto genera una complejidad innecesaria. Por ejemplo, la carpeta de pruebas contendrá archivos de Python y Go, lo que generará un gran desorden. Como estas funciones implementan dominios diferentes y tienen requisitos diferentes, esto refuerza la idea de dividir el servicio en dos microservicios en dos repositorios: uno con funciones Lambda escritas en Python y el otro en GO.
Ahora, debemos abordar la segunda cuestión: ¿Qué lenguaje CDK deberíamos elegir para el segundo microservicio, el que contiene las funciones Go?
Lenguaje CDK IaC: ¿Único o múltiple?
Si bien el uso de un solo lenguaje para los scripts IaC y los controladores Lambda puede agilizar el desarrollo y el mantenimiento, adoptar un enfoque multilingüe puede generar claras ventajas.
Analizo las ventajas y la sinergia entre el código CDK y el código Lambda en mi sesión AWS re:invent de 2023 a continuación:
Siempre he utilizado el mismo lenguaje para la definición del CDK de IaC y el código de la función Lambda. Administrar las dependencias es más fácil, pero puedes considerarlas como dos proyectos separados en el mismo repositorio: uno para el IaC y el otro para el código del dominio empresarial, la función Lambda.
Por lo tanto, podría estar bien utilizar dos idiomas diferentes .
Para empezar, ¿por qué debería escribir CDK en Go? CDK se puede escribir en Go, pero digamos que mañana cambiamos a Rust. ¿Deberíamos cambiar nuestro código CDK a Rust? CDK no tiene una variante de Rust, ¿eso significa que nunca podremos usar Rust? No, por supuesto que no; no tiene ningún sentido. Además, no tiene sentido reescribir la construcción CDK de Python en Go solo porque el dominio empresarial está en Go. Podemos importar construcciones Python existentes en el proyecto y reutilizar el código para acelerar nuestro desarrollo. Tiene poco sentido renunciar a estas ventajas porque nuestra función Lambda está escrita en Go.
Una de las principales ventajas de CDK Python es la familiaridad que tienen nuestros desarrolladores con él. Al utilizar Python, pueden escribir rápidamente la parte de CDK, lo que les permite centrarse en el dominio empresarial en Go y mitigar el riesgo y la complejidad generales del servicio.
En última instancia, el dominio empresarial tiene prioridad sobre el código CDK. Independientemente del lenguaje que elijamos, CDK creará los recursos necesarios. El rendimiento de las funciones de Go afecta directamente al negocio, por lo que es fundamental dirigir nuestros esfuerzos hacia donde más importan.
En resumen, Python CDK está bien y se puede utilizar para crear funciones Go Lambda o cualquier otro lenguaje.
La documentación de AWS es sorprendentemente excelente y creé una canalización CI/CD con CDK que compila un ejecutable Go e implementa un API Gateway en una hora, activando una función Go Lambda.
Diversidad en servidores sin servidor y contenedores
Podemos llevarlo aún más lejos. Me atrevo a decir, como héroe sin servidor , que las funciones Lambda pueden no ser el mejor caso de uso para mi nuevo servicio. Suponiendo una gran escala y un tráfico constante, las funciones Lambda pueden costar mucho más que sus contrapartes en contenedores. Sin embargo, debe considerar el costo de mantenimiento, parches, seguridad y tiempo de desarrollo y combinar todos los factores para decidir. En esta publicación, analizo FinOps y la importancia de considerar el costo en la etapa de diseño.
En un principio, mi servicio utilizará funciones Lambda para comenzar y brindar valor a nuestros clientes de API lo antes posible. Sin embargo, en el futuro, sería prudente considerar el uso de contenedores teniendo en cuenta la escala y el costo futuros.
Mi opinión final
No tengas miedo de probar algo nuevo.
Como arquitecto, debes adaptar la solución a los requisitos y tener en cuenta los cambios futuros. No elijas una solución porque siempre lo has hecho así. Cuando te des cuenta de que no se ajusta a tus requisitos, debes ser lo suficientemente valiente como para hacer un cambio.
La diversidad en los lenguajes sin servidor es un excelente ejemplo de este enfoque.
Debes elegir Go o Rust para casos de uso orientados al rendimiento y Python para los demás (o Node.JS si tienes experiencia).
Por último, no hay problema si se combina un CDK de Python con un lambda de Go en el mismo proyecto si se utiliza AWS CDK. El lenguaje del CDK NO tiene por qué coincidir con el lenguaje Lambda.