Funções Serverless Avançadas em JavaScript na AWS Lambda: da teoria à produção
\nA arquitetura Serverless baseada na AWS Lambda tornou-se padrão para a construção de microsserviços e sistemas orientados a eventos. Se você já domina as funções básicas (gatilhos do S3, API Gateway, DynamoDB), é hora de passar para o próximo nível. Neste artigo, abordaremos técnicas avançadas de trabalho com AWS Lambda em Node.js: otimização de cold start, trabalho em VPC, uso de camadas, monitoramento e depuração adequados. Cada seção é acompanhada de exemplos práticos de código.
\n\n1. Otimização do Cold Start
\nO cold start é o principal inimigo do desempenho das funções Serverless. Quando uma função Lambda não é usada por algum tempo, a AWS cria um novo contêiner, carrega o código e inicializa as dependências. Isso pode levar de 200 ms a vários segundos. Vejamos como minimizar esse efeito.
\n\n1.1. Uso do escopo global
\nO código fora do manipulador é executado apenas uma vez quando o contêiner é criado. Coloque ali operações pesadas: conexão com banco de dados, carregamento de configuração, inicialização do SDK.
\n// ❌ Ruim: cada chamada cria uma nova conexão\nexports.handler = async (event) => {\n const AWS = require('aws-sdk');\n const dynamoDB = new AWS.DynamoDB.DocumentClient();\n // ...\n};\n\n// ✅ Bom: a conexão é criada uma vez\nconst AWS = require('aws-sdk');\nconst dynamoDB = new AWS.DynamoDB.DocumentClient();\n\nexports.handler = async (event) => {\n // usamos dynamoDB\n};\n\n1.2. Redução do tamanho do pacote
\nCada módulo extra aumenta o tempo de carregamento. Use o aws-sdk versão 3 com tree-shaking ou importe apenas os clientes necessários:
// Em vez do SDK completo:\nconst { DynamoDBClient } = require('@aws-sdk/client-dynamodb');\nconst { DynamoDBDocumentClient } = require('@aws-sdk/lib-dynamodb');\n\n1.3. Provisioned Concurrency
\nPara funções críticas em relação à latência (por exemplo, API sob carga), ative o Provisioned Concurrency. Isso garante que um número definido de contêineres esteja sempre "quente".
\n// Exemplo via AWS CLI:\naws lambda put-provisioned-concurrency-config \\\n --function-name my-function \\\n --qualifier PROD \\\n --provisioned-concurrent-executions 10\n\n2. Trabalho com VPC: segurança e desempenho
\nQuando uma função Lambda precisa acessar recursos dentro de uma VPC (RDS, ElastiCache, APIs privadas), é necessário configurar o acesso à rede. No entanto, conectar-se a uma VPC aumenta o cold start em 5 a 10 segundos devido à criação de ENI (Elastic Network Interface).
\n\n2.1. Otimização de funções em VPC
\n- \n
- Use VPC Endpoints para serviços AWS (S3, DynamoDB, SQS) — isso permite acessá-los sem passar pelo NAT/Internet Gateway. \n
- Minimize o número de sub-redes — a Lambda cria uma ENI em cada sub-rede especificada. Limite-se a duas (AZs diferentes). \n
- Armazene em cache as conexões — se a função se conectar ao RDS, use um pool de conexões (por exemplo,
pg-poolpara PostgreSQL). \n
const { Pool } = require('pg');\n\n// Pool criado fora do manipulador\nconst pool = new Pool({\n host: process.env.DB_HOST,\n database: 'mydb',\n max: 5, // limite de conexões\n idleTimeoutMillis: 30000,\n});\n\nexports.handler = async (event) => {\n const client = await pool.connect();\n try {\n const result = await client.query('SELECT NOW()');\n return { statusCode: 200, body: result.rows };\n } finally {\n client.release();\n }\n};\n\n2.2. VPC e Cold Start
\nSe o cold start for crítico, considere alternativas:
\n- \n
- Use Aurora Serverless ou DynamoDB em vez de RDS. \n
- Mova os dados para o ElastiCache (Redis) e conecte-se atrav