Intelipost Stack 2021–2022

Christian Dorner
Tech Intelipost
Published in
9 min readJan 31, 2022

Um guia de nossa Stack de tecnologia, história e futuro

Um pouco de história

Esse é o primeiro documento público da Intelipost para falar sobre nossa “Stack” de tecnologia e como é trabalhar aqui como engenheiro de software, como autor dessa primeira versão espero que ela esteja em constante mudança e melhoria assim como a Intelipost vem sendo aprimorada ao longo do tempo.

Quando entrei na Intelipost em Setembro de 2019, éramos cerca de 20 pessoas na equipe de engenharia de software, hoje temos cerca de 150 pessoas na área de engenharia em 3 empresas do grupo Intelipost, crescemos um pouco.

Ao longo desse tempo saímos de um monolito onde todos trabalhávamos, que rodava em EC2 puro sem nenhum tipo de escalabilidade, qualquer indisponibilidade precisava de atuação manual e levava cerca de 20 minutos para boot da aplicação. Agora estamos migrando para um modelo mais moderno voltado para microserviços executando em Kubernetes. O número de serviços vem crescendo e a cada dia nossas equipes vêm atuando cada vez menos no monolito, algumas nem o conhecem. Ainda realizamos manutenções, melhoramos nossas APIs, mas isso vem diminuindo cada vez mais. Em termos de escalabilidade ele faz "scale-out e scale-in" de acordo com a demanda de requisições nas APIs o que nos deixa muito mais tranquilos ao lidar com os picos de requisições ao longo do dia e agora ele leva cerca de um minuto e vinte para iniciar, isso porque carregamos alguns caches na VM para melhorar nosso tempo de resposta.

Não estou falando mal dos engenheiros da época, pelo contrário, foi uma das equipes mais competentes que eu já vi, mas o número limitado de pessoas, as altas demandas de produtos e algumas customizações para clientes limitavam muito o tempo para atuação em débito técnico e modernização da aplicação.

Backend e Microserviços

Linguagem e Frameworks

Nossa linguagem principal é Java, com a entrada da Agile Process e o produto de Roteirização a linguagem Python foi introduzida em nossa Stack, até então era somente utilizado em tools e pequenos lambdas. Lambdas em NodeJS também existem em alguns pontos para tarefas específicas, mas temos intenção de começar a utilizar mais em produção.

Escolhemos a versão 11 do Java no início de 2021, estou acompanhando bem de perto a evolução do Java e gostaria de atualizar nossa versão em breve.

Sprint Boot é nossa escolha de framework, usamos os módulos de acordo com a necessidade de cada serviço e estamos em constante atualização nas suas versões, usamos bastante os módulos spring-messaging e spring-data, um dos pontos que pretendemos revisitar é a utilização de sprint-cloud-config gostaríamos de mover as configurações mais próximas da plataforma rodando dentro do k8s em config-map ou secrets.

Banco de Dados

Como solução de banco de dados relacional, utilizamos bastante Postgres 13, além de MySQL em alguns produtos.

Como solução de NoSQL a escolha foi utilizar MongoDB.

Como chave-valor temos o Redis e DynamoDB.

Além de amplamente utilizado para logs, temos também algumas features plugadas no ElasticSearch usando-o para armazenamento da informação como um banco de dados.

Como você pode ver temos abertura para qualquer tipo de solução de banco de dados, fica a escolha do desenvolvedor selecionar a que melhor se adequa a sua solução.

Brokers

Para filas utilizamos fortemente RabbitMQ e Kafka, ficando à escolha do desenvolvedor escolher a que mais atende sua necessidade.

Comunicação entre Serviços

A comunicação entre os serviços pode ser feita de duas maneiras, através de mensageria ou através de api, no caso de api deixamos para Ingress resolver todo o service discovery, e usamos na maioria das vezes OpenFeign para a comunicação além da facilidade de desenvolvimento ele já se encarrega de realizar os retries caso necessário.

Logs e Métricas

Como já mencionado para os logs utilizamos a stack ELK e para métricas no momento estamos utilizando uma plataforma completa chamada Instana, mas temos intenção de ser mais opensource e partir para um Grafana devido a capacidade de juntar diversas métricas diferentes e agregar tudo em um único dashboard.

Experimentos

Estamos construindo/experimentando alguns modos de projetos de template, dessa forma para se criar um novo projeto é possível descrever o mesmo e conseguir tudo necessário para a sua execução, seja libs ou até mesmo infraestrutura, na parte de libs java seria a criação de um pom (usamos maven aqui) ou a criação de um terraform para a infraestrutura.

Venho pensando se valeria a pena manter somente um solução para fila, Kafka por exemplo, tenho certeza que ele atenderia praticamente todas as nossas features.

Monolito

Assim como praticamente toda empresa que um dia foi uma startup pequena temos também nosso monolito, é escrito em Java 8 com Spring Framework 4, apesar de ser um monolito temos bastante tecnologias novas nele, utilizamos Redis, Rabbit, elasticsearch, mas criamos uma meio de criar novos produtos e serviços ao redor dele sem necessariamente extrair funções/apis dele, aqui um link contando um pouco dessa estratégia. Todo esse trabalho valeu a pena, já que temos serviços incríveis nascendo desse modelo.

Ainda temos planos de olhar para ele e criar novas versões das apis que lá residem.

Plataforma e SRE

Atuamos 100% dos nossos serviços na AWS, existem conversas para que alguns produtos executem também na GCP.

Praticamente todos nossos serviços são gerenciados, acreditamos que serviços essenciais merecem ser atendidos dessa forma, isso nos permite delegar para a cloud atividades de backup, replicação de dados, manutenção, multi-zonas de disponibilidade e nos concentrarmos mais em nossos produtos do que manutenção de infraestrutura.

Estamos na AWS por alguns motivos:

  1. Ela ainda é o maior provedor de cloud atualmente, incrivelmente rica em produtos e ferramentas o que facilita bastante.
  2. Vemos que os desenvolvedores têm bastante conhecimento e experiência na plataforma.
  3. Temos um bom relacionamento com eles, o que facilita em movimentos estratégicos a longo prazo.

Estamos migrando nosso cluster Kubernetes para Fargate mantendo um modelo mais serverless e dando mais liberdade para o desenvolvedor escolher o que mais atende sua necessidade.

Nosso monolito roda em ASG com as definições de AMI. E também temos diversos serviços agora migrados para instâncias Spot.

80% de nossa plataforma fica na região de SP, pois é onde a maioria de nossos clientes e parceiros estão, na Virgínia estão nossa infraestrutura de QA e um dos serviços que possui replicação para atender a nosso requisito de baixa latência.

Estamos trabalhando fortemente na inclusão de tags em toda a plataforma e com isso vamos reportar diretamente aos times os custos operacionais dos serviços. Estamos melhorando nossa infraestructure-as-code em terraform queremos chegar a 50% em breve e daí ir subindo gradativamente até atingir 100%.

Estamos em estudo entre Cloudflare e Akamai para ficar no edge das nossas apis e aumentar nosso nível de segurança, mesmo sendo uma plataforma B2B e conhecermos os clientes de nossas apis segurança é um ponto importante que sempre nos preocupamos, atualmente utilizamos WAF.

Cultura DevOps

É importante tocar nesse assunto pois vejo muitas definições de “DevOps” diferentes no mercado, incluindo aquela em que DevOps é confundindo com SRE, não estou abrindo uma discussão do que é DevOps mas gostaria de demonstrar como gostamos de pensar aqui na Intelipost.

Aqui na Intelipost gostamos de pensar em DevOps como uma Cultura e não um time, todos os desenvolvedores participam da Cultura “DevOps”, pois acreditamos em “You build it you run it”, ou seja, o desenvolvedor é responsável pelo produto desde seu desenvolvimento até seu deployment e execução. Não se preocupe, isso não quer dizer que iremos tocar seu telefone às 02:00h da manhã, situações desse tipo são extremamente raras e quando acontecem a equipe de SRE é muito boa em atuar nesse primeiro suporte nesses períodos do dia.

Sendo assim o que esperamos do desenvolvedor é uma preocupação com o produto em produção, é importante criar monitorias nas ferramentas e acompanhar o seu comportamento, por exemplo, o response time das suas API estão dentro da SLA definida, alguma DLQ está crescendo por qualquer motivo, etc.

Pensando no dia a dia, o desenvolvedor pode participar e dar ideias para a concepção do produto eu chamo de “Product Developer”, você vai participar de refinamentos e plannings, desenvolver o produto na sprint, garantir a qualidade do produto e do código, realiza o build e deploy do produto através de nossas ferramentas de CI/CD e acompanha o andamento através das stacks de monitoramento, você consegue ver seus pods no kubernetes através do Rancher, acompanhar os logs pelo Kibana e acompanhar a saúde das apis através do Instana.

Front-end e Mobile

Front-end

A maior parte do nosso front-end foi desenvolvida utilizando o framework Javascript Vue Js. Seguimos os padrões de componentes definidos pelo StyleGuide do Vue Js.

É utilizado o Vuex e Vue Router dentro da aplicação.

O javascript utilizado foi escrito com ES6. Utilizamos também o Eslint dentro do nosso projeto, que é feito através dos padrões definidos.

Para o CSS utilizamos o BEM como padrão.

Para gerenciamento de pacotes e dependências é utilizado o Yarn.

Os testes unitários são feitos com Jest.

Referente a arquitetura do projeto é utilizado o conceito de libs e módulos. As nossas libs são responsáveis por prover os componentes visuais, a identidade visual da plataforma e também por centralizar a lógica javascript.

Os nossos componentes são feitos utilizando Buefy que são componentes de UI baseados no Bulma(framework css).

Já os nossos módulos são compostos de acordo com o negócio. Cada negócio é uma feature que possui um conjunto de rotas que dá acesso às telas do sistema e cada tela possui a sua store para gerenciar seu estado.

Para fazer a ligação do Front-end com o Back-end é utilizado o GraphQL que é feito de acordo com cada módulo, contendo resolvers, mutations , queries e schemas.

Mobile

Nossos aplicativos foram desenvolvidos para IOS e Android de forma nativa.

Utilizamos a biblioteca Javascript React Native.

Em um dos aplicativos utilizamos o React Hooks que facilita muito na utilização do ciclo de vida, estado, sem precisar escrever componentes com classe.

Para gerenciamento de estados em ambos os aplicativos utilizamos o Redux.

Os testes unitários são feitos com Jest.

Também utilizamos o Eslint para garantir que nossos padrões de código sejam mantidos.

Para gerenciamento de pacotes e dependências é utilizado o Yarn.

Os componentes foram criados baseados no UI Kitten(framework react native para criar aplicativos móveis multiplataformas).

Para fazer a ligação do aplicativo com o Back-end é utilizado o GraphQL assim como nosso front-end.

Deployments

Usamos dois modelos diferentes dependendo da empresa do grupo, na Intelipost o código fica no GitHub e usamos Jenkins como solução de pipeline CI/CD, os artefatos quando jars são enviados para o Nexus, utilizamos o ECR quando são imagens do Docker.

No caso de alguns outros projetos usamos o GitLab para CI/CD.

Todo nosso deployment é feito dentro da esteira de pipeline, seja gerar uma nova imagem AMI, um cloudformation ou um deployment no kubernetes.

Estamos avaliando unificar as soluções e utilizar GitLab para ambas as empresas do grupo.

Volume de dados

Trafegamos mais de dois bilhões de chamadas em nossas apis expostas aos clientes, com um tráfego de 13T de dados, se você deseja ganhar experiência com sistemas de alto volume de dados a Intelipost é o lugar certo para você. Alguns candidatos me perguntam isso durante as entrevistas e gosto de brincar expondo a quantidade de chamadas em uma de nossas apis somente durante o período da entrevista.
Nosso RabbitMQ lida com centenas de mensagens por segundo, idem nosso Kafka.

Um olhar no Futuro

O monolito ficou no passado, uma requisição chega até nossos serviços após passar por todo controle do nosso CDN escolhido, recebemos em nosso load balancer que envia para nosso gateway Kong que valida a chave JWT e faz o roteamento para o serviço adequado. Esse serviço é construído potencialmente em Kotlin, foi deployado no Fargate após passar por um pipeline de CI/CD que garantiu que a alteração não trouxe impactos negativos, podemos acompanhar toda a requisição através do Grafana e acompanhar os logs no Kibana.

Nossas APIs de POST e PUT são em sua grande maioria assíncronas, e temos liberdade para realizar grandes mudanças e pausas em nossos banco de dados sem a percepção de nossos clientes.

Nossos serviços são construídos respeitando suas fronteiras, construídos através de uma arquitetura hexagonal e os próprios colegas de time se ajudam para garantir essas fronteiras.

Toda nossa estrutura possui replicação em multi-zona de disponibilidade, e alguns serviços até são executados em regiões diferentes para melhorar o tempo de resposta.

Implementamos novos meios de comunicação através de GRPC.

--

--