Como Processar Bilhões de Eventos por Segundo Sem Matar a Latência
Imagine o seguinte: você precisa verificar transações bancárias em busca de fraudes em tempo real durante o processo de pagamento. Você tem apenas alguns milissegundos para tomar uma decisão. O Apache Kafka está transmitindo eventos sem parar, mas para cada um deles você precisa recuperar o histórico do cliente do banco de dados. Se você consultar um PostgreSQL ou MySQL tradicional para cada mensagem, o sistema vai colapsar sob a carga instantaneamente.
Este é um beco sem saída comum que engenheiros encontram ao projetar sistemas de alta carga. Um cache comum como o Redis ajuda a acelerar leituras individuais de chaves, mas quando se trata de construir lógica de negócio complexa e análises sobre um fluxo de dados, suas capacidades começam a ser insuficientes. Você é forçado a integrar caches, brokers de mensagens e motores de processamento de terceiros. Neste ponto, faz sentido dar uma olhada no Hazelcast.
O Hazelcast combina armazenamento distribuído em memória e um motor de processamento de streams em um único sistema. Em vez de montar uma estrutura com três serviços diferentes, você obtém uma plataforma unificada capaz de ingestar, enriquecer e analisar dados em tempo real.
O que acontece dentro da plataforma
O coração da plataforma é o motor Jet. Ele é responsável por construir pipelines de processamento de dados. O Jet pode trabalhar igualmente bem com streams contínuos e conjuntos de dados estáticos, como buckets no Amazon S3 ou tabelas em um banco de dados relacional.
As métricas de desempenho aqui são interessantes. Um único nó Hazelcast pode agregar 10 milhões de eventos por segundo mantendo a latência dentro de 10 milissegundos. Se você clusterizar os servidores juntos, a taxa de transferência escala até um bilhão de eventos por segundo.
Para escrever consultas contra streams de dados, você não precisa mergulhar nas APIs Java de baixo nível. A plataforma suporta SQL padrão. Você pode escrever uma SELECT familiar contra o stream de dados de entrada, juntá-la com uma tabela em memória e rotear imediatamente o resultado para o serviço de destino.
Aqui está como fica a conexão com fontes externas. Pronto para uso, você obtém um conjunto de conectores:
- Apache Kafka e JMS para trabalhar com filas
- Hadoop e Amazon S3 para acessar armazenamento de arquivos
- Bancos de dados relacionais via JDBC padrão
- Modelos Python para executar machine learning diretamente dentro do pipeline
Memória distribuída e coordenação
Se você remover a análise de streams da equação, o Hazelcast permanece como um armazenamento chave-valor distribuído. Os dados são distribuídos entre os nós do cluster como partições. Desenvolvedores têm acesso a estruturas Java familiares (IMap, IQueue, ITopic), com a única diferença sendo que elas são distribuídas pela rede. Buscas por chave levam microssegundos.
Para operações de banco de dados, padrões clássicos de cache são suportados: read-through, write-through e write-behind. Ao usar write-behind, a aplicação salva dados exclusivamente na RAM do Hazelcast, e a plataforma os persiste de forma assíncrona no disco e no banco de dados principal. Se o SGBD relacional ficar temporariamente fora do ar, sua aplicação continuará aceitando requisições sem falhas.
Um recurso separado é a coordenação de microsserviços. O Hazelcast pode gerenciar locks distribuídos, emitir sequências de IDs únicos e manter contadores compartilhados. Isso elimina a necessidade de implantar e manter um cluster Apache ZooKeeper separado para tarefas mundanas de sincronização.
Como construir e executar o projeto
O código-fonte do projeto é escrito em Java. JDK 17 ou mais recente é necessário para compilar a partir do código-fonte. A forma mais fácil de compilar o projeto é usar o script Maven Wrapper:
git pull origin master
./mvnw clean package -DskipTests
A compilação completa com todas as verificações pode demorar um pouco. Se você só precisa verificar rapidamente mudanças locais, passe o parâmetro -Dquick:
./mvnw clean package -DskipTests -Dquick
Este parâmetro desabilita a geração de Javadoc, verificações do Checkstyle e compilação de módulos secundários.
A situação dos testes é interessante. O repositório tem milhares de testes divididos em três perfis:
- O perfil padrão
./mvnw testexecuta testes de integração rápidos. - O perfil nightly
./mvnw test -P nightly-buildinclui testes lentos que não podem ser executados em paralelo. - O perfil completo
./mvnw test -P all-testsexecuta sequencialmente absolutamente todas as verificações usando a rede.
Alguns testes dependem do Docker. Se o Docker não estiver instalado na sua máquina, esses testes vão falhar. Para desabilitá-los, use o parâmetro -Dhazelcast.disable.docker.tests. Ao criar um Pull Request, o servidor de CI do projeto executa o conjunto completo, então localmente é suficiente executar testes apenas do seu próprio módulo.
Você pode escrever clientes não apenas em Java. A comunidade e a empresa mantêm bibliotecas oficiais para Python, Node.js, .NET, C++ e Go.
Licença e um par de nuances práticas
O código no repositório é dividido em duas partes. O núcleo é distribuído sob a permissive Apache License 2.0. No entanto, alguns recursos e módulos enterprise são protegidos pela Hazelcast Community License. Ela proíbe usar o código para criar serviços gerenciados pagos (Cloud Service Provider) que competem com o produto cloud original da empresa.
O segundo ponto são os requisitos de recursos. Como todos os dados quentes residem na RAM, você precisará adquirir uma quantidade substancial de memória para trabalhar com grandes volumes. Além disso, em um ambiente Java, você deve prestar muita atenção às configurações do Garbage Collector para evitar pausas ao limpar gigabytes de memória. No entanto, engenheiros do Hazelcast mitigam esse problema com armazenamento off-heap, movendo dados para fora do heap Java.
Quem deveria dar uma olhada no Hazelcast
A plataforma tem bom desempenho onde a resposta a eventos em tempo real é importante:
- Prevenção de fraudes e scoring em fintech
- Processamento de telemetria e sinais IoT de alta frequência
- Cálculo de preços e descontos em e-commerce exatamente no momento do clique do cliente
- Sincronização de dados entre data centers distribuídos (replicação WAN)
Se você só precisa de um cache simples para alguns endpoints, o Hazelcast seria overkill: um Redis mais simples lidaria com essa tarefa muito bem. Mas se seu projeto cresceu até uma escala onde a análise de streams precisa intersectar com memória distribuída sem viagens constantes ao armazenamento em disco, o Hazelcast vai economizar meses de desenvolvimento.
Projetos relacionados