Hoje vou comentar sobre o processo de desenvolvimento do novo shopping cart, o carrinho de compras, da KingHost. O sistema foi desenvolvido internamente e cuida basicamente de todas as vendas de produtos realizadas na empresa.
Tá sem tempo? Clica no play abaixo e ouça todo o material 🙂
Anteriormente à mudança, o antigo formato era totalmente acoplado ao site, independente de onde era ofertado o produto. O cliente era encaminhado para o carrinho no site para concluir a compra – exceto em algumas situações, como em compras pós-pagas dentro do painel de controle. Ou seja, nosso shopping cart era bastante centralizado, um dos pontos que precisava ser corrigido.
Além de vender produto, o carrinho também o configurava.
Como assim o configurava? Sim! Era preciso informar vários dados que seriam necessários para a ativação do serviço/produto contratado. Diagnosticamos então que todo esse processo para o cliente acabava tendo como consequência um alto índice de abandono de compra.
Como podemos ver nessa imagem, além de alguns desafios de negócios, nós tínhamos várias dificuldades técnicas, como escalabilidade, resiliência, sistema totalmente monolítico. Tudo isso causava impacto na hora de dar manutenção e de criar novas funcionalidades no sistema.
Inicialmente começamos a fazer uma análise, buscando entender nossa real necessidade, cases de soluções e de possíveis arquiteturas.
Uma arquitetura de software que tem ganhado muita atenção nos últimos anos é a de microsserviços. Ela é uma alternativa à de aplicação monolítica e, basicamente, consiste em dividir uma aplicação grande em várias menores, com propósitos específicos.
Se você quer ler mais sobre o assunto, indico este artigo falando sobre quando utilizar microsserviços.
Após avaliarmos a situação, optamos por tentar migrar nosso sistema de vendas para a arquitetura de microsserviços. Falo em “tentar” porque quem trabalha ou já trabalhou com sistemas legados sabe que não é tão fácil e simples sair criando algo novo.
Arquitetura do Novo Shopping Cart
Com o desenvolvimento da nova arquitetura, separamos as responsabilidades, deixando no shopping cart somente o necessário para o cliente conseguir adquirir os serviços. Assim, ficou para outra etapa a configuração do produto, com isso já diminuímos duas etapas do processo de compras antigo.
Distribuindo as responsabilidades, nós temos hoje a seguinte arquitetura, com aplicações isoladas em containers Docker: uma API recebe os dados do pedido e envia para uma fila, essa fila envia para uma outra aplicação, que então processa o pedido.
Cart-Admin: sistema interno para gestão de produtos, combos e pedidos;
Site e Cart-Client: Interface do carrinho de compras;
Cart-Painel: Interface do shopping cart dentro do painel de controle;
API Oauth: API de autenticação de aplicações clients e usuários internos;
DB Master: Banco de dados legado, onde pedidos são inseridos;
DB Slave: Réplica do DB Master, para consultas necessárias na API do Cart, assim a API Cart não tem dependência do banco de dados legados;
Cart-Server: API, fila e o consumer
Abaixo temos uma visão mais detalhada sobre as aplicações que recebem, enviam para a fila e processam o pedido.
Optamos por ter uma fila utilizando o RabbitMQ para termos total controle e independência dos sistemas legado. Se, por algum motivo, o consumer não conseguir inserir o pedido, a fila consegue gerenciar isso, fazendo novas tentativas ou até armazenando em uma fila de erros.
Com esta arquitetura, temos a possibilidade de escalar facilmente cada aplicação ou banco de dados, conforme a necessidade. Também podemos adicionar o carrinho onde for necessário, fazendo somente a integração com a API.
Monitoramento / Logs
Uma arquitetura de microsserviços distribuído é muito mais difícil de monitorar, mas é imprescindível, para isso não poupamos na monitoria e logs.
Para monitorar as aplicações e a comunicação entre elas, utilizamos a stack open source da Elastic.
Com os Bets conseguimos capturar as informações que necessitamos como, por exemplo, arquivos de logs e requisições HTTP. Através do Logstash enviamos para armazenar no Elasticsearch somente os dados que achamos cruciais para identificar possíveis problemas e, no Kibana, criamos nossos dashboard para visualizar esses dados.
Como nosso desenvolvimento hoje dentro da KingHost é basicamente utilizando a linguagem PHP, nós também utilizamos o Monolog para armazenar os logs e nos notificar se acontecer qualquer problema.
Com o Monolog, nós categorizamos e identificamos a gravidade de uma exceção, por exemplo, e notificamos a equipe por e-mail ou chat, dependendo da gravidade.
Outras stacks que utilizamos para nos auxiliar no monitoramento foi o Prometheus, Grafana, AlertManager, NodeExporter e cAdvisor.
Com esta stack nós conseguimos monitorar o servidor e os containers Docker, capturar estas métricas, enviar alertas e criar dashboards no grafana.
Para quem quiser saber mais sobre essa stack e como utilizá-la, pode ler o artigo monitorando aplicações PHP com Prometheus.
Principais Tecnologias Utilizadas
Como comentei anteriormente, a principal linguagem utilizada no desenvolvimento de aplicações na KingHost é o PHP. Neste projeto nós utilizamos alguns frameworks, como Lumen que é um micro-framework do Laravel além do micro-framework Slim.
Além do próprio PHP, utilizamos também seus frameworks e as stacks para logs, ferramentas como RabbitMQ para gerenciamento da fila de pedidos, GitLab como repositório de código fonte, Jenkins para build e deploy, e Portainer para gerenciar de forma gráfica os containers Docker.
Melhorias e Considerações Finais
Como comentei no início do artigo, este projeto foi um dos nossos primeiros utilizando este tipo de arquitetura dentro da KingHost, então temos muito a melhorar e refinar.
Falando um pouco de resultados e benefícios, já estamos vendo vários impactos desde a implementação do projeto que começou em fevereiro deste ano. Tanto voltado para questões do negócio como para questões técnicas, é possível relatar alguns resultados.
Por exemplo, diminuímos o tempo para o cliente completar a compra, baixamos o índice de abandono e vendas perdidas, aumentamos a taxa de conversão, como consequência aumentando a porcentagem de compras concluídas em até 60%. E como resultados técnicos, fomos beneficiados com algumas facilidades, como deploys separados, melhor manutenção, ganho de escalabilidade e flexibilidade.
Essa arquitetura, com a qual temos um grande sistema quebrado em serviços menores e mais leves, por critério de funcionalidades de negócio e integrados via HTTP (ou alguma arquitetura de mensageira), é o que forma a famosa arquitetura de microsserviços. Evidentemente, existem outros casos que podem usar diferentes tecnologias, bancos de dados compartilhados entre serviços, serviços que se comunicam com outros serviços e assim por diante.
Faz parte do papel do arquiteto de software tomar decisões baseadas em trade-offs. Nunca teremos uma solução perfeita. Sempre precisamos escolher entre vantagens e desvantagens, como foi o nosso caso com a utilização de microsserviços. O importante é analisar calmamente qual é a melhor abordagem para cada situação.
O que você achou deste conteúdo?