Há dois anos, a aplicação de bate papo anterior da Uber começou a apresentar sinais de que ele não conseguiria acompanhar nosso crescimento. Haviam travamentos na aplicação, oscilações de performance, e quedas que prejudicavam a habilidade de se comunicar efetivamente online de nossa empresa. Com a satisfação do cliente no menor nível de todos os tempos, nós precisávamos de uma nova solução.
Com operações em mais de 620 cidades, era crucial que identificássemos uma solução de bate papo que permitiria aos colaboradores da Uber se comunicar confiavelmente em nossos aparelhos desktop e móveis, independentemente de onde eles estivessem no mundo. Para atingir esse objetivo, nós estabelecemos alguns requisitos principais. Para começar, precisávamos de algo que pudesse ser escalonado para suportar nossa crescente população de colaboradores e, como subproduto, controlar os custos. Nós também precisávamos de uma plataforma que pudesse ser integrado facilmente com uma variedade de ferramentas internas de engenharia, de negócios e de operações.
Enquanto avaliamos o Internet Relay Chat (IRC) e muitas outras soluções de bate papo, ficou claro que não havia uma ferramenta de terceiros completa que fosse capaz de atender aos requisitos principais da Uber.
Então, após testar muitas alternativas de soluções prontas, nós construímos o uChat, nossa plataforma de mensagens internas personalizada, aprimorando o Mattermost e o Puppet, o padrão da Uber para gerenciamento de instalações. Nesse artigo, discutimos como em apenas três meses nossa equipe fez a transição para uma nova solução capaz de entregar com segurança mais de um milhão de mensagens por dia para dezenas de milhares de usuários, tudo em um ambiente de mensagens unificado.
Passando para o open source
Para agilizar o processo de desenvolvimento, nós decidimos construir nossa solução em cima de uma plataforma open source. Essa opção teve um apelo particular, dado o nosso desejo de influenciar diretamente planos de ação e controlar custos recorrentes de longo prazo, o que teria sido mais difícil se tivéssemos começado do zero.
Para conseguirmos aproveitar o máximo de nossa abordagem de construção híbrida, precisávamos de uma solução com uma API versátil, uma base de código de alta qualidade, e uma comunidade de desenvolvimento vibrante. Nós avaliamos uma grande variedade de opções baseadas em XMPP, Erlang e JavaScript. Como nosso requisito principal era a capacidade de suportar o crescimento da Uber, nós prestamos uma atenção especial às plataformas de bate papo conhecidas por sua escalabilidade.
Como parte da nossa validação de performance, nós forçamos cada produto open source até seus limites. Por exemplo, um de nossos objetivos iniciais era simular os comportamentos de conversa de 50.000 usuários em um único ambiente de mensagens. Imediatamente, muitas dessas plataformas não foram capazes de executar os testes de performance básicos.
Com as opções restantes, nós escrevemos um teste para simular milhares de usuários. O projeto do conjunto de testes (Figura acima) foi extremamente simples; isso garantia que os requisitos do produto pudessem ser validados com um esforço mínimo da nossa parte. Nesse ambiente de teste, uma estrutura simples EntityConfig em Go (Figura abaixo) encapsulava um usuário que poderia acessar o sistema, unir-se a canais e enviar mensagens. Combinado às co-rotinas nativas do Go, foi fácil atingir nossos objetivos de simulação. Com o tempo, os testes cresceram para oferecer mais funcionalidades e simular melhor os cenários complexos dos usuários.
Após meses de testes e análises minuciosas, nos concentramos no Mattermost. O Mattermost excedeu nossas expectativas mínimas de performance e se alinhou bem às tecnologias existentes na Uber.
Além disso, suas interfaces de usuário eram similares às das aplicações populares utilizadas entre os colaboradores da Uber.
O próximo passo lógico foi avaliar se a ferramenta poderia, ou não, tanto acompanhar o hiper crescimento da Uber, quanto sustentar nossa dependência operacional das mensagens. Após considerações cuidadosas dos fatores necessários, nós nos perguntamos: o Mattermost poderia alcançar a escalabilidade da Uber?
Para testar a habilidade do Mattermost em se adaptar à essas condições, nossos testes de carga buscaram identificar os principais gargalos na arquitetura e nos servidores que pudessem impactar a performance. Nós simulamos taxas variáveis de envio de mensagens, intensificamos as janelas, e os picos de usuários concorrentes para estabelecer uma base. Milhares de contas de usuário falsas foram criadas e programadas para acessar o sistema, juntar-se a salas, e conversar intensamente para acionar as quebras do sistema e travar o banco de dados.
Durante os testes não ficamos surpresos em descobrir que não era apenas o back-end que apresentava escalabilidade limitada. A maioria das interfaces de usuário que testamos não poderia suportar nossos objetivos agressivos: por exemplo, as salas de bate papo podiam suportar aproximadamente 1000 participantes, e as interfaces de usuário existentes não eram capazes de realizar buscas em mais de 20.000 canais simultaneamente.
Conforme encontramos os gargalos durante nossos testes de escalabilidade, nós focávamos em corrigir os mais impactantes ofensores de performance e repetíamos o processo a partir dos níveis de carga que sabíamos que eram estáveis. Ao mesmo tempo, nós continuamos atualizando nossos testes para imitar os crescentes casos de uso reais. Nossa meta inicial era 70,000 usuários simultâneos com uma taxa de envio de mensagens de 80 a 200 mensagens por segundo. Se essa carga pudesse ser tratada com sucesso, poderíamos garantir um caminho largo para nosso crescimento futuro.
Trabalhando com a comunidade open source, nós continuamente analisávamos detalhadamente os registros, identificávamos as causas raiz, e entregar novas correções; a velocidade de resposta era fundamental. Com cada nova descoberta e desenvolvimento, nós criávamos um senso mais aprofundado das limitações gerais do sistema e sua capacidade de se adaptar aos requisitos de escalabilidade.
Ao longo do tempo, ficou claro que o Mattermost era o mais capaz de ser amadurecido na escala da Uber, e nós havíamos adquirido confiança na plataforma. Para ajudar os outros a criarem suas próprias plataformas de bate papo utilizando nosso novo parceiro de desenvolvimento, nós contribuímos com a comunidade open source disponibilizando nossos testes de carga.
Gerenciando a arquitetura do uChat com o Puppet
Enquanto realizávamos os testes de carga com a plataforma Mattermost, nós precisávamos realizar mudanças constantes e confiáveis na infraestrutura da nossa nova solução e nas configurações da aplicação. O modo de alta disponibilidade do Mattermost ainda estava na versão beta, então com frequência encontrávamos defeitos a serem corrigidos em nosso código.
Durante o início dos testes e os primeiros estágios de desenvolvimento, a equipe de infraestrutura da Uber realizava essas alterações manualmente. Estabilizar as novas versões do uChat e as configurações dos servidores era um processo entediante e susceptível a erros, exigindo mudanças frequentes para corrigir erros não intencionais de configuração. Quando ficou claro que a administração manual da infraestrutura estava nos atrasando, nós mudamos para o Puppet.
Codificar a arquitetura e configurações de servidores com o Puppet nos propiciou uma fundação sólida para o gerenciamento dos vários servidores e ambientes de rede necessários para suportar as rápidas melhorias do uChat. O Puppet nos propiciou alterações consistentes e repetitivas nas máquinas em nossa topologia de banco de dados e nos permitiu reforçar as revisões dos códigos para instalação.
A introdução inicial do Puppet reduziu muito os erros não intencionais durante as instalações. No entanto, mesmo com a infraestrutura como código básica do Puppet solucionando um pouco da repetitividade e consistência dos nossos problemas, ainda não tínhamos atingido a velocidade que precisávamos. Nesse ponto, não estávamos utilizando servidores invariáveis, o que significava que mudanças no código do Puppet para atingir nossa arquitetura de alta disponibilidade trazia riscos consideráveis de efeitos colaterais. Além disso, estávamos utilizando um grande e único repositório para onde todas as informações do Puppet deveriam convergir, aumentando as complicações.
Essa restrição significava que não poderíamos aplicar novas infraestruturas e novas versões do aplicativo com a velocidade que precisávamos, limitando severamente nossas taxas de iteração. Como resultado, a atualização das configurações de implantação do Puppet pode levar um dia ou dois para ser finalizada com segurança. Nesse período, melhorias não relacionadas com a performance do uChat eram enviadas de hora em hora. Nosso novo fluxo baseado no Puppet estava melhor, mas ainda existiam possibilidades de melhorias.
Para aumentar a velocidade de implantação do uChat, nós transferimos nossa infraestrutura como código para um repositório separado como um módulo do Puppet. Isso nos permitiria isolar, criar versões e testar independentemente mudanças de configurações específicas da aplicação uChat, independentemente das configurações do nosso servidor de infraestrutura.
Após nosso novo módulo Puppet ser refatorado e completamente testado, nós confiamos no Gerenciador de Códigos do Puppet para promover as mudanças de infraestrutura nos recentemente criados ambientes de testes e produção.
Essa abordagem baseada em módulos nos permitiu separar as preocupações com as configurações da aplicação das preocupações com as configurações de servidor e infraestrutura, distribuindo mais facilmente as alterações baseando-se nas necessidades e linha do tempo de lançamento do próprio uChat.
Com os módulos do Puppet, o Gerenciador de Códigos do Puppet e o suporte para as implantações A/B, nós finalmente atingimos o controle rápido e consistente de implantações que precisávamos. Agora, a criação de nossos ambientes de testes e de produção poderia ser realizada confiavelmente em menos de um dia.
Criando uma experiência de usuário perfeita
Paralelamente ao amadurecimento de nossa infraestrutura, nós também tínhamos que criar um conjunto de aplicações intuitivas, para web, desktop e aparelhos móveis. Para nos dar uma vantagem, nós dividimos as aplicações desktop do Mattermost e começamos uma rotulação direta dos nossos clientes internos. Os aplicativos móveis do Mattermost, por outro lado, precisavam de uma reestruturação completa para atingir o tipo de experiencia de usuário que estávamos buscando.
As aplicações originais uChat para iOs e Android incorporavam um webview simples para carregar a página completa do uChat, causando um carregamento extremamente lento. Adicionalmente, os webviews causavam atualizações desnecessárias das páginas, downloads incompletos dos arquivos e experiências irregulares. Para aumentar nossa equipe e acelerar o desenvolvimento, nós fizemos uma parceria com a Fullstack Labs para reescrever essas aplicações nativas em React e, conforme fizemos com nossa plataforma em Mattermost, contribuímos com tudo o que foi construído para a comunidade open source.
Atualmente, os clientes uChat móveis são implantados através da nossa loja interna de aplicativos, e os clientes desktop são gerenciados via Chef e Sistema Central de Gerenciamento de Configurações. Tanto para limitar a quantidade de versões do aplicativo móvel uChat em utilização quanto para simplificar o suporte, nós criamos mecanismos personalizados dentro do iOs e do Android que pedem ao usuário que atualize o aplicativo quando uma nova versão estiver disponível. Nós também criamos a possibilidade de invalidar versões antigas para o caso de precisarmos forçar uma atualização.
Nossa visão extensível para a plataforma garantiu que nós fornecêssemos um UX integrado com outras ferramentas em nosso ecossistema. Para realizar isso, gastamos vários meses transicionando de mais de 50 integrações legadas da nossa solução anterior para uChat. As APIs e webhooks permitiram que os serviços internos existentes integrassem e ampliassem os recursos do bate-papo além de conversas individuais, como o sistema de implantação interna da Uber, o uDeploy, que notifica os engenheiros quando uma nova compilação é concluída ou o Envoy, que é compatível com o nosso ofice visitor registration service.
Construindo a confiança dos usuários
Quando implementamos qualquer aplicação empresarial, motivas sua adoção e a mudança de comportamentos existentes pode ser desafiador. Ao mudar a empresa para uma ferramenta criada “em casa” como o uChat, um cuidado extra era necessário para criar a confiança de que o uChat seria mais confiável do que a plataforma de mensagens atual. Para estabelecer essa confiança e realizar a transição para o uChat da maneira mais tranquila possível, nós criamos previamente as contas de todos os colaboradores e migramos aproximadamente 20,000 salas de bate papo para que os colaboradores não precisassem recriar ou entrarem novamente nas salas das quais eles participavam previamente.
Apesar dos nossos grandes esforços, houveram pedras no caminho. Conforme integrávamos mais e mais colaboradores ao uChat, quedas intermitentes fizeram alguns dos primeiros usuários ficarem relutantes em adotar completamente o uChat. Para atenuar as preocupações, nós mantivemos nosso sistema de mensagens legado ativo enquanto estabilizávamos o uChat e ele tinha mais tempo para se estabelecer.
Para agradar ainda mais os colaboradores em relação ao uChat, nós aumentamos a transparência. Nós avisávamos sobre os erros conforme eles eram descobertos, comunicávamos os planos de correção e implementávamos os pacotes de correção. Nós também disponibilizamos os gráficos de disponibilidade para que todos os interessados pudessem verificar a saúde do uChat em tempo real.
Quando pudemos consistentemente demonstrar um percentual de disponibilidade de 99,9% com o uChat, nós desativamos nosso sistema legado. A desativação total foi atingida desabilitando aos poucos algumas funcionalidades como a criação de novas salas e integrações, até nós tirarmos o sistema legado da tomada completamente. Nós anunciávamos regularmente atualizações de produto, compartilhávamos dicas, e adicionávamos recursos como FAQs e guias de usuário, para garantir que os colaboradores se sentissem completamente suportados. Nós também criamos um canal de feedback onde os colaboradores poderiam receber assistência imediata e sugerir novas funcionalidades.
Uma lição importante aprendida durante nossa experiencia foi que o nível de alinhamento organizacional necessário para desativar uma aplicação de mensagens exigia muito mais aceitação e coordenação com nossos usuários do que nos prevíamos inicialmente. Mas mantendo a transparência, acessibilidade, e entrega rápida das melhorias, nós estabelecemos uma base de boa sintonia com os primeiros usuários, que, ao longo do tempo, foi transmitida para toda a empresa.
O Futuro do uChat
Nos próximos meses, pretendemos implementar mais funcionalidades, continuar monitorando o feedback dos usuários e incorporar melhorias adicionais oferecidas pela Mattermost Inc e sua comunidade open source.
O uChat é apenas uma das soluções que nossa equipe construiu para estimular a colaboração, comunicação e produtividade na Uber. Estamos constantemente desenvolvendo, implantando e mantendo o kit de ferramentas “caseiras” da Uber, economizando para a empresa milhões anualmente em produtividade e licenças de softwares. Se o desenvolvimento de ferramentas internas de última geração para uma empresa em rápido desenvolvimento global, como a Uber, parece interessante para você, pense em se candidatar a uma vaga nas equipes de ferramentas de produtividade da Uber.
***
Este artigo é do Uber Engineering. Ele foi escrito por Marissa Alvarado-Lima, Stanley Chan, Chris Duarte e Ed Wolf. A tradução foi feita pela Redação iMasters com autorização. Você pode conferir o original em: https://eng.uber.com/uchat/