BIG DATA, PERFORMANCE, POSIX, RTB E OS DESAFIOS DA Tiago Peczenyj Weborama PROPAGANDA NA WEB
QUEM SOU EU? Tiago Peczenyj @pac_man Programador poliglota (ruby, java, perl, python, lua) trabalhei por quase 5 anos com distribuição de vídeos na globo.com. Hoje sou Software Engineer no time de Big Data da Weborama (França). Bebo cerveja nas horas vagas.
PROPAGANDA
QUEM ANUNCIA?
O QUE AS EMPRESAS BUSCAM?
LUCRO!
PROPAGANDA É UM CUSTO NECESSÁRIO PARA OS NEGÓCIOS
PROPAGANDA NA INTERNET
WHY?
É LÁ QUE ESTÁ A MINHA AUDIÊNCIA
OFERTA X DEMANDA
O AD SERVER
IFRAME + REDIRECTS
MUITOS REDIRECTS
MONETIZAÇÃO
TIPOS CPC custo por click CPM custo por mil impressões CPA custo por ação
CAMPANHA OFF LINE
CAMPANHA ON LINE
PARA UM DADO USUARIO O Ad Server precisa decidir qual campanha sera mostrada É preciso decidir também o que mostrar
EXEMPLO : BANNERS
MUITOS BANNERS
VEJAMOS
DYNAMIC CREATIVE OPTIMIZATION
DCO Section of the ad that changes dynamically, during ad view.
WORKFLOW
ADOBE CREATIVE SUITE EXTENSION +! +!
ALEM DO RANDÔMICO O ad server sabe o ip de origem do request http Utilizando uma base de dados geográfica (ex MaxMind) posso saber qual a provavel localização do visitante Posso então fazer referências locais (nome do País, Estado, Cidade, Bairro ) Também é possivel saber o provedor de acesso (Intelig, Vivo, Net )
HTTP HEADER / USER AGENT
SABENDO O USER AGENT O Sistema Operacional Nome do Browser / versão Se é um Mobile, Tablet, Video Game ou Desktop Posso inferir alguns perfis de consumo!
RETARGETING
RETARGETING Com retargeting, eu posso marcar um usuário para mostrar insistentemente uma campanha de forma a acelerar uma possivel conversão. O protocolo HTTP é stateless, porém é possivel utilizar COOKIES para identificar usuarios Estabelecemos uma sessão para cada usuario no nosso ad server
COOKIES
DCO + RETARGETING Funcionam muito bem juntos Porém é relativamente caro Solução: aumentar eficiencia ao restringir o grupo de usuarios, ao qual tenha mais potencial de convergir após algumas impressões Surgem os perfis geográficos, demograficos e comportamentais.
BIG DATA!
BIG DATA!! Cada vez que um banner / ads é impresso eu sei: Qual Usuário / Cookie está envolvido Aonde ele está geográficamente Qual é o aparelho, resolução da tela, sistema operacional Qual pagina ele visitou!
SALVANDO O REQUEST
BIG DATA!!! A partir do Historico do Usuário, eu posso usar uma série de Algoritmos de Inteligência Artificial para determinar os provaveis perfis A segmentação é algo constante, feita a cada vez que o usuario surge na internet Os Algoritmos não são fixos ( a pesquisa é constante) Surgem novas Oportunidades de Negócio, Algoritmos e Competidores
DATA PROVIDERS Existem muitas empresas no ramo de tracking de usuarios segundo alguns criterios. É possivel trocar informações sobre um determinado usuario de forma a melhorar os perfis existentes. Geralmente é feito através da troca de pixels
PIXEL SYNC Domínio A quer trocar dados com o Domínio B 1. No domínio A adicionamos <img src> para um pixel 1x1 localizado no domínio B 2. O domínio B redireciona para o A, utilizando uma determinada regra de formação de url + query string 3. O domínio A salva localmente as informações e serve um pixel 1x1 gif
EXEMPLO PIXEL SYNC Cookies: dominioa => id=x dominiob => id=y A quer saber qual o id do usuario X no dominio B". Add pixel: http://dominiob.com/pixel.gif?from=a (que redireciona para) http://dominioa.com/pixel.gif?id=y A salva internamente no perfil de X: Ids => { dominio B => Y }
PARA QUEM? Vimos ser possivel marcar usuarios para retargeting, alterar o conteudo de acordo com o perfil, mas como determinar para quem mostrar a propaganda? A regra para escolher uma dada campanha pode levar em conta o sistema operacional, tipo de aparelho mobile, região geográfica e alguns tipos de perfis mais simples. Escolher individuos baseados em algoritmos mais complexos/especificos exige ser o ad server. Exige?
REAL TIME BIDDING!
SSP E DSP
LEILÃO
REAL TIME BIDDING Permite que diferentes DSPs possam disputar o mesmo usuario (competitividade). Cada DSPs possui um conjunto de campanhas e uma forma proprietária de segmentar os usuarios. Assim um dado usuario pode ser muito relevante para a DSP A, enquanto não é tão atrativo para a B. Os dois maiores BIDs pagam. É possivel não fazer nenhum BID. Exige baixa latência nas transações ( da ordem de 100 ms).
PERFORMANCE/ESCALABILIDADE! Operações relativas a advertising exigem rapidez (ou podem não ser percebidos a tempo) e escalabilidade. Essencial entender qual é o maior problema relacionado a performance em operações web.
BIOS
ESCALABILIDADE Linguagem não escala Framework não escala Componente não escala Biblioteca não escala Arquiteturas muito bem construidas é que escalam (ou não)
ARQUITETURA É possivel desenhar uma aplicação web quase perfeita. Todavia, uma vez em produção, não raro se adiciona entropia/ruido na arquitetura/ aplicação para atender melhor a requisitos de negócios (ditos urgentes) A soma da aplicação + infraestrutura + arquivos de configuração + sistema operacional + hardware + versões de bibliotecas/ linguagem + aspectos ambientais nem sempre funciona da forma esperada.
PERFORMANCE A duração total de uma tarefa é a soma das durações das sub-tarefas associadas. Para que uma tarefa seja completada em menos tempo, podemos optar por Hardware mais rapido Utilizar um algoritmo mais eficiente (Big O) Paralelizar algumas sub-tarefas Utilizar melhor os recursos disponiveis Diminuir o overhead!
PERFORMANCE L1 cache reference Branch Mispredict L2 cache reference Mutex lock/unlock Main memory reference Send 1 K bytes 1 Gbps Net Read 1 MB from RAM (sequenc) Read 1 MB from SSD (sequenc) Disk Seek Read 1 MB from Disc (sequenc) Send packet CA->NE->CA 0.5 ns 5 ns 7 ns 14 x L1 25 ns 100 ns 14 x L2, 200 x L1 10.000 ns 250.000 ns 1 ms 4x memory 10 ms Antigo Delay 20 ms 80x RAM, 20x SSD 150 ms Netherlands / California Fonte: https://gist.github.com/jboner/2841832
CAOS
DESIGN Manter e evoluir uma aplicação web (advertising por exemplo) é uma tarefa que não deve ser subestimada. A aplicação depende de uma série de times diferentes para funcionar adequadamente. Comunicação é essencial
EQUILIBRAÇÃO (PIAGET) É o processo mediante o qual se equilibra aquilo que já sabemos (assimilação) com aquilo que podemos ser solicitados aprender e que não se ajusta completamente à nossa compreensão (acomodação)
CAUSALIDADE A mente humana, para resolução de problemas, funciona de forma causal. Quando nós não percebemos as causas, nós frequentemente inventamos alguma.
LOAD BALANCE
HTTP SESSION
HTTP SESSION COOKIE-BASED
SERVIR ESTATICOS DIRETAMENTE
USE CACHE
MULTIPLOS REQUESTS EM PARALELO
MISCELÂNEA Fazer um bom uso da infraestrutura: servidor web, servidor de aplicação, middlewares, caches, load balance, proxy, etc Design da solução de forma a evitar ponto unico de falha Fazer uso racional dos logs / unix signals Automatizar e versionar infraestrutura (git + puppet, chef ) Possuir ambiente espelho ao produção para teste/ homologação Monitorar tudo (nagios, new relic, statsd) Ferramentas para detecção de problemas (wireshark) Time multidisciplinar ( #devops )
BIG DATA : REDIS Armazenamento chave/valor Muito rapido Uso intenso de memória Possui coleções, listas, etc Expiração de chaves Suporte a scripts em Lua
BIG DATA : REDIS Modelagem de Dados: Um objeto pode ter varias entradas no Redis versus armazenar id => objeto serializado (xml, blob). Se o acesso ao Redis for um gargalo, minimizar acesso trafegando o mínimo de dados e/ou no mínimo de vezes. Compare o preço de recuperar o objeto, deserializar, alterar, serializar e armazenar novamente com o tempo de submeter um script lua que faça o mesmo
BIG DATA : REDIS É possivel enviar codigo Lua para o Redis usando EVAL É possivel executar um script usando EVALSHA É possivel chamar a funcao atraves de f_<sha1>() Produz processamento no servidor, mas Lua é eficiente, pode valer a pena.
REDIS : EXEMPLOS INCREMENTAR VALOR SERIALIZADO local key = KEYS[1] local value = KEYS[2] local decoder = LUA(decode) () -- substituir por f_93983 () local encoder = LUA(encode) () -- antes de utilizar local sereal_string = redis.call( 'get, key ) local decoded_string = decoder.decode_sereal(sereal_string) local decoded_number = tonumber(decoded_string) sereal_string = encoder.encode_sereal(decoded_number + value) return redis.call( 'set, key, sereal_string)
REDIS : CONCLUSÃO Encarar os problemas de forma pragmática Esconder os detalhes do acesso ao Redis através de uma abstração de alto nivel (um objeto/client/driver) Lembrar que acesso ao REDIS é I/O (bloqueante), mas não necessariamente devemos entrar em paranóia
BIG DATA : RIAK Banco NoSQL Chave / Valor com alta disponibilidade, tolerante a falhas e com escalabilidade quase linear Trabalha facilmente com grandes volumes de dados Não é tão rapido quanto Redis Excelente para armazenar dados de forma permanente Suporta map-reduce em JavaScript e Erlang Trabalha com interfaces Rest e Protocol Buffer Suporta multiplos backends plugaveis (Memory, LevelDB, )
RIAK::LIGHT O problema: com uma estrutura de centenas de processos assincronos que acessam MySQL, apresentou, entre outros gargalos, o acesso ao Riak O Backend da Weborama é totalmente feito em Perl. O driver em questão era o Net::Riak. Surge a ideia de escrever um novo cliente, extremamente leve e direto (CRUD) utilizando a interface Protocol Buffer. Nasce o primeiro projeto open-source da Weborama: Riak::Light
(PERL) $scalar @array %hash
(PERL) Atualmente está na versão 5.18.1 Linguagem procedural (C, shell script, awk, sed) com suporte à orientação a objetos. Perl versão 5 é mais antigo do que Java, Ruby ou PHP (backward compatibility insano). Mais de 124.284 módulos disponíveis no CPAN. Presente no começo da web interativa (cgi-bin) Profundas ligações com o movimento open source (Patch). Movimento de renovação da linguagem Modern Perl BioPerl, CERN, Estante Virtual, Booking.com, youporn
MOOSE package Point; use Moose; has 'x' => (is => 'rw', isa => 'Int'); has 'y' => (is => 'rw', isa => 'Int'); sub clear { my $self = shift; $self->x(0); $self->y(0); } my $point = Point->new( x=> 1, y => 2);
MOOSE package Point3D; use Moose; extends 'Point'; has 'z' => (is => 'rw', isa => 'Int'); after 'clear' => sub { my $self = shift; $self->z(0); };
MOOSE ROLES package Comparable; use Moose::Role; requires 'compare'; sub equal_to { my ( $self, $other ) = @_; $self->compare($other) == 0; } package Foo; use Moose; with Comparable ; # inject equal_to method sub compare { }
RIAK::LIGHT CRUD -> GET / PUT / DELETE Interface Protocol Buffer Orientação a Objetos com Moo Foco em Performance Uso da API POSIX não bufferizada Timeout I/O
RIAK::LIGHT use Riak::Light; my $client = Riak::Light->new( host => '127.0.0.1', port => 8087 ); $client->is_alive() or die "ops, riak is not alive"; $client->put_raw( foo => baz => "sometext"); # plain/text my $text = $client->get_raw( foo => 'baz'); $client->del(foo => 'bar');
BENCHMARK (GET) Requests/segundo Data::Riak (REST) Data::Riak (REST) 318 Net::Riak (REST) 478 50% Riak::Tiny (REST) 544 71% Data::Riak::Fast (REST) 594 87% Net::Riak (PBC) 1031 224% Riak::Light (PBC) 3774 1086% https://github.com/weborama/riak-light
POSIX Abstração I/O (socket, arquivos, named pipes) Bufferizado ou não Bloqueante ou não Funções sysread / syswrite É preciso observar que nem sempre vc vai escrever/ler todos os bytes que vc espera de uma vez ERRNO global
TIMEOUT IO IO::Socket::INET Alarm (signals) Select Setsockopt Windows / SunOS / NetBSD 6
RIAK CONCLUSÃO As vezes é necessario reescrever a roda Interface PBC < overhead < REST Uso de secondary indexes pode evitar duplicação de dados Não acessar diretamente da camada de negócios! Map/Reduce não apresentou a performance esperada Dividimos o perfil entre diferentes buckets para propositos diferentes
BLOOMD SERVER Servidor de alta performance escrito em C que permite trabalhar com filtros de Bloom Verificar se um dado está no Riak é relativamente lento Armazenas as chaves no Redis utiliza muita memoria Nesse filtro, um falso negativo é impossivel! Atenuamos o problema pois liberamos memoria no Redis e poucos requests efetivamente vão ao Riak https://github.com/armon/bloomd
OUTROS DESAFIOS Ad Blocking (21 %) Browser refusing third-party cookies Privacy Browser Fingerprint
OBRIGADO! Tiago Peczenyj @pac_man http://pacman.blog.br tiago.peczenyj@gmail.com