Iniciando o design arquitetural de um "serviço para compartilhar atualizações" (como o Twitter)

Scalability. The #1 problem people don’t actually have but still solve.
Eberhard Wolff

Quase todas as plataformas sociais tem como funcionalidade principal o compartilhamento de atualizações entre “amigos” ou “seguidos e seguidores”. Sejam com fotos, no Instagram, micro postagens, no Twitter, ou novidades do cotidiano, no Facebook, quase todas as redes sociais funcionam no entorno de uma timeline.

Nesse capítulo, vamos utilizar alguns dos conceitos discutidos nesse livro para “pensar a arquitetura” de um sistema para compartilhamento de atualizações. Nosso objetivo não vai ser fazer uma proposta completa, tampouco definitiva, mas “aquecer os motores”. Obviamente, iremos trabalhar um um cenário fictício (afinal, precisamos de algumas delimitações para nossa solução).

Coletando informações para o Haiku

Em nosso cenário fictício, nosso desafio é gerar um sistema para compartilhamento de atualizações, como o Twitter. Esse serviço deverá ser consumido tanto por aplicações web quanto mobile.

Em alto nível, o sistema deve permitir aos seus usuários compartilhar atualizações que deverão ficar visíveis para seus “seguidores”. Também deve permitir aos usuários “seguir” outros usuários. Não é necessário haver reciprocidade (a relação é de seguido/seguidores e não de amizades).

Cada usuário deverá ter acesso a um timeline de suas próprias atualizações. Além disso, deverá ter acesso a uma timeline combinando as atualizações de seus “seguidos” e as próprias. Todas as timelines devem apresentar as atualizações em ordem cronológica inversa.

Não há limites para o número de seguidores para um determinado usuário. Tampouco há restrições para a quantidade de usuários cada membro da plataforma poderá seguir.

As atualizações deverão ser apenas texto (restrito a 500 caracteres) e links.

Estima-se 5 milhões DAU (daily active users). Estimam-se 2 milhões de atualizações, com 150 caracteres em média, todos os dias. A taxa entre leituras (recuperação de atualizações) e gravações (inserção de novas atualizações) é de 600 para 1.

Os atributos de qualidade associados a este serviço são, em ordem de importância: disponibilidade, escalabilidade e desempenho. Consistência, embora desejável, poderá ser eventual.

Twitter em números

Estima-se, hoje, que o Twitter possui:

  • 217 milhões DAU.
  • 500 milhões de tuítes por dia.
  • 391 milhões de usuários não tem seguidores
  • 30% dos usuários do twitter afirmam acessar acessar a plataforma mais do que uma vez diariamente
  • 44% de todos os usuários do Twitter nunca compartilharam um tuíte.

Fonte: omnicoreagency.com/twitter-statistics/

Algumas estimativas de “papel de pão”

Com base nas informações levantadas com o negócio, em nosso cenário fictício, é possível elaborar algumas estimativas, grosseiras, mas já suficientes para orientar algumas decisões de design.

A ideia não é, necessariamente, chegar a precisão decimal, mas “compartilhar a visão” de números mais tangíveis e começar a estabelecer restrições.

Os números levantados aqui mostram que estamos lidando com grandes volumes de dados e com uma desproporcionalidade relevante entre os números de leituras e gravações.

Explicitando as principais features

O arquiteto de software deve ser, essencialmente, um orquestrador. Como tal, sua principal atribuição é promover alinhamento de propósitos de maneira a gerar autonomia de atuação.

Em sistemas grandes e potencialmente complexos, é importante explicitar quais são as principais funcionalidades e garantir que todos estejam alinhados quanto a isso.

No nosso cenário fictício, as principais funcionalidades são:

  1. Permitir que usuários compartilhem atualizações;
  2. Fornecer timelines com as atualizações de cada usuário, individualmente;
  3. Permitir que usuários sigam outros outros usuários;
  4. Fornecer timelines para cada usuário (follower) combinando as atualizações compartilhadas pelos usuários que eles seguem.

Há importantes omissões nessa lista! Não há menção para deteção de trends ou composição de timelines para hashtags.

Eventualmente, podem ocorrer discordâncias sobre “o que é mas importante”. Produzir consenso evita desgastes futuros, durante a execução (onde geralmente tempo e orçamento se tornam escassos).

Proposta ingênua de design arquitetural

Inicialmente, a solução para todas as principais features do sistema parece ser trivial. O modelo de dados para acomodar as informações é simples e a elaboração das consultas necessárias parece demandar apenas conhecimentos básicos de SQL.

Entretanto, é importante reconhecer que os volumes de dados e “potenciais” scans na tabela Updates são restrições evidentes.

A escala “quebra” tudo! Invariavelmente, qualquer solução de design arquitetural precisará ser revista, em algum momento, devido a mudanças de escala.

Organizando informações para gerar as primeiras ADRs

A partir das informações obtidas para formulação do Haiku e do “design de alto nível”, já é possível indicar algumas ADRs com status de “aberta para discussão”. Essas ADRs indicariam a “inclinação arquitetural” para diversos aspectos importantes, possibilitando debates entre especialistas.

Demanda por sharding

Os volumes de dados associados as atualizações torna evidente a adoção de alguma estratégia para particionamento horizontal das bases de dados.

Definição: Sharding

Um shard é uma partição horizontal de dados em um banco de dados ou mecanismo de pesquisa. Cada shard é mantido em uma instância de servidor de banco de dados separada, visando distribuir a carga de trabalho.

Tal demanda implica no planejamento de alguma técnica para consistent hashing.

Definição: Consistent Hashing

Consistent Hashing é uma técnica especial que permite o redimensionamento da infraestrutura de armazenamento (por exemplo, tamanho de uma hash table ou cluster de banco de dados) com um mínimo de remapeamentos (deslocamento entre slots).

Demanda por caching

A proporção entre leituras e gravações (600:1) não deixa dúvidas de que o serviço é read-intensive, logo, ideal para uso de caching.

Sistemas de bases de dados podem ser utilizadas para criar uma “memória” de longo prazo para o registro das interações. Entretanto, o segredo para a disponibilidade estará na “pré-computação”.

Scaling Redis at Twitter

O Twitter utiliza Redis como principal mecanismo de caching para a construção de suas timelines.

Nesse vídeo, Yao Yu compartilha algumas das lições aprendidas usando Redis, em escala, no Twitter, desde 2010.

Acessar vídeo

Dados dos usuários podem ser mantidos e recuperados em uma estrutura de caching chave/valor onde a chave é o id (ex: usr_<id>) do usuário. O mesmo pode ser ser dito com relação a cada atualização individualmente (ex: upd_<id>) .

As listas de “usuários seguidos” por cada usuário da plataforma também podem ser mantidas no cache, devidamente identificadas (ex: flby_<user_id>) .

Tanto as timelines com atualizações por usuário (ex: tl_usr_<user_id>), quanto aquelas com a combinação das atualizações de usuários seguidos para cada usuário (ex: tl_home_<user_id>), podem ser mantidas como listas de ids apontando para atualizações “cacheadas”.

Para manutenção de todos os caches segue “fluxo de trabalho” para quando ocorrer o compartilhamento de uma informação.

Explicite processos relacionados com as principais features usando fluxogramas “fáceis de entender” (não se detenha em detalhes).

Adoção de bases NoSQL de grafos para dados de usuários (incluindo seguidores)

Pesquisas do tipo “usuários que seguem X e Y, geralmente também seguem Y”, comuns para construção de mecanismos de recomendações, são incrivelmente desafiadoras em bases de dados relacionais, mas triviais em bases de dados baseadas em grafos.

Cypher

Cypher é a linguagem de consulta de grafos idealizada para o Neo4j.. É como o SQL para grafos, e foi inspirado pelo SQL, sendo, também, declarativa.

A consulta abaixo, por exemplo, permite encontrar o “tamanho do menor caminho” entre os atores Kevin Bacon e Tom Cruise, baseado em pessoas que atuaram com eles em filmes (obviamente, considerando a existência de uma base de dados em grafo com registro dos filmes)


MATCH path = shortestPath(
(Bacon:Person {name:"Kevin Bacon"})-[*]-(Keanu:Person {name:"Keanu Reeves"})
)
RETURN length(path);

Considera-se utilizar base de dados como Neo4J como base para dados dos usuários e relações sociais (following/followers).

Graph Algorithms: Practical Examples in Apache Spark and Neo4j

“Entender o mundo” sob a perspectiva de grafos ajuda a encontrar respostas simples para problemas complexos. Nesse livro, encontra-se uma série de dicas e insights que podem acelerar o entendimento do conceito para a construção de soluções poderosas.

Acessar livro

Adoção de fanout para atualização das timelines dos seguidores

A decisão de utilizar caching de maneira intensiva, inclusive com a pré-computação das timelines, introduz desafio para a atualização dessas estruturas.

Toda vez que um usuário resolver compartilhar uma atualização, é necessário recuperar sua lista de seguidores para, então, visitar cada timeline armazenada em caching introduzindo referência para tal atualização.

Tratamento especial para celebridades

A decisão de realizar fanout para atualizar timelines de seguidores pode ser consideravelmente dispendiosa para usuários com milhares seguidores (por exemplo, 100 mil). Felizmente, usuários “celebridades” costumam ser exceção.

Pode ser preferível não realizar qualquer atualização durante a inclusão de uma  nova atualização por parte de uma “celebridade” fazendo com que dados sejam “mesclados” na timeline de seguidores, sob demanda.

Tratando usuários inativos

Uma quantidade considerável dos usuários da plataforma pode se manter inativa por muito tempo. Logo, manter dados relacionados a usuários em memória pode ser algo “desnecessário” e um peso para processos de fanout.

Deve-se considerar “descartar” caching de usuários inativos por, por exemplo, mais de 30 dias.

Pontos que ainda necessitam reflexão

O processo de elaboração da arquitetura deve ser incremental. Tão importante quanto relacionar decisões realizadas é indicar claramente o que ainda precisa ser ponderado.

Com relação ao sistema que estamos projetando é importante, ainda, considerar:

  • Rate Limiting, visando mitigar o risco potencial de usuários mal-intencionados enviarem um número esmagadoramente grande de atualizações.
  • Processamento de streaming das atualizações, afim de avaliar tendências por hashtags.

Takeaways

A elaboração desse “início de trabalho arquitetural” para um “serviços de compartilhamento de atualizações” permite alguns aprendizados importantes:

  1. Em sistemas complexos, pode ser interessante explicitar a relação das principais features associadas.
  2. Soluções triviais para pequenos volumes de dados raramente funcionam em grandes escalas.
  3. Caching agressivo costuma ser a solução para sistemas reading-intensive.
  4. Fluxogramas são excelentes ferramentas de comunicação para features mais complexas.
  5. Há diversos “sabores” de NoSQL. Invista algum tempo conhecendo-os!

Dúvidas ou sugestões? Deixe suas contribuições nos comentários.

Compartilhe este capítulo:

Compartilhe:

Comentários

Participe da construção deste capítulo deixando seu comentário:

Inscrever-se
Notify of
guest
0 Comentários
Feedbacks interativos
Ver todos os comentários

Fundador e CEO da EximiaCo, atua como tech trusted advisor ajudando diversas empresas a gerar mais resultados através da tecnologia.

Mentorias

para arquitetos de software

Imersão, em grupo, supervisionada por Elemar Júnior, onde serão discutidos tópicos avançados de arquitetura de software, extraídos de cenários reais.

Consultoria e Assessoria em

Arquitetura de Software

EximiaCo oferece a alocação de um Arquiteto de Software em sua empresa para orientar seu time no uso das melhores práticas de arquitetura para projetar a evolução consistente de suas aplicações.

ElemarJúnior

Fundador e CEO da EximiaCo, atua como tech trusted advisor ajudando diversas empresas a gerar mais resultados através da tecnologia.

Podcast

Arquitetura de Software Online

55 51 9 9942 0609  |  me@elemarjr.com

+55 51 99942-0609 |  contato@eximia.co

+55 51 99942-0609  contato@eximia.co

0
Quero saber a sua opinião, deixe seu comentáriox
()
x