Lamba LLRT(Low Latency Runtime Javascript)

Paulo Lôbo - Aug 20 - - Dev Community

Aviso: todo e qualquer conteúdo postado é com objetivo de relembrar ou manter os meus conhecimentos e espero que possa te ajudar na sua caminhada pelo aprendizado também.
Esse post é vivo e será atualizado periodicamente.
Caso você encontre alguma falha ou perceba que falta algo, me ajude a melhorar :)


Você já parou para pensar que estamos sendo cada vez mais exigidos em relação à performance das nossas aplicações? A cada dia, somos desafiados a torná-las mais rápidas, e, com isso, somos levados a avaliar soluções e arquiteturas que nos possibilitem alcançar esse resultado.


Portanto a ideia é trazer um post curto, informando sobre uma nova evolução que pode nos ajudar a ter um aumento considerável de performance em aplicações serverless no AWS Lambda. Essa solução é o LLRT Javascript.

LLRT Javascript(Low Latency Runtime Javascript)

Um novo runtime JavaScript está sendo desenvolvido pela equipe da AWS. No momento, ele é experimental, e há esforços para lançar uma versão estável até o final de 2024

veja a descrição que a AWS apresenta:

LLRT (Low Latency Runtime) is a lightweight JavaScript runtime designed to address the growing demand for fast and efficient Serverless applications. LLRT offers up to over 10x faster startup and up to 2x overall lower cost compared to other JavaScript runtimes running on AWS Lambda
It's built in Rust, utilizing QuickJS as JavaScript engine, ensuring efficient memory usage and swift startup.

Veja que eles pretendem entregar algo até 10x mais rápido do que outros runtimes JS.

Toda essa construção é feita utilizando o Rust, que é uma linguagem com alto poder de desempenho e o QuickJS, que é um motor de JavaScript leve e de alto desempenho, projetado para ser pequeno, eficiente e compatível com a especificação ECMAScript mais recente, incluindo recursos modernos como classes, async/await, e módulos. Além disso, é utilizada uma abordagem que não usa JIT. Com isso, ao invés de alocar recursos para compilação Just-In-Time, conserva esses recursos para a execução de tarefas do próprio código.

Mas calma que nem tudo são flores, são tradeoffs(trocadilho horrível, eu sei rsrs).
Portanto, há alguns pontos importantes para se avaliar antes de pensar em adotar o LLRT JS. Veja o que a AWS informa:

There are many cases where LLRT shows notable performance drawbacks compared with JIT-powered runtimes, such as large data processing, Monte Carlo simulations or performing tasks with hundreds of thousands or millions of iterations. LLRT is most effective when applied to smaller Serverless functions dedicated to tasks such as data transformation, real time processing, AWS service integrations, authorization, validation etc. It is designed to complement existing components rather than serve as a comprehensive replacement for everything. Notably, given its supported APIs are based on Node.js specification, transitioning back to alternative solutions requires minimal code adjustments.

Além disso, a ideia é que o LLRT JS não seja um substituto para o node.js e nem nunca será.

Veja:

LLRT only support a fraction of the Node.js APIs. It is NOT a drop in replacement for Node.js, nor will it ever be. Below is a high level overview of partially supported APIs and modules. For more details consult the API documentation.


Testes Avaliativos

Levando em consideração a aplicabilidade que foi citada pela própria AWS, vamos realizar dois testes para avaliar e comparar o LLRT com o NodeJS. Um dos testes será para o cálculo de números primos e o outro para uma chamada simples de API.

Porque utilizar o cálculo de números primos?
A resposta é que o alto processamento requerido para identificar números primos resulta da necessidade de realizar muitas operações matemáticas(divisões) para verificar a primalidade, da distribuição imprevisível dos primos, e da complexidade crescente com o tamanho dos números. Esses fatores combinam-se para tornar a verificação de primalidade e a busca por números primos uma tarefa computacionalmente intensa, especialmente em grandes escalas.


Mãos na massa então...

Crie a primeira função lambda com nodejs:

Image description

Agora, vamos criar a função com o LLRT JS. Optei por utilizar a opção de layer.

Crie a layer:
Image description

Depois crie a função:
Image description

E adicione essa layer a função LLRT JS criada:
Image description

Para o teste de números primos, vamos usar o seguinte código:

let isLambdaWarm = false
export async function handler(event)  {

    const limit = event.limit || 100000;  // Defina um limite alto para aumentar a complexidade
    const primes = [];
    const startTime = Date.now()
    const isPrime = (num) => {
        if (num <= 1) return false;
        if (num <= 3) return true;
        if (num % 2 === 0 || num % 3 === 0) return false;
        for (let i = 5; i * i <= num; i += 6) {
            if (num % i === 0 || num % (i + 2) === 0) return false;
        }
        return true;
    };

    for (let i = 2; i <= limit; i++) {
        if (isPrime(i)) {
            primes.push(i);
        }
    }

  const endTime = Date.now() - startTime

    const response = {
        statusCode: 200,
        body: JSON.stringify({
            executionTime: `${endTime} ms`,
            isLambdaWarm: `${isLambdaWarm}`
        }),
    };


    if (!isLambdaWarm) { 
        isLambdaWarm = true
    }

    return response;
};


Enter fullscreen mode Exit fullscreen mode

E para o teste de API, vamos usar o código abaixo:

let isLambdaWarm = false
export async function handler(event) {

  const url = event.url || 'https://jsonplaceholder.typicode.com/posts/1'
  console.log('starting fetch url', { url })
  const startTime = Date.now()

  let resp;
  try {
    const response = await fetch(url)
    const data = await response.json()
    const endTime = Date.now() - startTime
    resp = {
      statusCode: 200,
      body: JSON.stringify({
        executionTime: `${endTime} ms`,
        isLambdaWarm: `${isLambdaWarm}`
      }),
    }
  }
  catch (error) {
    resp = {
      statusCode: 500,
      body: JSON.stringify({
        message: 'Error fetching data',
        error: error.message,
      }),
    }
  }

  if (!isLambdaWarm) {
    isLambdaWarm = true
  }

  return resp;
};

Enter fullscreen mode Exit fullscreen mode

Resultados dos testes

O objetivo é mais educacional aqui, portanto nossa amostra para cada teste é constituído de 15 dados em warm start e 1 de cold start.

Consumo de memória

LLRT JS - para ambos os testes, houve o consumo da mesma quantidade de memória: 23mb.

NodeJS - para o teste de números primos, o nodejs começou consumindo 69mb e indo até 106mb.
Já para o teste de API, o mínimo foi 86mb e o máximo com 106mb.

Tempo de execução
após a remoção dos outliers, esse foi o resultado:

Image description

Image description

Relatório final

Consumo de memória - para o consumo de memória foi observado que o LLRT fez o melhor uso do recurso disponível se comparado ao nodejs.

Performance - percebemos que no cenário de alto processamento, o node manteve uma performance bem superior ao LLRT, tanto no cold start quanto warm start.
Para o cenário de menor processamento, o LLRT obteve uma certa vantagem, principalmente no cold start.

Vamos, então, aguardar os resultados finais e esperar que possamos ter ainda mais melhorias significativas. Mas é muito bom ver a flexibilidade do JavaScript e perceber o quanto ele pode e ainda tem a nos oferecer.


Espero que tenha gostado e que isso tenha ajudado a melhorar sua compreensão ou até mesmo aberto caminhos para novos conhecimentos. Conto com você para críticas e sugestões, para que possamos melhorar o conteúdo e mantê-lo sempre atualizado para a comunidade.

. .
Terabox Video Player