AWS Serverless: Vale a pena importar o AWS SDK?
Tags: ptbr, serverless, aws, javascript
Published: 2019-09-09 07:36:13

## Resultando em Lambdas menores em tamanho final

_Se você não está familiarizado com o início frio (cold start) no contexto do AWS Lambda, [leia esta postagem primeiro](https://theburningmonk.com/2018/01/im-afraid-youre-thinking-about-aws-lambda-cold-starts-all-wrong/)._

**Atualização 24/03/2019: Os testes agora incluem o [serverless-webpack](https://github.com/serverless-heaven/serverless-webpack).**

Quando uma função Lambda do Node.js é iniciada a frio (_cold start_), várias coisas acontecem:

- o serviço Lambda precisa encontrar um servidor com capacidade suficiente para hospedar o novo contêiner
- o novo contêiner é inicializado
- o ambiente de execução do Node.js é inicializado
- seu módulo/manipulador é inicializado, o que inclui a inicialização de quaisquer variáveis ​​e funções globais que você declara fora da função manipuladora

Se você [ativar o rastreamento](https://docs.aws.amazon.com/lambda/latest/dg/lambda-x-ray.html) para uma função Lambda, poderá ver quanto tempo é gasto nessas etapas no X-Ray. Infelizmente, o tempo necessário para inicializar o contêiner e o tempo de execução do Node.js não são registrados como segmentos. Mas você pode calcular a diferença de durações.

Abaixo, o `Initialization` refere-se ao tempo necessário para inicializar o módulo/manipulador:

![](https://theburningmonk.com/wp-content/uploads/2019/03/img_5c964abe4bf42-1024x325.png)

O rastreamento acima é para a função abaixo, que requer o [AWS SDK](https://www.npmjs.com/package/aws-sdk) e nada mais. Como você pode ver, este simples `require` **adicionou 147ms ao início frio**.

```js
const AWS = require("aws-sdk");
module.exports.handler = async () => {};
```

Considere esse o custo de fazer negócios quando sua função precisar interagir com os recursos da AWS. Porém, se você precisar interagir apenas com um serviço (por exemplo, DynamoDB), poderá economizar algum tempo de inicialização com recursos de linha única:

```js
const DynamoDB = require("aws-sdk/clients/dynamodb");
const documentClient = new DynamoDB.DocumentClient();
```

Acima importamos o cliente DynamoDB diretamente, sem inicializar todo o AWS SDK. Fiz um experimento para ver quanto tempo de inicialização fria você pode economizar com essa alteração simples.

_O crédito é dado ao meu colega [Justin Caldicott](https://www.linkedin.com/in/justin-caldicott-96b36a9/) por despertar meu interesse e fazer muitas análises iniciais._

Além do AWS SDK, geralmente também precisamos do XRay SDK e o usamos para instrumentar automaticamente o AWS SDK. Infelizmente, o pacote `aws-xray-sdk` também possui algumas bagagens adicionais que não precisamos. Por padrão, ele suporta aplicativos Express.js, MySQL e Postgres. Se você estiver interessado apenas em instrumentar o AWS SDK e módulos `http`/`https`, precisará apenas do `aws-xray-sdk-core`.

![](https://theburningmonk.com/wp-content/uploads/2019/03/img_5c964b0bde622-e1553353537965.png)

# Metodologia

Eu testei várias configurações:

- [sem SDK da AWS](https://github.com/theburningmonk/aws-sdk-coldstart-overhead/blob/master/functions/no-aws-sdk.js)
- [importando apenas o cliente DynamoDB](https://github.com/theburningmonk/aws-sdk-coldstart-overhead/blob/master/functions/dynamodb-only.js)
- [importando o AWS SDK completo](https://github.com/theburningmonk/aws-sdk-coldstart-overhead/blob/master/functions/aws-sdk.js)
- [importando apenas o XRay SDK (sem AWS SDK)](https://github.com/theburningmonk/aws-sdk-coldstart-overhead/blob/master/functions/aws-xray-sdk-require-only.js)
- [importando o XRay SDK e instrumentando o AWS SDK](https://github.com/theburningmonk/aws-sdk-coldstart-overhead/blob/master/functions/aws-xray-sdk.js)
- [importando o XRay SDK Core e instrumentando o AWS SDK](https://github.com/theburningmonk/aws-sdk-coldstart-overhead/blob/master/functions/aws-xray-sdk-core.js)
- [importando o XRay SDK Core e instrumentando apenas o cliente DynamoDB](https://github.com/theburningmonk/aws-sdk-coldstart-overhead/blob/master/functions/trace-dynamodb-only.js)

Cada uma dessas funções é rastreada pelo X-Ray. Taxa de amostragem (_sample rate_) definida para 100%, para não perdermos nada. Estamos interessados ​​apenas na duração do segmento `Initialization`, pois corresponde ao tempo para inicializar essas dependências.

![](https://theburningmonk.com/wp-content/uploads/2019/03/img_5c964b69140eb-1024x285.png)

O caso `sem SDK da AWS` é o nosso grupo de controle. Podemos ver quanto tempo cada dependência adicional adiciona à duração de `Initialization`.

Para coletar um conjunto de dados estatisticamente significantes, decidi automatizar o processo usando as Funções de Etapa (_Step Functions_).

![](https://theburningmonk.com/wp-content/uploads/2019/03/img_5c964ba43891e-1024x669.png)

- A máquina de estado recebe uma entrada `{ functionName, count }`.
- A etapa `SetStartTime` adiciona o registro de data e hora UTC atual ao estado de execução. Isso é necessário, pois precisamos da hora de início do experimento para buscar os traços relevantes do X-Ray.
- A etapa `Loop` aciona o número desejado de chamadas frias para a função especificada. Para executar chamadas frias, eu atualizo programaticamente uma variável de ambiente antes de chamar a função. Dessa forma, garanto que toda chamada tenha um começo frio.

![](https://theburningmonk.com/wp-content/uploads/2019/03/img_5c964c2c836d5-1024x199.png)

- A etapa `Wait30Seconds` garante que todos os rastreamentos sejam publicados no X-Ray antes de tentarmos analisá-los.
- A etapa `Analyze` busca todos os rastreamentos relevantes no X-Ray e gera várias estatísticas em torno da duração `Initialization`.

Cada configuração é testada em torno de 1000 chamadas frias. Ocasionalmente, os rastreamentos do X-Ray estão incompletos (veja abaixo). Esses rastreamentos incompletos são excluídos na etapa `Analyze`.

![](https://theburningmonk.com/wp-content/uploads/2019/03/img_5c964c4e90568-1024x212.png)
_Onde está o segmento AWS::Lambda:Function?_

Cada configuração também é testada com o WebPack (usando o   plugin [serverless-webpack](https://github.com/serverless-heaven/serverless-webpack)). _Obrigado a Erez Rokah pela sugestão nos comentários._

# Os Resultados

Abaixo está a análise do `Initialization` para todos os casos de teste:

![](https://theburningmonk.com/wp-content/uploads/2019/03/img_5c97ab80261a6-1024x433.png)

![](https://theburningmonk.com/wp-content/uploads/2019/03/img_5c97ab9946bd1-1024x631.png)

Observações chave:

- O WebPack melhora o tempo do Initialization` em geral.
- Sem nenhuma dependência, o tempo médio do `Initialization` é de apenas 1,72ms sem o WebPack e 0,97 ms com o WebPack.
- Adicionar o AWS SDK como a única dependência adiciona uma média de 245ms sem o WebPack. Isso é bastante significativo. Adicionar WebPack também não melhora significativamente as coisas.
- Exigir apenas o cliente DynamoDB (a alteração de uma linha discutida anteriormente) economiza até 176ms! Em 90% dos casos, a economia foi superior a 130ms. Com o WebPack, a economia é ainda mais dramática.
- O custo de importar o X-Ray SDK é quase o mesmo que o AWS SDK.
- Não há diferença estatisticamente significativa entre o uso do X-Ray SDK completo e do X-Ray SDK Core. Com ou sem WebPack.

---

# Créditos

- [Just how expensive is the full AWS SDK?](https://theburningmonk.com/2019/03/just-how-expensive-is-the-full-aws-sdk/), escrito originalmente por @theburningmonk