Blog de Amazon Web Services (AWS)
Sostenibilidad con Rust
Por Shane Miller y Carl Lerche
Eficiencia Energética en la Nube
Fuente: IEA (2021), Global data centre energy demand by data centre type, 2010-2022. Derechos reservados.
En todo el mundo, los data centers consumen alrededor de 200 teravatios/hora al año. Eso es aproximadamente el 1% de toda la energía consumida en nuestro planeta. Si nos fijamos en la gráfica del consumo de energía, la línea superior es básicamente plana que se remonta a 2010. Esto podría considerarse increíblemente contrario a la intuición dado el crecimiento de big data, machine learning y dispositivos de borde que nuestra industria ha experimentado durante ese mismo período de tiempo.
Otro detalle interesante es que si bien la línea superior del gráfico es plana, dentro del gráfico, la distribución sobre los centros de datos tradicionales, en la nube y de hiperescala ha cambiado dramáticamente en el mismo período. Esos centros de datos en la nube e hiperescala han estado implementando enormes mejoras de eficiencia energética, y la migración a esa infraestructura en la nube ha mantenido la utilización total de energía de estos en equilibrio a pesar del crecimiento en almacenamiento de información y computación.
Han habido marcadas mejoras en la eficiencia de los data centers durante este periodo, por ejemplo, se ha optimizado el hardware e implementado una utilización más inteligente de los recursos para reducir el tiempo de inactividad. Hemos desacelerado el crecimiento de nuestros servidores con soporte para múltiples instancias y múltiples ambientes, y hemos mejorado la densidad de unidades y la eficiencia para el almacenamiento de información. También hemos adoptado materiales de construcción y sistemas de refrigeración más eficientes energéticamente.
Por increíble que sea esa historia de éxito, son dos las preguntas que plantea: En primer lugar, ¿el status quo es lo suficientemente bueno? ¿Es adecuado mantener el uso de energía del centro de datos al 1% del consumo mundial de energía? En otras palabras, ¿las innovaciones en eficiencia energética continuarán a la par del crecimiento en almacenamiento de información y computación en el futuro? Dada la explosión que sabemos que se avecina en drones autónomos, robots de entrega y vehículos, y la increíble cantidad de consumo de datos, procesamiento y capacitación e inferencia que se requiere para soportar esas tecnologías, parece poco probable que las innovaciones de eficiencia energética puedan seguir el ritmo de la demanda.
Al igual que la seguridad, la sostenibilidad en la nube es una responsabilidad compartida. Los clientes de AWS son responsables de las opciones de eficiencia energética en cuanto a políticas de almacenamiento de información, diseño de software y utilización informática; mientras que AWS posee eficiencias en hardware, características de utilización y sistemas de enfriamiento. También estamos haciendo enormes inversiones en energías renovables.
AWS está en camino de tener el 100% de nuestros centros de datos alimentados con energía renovable para 2025. Se tomarán alrededor de medio millón de acres de paneles solares para generar los 200 teravatios hora de energía que utilizan los centros de datos en la actualidad. La minería, fabricación y gestión de tantos paneles solares tiene un impacto ambiental sustancial. Entonces, si bien estamos realmente orgullosos de nuestro éxito con las energías renovables, como dijo Peter DeSantis, SVP de AWS en re:Invent 2020, “La energía más verde es la energía que no usamos”.
Las energías renovables no deben reemplazar la eficiencia energética como principio de diseño. De la misma manera que la excelencia operativa, la seguridad y la confiabilidad han sido principios del diseño de software tradicional, la sostentabilidad debe ser un principio en el diseño de software moderno. Es por eso que AWS anunció un sexto pilar de sostenibilidad para AWS Well-Architected Framework.
Con referencia a lo práctico, una de las opciones puede ser el relajar los SLA para funciones no críticas y priorizar la eficiencia en el uso de recursos. También, podemos aprovechar la virtualización y permitir ciclos de actualización de dispositivos más largos. De la misma manera, aprovechar el almacenamiento en caché y los TTL más largos siempre que sea posible. Clasificar nuestros datos e implementar políticas de ciclo de vida automatizadas que eliminen los datos lo antes posible. Al elegir algoritmos para criptografía y compresión, podemos incluir eficiencia en nuestros criterios de decisión. Por último, pero no menos importante, podemos optar por implementar nuestro software en lenguajes de programación energéticamente eficientes.
Lenguajes de programación de eficiencia energética
Hace unos años se realizó un estudio realmente interesante que analizó la correlación entre el consumo de energía, el rendimiento y el uso de la memoria. Esta es una conversación muy común en materia de sostenibilidad. Dada la poca visibilidad que tenemos sobre el uso de energía o carbono por parte de nuestros servicios, ¿existe alguna métrica que pueda servir como un proxy? ¿Puedo ver mis paneles de servicio existentes con costos de infraestructura, performance, memoria, etc. y usar las tendencias que veo para inferir algo sobre las tendencias en el consumo de energía de mi servicio?
Lo que hizo el estudio fue implementar 10 problemas de comparación de rendimiento en 27 lenguajes de programación diferentes y medir el tiempo de ejecución, el consumo de energía y el uso máximo de memoria. C y Rust superaron significativamente a otros lenguajes en eficiencia energética. De hecho, eran aproximadamente 50% más eficientes que Java y 98% más eficientes que Python.
No es una sorpresa que C y Rust sean más eficientes que otros lenguajes. Lo que es de destacar es la magnitud de la diferencia. La amplia adopción de C y Rust podría reducir el consumo de energía de la computación en un 50%. Entonces la pregunta es ¿por qué no usar más C? El lenguaje y las herramientas de desarrollo son extremadamente maduras, y el tamaño de la comunidad de desarrolladores es mucho mayor que Rust. Durante su discurso de apertura en Open Source Summit en 2021, Linus Torvalds, el creador de Linux, reconoció que implementar código en C puede ser como hacer malabares con motosierras. Como programador de C de toda la vida, Torvalds sabe que “[las interacciones de tipo sutil de C] no siempre son lógicas [y] son trampas para casi cualquier persona”. Torvalds llamó a Rust el primer idioma que ha visto que en realidad podría ser una solución. Rust entrega la eficiencia energética de C con un comportamiento mucho más definido. Podemos reducir el consumo de energía a la mitad sin perder los beneficios de la seguridad de la memoria.
Varios análisis han concluido que más del 70% de los CVE de alta gravedad que ocurren en C/C++ se prevendrían implementando esas mismas soluciones en Rust. De hecho, el Grupo de Investigación de Seguridad de Internet (ISRG), la organización sin fines de lucro que apoya el proyecto Let’s Encrypt (la Autoridad Certificadora para más de 260 millones de sitios web), tiene el objetivo de mover toda la infraestructura sensible a la seguridad de Internet a lenguajes seguros de memoria. Los proyectos en curso incluyen soporte para Rust en el kernel de Linux y migración de curl a implementaciones de Rust de TLS y HTTP.
Mirando nuevamente ese estudio sobre correlación, tenemos mediciones para algo más que solo consumo de energía. La columna central muestra los resultados para el tiempo de ejecución, y los tiempos para Rust y C son realmente similares. Ambos idiomas se ejecutan más rápido que otros idiomas. Eso significa que, cuando elige implementar su software en Rust para obtener los beneficios de sostenibilidad y seguridad, también obtiene el rendimiento optimizado de C.
Historias de éxito de clientes de Rust
https://medium.com/tenable-techblog/optimizing-700-cpus-away-with-rust-dc7a000dbdb2
Tenable es un proveedor de soluciones de seguridad cibernética enfocado en herramientas de visibilidad de exposición que tienen un agente sidecar que filtra métricas innecesarias. Este estaba escrito en JavaScript y llevaba algunos meses trabajando en producción cuando el rendimiento comenzó a degradarse debido al escalamiento. Tenable decidió reescribir el filtro en un lenguaje más eficiente, y eligieron Rust por su rendimiento y seguridad. El resultado fue una mejora de aproximadamente 50% en la latencia tanto en la mediana como en la P95.
De la misma manera, Tenable vio una reducción del 75% en el uso de CPU y una reducción del 95% en el uso de memoria. Eso es un ahorro sustancial, y eso no es solo dólares ahorrados, eso es energía ahorrada. Estas son las gráficas de una implementación energéticamente eficiente, sostenible.
Rust se utiliza hoy en día para desplegar software de producción en el mundo real. Cuando preguntamos a los desarrolladores de Rust por qué comenzaron a usar Rust, por mucho la respuesta más común es alguna variante del performance en tiempo de ejecución, ya sea porque Rust es más rápido o porque Rust tiene latencias de cola más confiables. Casi siempre se trata de rendimiento.
https://discord.com/blog/why-discord-is-switching-from-go-to-rust
Discord comenzó como una tienda mayoritariamente Python, Go y Elixir, y tuvieron un problema con uno de sus servicios clave de Go. Era un servicio bastante sencillo, pero tenía latencias de cola lentas. Debido a que Go es un lenguaje de recolección de basura (GC), éste necesita detener la ejecución del programa de vez en cuando y ejecutar un pase de recolección. Mientras se ejecuta el GC, el proceso no puede responder a las solicitudes lo que se observa en los siguientes gráficos donde se ven los picos en la CPU y los gráficos de tiempo de respuesta cuando se está ejecutando.
Para solucionar el problema, Discord decidió intentar reescribir el servicio en Rust, y estos son los resultados: la implementación de Go está a la izquierda y la implementación de Rust a la derecha. Si bien el patrón de pico GC se ha ido en el gráfico de Rust, la diferencia realmente sorprendente es la magnitud del cambio.
La versión Rust es 10 veces más rápida en general. Se trata de mejoras tangibles y, debido a que el servidor es capaz de responder a las solicitudes de manera mucho más eficiente, se necesitan menos servidores lo que y por lo tanto se utiliza menos energía. Si bien Discord no decidió comenzar a usar Rust para reducir el consumo de energía, este es el impacto.
Una vez más, Rust no es el primer lenguaje eficiente. C ha existido durante mucho tiempo, pero Rust es el primer lenguaje de programación convencional que es eficiente sin sacrificar la seguridad. El 70% de todas las vulnerabilidades de seguridad de alta gravedad escritas con C y C ++ se deben a la falta de seguridad de la memoria, y Rust le brinda eficiencia sin sentir que está jugando con fuego.
Revelando la Salsa Secreta de Rust
La mayoría de los idiomas logran la seguridad de la memoria al administrar automáticamente la memoria en tiempo de ejecución con un recolector de basura. Los recolectores de basura rastrean referencias sobresalientes a una pieza de memoria y cuando todas las referencias salen del alcance, la memoria asociada se puede liberar.
En lugar de usar un recolector de basura para mantener la seguridad, Rust utiliza la propiedad y la verificación de préstamos. La propiedad es bastante simple, pero tiene profundas implicaciones para el resto del lenguaje de programación Rust. En Rust, toda la memoria es propiedad de una sola variable. Solo puede haber un propietario a la vez, pero la propiedad de los datos se puede transmitir.
Aquí hay un ejemplo de paso de mensajes con Go. En el lado izquierdo, creamos un regalo (gift en inglés), luego lo enviamos a través del canal. En el lado derecho, el regalo se recibe y se abre. El recolector de basura de Go va a administrar la memoria por nosotros. No obstante, en el código del lado izquierdo, accidentalmente abrimos el regalo después de enviarlo al canal. El regalo se va a abrir dos veces, resultando en un error.
Aquí está el mismo ejemplo de paso de mensajes con Rust. El regalo es creado y asignado. Decimos que la variable gift posee los datos. La propiedad del regalo se pasa al canal. El consumidor del canal recibe el regalo, tomando posesión, y es capaz de abrirlo. Si intentamos abrir el regalo después de enviarlo al canal, el compilador nos gritará, porque estamos violando las reglas de propiedad. Ya, estamos viendo como Rust nos ayuda a prevenir bugs.
Debido a que Rust aplica la regla de que solo una variable posee datos, cuando esa variable sale del alcance sin pasar la propiedad, no hay forma posible de acceder a los datos. Rust aprovecha eso y liberará automáticamente la memoria en ese momento. No es necesario liberar manualmente la memoria.
El modelo de propiedad de Rust es parte del sistema de tipos y se basa en un concepto llamado tipos afines. Un tipo afín impone una regla de que cada variable se usa como máximo una vez. La clave está en definir qué significa “usado”. En el contexto de Rust, un uso es mover los datos o eliminarlos. Mediante el uso de tipos afín, el compilador de Rust puede razonar sobre un programa y hacer cumplir sus reglas de propiedad.
El sistema de tipo afín utilizado por Rust se basa en el trabajo realizado a principios de la década de 1990, cuando algunas personas intentaron diseñar un lisp sin recolector de basura. Si bien tuvieron éxito, descubrieron que perdieron mucho performance en tiempo de ejecución debido a la copia excesiva introducida al no poder tener múltiples referencias a la misma pieza de datos.
Y esto nos lleva a la segunda innovación que ha habilitado a Rust: el verificador de préstamos. Al escribir programas más grandes tendemos a usar abstracciones para ayudar a organizar ideas. Una abstracción con la que probablemente esté familiarizado es una función. Las funciones a menudo requieren argumentos. Con solo la propiedad, para llamar a una función, necesitaríamos pasar la propiedad de los datos a la función y la función tendría que devolver la propiedad de los datos al regresar. Esto requiere copiar memoria y fue el origen de los desafíos de performance de lisp sin recolector de basura.
Para resolver esto, Rust le permite tomar prestados datos. Entonces, si tenemos un don, lo poseemos. Es nuestro. Si nuestra amiga quiere admirarlo, puede pedirlo prestado por un momento, pero luego tiene que devolvernos. Además, mientras nuestro amigo está tomando prestado el regalo, no podemos entregar la propiedad del regalo a nadie más, porque actualmente se está tomando prestado. Lo más importante es que el compilador Rust hace cumplir estas reglas, por lo que nuestro amigo no puede simplemente huir con el regalo. Y debido a que el compilador de Rust hace cumplir esa garantía, al tomar prestados datos, la memoria no tiene que ser copiada. La memoria permanece donde está y se pasa un puntero. Se garantiza que el puntero sea válido. Cuando lo pones todo junto, tienes un sistema que es eficiente y evita errores, incluso a medida que el programa se hace más grande y más complejo.
Y el mismo sistema que evita la falta de seguridad de la memoria también puede evitar carreras de datos, una categoría de error de concurrencia. Una carrera de datos ocurre cuando dos o más subprocesos acceden simultáneamente a los mismos datos y al menos uno de esos accesos es una mutación. El sistema de tipos que modela la propiedad y el préstamo es capaz de mantener la misma garantía en múltiples subprocesos, lo que permite un uso más agresivo de la concurrencia.
A continuación, se muestra un ejemplo de lo fácil que puede ser agregar concurrencia de manera segura a una aplicación de Rust. Tenemos una función que itera a través de una matriz de números y suma todos los números pares. Esta es una operación altamente paralelizable y para arreglos muy grandes, podríamos ver que la función se acelera significativamente al agregar concurrencia.
El lado izquierdo muestra una de un solo hilo y el lado derecho muestra la versión paralela usando la librería rayon. Y mira lo similares que son las funciones. Obtienes todo el poder de la concurrencia, sin los peligros, básicamente escribiendo el mismo código. La única diferencia es que usamos el método par_iter () en lugar de iter ().
La versión paralela extenderá el cálculo a través de muchos subprocesos, todo mientras evita copiar la matriz de números que se pasan como argumento. Rayon es capaz de proporcionar esta API de forma segura gracias al sistema de control de propiedad y préstamos de Rust. Todas las comprobaciones para garantizar la seguridad se realizan en tiempo de compilación.
Primeros pasos con Rust
Esperemos que a estas alturas te hayamos hecho interesarte en Rust y comenzar tu viaje de sostenibilidad en la nube. Entonces, ¿por dónde empezar? La buena noticia es que todo el contenido que necesitas está disponible en línea y hay lugares a los que puedes ir para empezar.
Primero, necesitarás aprender el lenguaje de programación Rust. El libro de Rust es un excelente recurso para comenzar a aprender el idioma. Le ayudará a instalar la cadena de herramientas de Rust y le enseñará el idioma. El sitio web también tiene ejercicios y muchos ejemplos de código para leer. Si se queda atascado en algún momento, tiene preguntas o necesita una aclaración, puede publicar en el foro de usuarios o hablar directamente en el servidor de Discord de la comunidad. El servidor Discord suele ser la forma más rápida de obtener ayuda. Siempre hay gente activa ahí que puede responder preguntas en tiempo real.
Una vez que haya pasado por el sitio web de Rust, debería estar lo suficientemente cómodo como para comenzar a construir cosas, pero hay otro recurso que queremos mencionar para profundizar. Crust of Rust es un gran canal de YouTube de Jon Gjenset. Hace inmersiones realmente profundas sobre diversos temas relacionados con Rust, levantando el capó y explicando cómo funcionan las cosas. Sus videos son de varias horas de duración, pero seguimos escuchando de la gente lo valiosos que son para aprender Rust.
El futuro de Rust
https://blog.rust-lang.org/2020/12/16/rust-survey-2020.html
Rust es difícil de aprender. De los más de 8,000 desarrolladores que respondieron a la encuesta de usuarios de Rust 2020, solo unos 100 se identificaron como “expertos”, y de los encuestados que dijeron que ya no usaban Rust, 55% citó el aprendizaje o la productividad como su razón para abandonar el lenguaje.
Se necesitan ingenieros experimentados de 3 a 6 meses de estudio, respaldados por el acceso a expertos en la materia, para ser productivos con Rust. Algunos ingenieros han comparado aprender Rust con aprender a comer tus verduras, y si bien a muchos de ellos les encanta una vez que son productivos, muchos ingenieros están decidiendo no aprenderlo o abandonar el esfuerzo antes de volverse productivos. El impacto potencial de Rust en la sostentabilidad y la seguridad solo se materializará si convertimos el brócoli en un brownie.
SlashData, State of the Developer Nation Q3 2021
Ningún desarrollador, servicio o corporación puede lograr un impacto sustancial en la sostentabilidad. La adopción de Rust es como reciclar; solo tiene impacto si todos participamos. Para lograr una adopción amplia, vamos a tener que hacer crecer la comunidad de desarrolladores.
La comunidad de desarrolladores de Rust ha sido la de más rápido crecimiento en los últimos dos años, pero con base en tendencias históricas, sabemos que del medio millón de desarrolladores que se unieron a la comunidad de Rust en los últimos 12 meses, la mayoría de ellos aún no son competentes con el lenguaje. Tenemos algo de trabajo que hacer en la experiencia de desarrollador de Rust.
La pregunta que plantea es ¿qué experiencia de desarrollador? Los ingenieros que trabajan en el kernel de Linux tienen una experiencia ideal de desarrollador muy diferente a la de un ingeniero que construye un servicio de base de datos o un ingeniero que entrega un sitio web minorista. Podemos identificar las personas de usuario de Rust mirando tres dimensiones.
La primera distinción es su razón de venir a Rust. ¿Están eligiendo Rust para el rendimiento? ¿Por seguridad? ¿Por la sostentabilidad? La segunda distinción es el dominio. ¿Están trabajando en un entorno integrado con recursos restringidos? ¿Están trabajando en aprendizaje automático con trabajos de larga duración que tienen enormes cantidades de datos en computaciones incrementales? La tercera distinción es la experiencia del desarrollador. ¿Son programadores de sistemas? ¿Quizás solo han trabajado con lenguajes de tipos dinámicos?
Necesitamos evolucionar esas permutaciones de prioridad, dominio y experiencia del desarrollador en personas que nos permitan desarrollar una comprensión sólida, un vocabulario común y un conjunto explícito de compensaciones de ingeniería. Por lo general, damos nombres a estas personas, así que consideremos un ejemplo que llamaremos “Bob”.
Bob está construyendo una solución criptográfica y está eligiendo Rust por las propiedades de seguridad. Bob tiene un conjunto distinto de concesiones de ingeniería. Bob prioriza la seguridad sobre el performance; prioriza la seguridad sobre las operaciones. Lo que eso significa en la práctica es que Bob preferiría tener una respuesta lenta que un texto plano, y preferiría tener una interrupción que responder a una solicitud sin firmar.
Para cada una de estas personas, hay compensaciones de ingeniería únicas, y lo que queremos hacer es crear un espacio en el paisaje de Rust que esté bien definido y fácilmente descubrible y que permita a todos los Bobs colaborar en la construcción de la mejor experiencia de desarrollador completa para ellos mismos sin impactar negativamente a otras personas.
Rust es una tecnología increíble para sostener y asegurar nuestra industria, y puede comenzar a hacerlo hoy mismo. Tenemos mucho trabajo que hacer antes de que todos puedan usar Rust, y la Fundación Rust está trabajando para crear plataformas para una colaboración efectiva entre industrias en ese trabajo. Esperamos que se una a nosotros.
Acerca de los autores
Shane Miller es senior engineering manager.
Carl Lerche ha estado involucrado en el código abierto durante los últimos quince años. Primero se involucró con Ruby on Rails y fue coautor del administrador de paquetes Bundler para Ruby. Carl fue uno de los primeros en contribuir al panorama del lenguaje de programación Rust y fue el autor de gran parte de la infraestructura de E/S asincrónica, incluido Tokio. Actualmente, Carl es ingeniero principal en AWS, donde dirige el desarrollo de la plataforma de Tokio.
Traductor
Gonzalo Vásquez es Senior Solutions Architect de AWS Chile para clientes de los segmentos Independent software vendor (ISV) y Digital Native Business (DNB) de Argentina, Paraguay y Uruguay. Antes de sumarse a AWS, se desempeñó como desarrollador de software, arquitecto de sistemas, gerente de investigación y desarrollo y CTO en compañías basadas en Chile.
Revisores
Magali Pinto es Gerente de Arquitectura de Soluciones para AWS en Perú, con más de 20 años de experiencia en compañías de diversas industrias a nivel LATAM. Experta en definición de estrategias y gestión de infraestructura tecnológica, de la nube y ciberseguridad. Ella es ingeniera informática y de sistemas de la Universidad Pontificia Católica del Perú y tiene una maestría en Administración de Sistemas de la Escuela EAE-OBS de la Universidad de Barcelona.