Iniciando o design arquitetural de um "encurtador de URLs"

Without high availability, you have no reason to scale.
Lee Atchison

Conhecimento, ganha-se estudando. Entendimento, ganha-se refletindo sobre algo estudado. Sabedoria, ganha-se com a prática.

Nesse capítulo, usaremos alguns dos conceitos discutidos nesse livro para iniciar a elaboração do design arquitetural de um encurtador de URLs. Iremos tratar, obviamente de um cenário fictício.

O que é um “Encurtador de URLs”

URLs longas são mais difíceis de lembrar, manter e compartilhar. O encurtamento de URL é uma técnica, adotada frequentemente, para transformar endereços HTTP em links mais curtos. 

O encurtamento de URLs ganhou destaque, primeiro, com a popularização do Twitter – onde, originalmente, havia um limite de 140 caracteres por postagens. A ideia original era “economizar” caracteres nas URLs compartilhadas para permitir a adição de mais informações em um tuíte. Atualmente, a plataforma já oferece esse recurso built-in.

Alguns serviços para encurtamento de URLs geram estatísticas de acessos a partir dos links encurtados. Também tem se tornado comum permitir a personalização da URL curta, facilitando a leitura.

A adoção de um encurtador de URL pode tornar o acesso a um site perceptivelmente mais lento, devido a necessidade de mais requisições HTTP e DNS.

Coletando informações para o Haiku

Designs arquiteturais devem atender os objetivos do negócio, respeitando restrições, satisfazendo atributos de qualidade, mitigando riscos e reduzindo custos. Não há trabalho de arquitetura sem explicitação dos requisitos do negócio.

Em nosso “cenário fictício”, as pessoas do negócio têm (para variar) a expectativa de lançar o serviço no menor prazo possível. Algumas já atuaram em empresas que forneciam serviços semelhantes, por isso, tem bom conhecimento do que funciona e não funciona na área.

As principais features do serviço, segundo descrito pelas pessoas do negócio, são:

  1. Encurtar URLs; ou seja, fornecida uma URL longa pelo usuário, gerar uma URL muito menor.
  2. Redirecionamento rápido; ou seja, acessada uma URL encurtada, gerada pela plataforma, redirecionar o usuário para a URL original

Infere-se, por características do que se está oferencendo, que os atributos disponibilidade, escalabilidade e resiliência são aqueles que se destacam.

NÃO há expectativa de gerar estatísticas, permitir alteração ou exclusão de URLs inseridas na plataforma, tampouco permitir customização das URLs geradas.

Definição: Requisito inverso

Requisito Inverso é uma descrição para demandas em uma especificação de escopo negativo, ou seja, de algo que não será feito ou ou expectativa que não será atendida.

Estimam-se 10 milhões de novas URLs sendo encurtadas diariamente. O formato da URL encurtada deverá ser www.abc.com/<id>. Sendo que a parte id deve ser uma cadeia o mais curta possível compostas por números (0-9) e letras (a-z, A-Z).

Não é possível discutir escalabilidade e disponibilidade com nenhuma estimativa relacionada a workloads.

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.

A proporção de 10 para 1 em operações de leitura e gravação é uma referência segura, embora conservadora, para a maioria dos cenários. Serve, pelo menos, como um bom ponto de partida.

Eventualmente, é interessante discutir com o negócio sobre possíveis sazonalidades, como horários com volumes de uso mais altos.

Pessoas do “negócio” têm tremenda validade de “apontar os números”. Daí, a importância de criar um referencial, mesmo que impreciso, como ponto de partida, buscando obviamente aprimorá-los com o andamento do projeto.

Para começar a dimensionar infra, é importante considerar que os recursos alocados podem estar “consumidos” até 80% durante a execução para evitar riscos de exaustão.

Sempre explicite desdobramentos associados a carga de trabalho que está sendo projetada. Isso facilita no alinhamento do time e no estabelecimento de fitness functions.

A partir da carga identificada, é possível determinar algumas fitness functions. 

E as integrações?

Raramente um software irá funcionar de forma isolada e independente, como uma ilha. Integrações, muitas vezes, são necessárias para que o software atenda os objetivos de negócios. Um modelo alto nível de quais integrações são necessárias é um ótimo ponto de partida, para abrir um diálogo com o time de negócios.

Utilizar uma ADL pode auxiliar a comunicação com o time de negócio. Uma modelagem de System Context da notação C4 model é um ótimo ponto de partida!

Planejar as integrações é algo crítico, não raro softwares apresentam instabilidades por falhas na integração com outros sistemas. Buscar uma visão mais clara das integrações, pode levar ao refinamento dos objetivos de negócio, restrições e atributos de qualidade.

Adicionar uma perspectiva de integrações no documento de Haiku, produz novas linhas de questionamento junto ao time de negócio a fim de validar a solução. Por exemplo,  ao explicitar as integrações percebe-se que o software proposto tem como objetivo ser um serviço interno da plataforma atual e deveria se integrar com outros “serviços” existentes. Considerando esta hipótese, o time pode conduzir uma nova proposta de solução avaliando ferramentas existentes no mercado.

O papel do arquiteto é garantir que a solução proposta atenda os objetivos de negócio, respeite as restrições, atenda atributos de qualidade com o menor custo ou risco. Ou seja, algumas vezes “comprar” pode ser mais adequado do que desenvolver em casa!

Organizando informações para gerar as primeiras ADRs

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

Endpoints

Parece ser adequado desenvolver o serviço como uma API REST. Destacam-se dois endpoints principais.

  1. Encurtamento de URL com POST www.abc.com/shorten?url=<long-url>
  2. Redirecionamento com GET www.abc.com/<short-url>

Redirecionamentos

Há duas opções básicas de redirecionamento em HTTP:

  • Status code 301 – indicando que o recurso endereçado pela URL solicitada foi movido permanentemente para um novo endereço;
  • Status code 302 – indicado que o recurso endereçado pela URL solicitada foi movido temporariamente para um novo endereço

Retornar 301 é, de longe, a forma mais econômica de implementar o redirecionamento, afinal, evitará que os servidores do serviço sejam acionados desnecessariamente, uma vez que o browser cliente deverá promover o redirecionamento sozinho.

Retornar 302, por outro lado, não diminui a quantidade de acionamentos, mas habilita fazer tracking de acesso e gerar estatísticas (algo desnecessário, conforme o negócio)

Sempre valide com o negócio o que está indicado nas expectativas antes de tomar decisões que sejam absolutamente difíceis de reverter.

Pelo indicado, até aqui, nas informações de negócio, o retorno mais adequado é 301.

Tamanho da chave para URLs encurtadas

Cada URL longa deverá ser submetida a uma função de hashing capaz de gerar uma chave encurtada. Essa chave poderá ser composta por números (0-9) e letras (a-z, A-Z), totalizando 62 possíveis caracteres.

Em análise simples, chaves com 6 caracteres de comprimento seriam mais que suficientes para acomodar o período estimado de operação. Entretanto, 7 caracteres seriam suficientes para a eternidade.

Estratégia para geração da chave

Sabendo-se o tamanho adequado da chave (6 ou 7 caracteres) é interessante determinar qual seria a estratégia para geração da chave.

Uma primeira abordagem possível seria utilizar algum algoritmo de hashing como CRC32 ou MD5. O problema é que ambos geram saídas com mais de 7 caracteres (CRC32 tem 8 caracteres e MD5 tem 32 caracteres), demandando alguma estratégia de corte.

Além disso, há riscos de colisões. Ou seja, duas URLs gerando chaves idênticas (risco significativamente ampliado com o necessidade de corte). Na prática, o uso de hashing implica em “idas e voltas” ao banco para detecter chaves já utilizadas em consultas potencialmente onerosas, eventualmente minimizadas pela adoção de técnicas como Bloom Filters.

Bloom Filter

Um Bloom Filter é uma estrutura de dados probabilística, que demanda pouquíssimo espaço, concebida por Burton Howard Bloom em 1970. Ela é utilizada para testar se um elemento está presente em um conjunto sem necessitar consultar a lista completa de elementos presente nesse conjunto.

Eventualmente, a estrutura pode apontar um falso positivo (indicando que um elemento está em um conjunto quando, na verdade, não está). Entretanto, jamais gera um falso negativo.

Quanto mais elementos são adicionados a uma Bloom filter, maiores são as chances de um falso positivo.

Outra alternativa é utilizar o índice inteiro, auto-incrementado, para gerar chaves através de conversão usando base62 (aderente a quantidade de caracteres suportados). A obtenção dos índices contínuos sem gerar gargalos em um sistema distribuído poderia acontecer pela adoção da técnica como HiLo.

HiLo

HiLo é uma técnica extremamente eficiente para gerar sequências numéricas, sem riscos de colisão, em ambientes distribuídos.

Nessa técnica “clientes” HiLo solicitam para um servidor um intervalo de identificadores, por exemplo [0-32] que não será mais fornecido em qualquer futura requisição.  Caberá ao servidor, manter controle dos intervalos fornecidos.

Com posse do intervalo, um “cliente” HiLo poderá utilizar seus elementos com segurança.

Entre as duas abordagens, a melhor solução parece ser aquela que utiliza índices auto-incrementados.

Caching

Toda vez que escalabilidade figurar entre os principais atributos de qualidade de um sistema, deve-se considerar a utilização de caching.

Como a expectativa de que a proporção de leituras e gravações é de 10 para 1, faz sentido considerar a adoção de estratégias de caching. Aparentemente, a melhor solução aparenta ser caching distribuído, eventualmente recorrendo a alguma solução de borda.

Estilo arquitetural e principais tecnologias candidatas

Todas as ADRs identificadas até aqui parecem ser favoráveis a arquiteturas modernas, usando funções (FaaS). Na plataforma da Microsoft, isso pode ser feito com Azure Functions. Na plataforma da AWS, faz sentido considerar AWS Lambdas.
A natureza não relacional, pelo menos aparente, dos dados parece recomendar uma solução NoSQL baseada em chave-valor.

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 design de um encurtador de URLs é importante, ainda, considerar:
  • Rate Limiting, visando mitigar o risco potencial de usuários mal-intencionados enviarem um número esmagadoramente grande de solicitações de encurtamento de URL.
  • Escalabilidade para banco de dados e aplicação, afinal, até aqui, consideramos apenas o caminho mais fácil que seria utilizando FaaS.

Proposta inicial de solução

Com base nas informações elementares do Haiku e das ADRs, uma boa proposição de design para implementação, suficiente para iniciar as discussões, seria a indicada no diagrama abaixo.

Um aspecto interessante é a utilização, ou não, do DAX (uma espécie de cache para o DynamoDB). Os limites de escala indicados acima seriam suportados pelo banco. Simples incremento de custo?

No diagrama abaixo, uma proposta de solução usando Azure.

Takeaways

A elaboração desse “início de trabalho arquitetural” para um “encurtador de URLs” permite algumas lições importantes:

  1. Mesmo soluções muito simples se tornam desafiadoras quando envolvem suporte a escala.
  2. Pensar a arquitetura fica muito mais simples quando parâmetros abstratos, como desempenho e escala, são explicitados em números (mesmo que “de papel de pão”).
  3. Sempre há mais de uma alternativa para resolver um problema arquitetural e, consequentemente, trade-offs.
  4. Conhecer boas estruturas/estratégias de dados (como Bloom Filters e HiLo) podem ajudar a viabilizar algumas propostas de design.
  5. Em tempos de “nuvem”, uma primeira boa “arquitetura de solução” serve como ponto de partida para discussões mais profundas.

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