Lamba LLRT(Low Latency Runtime Javascript)
Paulo Lôbo
Posted on August 20, 2024
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:
Agora, vamos criar a função com o LLRT JS. Optei por utilizar a opção de layer.
E adicione essa layer a função LLRT JS criada:
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;
};
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;
};
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:
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.
Posted on August 20, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.