Cloud Intelligence™Cloud Intelligence™

Cloud Intelligence™

Data Streaming na AWS: opções demais

By Matthew PorterSep 21, 202117 min read

Esta página também está disponível em English, Deutsch, Español, Français, Italiano e 日本語.

Se você já encarou um caso de uso de data streaming na nuvem, é bem provável que tenha aberto mais abas no navegador do que gostaria de admitir enquanto pesquisava as várias opções da AWS e seus FAQs, digamos, quilométricos.

Quem tem tempo de ler cinquenta páginas de documentação só para descobrir qual serviço escolher?

Abaixo estão alguns dos principais serviços da AWS voltados para ingestão, transformação, armazenamento e análise de dados em streaming. Quando você estiver lendo este post, talvez essa lista nem esteja mais completa:

  • Kinesis Data Streams
  • Kinesis Firehose com integração opcional com Lambda
  • Kinesis Data Analytics
  • Managed Streaming for Apache Kafka (MSK)
  • Spark Streaming com Elastic MapReduce (EMR)
  • Glue Streaming ETL
  • IoT Analytics dentro do IoT Core

Se você anda frustrado ou perdendo tempo demais para decidir qual opção usar, fica comigo: vou descomplicar essa história cobrindo os fundamentos e o caso de uso ideal de cada serviço.

No fim do artigo tem um resumo rápido sobre quando escolher cada um.

Kinesis: a escolha padrão

A grande aposta da Amazon para data streaming, e o serviço que você deve considerar como escolha padrão na maioria dos casos de uso, é o Kinesis. Só que dentro do Kinesis existe uma porção de subserviços com nomes meio enigmáticos. Os mais relevantes são:

  • Kinesis Data Streams (muitas vezes chamado só de Streams)
  • Kinesis Firehose (ou só Firehose), e
  • Kinesis Data Analytics (ou só Analytics)

Vamos a cada um deles em detalhes.

Kinesis Data Streams vs. Kinesis Firehose

Streams vs. Firehose: visão geral dos recursos

Tanto o Data Streams quanto o Firehose ingerem dados e os despejam em um destino (sink). Por que, então, existem dois serviços diferentes que parecem fazer a mesma coisa?

A principal diferença entre Streams e Firehose é que o Streams foi pensado para enviar dados a serviços de computação com consumidores customizados, como aplicações rodando em EC2, EMR ou Lambda, que cuidam da transformação e do processamento dos dados em tempo quase real, com um atraso de apenas ~70 ms. Isso torna o Streams especialmente útil para sustentar dashboards em tempo real, detecção de anomalias e outras aplicações sensíveis ao tempo. O Streams também se integra muito bem ao Apache Spark, simplificando a manipulação de dados em tempo real via streaming Data Frames quando entram em cena análises mais complexas.

Já o Firehose não foi feito para entrega em tempo quase real. Em vez disso, ele agrupa as mensagens recebidas, opcionalmente as comprime e/ou as transforma com AWS Lambda e, então, despeja os dados, normalmente em um serviço da AWS. Em geral, o destino é o S3, o Redshift ou o Elasticsearch.

Embora as mensagens do Streams normalmente sejam consumidas por aplicações customizadas, você também pode configurar o Streams para encaminhar dados a um stream do Firehose, viabilizando análises em tempo real e, ao mesmo tempo, agrupamento e armazenamento dos dados para retenção de longo prazo.

Se o seu caso de uso não exige processamento em tempo quase real, o Firehose tende a ser a melhor opção e também é mais fácil de operar diretamente.

Firehose: na maioria das vezes, a melhor escolha

Por que, afinal, o Firehose costuma ser a melhor opção entre os dois?

Primeiro: o Kinesis Streams exige um esforço maior de codificação, com programas escritos usando a Kinesis Producer Library (KPL) e a Kinesis Consumer Library (KCL), ambas centradas em Java. O Firehose, por sua vez, foi projetado principalmente para escoar dados em serviços específicos da AWS, ou seja, não há esforço de codificação no componente de sink. Publicar mensagens no Firehose também é simples:

import boto3firehose_client = boto3.client('firehose')
response = firehose_client.put_record(
    DeliveryStreamName='string',
    Record={'Data': b'bytes'} # base64-encoded
)

Se você topa que o Kinesis Streams provavelmente vai ter algumas perdas de performance tanto do lado do produtor quanto do consumidor, além de abrir mão de outros benefícios, dá para usar os SDKs da AWS e publicar mensagens de forma mais simples, em vez de partir para um desenvolvimento mais robusto com a KPL:

import boto3kinesis_client = boto3.client('kinesis')
response = kinesis_client.put_record(
    StreamName='string',
    Data=b'bytes', # base64-encoded
    PartitionKey='string'
)

Segundo: tanto o Streams quanto o Firehose são totalmente gerenciados e fazem auto-scaling, mas o Streams é "menos" auto-scaling e não chega a ser totalmente serverless.

O auto-scaling do Firehose permite aumentar o throughput de forma imediata e contínua, indo de testes em desenvolvimento até GBs de dados por segundo sem solavancos, desde que você não esbarre nos limites de throughput do Firehose impostos pela AWS.

O escalonamento do Streams dá mais trabalho. Mesmo sem gerenciar diretamente a infraestrutura por trás, você precisa definir, para um Kinesis Stream, uma quantidade de "shards" que se traduz no throughput suportado por aquele stream. Um shard equivale, no máximo, a 1 MB/s ou 1.000 registros/s de throughput de escrita, e 2 MB/s de throughput de leitura. Ou seja, é preciso pré-provisionar uma certa quantidade de "shards" para suportar um determinado nível de throughput. Você pode mudar manualmente a contagem de shards de um stream ou configurar auto-scaling, mas esse último processo é mais complicado do que deveria.

Para alcançar um throughput maior, portanto, você escala a contagem de shards do stream. Mas tem um detalhe importante: cada shard leva, em média, cerca de 30 segundos para ser adicionado ou removido de um stream, e só dá para adicionar ou remover um shard por vez.

Vamos ver o impacto disso em um exemplo do mundo real: se você tem um stream com 1.000 shards (~1 GiB/s de throughput de escrita) e prevê precisar dobrar o throughput em breve, vai levar mais de 8 horas para o stream escalar totalmente com 1.000 shards adicionais.

Se você tem motivos para acreditar que pode, em algum momento, enfrentar um pico repentino e inesperado de volume de dados, o Kinesis Data Streams não vai conseguir escalar rápido o suficiente.

Com isso em mente, o Streams não é adequado para casos de uso com alta variabilidade de throughput de streaming, a menos que você aceite superprovisionar e pagar a mais nessas ocasiões, ou esteja confiante na sua capacidade de antecipar eventos de pico e se planejar de acordo. O Firehose, simplesmente, é mais fácil de escalar, mais fácil de desenvolver e, como veremos a seguir, mais fácil de precificar. O Kinesis Streams só deve ser usado quando análises em tempo real forem realmente necessárias.

Streams vs. Firehose: comparação de complexidade de preço

A abordagem serverless e com auto-scaling do Firehose para data streaming traz junto um esquema de preços pay-as-you-go bem direto, baseado em:

  • GBs de dados ingeridos por mês e, para os casos de uso pertinentes:
  • GBs de conversões de formato de dados realizadas
  • GBs de dados entregues em uma VPC

Já o preço do Data Streams é mais difícil de prever, porque é baseado em:

  • Número de shard-horas provisionadas, que pode variar com o auto-scaling. Você provavelmente vai precisar superprovisionar para garantir uptime confiável.
  • Número de payloads PUT de 25 KB enviados
  • Mudanças opcionais de retenção de dados de longo prazo
  • Habilitação opcional do enhanced fan-out, recurso que melhora o throughput quando muitos consumidores leem do mesmo shard

Streams vs. Firehose: resumo

Se o seu objetivo é fazer transformações básicas de dados e carregar em lote os dados de streaming em um data store, e você não tem requisito de processamento em tempo real, publique seus dados direto no Firehose. Também escolha o Firehose se quiser minimizar o tempo gasto no desenvolvimento da aplicação ou reduzir preocupações com escalabilidade rápida da infraestrutura.

Se você precisa processar dados em tempo real, mande pelo Streams, mas saiba que, mesmo com auto-scaling habilitado, ele pode não dar conta muito bem de aumentos repentinos de throughput.

Se você precisa processar dados em tempo real e também armazená-los depois para analytics, dá para enviar os dados primeiro ao Streams e, no console web do Kinesis, configurar facilmente o Streams para encaminhá-los ao Firehose, sem precisar escrever código (a não ser que você queira etapas opcionais de transformação no Lambda).

Pode ajudar pensar no Streams como funcionalmente parecido com o Apache Kafka, mas com armazenamento persistente temporário de mensagens que podem ser repassadas a vários consumidores. Os consumidores podem ser aplicações customizadas (EC2 ou EMR) ou serviços gerenciados pela AWS (Firehose). O Firehose costuma ser tratado como um carregador em lote para serviços específicos, geralmente da AWS (S3, Redshift, Elasticsearch), com transformações de dados serverless opcionais via Lambda.

Kinesis Data Analytics: análises em janela serverless

Streams e Firehose dão conta muito bem da ingestão, da transformação e do encaminhamento de dados de streaming para aplicações de análise em tempo real (Streams) e para sinks de armazenamento de longo prazo (Firehose). Que papel sobra para o Analytics, então?

O Data Analytics, oferta serverless e totalmente gerenciada de Apache Flink da Amazon:

  • Integra-se com o Data Streams ou com o Firehose
  • Executa consultas SQL sobre esses dados em streaming, e
  • Envia os resultados a um serviço da AWS, como outro Data Stream, stream do Firehose ou Lambda
  • O Data Analytics também consegue tratar arquivos estáticos CSV ou JSON localizados no S3 como tabelas SQL, permitindo JOINs entre dados de referência e dados em streaming.

O Data Analytics é usado, sobretudo, para calcular continuamente agregações de dados em streaming, anotados com dados de referência estáticos, em janelas de tempo — geralmente para alertas em tempo real — sem nenhum código ou infraestrutura provisionada, apenas SQL puro. Você até poderia escrever código Flink e implantá-lo em vez de SQL, mas, por uma questão de manutenção, eu ficaria com SQL, já que Scala e Java são menos usados no mundo de data science.

A documentação da AWS mostra um exemplo de análise de janela deslizante usando dados de cotações de ações, mas eu recomendaria estudar este exemplo do mundo real bem mais interessante, em que velocidades de tráfego em toda a Bélgica são ingeridas em um stream do Firehose, o Data Analytics é usado para comparar as velocidades atuais com as históricas com a ajuda de dados de referência no S3, a presença de engarrafamentos é determinada via SQL e alertas em tempo real são disparados com Lambda.

Managed Streaming for Apache Kafka (MSK)

Tanto o Kinesis Data Streams quanto o MSK, oferta gerenciada pela AWS para o Apache Kafka, são sistemas "pub-sub" eficazes que permitem publicar e consumir mensagens com alto throughput, baixa latência, alta disponibilidade e tolerância a falhas. Em termos gerais de escalabilidade e confiabilidade como plataforma de ingestão e entrega de dados, não há tanta diferença entre os dois, pelo menos na superfície.

Existem diferenças críticas nos detalhes, no entanto, e elas costumam favorecer o Kinesis:

  • Você só pode aumentar o número de message brokers. Ou seja, não dá para reduzir um deployment do MSK.
  • Mesmo sendo totalmente gerenciado, o MSK não é Kafka serverless. Por isso, ele envolve alguma configuração de cluster. Você precisa definir as zonas e as sub-redes em que seus brokers serão lançados, o número de brokers por zona, o tipo de instância que sustenta seus brokers e por aí vai.
  • Como o MSK não é serverless, você também paga pelo armazenamento baseado em EBS que sustenta as instâncias. Isso também não pode ser reduzido.
  • Você não pode mudar o tipo de instância depois do setup inicial do cluster. A única opção para escalar é aumentar a quantidade de instâncias.
  • O Kinesis é o serviço de streaming totalmente gerenciado e serverless da própria AWS, então naturalmente tem uma integração melhor com os outros serviços da AWS. Alguns consumidores do Kinesis podem ser conectados sem código, enquanto o MSK exige que todas as aplicações consumidoras sejam construídas sob medida, por exemplo, em EC2, EKS, EMR ou com código Flink implantado no Kinesis Data Analytics.
  • Você só pode ter um consumidor Kafka em um determinado "grupo" de consumidores lendo de uma partição por vez. O Kinesis, por outro lado, suporta múltiplos consumidores por shard.

A configuração inicial e contínua do cluster, somada à incapacidade de reduzir deployments, significa mais sobrecarga de DevOps, tanto a curto quanto a longo prazo, ao usar MSK em comparação com o Kinesis.

O preço também é diferente entre os dois e, mais uma vez, costuma favorecer o Kinesis.

Como já mencionado, o preço do Kinesis Data Streams é majoritariamente sob demanda. Ele se baseia, principalmente, no número de payloads PUT de 25 KB enviados e no número de shard-horas provisionadas para habilitar o throughput de PUT e GET desejado. A contagem de shards pode ser configurada com auto-scaling, simulando um preço sob demanda, embora a implementação seja meio desajeitada.

Já o MSK é precificado com base em quantas instâncias de um determinado tamanho você escolheu rodar, somado aos volumes EBS que as sustentam. Nem a contagem de instâncias nem o tamanho do volume EBS podem ser reduzidos; se superprovisionar, você fica preso à conta, a menos que encerre o cluster. O armazenamento pode ser configurado com auto-scaling, mas o tamanho e a contagem de instâncias não. Em vez disso, você terá que monitorar continuamente as métricas do CloudWatch das instâncias, quantas partições estão sendo usadas por broker e outros indicadores de performance, e escalar o serviço manualmente em resposta. Para completar, é "altamente recomendado" que o uso de CPU no cluster fique abaixo de 60%, então você inevitavelmente vai pagar a mais por capacidade de computação.

Há uma grande vantagem em usar o MSK: o Kinesis oferece entrega "pelo menos uma vez" das mensagens, enquanto o Kafka garante entrega "exatamente uma vez". Em geral, porém, lidar com deduplicação de mensagens é bem mais simples do que com desafios de escalabilidade de infraestrutura com bom custo-benefício.

Mesmo que você consiga operar com sucesso um cluster MSK em altíssima escala de forma otimizada em custo e que saia mais barato que o Kinesis, eu apostaria que ainda economizaria mais usando o Kinesis pela redução de horas-homem (caras) de DevOps gastas mantendo um serviço pub-sub crítico para o negócio rodando, quando uma alternativa totalmente gerenciada faria o mesmo trabalho praticamente sem esforço.

Pessoalmente, só recomendo o AWS MSK para empresas que já têm uma aplicação baseada em Kafka que, por restrições de tempo, custo de refatoração ou recursos de equipe, precisa ser migrada por lift-and-shift, sem mudanças de arquitetura.

Se quiser saber mais, recomendo ler este "honest AWS MSK review". Os comentários do artigo também são esclarecedores e focam em comparações de preço entre MSK e Kinesis.

Spark Streaming com EMR

O AWS EMR é a oferta totalmente gerenciada e com auto-scaling (mas não serverless) da Amazon que permite a execução em cluster de scripts escritos para ferramentas open-source de processamento de big data. Entre essas ferramentas está o Apache Spark.

O Spark possibilita análises baseadas em DataFrame que podem rodar tanto em datasets estáticos quanto em datasets de streaming. Você pode fazer análises em DataFrames com chamadas de função programáticas tradicionais, ou rodar Spark SQL, compatível com ANSI SQL. Trabalhar com Spark SQL em dados de streaming é parecido com usar SQL no Apache Flink / Kinesis Data Analytics. O Spark pode usar como fonte de ingestão de streaming monitorada o Apache Kafka e o Apache Flume, além do AWS S3 e do AWS Kinesis Data Streams.

Dadas as excelentes integrações nativas do Spark com o Streams e o S3, e a curva de aprendizado baixa do PySpark, recomendo usar Spark Streaming com DataFrames no EMR quando você precisa:

O mais importante: você precisa estar ciente de que, com o Data Analytics:

  • Nenhuma linha de dados pode ter >512 KB. O limite do Spark é bem maior: 2 GB.
  • Seu dataset de referência ultrapassa 1 GB de tamanho. O Spark não tem limite.
  • Cada aplicação deve ter exatamente uma fonte de streaming e até uma fonte de dados de referência. Com o Spark, dá para juntar várias fontes de streaming e várias fontes estáticas de dados de referência.
  • Consultas em janela não devem ultrapassar 60 minutos, já que os dados ficam em armazenamento volátil de onde o stream pode ser reconstruído em caso de interrupções inesperadas da aplicação. O Spark não tem limite de janela de tempo.

Glue Streaming ETL

O Glue Streaming é uma oferta de Spark Streaming DataFrames totalmente gerenciada, com auto-scaling e serverless. Use-o se tiver experiência com Spark e quiser fazer transformações e análises customizadas em dados que vêm do Kinesis com este serviço, em vez de gerenciar um cluster EMR ou funções Lambda. O Glue Streaming pode escoar para os destinos habituais, como S3, Redshift e DynamoDB.

O Glue consegue, até certo ponto, gerar código Spark automaticamente com base em uma lista de transformações que você pede no console web. Ou seja, não é estritamente necessário ter muita experiência com Spark, embora dominar o básico ajude.

Pessoalmente, achei esse serviço meio chatinho. Spark serverless até parece conveniente, mas vem com algumas limitações:

  • Quando você usa detecção de schema, não dá para fazer joins de dados em streaming.
  • Você não pode mudar o número de shards do Kinesis Streams enquanto um job de Glue Streaming ETL está em execução. É preciso parar o job, mudar a contagem de shards do Data Streams, esperar a operação concluir e, então, reiniciar o job.

Só pela escalabilidade do upstream, eu pessoalmente preferiria rodar um cluster Spark autogerenciado com auto-scaling habilitado em vez de Glue Streaming ETL, mas, nos seus testes, talvez você ache que o auto-scaling e a natureza serverless do Glue Streaming ETL compensam as desvantagens.

IoT Analytics dentro do IoT Core

O que os componentes do IoT Analytics fazem não é tão transparente quanto deveria — então escrevi um artigo inteiro sobre o assunto! Production-Scale IoT Best Practices: Implementation with AWS (parte 2). Vamos ver o básico aqui e deixar muitos detalhes para aquele artigo.

Dispositivos IoT enviando dados em streaming para a AWS chegam ao IoT Core. A partir daí, essas mensagens podem ser enviadas a outros serviços para análises customizadas. Por exemplo, com IoT Rules dá para encaminhar facilmente os dados do IoT Core para:

  • DynamoDB
  • Firehose, que então despeja os dados em DynamoDB, S3, Redshift ou Elasticsearch
  • Data Streams, que pode mandar dados para EC2, EMR, Lambda ou Firehose

Como dá para ver, há uma ampla variedade de fluxos de dados de IoT que você pode montar.

Porém, se você quiser processar todos os seus dados de IoT, da chegada na sua plataforma até o armazenamento e a análise, totalmente dentro de uma plataforma unificada e centrada em IoT, completamente serverless, com auto-scaling e gerenciada, e que tenha várias integrações relacionadas a analytics com outros serviços da AWS como Sagemaker e Quicksight, é aí que vale ficar com o IoT Analytics. O IoT Core permite processar dados de IoT dentro de um único serviço, em vez de juntar vários.

Passar pelo wizard do IoT Analytics configura o seguinte:

  • Um IoT Channel é onde os dados de IoT chegam
  • Um IoT Pipeline pega os dados do Channel e permite, opcionalmente, enriquecer, transformar e filtrar mensagens com base nos atributos delas
  • Um IoT Data Store, onde os dados em streaming ficam armazenados, indefinidamente ou por um período definido. Por trás dos panos, esses dados ficam guardados em um bucket S3 gerenciado pela AWS.
  • Um IoT Data Set pode ser criado a partir de um Data Store. É um subconjunto de um IoT Data Store criado com IoT SQL, que possui seu próprio período de retenção e a capacidade de se recriar sob demanda ou em uma agenda recorrente. Como os Data Stores, os Data Sets ficam armazenados como arquivos CSV em um bucket gerenciado. Os Data Sets, no fim das contas, significam que você pode criar um conjunto estático com base em um filtro customizado (por exemplo, selecionar todos os dados de temperatura de uma janela de tempo restrita, mas interessante), gerar esse conjunto sob demanda uma vez e mantê-lo indefinidamente para análises downstream, deixando que as mensagens originais e brutas no data store expirem segundo um período de retenção considerado por sua organização como o melhor equilíbrio entre retenção de dados brutos e custo-benefício.
  • Alguns serviços da AWS que se integram com o IoT Analytics, como o Quicksight, só leem de data sets, enquanto outros, como o SageMaker, podem ler de data stores e data sets. De forma geral, todos os serviços conseguem ler de data sets. Devido à conectividade mais limitada com data stores e às implicações de custo de armazenar dados brutos indefinidamente no IoT Analytics, em um caso de uso em produção vale se acostumar com a metodologia de criar datasets discretos e filtrados para uso em analytics ou na geração de modelos de ML, deixando o data store bruto expirar com o tempo, a menos que sua organização considere aceitável pagar pelo armazenamento histórico completo dos dados de IoT.

Qual serviço devo usar?

No esforço de explicar de forma concisa as várias opções de streaming da AWS, receio ter escrito demais! Aqui vai um resumo rápido de quando escolher cada serviço:

  • Kinesis Data Streams: quando você precisa fazer análises em tempo real em EC2, EMR ou Lambda e não se importa com alguma complexidade adicional de desenvolvimento e com a incapacidade de escalar throughput rapidamente.
  • Kinesis Firehose: quando você precisa agrupar dados em streaming em lote, opcionalmente transformar e/ou comprimir e colocá-los em armazenamento de longo prazo no S3, Redshift ou Elasticsearch. Quando você quer uma plataforma de ingestão de dados em streaming fácil de usar, serverless e com auto-scaling imediato e não se importa que ela faça escrita em lote em vez de mandar mensagens aos consumidores em tempo real.
  • Kinesis Data Analytics: quando você quer fazer análises básicas em janela sobre dados do Data Streams ou Firehose, geralmente para alertas em tempo real, com SQL em uma plataforma simples, serverless e com auto-scaling.
  • Managed Streaming for Apache Kafka (MSK): quando você tem uma aplicação baseada em Kafka e quer fazer lift-and-shift para a AWS. Restrições de tempo ou de recursos impedem que você redesenhe a aplicação para usar Kinesis.
  • Spark Streaming com EMR: quando você precisa fazer análises em janela avançadas sobre o Kinesis Data Streams via JOINs envolvendo múltiplas fontes de streaming e/ou datasets de referência estáticos.
  • Glue Streaming ETL: parecido com Spark Streaming com EMR, exceto que você pode rodar workloads do Spark em um ambiente serverless e com auto-scaling. Não permite escalar shards no upstream do Data Streams sem parar e reiniciar os jobs do Glue Streaming conectados.
  • IoT Analytics dentro do IoT Core: uma plataforma all-in-one de ingestão, armazenamento e análise para dados de IoT em streaming, totalmente gerenciada, serverless e com auto-scaling. O IoT Core permite que você evite juntar vários serviços da AWS para alcançar a mesma funcionalidade.

Obrigado pela leitura! Para ficar por dentro, siga a gente no DoiT Engineering Blog , no DoiT LinkedIn Channel e no DoiT Twitter Channel . Para conhecer oportunidades de carreira, acesse https://careers.doit-intl.com .