Luciano Sabença apresentou sobre como escalar sistemas distribuídos para envio de SMS usando estruturas de dados probabilísticas. A solução inicial armazenava todos os números portados em memória, mas isso consumia muitos recursos. A nova abordagem usa um Bloom filter, que reduziu o uso de memória de 2.5GB para 100MB e o tempo de inicialização de 300s para 15s. Estruturas de dados são cruciais para lidar com grandes volumes de dados de forma escalável.
2. ● Bacharel com distinção em Ciência da Computação pela
Unicamp.
● Analista de Desenvolvimento Sênior na Movile.
● Trabalha há 6 anos na Movile e há 3 como maior
responsável técnico na área de Messaging.
● Tem interesses na área de Machine Learning, Sistemas
Distribuídos, Teoria da Computação e Sistemas de
alta-performance.
Luciano Sabença
lucianosabenca
Sobre Mim
5. Qual o Primeiro Passo para o Envio de um SMS?
○ Identificar a Operadora do telefone de destino!
O Telefone foi
Portado?
Sim
Verificar Para
Qual Operadora
o Número foi
portado
Verificar na base
de Intervalos
Pertencentes às
Operadoras
Não
Portabilidade Númerica
~27 milhões (Brasil) + 50 milhões (América Latina)
~ 80 milhões !!!
15%85%
6. Necessárias:
● Escalabilidade
● Baixo de tempo de inicialização
● Quando um número não está portado:
○ Baixíssima latência
○ Independência de sistemas externos
● Quando um números está portado:
○ Baixa latência
Desejável:
● Atualização online
Características da Solução
7. Solução: Armazenar TODOS os números portados em memória.
Solução Inicial - V1
Vantagens:
Fácil de implementar.
Acesso aos dados de forma rápida.
Desvantagens:
● Consumo de Memória:
○ 50 milhões * 16 bytes (tamanho de um Long) ≈ 1.3 GB, só
para armazenamento das chaves.
○ 1.3 GB * 2 (approx. load factor do Mapa) ≈ 2.6 GB
● Tempo de Inicialização
○ Cerca de 5 minutos só para carregar todos os números de um
arquivo local
8. Necessárias:
● Escalável
● Baixo de tempo de inicialização
● Quando um números não está portado:
○ Baixíssima latência
○ Independência de sistemas externos
● Quando um número está portado:
○ Baixa latência
Desejável:
Atualização online
Solução Inicial - V1
9. ● Estruturas de Dados Probabilísticas são:
○ Estruturas que retornam respostas aproximadas, não definitivas
○ Há uma "probabilidade" associada com a resposta estar correta
○ Normalmente apresentam um tradeoff entre uso de memória x
precisão
○ Especialmente úteis para lidar com grandes massas de dados!!
Estruturas de Dados Probabilísticas
○ Count-Min Sketch
○ Skip List
● Alguns Exemplos:
○ Bloom filter
○ HyperLogLog
10. ● Criada por Burton Howard Bloom em 1970 e é uma estrutura de dados
probabilística que responde a pergunta: dada uma chave, ela pode fazer
parte desse conjunto?
● Pode retornar falso-positivo, porém NUNCA retorna um falso-negativo
● Operações Suportada:
○ Inserção
○ Consulta
● Princípio: Encodar a existência de uma chave em N bits
Bloom Filter
11. Inserção:
1. Gerar o hash da chave a ser adicionada
2. A partir do hash, selecionar os índices que representam aquela chave
3. Coloca como 1 todos os bits nos índices selecionados na etapa 2
Índice 0 1 2 3 4 5 6 7 8 9
Bit 0 0 0 0 0 0 0 0 0 0
Índice 0 1 2 3 4 5 6 7 8 9
Bit 0 1 0 0 0 1 0 0 0 0
Bloom Filter - Inserção
Exemplo:
Chave: Luciano - Hash: 15 - Índices: 1 e 5
12. Consulta:
1. Gerar o hash da chave a ser consultada
2. A partir do hash, selecionar os índices que representam aquela chave
3. Se todos os bits nos índices estão com o valor 1, retorna verdadeiro.
Senão retorna falso
Índice 0 1 2 3 4 5 6 7 8 9
Bit 0 1 0 0 0 1 0 0 0 0
Exemplo:
Chave: Luciano - Hash: 15 - Índices: 1 e 5 - Valor Retornado: Verdadeiro
Chave: Luciana - Hash: 25 - Índices: 2 e 5 - Valor Retornado: Falso
Bloom Filter - Consulta
14. Necessárias:
● Escalável
● Baixo de tempo de inicialização
● Quando um número não está portado:
○ Baixíssima latência
○ Independência de sistemas externos
● Quando um número está portado:
○ Baixa latência
Desejável:
● Atualização online
Solução Final Com Bloom Filter
16. ● O consumo de memória caiu de aproximadamente 2.5GB para 100MB,
por instância
● Economia total de aproximadamente 100GB de Memória RAM
● Criação de um Cluster de recursos compartilhado para todas as
Aplicações
● Tempo de inicialização caiu de cerca de 300s para 15s
Total Redis Positivos Falso-Positivos %Falso-Positivos
318 380 39 847 37 800 2 047 ≈ 5,1
Resultados
17. ● Estruturas de dados são importantes!
○ "I will, in fact, claim that the difference between a bad programmer and
a good one is whether he considers his code or his data structures
more important. Bad programmers worry about the code. Good
programmers worry about data structures and their relationships."
Linus Torvalds
Conclusões
● Existem estruturas de dados com diferentes objetivos e tradeoffs
(e.g. estruturas de dados probabilísticas, CRDTs, persistentes)
● Ao lidar com volumes grandes de dados, muitas vezes é
necessário sacrificar a precisão em troca de um ganho
considerável de recursos.