This is a CDN
Essa não é uma apresentação sobre CDN, mas como a
apresentação requer algo que gere dados de forma
contínua, eu vou usar CDN como exemplo, até porque
trabalhei com isso.
CDN nada mais é que um cache distribuído; ao invés
de todo mundo ir até o servidor de origem, os dados
são entregues por um servidor mais próximo do cliente.
Assim temos um sistema distribuído (vários servidores)
que não tem pausa (porque os vários servidores estão
o tempo todo entregando dados).
This is a CDN
A AWS tem um limite máximo de 100.000 requisições/segundo.
CDN? Stream Processing?
Os clientes são cobrados pelo tráfego que passa pela CDN.
Queremos mostrar o consumo em tempo real.
... para todos os clientes.
...e os dados não páram de ser gerados.
Um dos problemas que a CDN enfrenta é que ela
está sempre atendendo requisições. Assim,
informações estão sempre aparecendo e tentar
gerar os resultados em tempo real é complicado.
CDN? Stream Processing?
Impossível guardar os 100.000 registros/segundo num
banco de dados e fazer um SELECT pra ver o total.
Precisamos os dados "read ready ".
"Read Ready"
Como resolver isso?
Poderíamos simplesmente ir somando o total
... se não tivéssemos várias máquinas processando.
Se estívessemos usando apenas uma máquina, a cada
linha de log gerada poderíamos ir somando o que
cada cliente consumiu. Acontece que temos várias
máquinas (de novo, em alguns POPs, tem mais de um
servidor) e aí entram questões de transferência de
dados de um lado para o outro, tempo de latência de
rede e tudo mais. Isso tudo complica na hora de
juntar os dados.
Como resolver isso?
Poderíamos mandar todos os dados para um banco de dados e ir calculando e marcando esses como processados.
... se isso não significasse que o banco cresceria infinitamente.
... a não ser que registros antigos fosse apagados.
... que é o que serviços de mensageria fazem.
Um message broker é um serviço que guarda dados
como um banco de dados, mas possui dois tipos de
clientes:
- Um dos clientes é um "Producer", responsável pela
geração de dados; numa analogia com banco de dados,
seria um aplicativo que somente fizesse INSERRTS.
- O outro cliente é o "Consumer", responsável por
ler os dados gerados os dados gerados pelo
Producer.
Uma das vantagens de message brokers é que, havendo
um aumento da geração dos dados, é possível
simplesmente plugar mais um Producer.
... e, da mesma forma, se a produção de dados for
muito grande e o consumer não estiver dando conta,
basta adicionar mais Consumers.
... e o próprio mesage broker vai cuidar para
distribuir os dados do Producer entre os Consumers.
Message Brokers são também muito usados em
micro-serviços.
Os Mesage Brokers mais usados são:
- Apache Kafka
- RabbitMQ
- SQS (dentro da Amazon)
- ZeroMQ
Desses, o ZeroMQ e RabbitMQ são os mais usados para
integração entre micro-serviços; para stream
processing, Kafka é o grande vencedor
(provavelmente pela forma como ele permite que mais
de um consumidor se conecte a uma fila de dados e
como os dados são particionados para permitir
consumidores concorrentes); SQS é mais utilizado
para integração entre outros serviços Amazon com o
Lambda.
sudo cat /etc/shadow | cut -d ':' -f 2 | sort | uniq -c
Entrada : conteúdo do arquivo /etc/shadow
Processamento : capturando o segundo campo separado por ":"
Agrupamento : ordenamento dos dados (sort + uniq)
Saída : total de duplicados (ainda uniq)
Batch processing seria o caso de processar os dados de um dia.
Se novos dados entrassem no total do dia, bastaria reprocessar os dados do dia.
ou do mês, ou do ano.
Esse é todo o conhecimento que eu tenho de batch
processing, simplesmente porque eu pulei
diretamente para stream processing sem nunca ter
feito muita coisa com batch processing.
Buzzwords!
Teoria das Categorias!
Monads!
Functors!
Funções Puras
Uma função é considerada pura se
ela sempre retorna o mesmo resultado para os mesmos
parâmetros.
def mult(a):
return a * 4
class LightSwitch:
def __init__(self):
self.state = False
def switch(self):
self.state = not self.state
print(self.state)
light = LightSwitch()
light.switch()
True
light.switch()
False
print()
Por mais estranho que possa soar, `print()` também
não é uma função pura, porque chamar print() duas
vezes vai deixar duas linhas na tela.
INSERT INTO table (value, value)
Insert também não é considerada uma função pura,
porque cada vez que é chamada adiciona um novo
registro na tabela.
random()
"Idempotência"
A ideia de que rodar alguma coisa e ela sempre
responde da mesma forma também é chamado de
"idempotência".
Imutabilidade
Uma vez que o dado é gerado, ele nunca muda.
(Transparência referencial)
Mas uma coisa legal que seguiu a teoria das
categorias, implementando programação funcional,
foi Lisp.
(map lambda iterable)
(fold lambda iterable start)
(filter lambda iterable)
map
: transforma cada um dos
elementos do iterador através do função lambda
em uma nova lista.
fold
: converte todos os elementos
da lista em um único valor, começando com um
valor adicionar (por exemplo, sum
).
filter
: remove elementos do
iterador que não sejam verdadeiros pelo lambda
e produz uma nova lista.
sudo cat /etc/shadow | cut -d ':' -f 2 | sort | uniq -c
sudo cat [broker] | cut -d ':' -f 2 | sort | uniq -c
sudo cat [broker] | map | sort | uniq -c
sudo cat [broker] | map | fold
sudo cat [broker] | map | fold
sudo cat [broker] | map | fold
sudo cat [broker] | map | fold
sudo cat [broker] | map | fold
sudo cat [broker] | map | fold
sudo cat [broker] | map | group_by | fold
sudo cat [broker] | map | group_by | fold
sudo cat [broker] | map | group_by | fold
sudo cat [broker] | map | group_by | fold
sudo cat [broker] | map | group_by | fold