O blog da AWS

Introdução ao streaming de respostas do AWS Lambda

Por Julian Wood
Hoje, o AWS Lambda está anunciando o suporte para streaming de payload de resposta. O streaming de resposta é um novo padrão de invocação que permite que as funções transmitam progressivamente os payloads de resposta de volta aos clientes.Você pode usar o streaming de payload de resposta do Lambda para enviar dados de resposta aos clientes que fizeram a chamada assim que estiverem disponíveis. Isso pode melhorar o desempenho de aplicativos móveis e Web. O streaming de resposta também permite criar funções que retornam payloads maiores e realizam operações de longa duração, ao mesmo tempo em que relatam o progresso incremental.

Nos modelos tradicionais de solicitação-resposta, a resposta precisa ser totalmente gerada e armazenada em buffer antes de ser devolvida ao cliente. Isso pode atrasar o desempenho do tempo até o primeiro byte (TTFB) enquanto o cliente espera que a resposta seja gerada. Os aplicativos Web são especialmente sensíveis ao TTFB e ao desempenho do carregamento da página. O streaming de respostas permite que você envie respostas parciais de volta ao cliente assim que elas estiverem prontas, melhorando a latência do TTFB em milissegundos. Para aplicativos web, isso pode melhorar a experiência do visitante e a classificação nos mecanismos de pesquisa.

Outros aplicativos podem ter grandes payloads, como imagens, vídeos, documentos grandes ou resultados de banco de dados. O streaming de resposta permite transferir esses payloads de volta para o cliente sem precisar armazenar todo o payload na memória. Você pode usar o streaming de respostas para enviar respostas maiores do que o limite de payload de resposta de 6 MB do Lambda até um limite flexível de 20 MB.

Atualmente, o streaming de respostas oferece suporte ao Node.js 14.x e aos tempos de execução gerenciados subsequentes. Você também pode implementar o streaming de respostas usando tempos de execução personalizados. Você pode transmitir progressivamente payloads de resposta por meio de URLs de funções do Lambda, inclusive como origem do Amazon CloudFront, além de usar o AWS SDK ou a API invoke do Lambda. Você não pode usar o Amazon API Gateway e o Application Load Balancer para transmitir progressivamente payloads de resposta, mas você pode usar a funcionalidade para retornar payloads maiores com o API Gateway.

Escrevendo funções habilitadas para streaming de respostas

Escrever o manipulador (handler) para funções de streaming de resposta difere dos padrões típicos do manipulador do Node. Para indicar ao tempo de execução que o Lambda deve transmitir as respostas da sua função, você deve envolver seu manipulador de funções com o decorador streamifyResponse(). Isso faz com que o tempo de execução use o caminho lógico de fluxo correto, permitindo que a função transmita respostas.

Este é um exemplo de manipulador com streaming de resposta ativado:

exports.handler = awslambda.streamifyResponse(
    async (event, responseStream, context) => {
        responseStream.setContentType(“text/plain”);
        responseStream.write(“Hello, world!);
        responseStream.end();
    }
);
JavaScript

O decorador streamifyResponse aceita o seguinte parâmetro adicional, responseStream, além dos parâmetros, event e event padrão do manipulador de nós.

O novo objeto responseStream fornece um objeto de fluxo no qual sua função pode gravar dados. Os dados gravados nesse fluxo são enviados imediatamente ao cliente. Opcionalmente, você pode definir o cabeçalho Content-Type da resposta para transmitir metadados adicionais ao seu cliente sobre o conteúdo do stream.

Escrevendo no fluxo de resposta

O objeto responseStreamimplementa a API Writable Stream do Node. Isso oferece um método write() para gravar informações no stream. No entanto, recomendamos que você use pipeline() sempre que possível para gravar no stream. Isso pode melhorar o desempenho, garantindo que um fluxo legível mais rápido não sobrecarregue o fluxo gravável.

Um exemplo de função usando pipeline() mostrando como você pode transmitir dados compactados:

const pipeline = require("util").promisify(require("stream").pipeline);
const zlib = require('zlib');
const { Readable } = require('stream');

exports.gzip = awslambda.streamifyResponse(async (event, responseStream, _context) => {
    // As an example, convert event to a readable stream.
    const requestStream = Readable.from(Buffer.from(JSON.stringify(event)));
    
    await pipeline(requestStream, zlib.createGzip(), responseStream);
});
JavaScript

Encerrando o fluxo de resposta

Ao usar o método write(), você deve encerrar o stream antes que o manipulador retorne. Use responseStream.end() para sinalizar que você não está gravando mais dados no stream. Isso não é necessário se você gravar no stream com pipeline().

Lendo respostas transmitidas

O streaming de respostas apresenta uma nova API InvokeWithResponseStream. Você pode ler uma resposta transmitida da sua função por meio de uma URL de função do Lambda ou usar o SDK da AWS para chamar a nova API diretamente.

Nem o API Gateway nem a integração de destino do Lambda com o Application Load Balancer oferecem suporte à codificação de transferência em partes. Portanto, ele não suporta TTFB mais rápido para respostas transmitidas. No entanto, você pode usar o streaming de respostas com o API Gateway para retornar respostas de payload maiores, até o limite de 10 MB do API Gateway. Para implementar isso, você deve configurar uma integração HTTP_PROXY entre seu API Gateway e uma URL de função Lambda, em vez de usar a LAMBDA_PROXY LAMBDA_PROXY.

Você também pode configurar o CloudFront com uma URL de função como origem. Ao transmitir respostas por meio de uma URL de função e do CloudFront, você pode ter um desempenho de TTFB mais rápido e retornar tamanhos maiores de payload.

Usando o streaming de resposta do Lambda com URLs de função

Você pode configurar um URL de função para invocar sua função e transmitir os bytes brutos de volta ao seu cliente HTTP por meio da codificação de transferência em partes. Você configura o URL da função para usar a nova API InvokeWithResponseStream alterando o modo de invocação do URL da função do BUFFERED padrão para RESPONSE_STREAM.

RESPONSE_STREAM permite que sua função transmita os resultados do payload à medida que eles se tornam disponíveis, se você encapsular a função com o decorador streamifyResponse(). O Lambda invoca sua função usando a API InvokeWithResponseStream. Se InvokeWithResponseStream invocar uma função que não está encapsulada com streamifyResponse(), o Lambda não transmitirá a resposta. No entanto, essa resposta está sujeita ao limite flexível de 20 MB do endpoint da API InvokeWithResponseStream, em vez de um limite de tamanho de 6 MB.

Usando o AWS Serverless Application Model (AWS SAM) ou o AWS CloudFormation, defina a propriedade invokeMode:

MyFunctionUrl:
    Type: AWS::Lambda::Url
    Properties:
      TargetFunctionArn: !Ref StreamingFunction
      AuthType: AWS_IAM
      InvokeMode: RESPONSE_STREAM
YAML

Usando bibliotecas de cliente HTTP genéricas com URLs de funções

Cada linguagem ou estrutura pode usar métodos diferentes para formar uma solicitação HTTP e analisar uma resposta transmitida. Algumas bibliotecas de cliente HTTP só retornam o corpo da resposta depois que o servidor fecha a conexão. Esses clientes não trabalham com funções que retornam um fluxo de resposta. Para obter o benefício dos fluxos de resposta, use um cliente HTTP que retorne dados de resposta de forma incremental. Muitas bibliotecas de clientes HTTP já oferecem suporte a respostas transmitidas, incluindo o Apache HttpClient para Java, o cliente http integrado do Node e as solicitações e pacotes urllib3 do Python. Consulte a documentação da biblioteca HTTP que você está usando.

Exemplos de aplicativos

Há vários exemplos de aplicativos de streaming Lambda na Serverless Patterns Collection. Eles usam o AWS SAM para criar e implantar os recursos em sua conta da AWS.

Clone o repositório e explore os exemplos. O arquivo README em cada pasta de padrões contém informações adicionais.

git clone https://github.com/aws-samples/serverless-patterns/ 
cd serverless-patterns
Bash

Tempo até o primeiro byte usando write ()

1. Para mostrar como o streaming melhora o tempo até a primeira mordida, implante o padrão lambda-streaming-ttfb-write-sam.

cd lambda-streaming-ttfb-write-sam
Bash

2. Use o AWS SAM para implantar os recursos na sua conta da AWS. Execute uma implantação guiada para definir os parâmetros padrão para a primeira implantação.

sam deploy -g --stack-name lambda-streaming-ttfb-write-sam
Bash

Para implantações subsequentes, você pode usar sam deploy.

3. Insira um nome de pilha e aceite os padrões iniciais.

O AWS SAM implanta uma função Lambda com suporte a streaming e um URL de função.

AWS SAM deploy --g

AWS SAM deploy –g

Após a conclusão da implantação, o AWS SAM fornece detalhes dos recursos.

AWS SAM resources

AWS SAM resources

A saída do AWS SAM retorna uma URL da função Lambda.

4. Use curl com suas credenciais da AWS para visualizar a resposta de streaming, pois a URL usa o AWS Identity and Access Management (IAM) para autorização. Substitua os parâmetros de URL e região para sua implantação.

curl --request GET https://<url>.lambda-url.<Region>.on.aws/ --user AKIAIOSFODNN7EXAMPLE:wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY --aws-sigv4 'aws:amz:<Region>:lambda'
Bash
Você pode ver a exibição gradual da resposta transmitida.

Using curl to stream response from write () function

Usando curl para transmitir a resposta da função write ()

Tempo até o primeiro byte usando pipeline ()

1. Para testar um exemplo usando pipeline(), implante o padrão lambda-streaming-ttfb-pipeline-sam.

cd ..
cd lambda-streaming-ttfb-pipeline-sam
Bash

2. Use o AWS SAM para implantar os recursos na sua conta da AWS. Execute uma implantação guiada para definir os parâmetros padrão para a primeira implantação.

sam deploy -g --stack-name lambda-streaming-ttfb-pipeline-sam
Bash

3. Enter a Stack Name and accept the initial defaults.

4. Insira um nome de pilha e aceite os padrões iniciais.

Use curl com suas credenciais da AWS para visualizar a resposta do streaming. Substitua os parâmetros de URL e região para sua implantação.

curl --request GET https://<url>.lambda-url.<Region>.on.aws/ --user AKIAIOSFODNN7EXAMPLE:wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY --aws-sigv4 'aws:amz:<Region>:lambda'
Bash

Você pode ver o fluxo de resposta em pipeline retornado.

Using curl to stream response from functionUsando curl para transmitir a resposta da função

Payloads grandes

1. Para mostrar como o streaming permite que você retorne payloads maiores, implante o aplicativo lambda-streaming-large-sam. O AWS SAM implanta uma função Lambda, que retorna um arquivo PDF de 7 MB maior do que o limite de payload de resposta não streaming de 6 MB do Lambda.

cd ..
cd lambda-streaming-large-sam
sam deploy -g --stack-name lambda-streaming-large-sam
Bash

2. A saída do AWS SAM retorna uma URL da função Lambda. Use curl com suas credenciais da AWS para visualizar a resposta do streaming.

curl --request GET https://<url>.lambda-url.<Region>.on.aws/ --user AKIAIOSFODNN7EXAMPLE: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY --aws-sigv4 'aws:amz:<Region>:lambda' -o SVS401-ri22.pdf -w '%{content_type}'
Bash

Isso baixa o arquivo PDF SVS401-ri22.pdf para seu diretório atual e exibe o tipo de conteúdo como application/pdf.

Você também pode usar o API Gateway para retornar uma grande payload com uma integração HTTP_PROXY com uma URL de função Lambda.

Invocando uma função com streaming de resposta usando o SDK da AWS

Você pode usar o SDK da AWS para transmitir respostas diretamente da nova API InvokeWithResponseStream do Lambda. Isso fornece funcionalidades adicionais, como lidar com erros intermediários. Isso pode ser útil ao criar, por exemplo, microsserviços internos. O streaming de respostas é compatível com o AWS SDK para Java 2.x, o AWS SDK para JavaScript v3 e os AWS SDKs para Go versão 1 e versão 2.

A resposta do SDK retorna um fluxo de eventos do qual você pode ler. O stream de eventos contém dois tipos de eventos. O PayloadChunk contém um buffer binário bruto com dados de resposta parcial recebidos pelo cliente. InvokeComplete sinaliza que a função concluiu o envio de dados. Ele também contém metadados adicionais, como se a função encontrou um erro no meio do stream. Os erros podem incluir exceções não tratadas geradas pelo código da função e pelos tempos limite da função.

Usando o AWS SDK para Javascript v3

1. Para ver como usar o AWS SDK para transmitir respostas de uma função, implante o padrão lambda-streaming-sdk-sam.

cd ..
cd lambda-streaming-sdk-sam
sam deploy -g --stack-name lambda-streaming-sdk-sam
Bash

2. Insira um nome de pilha e aceite os padrões iniciais.

O AWS SAM implanta três funções do Lambda com suporte a streaming.

  • HappyPathFunction: retorna um stream completo.
  • MidStreamErrorFunction: simula um erro no midstream.
  • TimeoutFunction: A função atinge o tempo limite antes da conclusão da transmissão.
  • Execute o aplicativo de exemplo do SDK, que invoca cada função do Lambda e gera o resultado.
npm install @aws-sdk/client-lambda
node index.mjs
Bash

Você pode ver cada função e como os erros de midstream e timeout são retornados ao cliente SDK.

Streaming midstream errorErro de streaming no midstream

Streaming timeout errorErro de tempo limite de streaming

Cotas e preços

As respostas de streaming incorrem em um custo adicional para a transferência de payload de resposta pela rede. Você é cobrado com base no número de bytes gerados e transmitidos da sua função Lambda nos primeiros 6 MB. Para obter mais informações, consulte os preços do Lambda.

Há um tamanho de resposta inicial máximo de 20 MB, que é um limite flexível que você pode aumentar. Os primeiros 6 MB do payload de resposta são transmitidos sem restrições de largura de banda. Além de 6 MB, há um limite máximo de taxa de transferência de largura de banda de 16 Mbps (2 MB/s).

Conclusão

Hoje, o AWS Lambda está anunciando o suporte ao streaming de payload de resposta para enviar respostas parciais aos clientes à medida que as respostas se tornam disponíveis. Isso pode melhorar o desempenho de aplicativos móveis e Web. Você também pode usar o streaming de resposta para criar funções que retornam payloads maiores e realizam operações de longa duração, ao mesmo tempo em que relatam o progresso incremental. Transmita respostas parciais por meio de URLs de funções do Lambda ou usando o AWS SDK. Atualmente, o streaming de resposta oferece suporte ao Node.js 14.x e runtimes superiores, bem como aos runtimes personalizados.

Há vários exemplos de aplicativos de streaming Lambda na Serverless Patterns Collection para explorar a funcionalidade.

O suporte ao streaming de resposta do Lambda também está disponível por meio de vários parceiros do AWS Lambda, como Datadog, Dynatrace, New Relic, Pulumi e Lumigo.

Para obter mais recursos de aprendizado serverless, visite Serverless Land.