You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
470 lines
17 KiB
470 lines
17 KiB
<!doctype html> |
|
<html lang="en"> |
|
<head> |
|
<meta charset="utf-8"> |
|
|
|
<title>Uma Não-Gentil Introdução ao Stream Processing</title> |
|
|
|
<meta name="description" content="Uma introdução não-gentil ao stream processing"> |
|
<meta name="author" content="Julio Biason"> |
|
|
|
<meta name="apple-mobile-web-app-capable" content="yes"> |
|
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent"> |
|
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, minimal-ui"> |
|
|
|
<link rel="stylesheet" href="reveal.js/css/reveal.css"> |
|
<link rel="stylesheet" href="theme/azion.css" id="theme"> |
|
|
|
<!-- Code syntax highlighting --> |
|
<link rel="stylesheet" href="reveal.js/lib/css/zenburn.css"> |
|
|
|
<!-- Printing and PDF exports --> |
|
<script> |
|
var link = document.createElement( 'link' ); |
|
link.rel = 'stylesheet'; |
|
link.type = 'text/css'; |
|
link.href = window.location.search.match( /print-pdf/gi ) ? 'css/print/pdf.css' : 'css/print/paper.css'; |
|
document.getElementsByTagName( 'head' )[0].appendChild( link ); |
|
</script> |
|
|
|
<!--[if lt IE 9]> |
|
<script src="lib/js/html5shiv.js"></script> |
|
<![endif]--> |
|
|
|
<style type="text/css" media="screen"> |
|
.happy { |
|
color: yellow; |
|
} |
|
|
|
.reveal section img { |
|
border: none; |
|
} |
|
|
|
.reveal ul.empty { |
|
list-style: none outside; |
|
} |
|
|
|
li { |
|
display: block; |
|
} |
|
|
|
.cursor { |
|
background-color: #666; |
|
color: white; |
|
} |
|
|
|
img { |
|
max-height: 90%; |
|
} |
|
|
|
td.seen { |
|
font-style: italic; |
|
font-weight: bold; |
|
} |
|
</style> |
|
</head> |
|
|
|
<body> |
|
<div class="reveal"> |
|
<div class="slides"> |
|
<section> |
|
<section data-background="_images/streamprocessing.jpg" data-header> |
|
<h1 class="semi-opaque"> |
|
Stream Processing |
|
</h1> |
|
</section> |
|
</section> |
|
|
|
<section> |
|
<section> |
|
<img src="_images/avatar-20170726.png" alt="Me" style="float:left;width:200px;" class="no-border"> |
|
|
|
<div> |
|
<ul class="empty"> |
|
<li>Júlio Biason</li> |
|
<li>Azion Technologies<img src="_images/azion-logo.png" alt="Azion logo" class='company-logo'></li> |
|
<li>@juliobiason</li> |
|
<li>https://functional.cafe/@juliobiason</li> |
|
<li>julio.biason@gmail.com</li> |
|
<li><a href="http://presentations.juliobiason.net">http://presentations.juliobiason.net</a></li> |
|
</ul> |
|
</div> |
|
</section> |
|
|
|
<section> |
|
<img src="_images/start-a-fight.jpg" alt="Eu faço perguntas em reuniões que eu não sei nada e reunião explode; não é de propósito" class='stretch'/> |
|
|
|
<aside class="notes"> |
|
Eu sou famoso (ou era) por entrar eu reuniões, fazer uma |
|
pergunta e a reunião explodir em discussões (úteis, diga-se |
|
de passagem). Mas eu não fazia isso de propósito. |
|
</aside> |
|
</section> |
|
|
|
<section> |
|
<img src="_images/mini-hitler.jpg" alt="Me chamaram de Mini Hitler"/> |
|
|
|
<aside class="notes"> |
|
Para alguns, eu sou um mini-Hitler. |
|
</aside> |
|
</section> |
|
</section> |
|
|
|
<section> |
|
<section> |
|
<img class="stretch" src="_images/streamprocessing-azion.png" alt="Lista de pontos de presença da Azion" /> |
|
</section> |
|
|
|
<section> |
|
<h3>O que é uma CDN</h3> |
|
</section> |
|
|
|
<section> |
|
<img class="stretch plain" src="_images/streamprocessing-connection.png" alt="" /> |
|
|
|
<aside class="notes"> |
|
Numa conexão "normal", o seu computador conecta no |
|
modem, que se conecta em um servidor do seu |
|
provedor, que se conecta em outro servidor, que se |
|
conecta em outro, que se conecta em outro até que, |
|
finalmente, ele chega ao servidor que você |
|
realmente quer. |
|
</aside> |
|
</section> |
|
|
|
<section> |
|
<img class="stretch plain" src="_images/streamprocessing-cdn.png" alt="" /> |
|
|
|
<aside class="notes"> |
|
Com uma CDN, ao invés do servidor do provedor |
|
atravessar toda a internet até chegar ao servidor |
|
de destino, o servidor da CDN verifica se ele tem o |
|
arquivo requisitado e, se tiver, responde |
|
imediatamente. |
|
|
|
Quem sai ganhando com uma CDN? |
|
|
|
- O usuário, já que a resposta vem mais rápida. |
|
- O cliente da CDN, pois ele não vai precisar ter |
|
um servidor ou uma banda larga para poder responder |
|
todos os usuários, já que alguns vão ficar somente |
|
na CDN. |
|
- O provedor, já que ele tem que pagar qualquer |
|
tráfego que saia da sua rede. |
|
</aside> |
|
</section> |
|
|
|
<section> |
|
<img class="stretch plain" src="_images/streamprocessing-names.png" alt="" /> |
|
|
|
<aside class="notes"> |
|
Apenas para dar "nomes aos bois": |
|
|
|
- "Usuário" é quem inicia a conexão. |
|
- Cada servidor da CDN é chamado de Edge (e podem |
|
haver mais de uma edge em cada ponto de presença) |
|
- O servidor do cliente da CDN é chamado de |
|
"origem" (já que esse tem os dados originais). |
|
</aside> |
|
</section> |
|
|
|
<section> |
|
<h2>Por que isso é importante?</h2> |
|
|
|
<ul> |
|
<li>Os clientes são cobrados pelo tráfego que passa pela CDN.</li> |
|
<li class="fragment"><strong>Queremos mostrar o consumo em tempo real.</strong></li> |
|
<li class="fragment"><strong>... para todos os clientes.</strong></li> |
|
</ul> |
|
</section> |
|
|
|
<section> |
|
<h2>Como resolver isso?</h2> |
|
|
|
<p>Poderíamos simplesmente ir somando o total</p> |
|
<p class="fragment">... se não tivéssemos várias máquinas processando.</p> |
|
</section> |
|
|
|
<section> |
|
<h2>Como resolver isso?</h2> |
|
|
|
<p>Poderíamos mandar todos os dados para um banco de dados e ir marcando os registros como processados</p> |
|
<p class="fragment">... se isso não significasse que o banco cresceria infinitamente.</p> |
|
<p class="fragment">... a não ser que registros antigos fosse apagados.</p> |
|
<p class="fragment">... que é o que serviços de mensageria fazem.</p> |
|
</section> |
|
</section> |
|
|
|
<section> |
|
<section data-background="_images/streamprocessing-message-broker.png"> |
|
<h1 class="semi-opaque">Message Brokers</h1> |
|
</section> |
|
|
|
<section> |
|
<img class="plain stretch" src="_images/streamprocessing-broker.png" alt="" /> |
|
|
|
<aside class="notes"> |
|
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. |
|
</aside> |
|
</section> |
|
|
|
<section> |
|
<img class="plain stretch" src="_images/streamprocessing-broker2.png" alt="" /> |
|
|
|
<aside class="notes"> |
|
Uma das vantagens de message brokers é que, havendo |
|
um aumento da geração dos dados, é possível |
|
simplesmente plugar mais um Producer. |
|
</aside> |
|
</section> |
|
|
|
<section> |
|
<img class="plain stretch" src="_images/streamprocessing-broker3.png" alt="" /> |
|
|
|
<aside class="notes"> |
|
... 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. |
|
</aside> |
|
|
|
<aside class="notes"> |
|
Message Brokers são também muito usados em |
|
micro-serviços. |
|
</aside> |
|
</section> |
|
|
|
<section> |
|
<img src="_images/streamprocessing-kafka.png" alt="Kafka Logo" style="float:left;width:200px;margin:50px;" class="no-border"> |
|
<img src="_images/streamprocessing-rabbitmq.png" alt="RabbitMQ Logo" style="float:left;width:200px;margin:50px;" class="no-border"> |
|
<img src="_images/streamprocessing-sqs.png" alt="AWS SQS Logo" style="float:left;width:200px;margin:50px;" class="no-border"> |
|
<img src="_images/streamprocessing-zeromq.gif" alt="ZeroMQ Logo" style="float:left;width:200px;margin:50px;" class="no-border"> |
|
|
|
<aside class="notes"> |
|
Os Mesage Brokers mais usados são: |
|
|
|
- Apache Kafka |
|
- RabbitMQ |
|
- SQS (dentro da Amazon) |
|
- ZeroMQ |
|
</aside> |
|
</section> |
|
</section> |
|
|
|
<section> |
|
<section data-background="_images/streamprocessing-monolith.jpg"> |
|
<h1 class="fragment semi-opaque">Batch Processing</h1> |
|
</section> |
|
|
|
<section> |
|
<pre><code>sudo cat /etc/shadow | cut -d ':' -f 2 | sort | uniq -c</code></pre> |
|
</section> |
|
|
|
<section> |
|
<ul> |
|
<li>Entrada: conteúdo do arquivo /etc/shadow</li> |
|
<li>Processamento: capturando o segundo campo separado por ":"</li> |
|
<li>Agrupamento: ordenamento dos dados (sort + uniq)</li> |
|
<li>Saída: total de duplicados (ainda uniq)</li> |
|
</ul> |
|
</section> |
|
|
|
<section> |
|
<p>Batch processing seria o caso de processar os dados de um dia.</p> |
|
|
|
<p>Se novos dados entrassem no total do dia, bastaria reprocessar os dados do dia.</p> |
|
|
|
<p class="fragment">ou do mês, ou do ano.</p> |
|
</section> |
|
|
|
<section> |
|
<img class="stretch plain" src="_images/dunno.jpg" alt="" /> |
|
|
|
<aside class="notes"> |
|
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. |
|
</aside> |
|
</section> |
|
|
|
<section> |
|
<img src="_images/streamprocessing-spark.png" alt="Apache Spark Logo" style="float:left;width:200px;margin:50px;" class="no-border"> |
|
<img src="_images/streamprocessing-hadoop.png" alt="Apache Hadoop Logo" style="float:left;width:200px;margin:50px;" class="no-border"> |
|
</section> |
|
</section> |
|
|
|
<section> |
|
<section data-background="_images/streamprocessing-functional.jpg"> |
|
<h1 class="semi-opaque">Programação Funcional</h1> |
|
</section> |
|
|
|
<section> |
|
<h2>Buzzwords!</h2> |
|
|
|
<ul> |
|
<li>Teoria das Categorias!</li> |
|
<li title="In category theory, a branch of mathematics, a monad (also triple, triad, standard construction and fundamental construction)[1] is an endofunctor (a functor mapping a category to itself), together with two natural transformations. Monads are used in the theory of pairs of adjoint functors, and they generalize closure operators on partially ordered sets to arbitrary categories.">Monads!</li> |
|
<li>Functors!</li> |
|
</ul> |
|
</section> |
|
|
|
<section> |
|
<img class="stretch" src="_images/fuck-that.jpg" alt="" /> |
|
</section> |
|
|
|
<section> |
|
<h2>Funções Puras</h2> |
|
|
|
<p class="fragment">Uma função é considerada pura se |
|
ela sempre retorna o mesmo resultado para os mesmos |
|
parâmetros.</p> |
|
</section> |
|
|
|
<section> |
|
<pre><code>def mult(a): |
|
return a * 4</code></pre> |
|
</section> |
|
|
|
<section> |
|
<pre><code>mult(2)</code></pre> |
|
<span class="fragment">8</span> |
|
|
|
<pre class="fragment"><code>mult(2)</code></pre> |
|
<span class="fragment">8</span> |
|
</section> |
|
|
|
<section> |
|
<pre><code>class LightSwitch: |
|
def __init__(self): |
|
self.state = False |
|
|
|
def switch(self): |
|
self.state = not self.state |
|
print(self.state)</code></pre> |
|
</section> |
|
|
|
<section> |
|
<pre><code>light = LightSwitch() |
|
light.switch()</code></pre> |
|
<span class="fragment">True</span> |
|
|
|
<pre class="fragment"><code>light.switch()</code></pre> |
|
<span class="fragment">False</span> |
|
</section> |
|
|
|
<section> |
|
<pre><code>print()</code></pre> |
|
|
|
<aside class="notes"> |
|
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. |
|
</aside> |
|
|
|
<pre class="fragment"><code>INSERT INTO table (value, value)</code></pre> |
|
|
|
<aside class="notes"> |
|
Insert também não é considerada uma função pura, |
|
porque cada vez que é chamada adiciona um novo |
|
registro na tabela. |
|
</aside> |
|
</section> |
|
|
|
<section> |
|
<h2>Imutabilidade</h2> |
|
|
|
<p>Uma vez que o dado é gerado, ele nunca muda.</p> |
|
|
|
<p class="fragment"><small>(Transparência referencial)</small></p> |
|
</section> |
|
|
|
<section> |
|
<img src="_images/lisp.png" alt=""> |
|
|
|
<aside class="notes"> |
|
Mas uma coisa legal que seguiu a teoria das |
|
categorias, implementando programação funcional, |
|
foi Lisp. |
|
</aside> |
|
</section> |
|
|
|
<section> |
|
<ul> |
|
<li><code>map()</code></li> |
|
<li><code>reduce()</code></li> |
|
<li class="fragment"><code>fold()</code></li> |
|
</ul> |
|
</section> |
|
|
|
<section> |
|
<ul> |
|
<li><code>(map lambda iterator)</code></li> |
|
<li><code>(reduce lambda iterator)</code></li> |
|
<li><code>(fold lambda iterator start)</code></li> |
|
</ul> |
|
</section> |
|
|
|
<section> |
|
<ul> |
|
<li><code>map</code>: transforma cada um dos |
|
elementos do iterador através do função lambda |
|
em uma nova lista.</li> |
|
<li><code>reduce</code>: remove elementos do |
|
iterador que não sejam verdadeiros pelo lambda |
|
e produz uma nova lista. </li> |
|
<li><code>fold</code>: converte todos os elementos |
|
da lista em um único valor, começando com um |
|
valor adicionar (por exemplo, <code>sum</code>).</li> |
|
</ul> |
|
</section> |
|
</section> |
|
|
|
<section data-background='_images/thats-all-folks.jpg'> |
|
</section> |
|
</div> |
|
</div> |
|
|
|
<script src="reveal.js/lib/js/head.min.js"></script> |
|
<script src="reveal.js/js/reveal.js"></script> |
|
|
|
<script> |
|
// Full list of configuration options available at: |
|
// https://github.com/hakimel/reveal.js#configuration |
|
Reveal.initialize({ |
|
controls: true, |
|
progress: true, |
|
history: true, |
|
center: true, |
|
// showNotes: true, |
|
|
|
transition: 'fade', // none/fade/slide/convex/concave/zoom |
|
|
|
// Optional reveal.js plugins |
|
dependencies: [ |
|
{ src: 'reveal.js/lib/js/classList.js', condition: function() { return !document.body.classList; } }, |
|
{ src: 'reveal.js/plugin/markdown/marked.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } }, |
|
{ src: 'reveal.js/plugin/markdown/markdown.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } }, |
|
{ src: 'reveal.js/plugin/highlight/highlight.js', async: true, callback: function() { hljs.initHighlightingOnLoad(); } }, |
|
{ src: 'reveal.js/plugin/zoom-js/zoom.js', async: true }, |
|
{ src: 'reveal.js/plugin/notes/notes.js', async: true } |
|
] |
|
}); |
|
</script> |
|
|
|
</body> |
|
</html> |
|
|
|
|