Hannes Mehnert sobre MirageOS y OCaml: «La programación funcional se basa en mejorar el mantenimiento del código y la comprensión del programa»
Introducción
Nuestro ingeniero de back-end, Pavel Argentov, viajó hasta Marrakech (Marruecos) para asistir al noveno retiro de MirageOS, que se celebró del 13 al 19 de marzo de 2020. El objetivo del evento es reunir a usuarios de MirageOS nuevos y experimentados para colaborar y sincronizar distintos subproyectos de MirageOS, iniciar nuevos proyectos y colaborar para corregir errores de código.
MirageOS es un sistema operativo de bibliotecas que construye unikernels para aplicaciones de red seguras y de alto rendimiento en una amplia variedad de plataformas móviles e informática en la nube. El código puede desarrollarse en Linux o macOS y, a continuación, se puede compilar en un unikernel especializado independiente que se ejecuta en un hipervisor Xen o KVM.
En el evento, Pavel habló con Hannes Mehnert, el coautor de MirageOS y anfitrión del evento, sobre su trabajo con MirageOS y OCaml. Nos dio algunos detalles sobre sus contribuciones en MirageOS y el motivo por el que se unió al proyecto. También explicó las ventajas de la programación funcional y por qué se sintió inicialmente atraído por ella. Además, nos dio detalles sobre el potencial y las limitaciones de MirageOS y OCaml, y nos proporcionó información sobre los nuevos avances y lo que podemos esperar en el futuro. Hemos incluido la transcripción completa de la entrevista a continuación para que pueda obtener la información más reciente, directamente de la mejor fuente.
La entrevista
Pavel: Creo que deberíamos empezar por hablar sobre OCaml. ¿Cómo y por qué empezaste a trabajar con OCaml??
Hannes: Hace seis años, nada más terminar mi doctorado en verificación formal de software, solía seleccionar al azar software ya desarrollado, aplicaba algunas especificaciones y, después, escribía pruebas para demostrar si el programa era correcto. Eso resultó ser bastante complejo y laborioso debido al uso ubicuo de un estado mutable compartido. Durante bastante tiempo, me ha interesado mucho la programación de sistemas (es decir, usar C y escribir tu propio sistema operativo en este lenguaje). Pero, dada mi formación en semántica, quería usar un lenguaje de alto nivel para escribir sistemas operativos. Por lo tanto, al terminar el doctorado, encontré por casualidad MirageOS con mi amigo David Kaloper.
MirageOS está escrito en OCaml, que es un lenguaje multiparadigma con un sistema modular y que se usa para la programación funcional. Esto quiere decir que puedes evitar el estado mutable compartido y, en realidad, verificar los programas en los sistemas operativos. Cuando di con MirageOS hace aproximadamente seis años, este ya funcionaba hasta cierto punto y mi primera contribución fue la pila de TLS y los algoritmos de cifrado.
Pavel: ¿Cómo se usa MirageOS y para qué podemos aprovecharlo?
Hannes: MirageOS empezó como un proyecto de investigación. Teníamos un prototipo y una idea de cómo usar distintos estilos de programación para sistemas operativos. Mi experiencia se centra mucho en la seguridad, y esa fue mi principal motivación para contribuir en MirageOS e intentar conseguir una versión de producción. Desde una perspectiva de seguridad, aquí tienes menos estados mutables y puedes ejecutar HTTPS o un servidor web con TLS. Y tienes mucho menos código, lo que equivale a menos errores y menos uso de recursos, ya que, si no tienes que ejecutar tanto código, no tienes que perder tantos ciclos de CPU y tanta memoria.
Pavel: Hablemos sobre TLS. Con frecuencia, puede que en algún momento alcances el límite del hardware y todo se ejecutará lentamente, ya que los algoritmos criptográficos son lentos. ¿Cómo soluciona OCaml este problema? ¿Se soluciona el problema de la velocidad? ¿Puedes desarrollar código rápidamente con OCaml?
Hannes: Sí, OCaml en sí tiene un entorno de ejecución muy rápido. Tenemos un recolector de elementos no utilizados (un administrador de memoria) que funciona con mucha rapidez. La pregunta es básicamente si OCaml permite o no escribir una interfaz que sea lo suficientemente buena para pasar los argumentos correctamente y no perder tanto tiempo de CPU. La respuesta es que es lo suficientemente rápido. Me gusta usar un lenguaje de programación razonable, en lugar de un microensamblador de bajo nivel.
El otro lado de TLS son los protocolos de enlace. Es criptografía asimétrica y, para conseguir que se ejecute con rapidez, usamos una biblioteca denominada GMP/GNU Multi-Precision Library. En OCaml, tenemos enlaces para esa biblioteca, pero son las excepciones. Normalmente, intentamos no escribir enlaces y no usar demasiado código de C. Las partes más complejas de cifrado y descifrado aún están escritas en OCaml, no en C.
Pavel: Los programadores de Haskell y otros programadores de lenguajes de alto nivel están preocupados por el rendimiento del recolector de elementos no utilizados, ya que afirman que ralentiza todo. En Haskell, no pueden escribir cualquier tipo de «aplicaciones de software en tiempo real». ¿Crees que OCaml puede conseguir eso? ¿Es el recolector de elementos no utilizados de OCaml lo suficientemente rápido para tener un rendimiento adecuado en casos de uso en los que se necesite la velocidad?
Hannes: Sí, creo que sí. Haskell tiene un entorno de ejecución completamente distinto, con una evaluación diferida de forma predeterminada. Pero OCaml es estricto, simplemente hacemos los cálculos sobre la marcha. El recolector de elementos no utilizados está optimizado para cargas de trabajo, es muy rápido y creo que, en OCaml, las «aplicaciones de software en tiempo real» son algo factible.
Pavel: Según tengo entendido, el «unikernel» como concepto ya no es único de OCaml. ¿Cuál ha sido la historia de los unikernels? ¿Tenían otro nombre cuando se concibió la idea? ¿Cómo surgió la idea de los unikernels?
Hannes: Creo que todo empezó en la Universidad de Cambridge, con los artículos teóricos sobre el denominado exokernel. La gente necesitaba un instrumento, un sistema que estuviera centrado en las tareas, consumiera menos recursos, se escribiera fácilmente y pudiera adaptarse de forma sencilla.
Pavel: Vale. Según tengo entendido, MirageOS usa la biblioteca de Lwt. Si tienes un servidor DNS que tiene que responder rápidamente en varias direcciones a la vez, ¿crees que Lwt tiene un rendimiento suficiente para generar una carga razonable? ¿Funciona lo suficientemente rápido?
Hannes: Creo que funciona bastante bien. Un buen ejemplo de aplicación para MirageOS es el firewall, que está integrado en Qubes OS. Qubes OS es un sistema operativo que usa Xen. El objetivo de Qubes OS es, por ejemplo, separar tu aplicación de correo del visor de PDF. Por lo tanto, si recibes un correo electrónico con un archivo PDF malintencionado, una vez lo visualices, no podrá acceder al correo. En su lugar, el PDF se guardará en otra máquina virtual. Dicha máquina virtual tiene el código necesario para ejecutar el visor de PDF.
Por lo tanto, el archivo PDF solo se abre y visualiza en un entorno aislado. MirageOS resulta muy útil en este caso, ya que tiene un uso de memoria más reducido. Podemos configurar el firewall como uno de los componentes dentro de una de las máquinas virtuales en el entorno de Qubes OS y recibir paquetes de otras máquinas virtuales que tengan acceso a la red. El unikernel de MirageOS funciona como un enrutador que redirige los paquetes.
Pavel: Has mencionado algo sobre el uso de memoria de MirageOS. ¿Cuánta memoria puede tener realmente? ¿Cuáles son los límites superiores o inferiores? He oído que MirageOS no puede configurarse para memorias de más de 1 GB. ¿Realmente existen esas limitaciones?
Hannes: Bueno, por el momento, sí. La cantidad mínima de memoria necesaria para el entorno de ejecución de OCaml y los unikernels de MirageOS es de 10 MB, mientras que el límite superior, por el momento, es de 1 GB de memoria. Pero eso se puede optimizar fácilmente si necesitas más memoria. Por ejemplo, mis servicios DNS necesitan entre 14 y 24 MB de memoria. No son millones de registros, sino cientos de ellos. Y los servicios web que ejecuto normalmente tienen entre 32 y 128 MB de memoria. Y eso es suficiente para almacenar los datos.
Pavel: ¿Has trabajado con el almacén de datos de Irmin? Según tengo entendido, es una especie de Git, y es el único almacén de datos escrito en OCaml para MirageOS.
Hannes: Sí. Irmin es un almacén inmutable que puede dividirse en ramas. No suelo usar Irmin directamente, sino a través de la implementación de Git, que lo usa en segundo plano. Por ejemplo, mi servidor DNS almacena el archivo de zona en un repositorio Git remoto y simplemente obtiene el repositorio, lo clona en memoria y, después, sirve los datos desde allí. En 2019, se publicó una versión principal de Irmin, la versión 2.0.
Pavel: Bueno, vamos a cambiar un poco para conocer el formato de la reunión. ¿Podrías contarnos un par de detalles sobre qué es un retiro de MirageOS? ¿Cómo se te ocurrió esa idea?
Hannes: Recibo mucha inspiración de distintas conferencias, y también de los hackathons de OpenBSD. La idea básica es reunir a un grupo de gente agradable. Te encuentras en un lugar bonito, con un tiempo agradable, comida, sol… y puedes disfrutar del entorno. Para mí, es esencial que la gente se reúna todo el día y que se comuniquen entre sí. No hay una programación estricta. Hay una ronda diaria de actualizaciones sobre quién hizo qué, quién está interesado en qué, y quién se encuentra atascado en un punto específico. Pueden participar otras personas que es posible que tengan una solución. Personas al azar empiezan a discutir sobre problemas y soluciones, mientras que otras personas están simplemente ocupadas escribiendo código.
Por una parte, intento llevar a gente que tenga experiencia en la comunidad e ideas sobre las distintas bibliotecas y el ecosistema con el fin de discutir cambios fundamentales en el ecosistema. Pero también me gusta tener gente nueva, conocer nuevas ideas y personas que puedan integrarse en el grupo y conseguir que programen en OCaml y MirageOS con el fin de hacer crecer la comunidad. No es algo exclusivo para las personas que ya conozcan MirageOS o que hayan desarrollado en OCaml durante años, sino que está abierto a todo aquel que quiera hacer un viaje a Marrakech.
Pavel: ¡Suena genial! ¿Crees que la programación funcional afecta a la forma de pensar de los programadores? Cuando empecé a escribir código de OCaml, me di cuenta de que hay tipos que se pueden transformar. Y esto me hizo pensar primero en los tipos y el significado de los datos con los que trabajo. Sé que la programación funcional en Europa forma parte del plan de estudios de informática en el nivel básico. Según tengo entendido, la mayoría de los estudiantes de Rusia aprenden a programar empezando con técnicas imperativas, y casi nunca se salen de eso.
Hannes: Sí. Pienso mucho en los tipos y aplico una gran cantidad de desarrollo basado en tipos antes de escribir código en sí. Por lo tanto, cuando escribo programas en un lenguaje funcional, primero pienso en cómo serán los tipos. Una vez consigo los tipos con la forma adecuada, todo el proceso de implementación resulta mucho más fácil. Para mí, se trata también del mantenimiento del código y de comprender el programa localizado en la programación funcional. Y creo que es mucho más fácil comprender mi código cinco años más tarde si está escrito en un lenguaje funcional, donde no uso una gran cantidad de características y sintaxis simplificada, en lugar de desarrollar ese código en un lenguaje imperativo y tener cientos de líneas en una función. Intento que las funciones sean breves y puedan comprenderse fácilmente. Sí, creo que la programación funcional cambia la forma de pensar sobre un programa.
Pavel: He visto que las mónadas se están haciendo camino en distintos lenguajes. Ya han aparecido en Ruby y en C++. ¿Es simplemente una forma de implementar conocimientos académicos en la programación cotidiana?
Hannes: Creo que es un instrumento útil, pero es muy difícil comprenderlo si no has descubierto las mónadas por tu cuenta. Intentar explicar qué son las mónadas a un nuevo programador imperativo resulta muy difícil. Aún usamos mónadas en MirageOS y en OCaml, pero espero que, cuando la rama multinúcleo forme parte del entorno de ejecución de OCaml en algún momento de este año, superaremos eso.
Pavel: Hablemos un poco sobre el código abierto. Todo lo que hemos hablado hasta ahora está relacionado con el código abierto. Existe cierto punto de vista que afirma que la tecnología solo tiene éxito cuando se invierte dinero suficiente en ella. Aunque el código abierto consume nuestros esfuerzos y tiempo, realmente no aporta dinero. Al defender una nueva tecnología en una comunidad abierta, tarde o temprano surge la idea de una colaboración de código abierto. En tu opinión, ¿qué importancia tiene el código abierto?
Hannes: Creo que el código abierto es un factor decisivo. Actualmente, lo que hago principalmente es desarrollar bibliotecas de OCaml que, después, se usan en unikernels de MirageOS. Y todos deberían ser capaces de combinarlos y hacerlos coincidir libremente. Cuando escribo una pila de TLS o una implementación de DNS, tengo un gran incentivo por convertirlo todo en código abierto, ya que hay otras personas que pueden reutilizarlo. Me gusta escribir software y me hace feliz saber que alguien usa ese software, ya sea una persona o una empresa que lo use con fines comerciales. No me importa.
En MirageOS, la mayor parte del software usa una licencia BSD, por lo que todo el mundo puede usarlo para cualquier finalidad. Creo que es muy importante tener una licencia. Todo el mundo puede comprender la licencia GPL, pero hay muchas páginas de texto, mientras que BSD tiene solo dos o tres párrafos y suele estar escrito con 25 líneas de código. Además, si quieres convencer a un sector para que use parte de tu software, es mejor usar una licencia permisiva. Te resultará mucho más fácil convencerlos, ya que, si usas una licencia GPL, sin duda te costará convencer a los abogados de que es una buena idea. Por ejemplo, en MirageOS tenemos contribuciones de código de IBM Research y hemos conseguido convencerles para usar una licencia muy permisiva, lo que no ha sido fácil, porque los abogados normalmente quieren ceñirse a una marca comercial.
Pavel: He leído que estás trabajando para una empresa que vende desarrollo de unikernel. ¿Cómo es trabajar en una empresa tecnológica que no vende, por decirlo de algún modo, programación imperativa bien conocida y consolidada?
Hannes: Trabajo para una organización sin ánimo de lucro llamada Robur. Trabajamos con subvenciones, donaciones y contratos comerciales para mejorar el ecosistema de MirageOS y desarrollar unikernels.
A lo largo del último año, hemos recibido financiación pública. De Alemania y la Unión Europea, hemos recibido subvenciones para desarrollar aplicaciones específicas (como OpenVPN Gateway), y actualmente recibimos financiación de la Unión Europea para trabajar en DNSmasq, que es uno de los componentes esenciales en la red de todos. Todo esto es realmente genial.
Pavel: ¿Con qué rapidez se desarrolla MirageOS a lo largo del tiempo? ¿Se desarrollan y amplían rápidamente nuevas características?
Hannes: El desarrollo es siempre bastante lento, pero también hacemos mucho trabajo. Intentamos deshacernos de la deuda técnica y adaptarnos a sistemas de compilación modernos, lo que a veces lleva más tiempo que con otros proyectos. En términos de características, se basa principalmente en el desarrollo de nuevas bibliotecas. Hablamos brevemente sobre el almacén de datos de Irmin en la versión 2.0, que se alcanzó el año pasado. Además, próximamente se publicará la pila de TLS 1.3. En relación con MirageOS, nos dirigimos hacia la versión 4.0 que, sin duda, mejorará la experiencia de desarrollo drásticamente al deshacerse del antiguo «ocamlbuild» y reemplazarlo por un nuevo sistema de compilación llamado «dune», que cuenta con compilaciones incrementales.
Pavel: Bueno, vamos a terminar nuestra charla con una declaración que sirva de inspiración a los desarrolladores que quieran aprender a usar MirageOS, adoptar OCaml y dejar de tener respeto a la programación funcional como devorador de mentes teórico. ¿Cómo animarías a la gente?
Hannes: Lo bueno de la programación funcional es el nivel de control que tienes sobre código bastante complejo. En la programación funcional, si identificas un error de código de alto nivel, puedes depurarlo hasta el nivel inferior y corregirlo en solo un fin de semana, mientras que tratar de hacer eso en los sistemas operativos comunes es prácticamente imposible debido al tamaño de la base de código y las bibliotecas que se usan.
Tienes control sobre toda la pila. Es desarrollo de pila completa, desde la tarjeta de dispositivo de red hasta la lógica empresarial y las ejecuciones reales de la aplicación.
En Evrone, nos esforzamos por estar al día de los nuevos desarrollos tecnológicos y adoptamos nuevas e innovadoras herramientas y métodos. Esto nos permite usar los recursos óptimos para proporcionar a nuestros clientes las mejores soluciones que se adapten a sus necesidades únicas. Trabajamos con una amplia variedad de herramientas y lenguajes de programación, y animamos a los miembros de nuestro equipo a participar en eventos y conferencias de tecnología, como el retiro de MirageOS. Si tiene una idea y necesita desarrollarla, díganos cómo ponernos en contacto con usted y le ayudaremos a hacerla realidad.