Más allá del navegador: Introducción a WebAssembly sin servidor

Publicado: 2022-03-10
Resumen rápido ↬ Probablemente haya oído hablar de WebAssembly y por qué es una herramienta poderosa en el navegador. En este artículo, exploramos por qué WebAssembly sin servidor podría ser igualmente poderoso fuera del navegador y cómo comenzar a usarlo.

Ahora que WebAssembly es compatible con todos los navegadores principales y con más del 85 % de los usuarios en todo el mundo, JavaScript ya no es el único lenguaje de navegador disponible. Si no lo ha escuchado, WebAssembly es un nuevo lenguaje de bajo nivel que se ejecuta en el navegador. También es un objetivo de compilación, lo que significa que puede compilar programas existentes escritos en lenguajes como C, C++ y Rust en WebAssembly y ejecutar esos programas en el navegador. Hasta ahora, WebAssembly se ha utilizado para trasladar todo tipo de aplicaciones a la web, incluidas aplicaciones de escritorio, herramientas de línea de comandos, juegos y herramientas de ciencia de datos.

Nota: Para obtener un estudio de caso detallado sobre cómo se puede usar WebAssembly dentro del navegador para acelerar las aplicaciones web, consulte mi artículo anterior.

WebAssembly fuera de la Web?

Aunque la mayoría de las aplicaciones de WebAssembly en la actualidad están centradas en el navegador, WebAssembly en sí no se diseñó originalmente solo para la web, sino para cualquier entorno de espacio aislado. De hecho, recientemente ha habido mucho interés en explorar cómo WebAssembly podría ser útil fuera del navegador, como un enfoque general para ejecutar archivos binarios en cualquier sistema operativo o arquitectura de computadora, siempre que haya un tiempo de ejecución de WebAssembly que admita ese sistema. En este artículo, veremos cómo se puede ejecutar WebAssembly fuera del navegador, sin servidor/función como servicio (FaaS).

¡Más después del salto! Continúe leyendo a continuación ↓

WebAssembly para aplicaciones sin servidor

En pocas palabras, las funciones sin servidor son un modelo informático en el que le entrega su código a un proveedor de la nube y le permite ejecutar y administrar el escalado de ese código por usted. Por ejemplo, puede solicitar que su función sin servidor se ejecute cada vez que llame a un punto final de la API, o que sea impulsada por eventos, como cuando se carga un archivo en su depósito en la nube. Si bien el término "sin servidor" puede parecer inapropiado, ya que los servidores están claramente involucrados en algún punto del camino, desde nuestro punto de vista, es sin servidor, ya que no necesitamos preocuparnos por cómo administrar, implementar o escalar esos servidores.

Aunque estas funciones generalmente están escritas en lenguajes como Python y JavaScript (Node.js), existen varias razones por las que podría elegir usar WebAssembly en su lugar:

  1. Tiempos de inicialización más rápidos
    Los proveedores sin servidor que admiten WebAssembly (incluidos Cloudflare y Fastly) informan que pueden lanzar funciones al menos un orden de magnitud más rápido que la mayoría de los proveedores de nube con otros lenguajes. Lo logran ejecutando decenas de miles de módulos de WebAssembly en el mismo proceso, lo cual es posible porque la naturaleza de espacio aislado de WebAssembly lo convierte en una forma más eficiente de obtener el aislamiento para el que se utilizan tradicionalmente los contenedores.
  2. No se necesitan reescrituras
    Uno de los principales atractivos de WebAssembly en el navegador es la capacidad de transferir el código existente a la web sin tener que volver a escribir todo en JavaScript. Este beneficio sigue siendo cierto en el caso de uso sin servidor porque los proveedores de la nube limitan los idiomas en los que puede escribir sus funciones sin servidor. Por lo general, admitirán Python, Node.js y quizás algunos otros, pero ciertamente no C, C ++ o Rust . Al admitir WebAssembly, los proveedores sin servidor pueden admitir indirectamente muchos más idiomas.
  3. Más ligero
    Cuando ejecutamos WebAssembly en el navegador, confiamos en la computadora del usuario final para realizar nuestros cálculos. Si esos cálculos son demasiado intensivos, nuestros usuarios no estarán contentos cuando el ventilador de su computadora comience a zumbar. Ejecutar WebAssembly fuera del navegador nos brinda los beneficios de velocidad y portabilidad de WebAssembly, al mismo tiempo que mantiene nuestra aplicación liviana. Además de eso, dado que estamos ejecutando nuestro código WebAssembly en un entorno más predecible, potencialmente podemos realizar cálculos más intensivos.

Un ejemplo concreto

En mi artículo anterior aquí en Smashing Magazine, discutimos cómo aceleramos una aplicación web al reemplazar los cálculos lentos de JavaScript con código C compilado en WebAssembly. La aplicación web en cuestión era fastq.bio, una herramienta para obtener una vista previa de la calidad de los datos de secuenciación de ADN.

Como ejemplo concreto, reescribamos fastq.bio como una aplicación que utiliza WebAssembly sin servidor en lugar de ejecutar WebAssembly dentro del navegador. Para este artículo, usaremos Cloudflare Workers, un proveedor sin servidor que admite WebAssembly y se basa en el motor de navegador V8. Otro proveedor de la nube, Fastly, está trabajando en una oferta similar, pero basada en su tiempo de ejecución de Lucet.

Primero, escribamos algo de código Rust para analizar la calidad de los datos de secuenciación de ADN. Para mayor comodidad, podemos aprovechar la biblioteca de bioinformática Rust-Bio para manejar el análisis de los datos de entrada y la biblioteca wasm-bindgen para ayudarnos a compilar nuestro código Rust en WebAssembly.

Aquí hay un fragmento del código que lee los datos de secuenciación de ADN y genera un JSON con un resumen de las métricas de calidad:

 // Import packages extern crate wasm_bindgen; use bio::seq_analysis::gc; use bio::io::fastq; ... // This "wasm_bindgen" tag lets us denote the functions // we want to expose in our WebAssembly module #[wasm_bindgen] pub fn fastq_metrics(seq: String) -> String { ... // Loop through lines in the file let reader = fastq::Reader::new(seq.as_bytes()); for result in reader.records() { let record = result.unwrap(); let sequence = record.seq(); // Calculate simple statistics on each record n_reads += 1.0; let read_length = sequence.len(); let read_gc = gc::gc_content(sequence); // We want to draw histograms of these values // so we store their values for later plotting hist_gc.push(read_gc * 100.0); hist_len.push(read_length); ... } // Return statistics as a JSON blob json!({ "n": n_reads, "hist": { "gc": hist_gc, "len": hist_len }, ... }).to_string() }

Luego usamos la herramienta de línea de comandos wrangler de Cloudflare para hacer el trabajo pesado de compilar en WebAssembly e implementar en la nube. Una vez hecho esto, se nos proporciona un punto final de API que toma datos de secuenciación como entrada y devuelve un JSON con métricas de calidad de datos. Ahora podemos integrar esa API en nuestra aplicación.

Aquí hay un GIF de la aplicación en acción:

GIF de nuestra aplicación haciendo llamadas paralelas a una función WebAssembly sin servidor y actualizando gráficos con los datos que devuelve.
En lugar de ejecutar el análisis directamente en el navegador, la versión sin servidor de nuestra aplicación realiza varias solicitudes POST en paralelo a nuestra función sin servidor (consulte la barra lateral derecha) y actualiza los gráficos cada vez que devuelve más datos. (Vista previa grande)

El código completo está disponible en GitHub (código abierto).

Poniéndolo todo en contexto

Para poner el enfoque de WebAssembly sin servidor en contexto, consideremos cuatro formas principales en las que podemos crear aplicaciones web de procesamiento de datos (es decir, aplicaciones web en las que realizamos análisis de los datos proporcionados por el usuario):

Esta figura muestra cuatro formas en que podemos estructurar el procesamiento de datos en una aplicación web: en el servidor (sin WebAssembly), en el navegador usando JavaScript, en el navegador usando WebAssembly y WebAssembly sin servidor.
Cuatro opciones arquitectónicas diferentes que podemos tomar para las aplicaciones que procesan datos. (Vista previa grande)

Como se muestra arriba, el procesamiento de datos se puede realizar en varios lugares:

  1. Lado del servidor
    Este es el enfoque adoptado por la mayoría de las aplicaciones web, donde las llamadas API realizadas en el front-end inician el procesamiento de datos en el back-end.
  2. JavaScript del lado del cliente
    En este enfoque, el código de procesamiento de datos está escrito en JavaScript y se ejecuta en el navegador. La desventaja es que su rendimiento se verá afectado, y si su código original no estaba en JavaScript, ¡tendrá que volver a escribirlo desde cero!
  3. Ensamblaje web del lado del cliente
    Esto implica compilar el código de análisis de datos en WebAssembly y ejecutarlo en el navegador. Si el código de análisis se escribió en lenguajes como C, C++ o Rust (como suele ser el caso en mi campo de la genómica), esto evita la necesidad de reescribir algoritmos complejos en JavaScript. También proporciona el potencial para acelerar nuestra aplicación (por ejemplo, como se discutió en un artículo anterior).
  4. Ensamblaje web sin servidor
    Esto implica ejecutar el WebAssembly compilado en la nube, utilizando un tipo de modelo FaaS (por ejemplo, este artículo).

Entonces, ¿por qué elegiría el enfoque sin servidor sobre los demás? Por un lado, en comparación con el primer enfoque, tiene los beneficios que conlleva el uso de WebAssembly, especialmente la capacidad de transferir el código existente sin tener que volver a escribirlo en JavaScript. En comparación con el tercer enfoque, WebAssembly sin servidor también significa que nuestra aplicación es más liviana, ya que no usamos los recursos del usuario para procesar números. En particular, si los cálculos son bastante complicados o si los datos ya están en la nube, este enfoque tiene más sentido.

Sin embargo, por otro lado, la aplicación ahora necesita realizar conexiones de red, por lo que es probable que la aplicación sea más lenta. Además, dependiendo de la escala del cálculo y de si se puede dividir en partes de análisis más pequeñas, este enfoque podría no ser adecuado debido a las limitaciones impuestas por los proveedores de nube sin servidor en el tiempo de ejecución, la CPU y la utilización de RAM.

Conclusión

Como vimos, ahora es posible ejecutar el código de WebAssembly sin servidor y aprovechar los beneficios tanto de WebAssembly (portabilidad y velocidad) como de las arquitecturas de función como servicio (escalado automático y fijación de precios por uso). ). Ciertos tipos de aplicaciones, como el análisis de datos y el procesamiento de imágenes, por nombrar algunas, pueden beneficiarse enormemente de este enfoque. Aunque el tiempo de ejecución sufre debido a los viajes de ida y vuelta adicionales a la red, este enfoque nos permite procesar más datos a la vez y no agotar los recursos de los usuarios.