Illustration of a bird flying.

Aplicações multi-tenant


Tenho uma plataforma incrível e quero replicar para diversos clientes, qual é o melhor caminho? Existem diversas formas de replicar sua aplicação para que diversos clientes utilizem. Aqui falarei de uma que se tornou comum aqui na empresa nos últimos tempos, a multi-tenant.

O que é multi-tenant

Em desenvolvimento de software utilizamos o termo multi-tenant para definir uma aplicação que atende à diversos grupos de usuários com apenas uma base de código. Em outras palavras você tem apenas uma instância de sua aplicação respondendo à diversos clientes, cada qual com suas configurações e eventuais customizações.

O maior exemplo de multi-tenant que você com toda certeza usa todos os dias é o Stack Overflow. Todas as soluções rodam sob a mesma aplicação, diferindo apenas conforme o domínio que o usuário acessa e alguns headers. Neste podcast do Hipsters Ponto Tech, por volta dos 17 minutos tem mais detalhes sobre como tudo funciona por lá. São cerca de 150 sites rodando em multi-tenant, ou seja, é um método que de fato funciona.

Veja nas ilustrações a seguir as diferenças entre single-tenant e multitenant.

Esquema single-tenant

Em uma aplicação single-tenant comumente cada cliente utiliza uma base de código e sua própria base de dados. Desta forma sempre que um novo cliente chegar você terá de replicar sua aplicação base, configurar layout, acessos à banco de dados, esquema de deploy, etc.

Esquema multi-tenant com base única

Em uma aplicação multi-tenant comumente os clientes utilizam a mesma aplicação com a mesma base de dados. Desta forma a implantação de um novo cliente, manutenção e atualização é unificada, tornando o trabalho mais simples.

Esquema multi-tenant com múltiplas bases

Neste cenário além de visual distinto para cada cliente a base de dados é exclusiva.

Como é criado?

Normalmente quando pensamos em um aplicação multi-tenant temos que prever cenários que servirão de ponto de entrada para que consigamos identificar qual versão da aplicação temos de rodar. No caso já mencionado do Stack Overflow utiliza-se o endereço da URL e alguns headers. Basicamente com isso você já consegue ter sucesso. Veja um exemplo.

A aplicação base está no endereço meusupersistema.com.br. Para cada cliente eu crio uma base de dados e um subdomínio: cliente1.meusupersistema.com.br e cliente2.meusupersistema.com.br. Além disso, cada cliente possui seu próprio layout customizado. Note que apresentei 3 endereços, cada qual com seu layout mas ao fundo o que está rodando para ambas as situações é um único sistema.

Podemos ainda ter necessidades diferentes como uma aplicação que rode via linha de comando por exemplo. Para uma situação semelhante sugiro que sejam informados parâmetros ao rodar o comando. Assim, com base no parâmetro de entrada, é possível identificar como a aplicação responderá. Veja o exemplo abaixo.

php index.php cliente1
php index.php cliente2

Após o comando a ser rodado (php index.php) informo qual cliente quero que a aplicação rode (cliente1 e cliente2). Desta forma minha aplicação teria de pegar a informação do cliente como no abaixo:

O primeiro parâmetro ($argv[0]) é o index.php e o segundo ($argv[1]) é o cliente.

Uma segunda abordagem para informar o cliente é definir um parâmetro para ser obtido através da global $_SERVER:

 

E pra pegar essa informação em nosso código, seria algo como isso:

Na prática

Feito isso basta carregar arquivos de layout e/ou css conforme o cliente bem como em uma possível lista de configurações de banco de dados, obter a correspondente ao cliente que está em execução.

Existem situações que a aplicação mesmo sendo multi-tenant utilizará somente um banco dados. Assim como em determinadas situações, cada tenant, ou seja, cada versão da aplicação se conectará com diversos bancos de dados. Já desenvolvemos de ambas as formas e vou contar um pouco da experiência nas próximas seções.

Case 1: Multi-tenant com múltiplas bases

No case do aplicativo Dimmi, o multi-tenant está em tudo: Endereço, visual, banco de dados, integrações e funcionalidades distintas. Em 2015 iniciamos o desenvolvimento em parceria com a FourItil tecnologia, onde eu fui gerente de desenvolvimento. Naquela época ainda nem se tinha noção de que precisaríamos de uma solução multi-tenant. Isso só veio à tona no final de 2016 quando a implantação começou a custar muito para a startup. Com isso viabilizei – na época sem muito saber sobre o assunto – uma saída que a implantação de um novo cliente passasse de 3 dias para apenas uma tarde.

Foi o primeiro case de multi-tenant. Após ter moldado muitas funcionalidades para um cliente, os próximos foram as deixando de usar. Estas funcionalidades eram integrações com CRM e ERP de uma grande concessionária de veículos de Curitiba. O problema é que tais integrações somente faziam sentido para aquele grupo. Assim que a primeira concessionária de motos se tornou cliente da startup, tais integrações tiveram simplesmente de ser removidas. Aí já tínhamos a distinção do endereço, do banco de dados, do layout e por fim de funcionalidades.

Quando outras concessionárias tornaram-se clientes da startup foi a mesma coisa, algumas integrações a menos, outras a mais e, mesmo sendo a mesma base de código, no mesmo servidor, a aplicação já atendia mais de 5 concessionárias com bases únicas e algumas funcionalidades distintas entre ambas.

Vantagens e desvantagens

Tivemos uma redução significativa no tempo de implantação, passando de cerca de 3 dias para uma tarde. Também conseguimos aumentar a maturidade da equipe por trabalhar com mais este nível de complexidade. E por fim, o fator mais importante para a startup: conseguimos reduzir os custos com cloud. No modelo anterior – single-tenant – cada cliente ocupava um server, isso gerava além de custo com o mesmo, maior empenho nos deploys, manutenções e monitoramento.

Com multi-tenant nossa equipe preocupou-se em ter apenas uma configuração de CI e de sempre pensar de forma simples. Qualquer funcionalidade complexa de um cliente estava atrelado exclusivamente ao seu stack da aplicação.

Mas houveram desvantagens, como sempre. Nada é 100%. O maior problema que tivemos foi com instabilidade e algumas vezes indisponibilidade da aplicação. Como estamos falando de multi-tenant, a aplicação parada significa todos os clientes parados. No mais foram mais vantagens.

 

Case 2: Multi-tenant com base única

O novo portal de seminovos do Grupo Marajó necessitou uma aplicação multi-tenant porque é algo muito simples. O portal apenas sincroniza o estoque com a plataforma de seminovos que o grupo usa, o Folhacar. No folhacar as concessionárias do grupo gerenciam todo o estoque de seminovos em suas 5 lojas distribuídas entre as marcas Fiat, Jeep e Citroën.

Para cada marca foi criado um layout, sendo 4 no total: Multimarcas, Fiat, Jeep e Citroën. Para este caso foi utilizada a distinção pela URL para saber qual aplicação rodar. Além do visual distinto o estoque também respeita cada uma das marcas, bem como o formulário de contato é específico para a marca correspondente. Veja mais detalhes no portfolio.

A base de dados é a mesma, o painel de gerenciamento também. O que difere é o estoque, o encaminhamento dos contatos e o layout.

Vantagens e desvantagens

As vantagens foram medidas novamente em simplicidade na implantação, unificação do painel administrativo e possibilidade de sincronização automática do estoque.

Nas desvantagens novamente entra a questão de se um dia o server estiver instável ou indisponível todos os sites ficarem fora do ar.

 

Case 3: Single tentant – multiplas bases e multi mapeamento

Este case na verdade nem se encaixa como multi-tenant, mesmo assim decidi listar porque possui uma característica um tanto interessante. A aplicação é uma só, que roda via linha de comando, conecta em 6 bases de dados e possui mapeamentos distintos para o mesmo fim.

O cliente novamente é o Grupo Marajó e falo de um projeto que ainda está em andamento, em vias de finalização. O grupo criou um e-commerce para venda de peças e acessórios de todas suas marcas: Fiat, Jeep e Citroën. Este e-commerce é uma plataforma chamada MKX com sede na mesma região de atuação: Maringá e Londrina – PR. A intenção é que o Agente MKX (como batizei o projeto) leia todas as bases do ERP das concessionárias, processe os itens que se repetem para agregar o estoque final e envie para a plataforma MKX para finalização do tratamento por parte da equipe de e-commerce do Grupo Marajó. Esta equipe cuidará dos detalhes como fotos, categorização e descrição mais chamativa para vendas.

No total são 6 bases de dados: 2 da Fiat, 2 da Citroën, 1 da Jeep e a base local do Agente MKX para realizar o correto tratamento dos estoques. Como exemplo pegamos um item chamado Kit do Uno 1.0. Ele tem 5 em estoque na unidade matriz da Fiat e 8 na filial, ambos respondendo pela mesma referência. Ao ler os dados da Fiat matriz o produto é persistido na base local com sua quantidade respectiva. Ao conectar e ler a base da Fiat filial o estoque é agregado. Finalizada leitura das 5 bases de dados os produtos estão prontos para a sincronização com o e-commerce.

Depois de tudo processado

Um segundo job é executado para enviar os produtos previamente processados à plataforma de e-commerce. Este job faz o cálculo do estoque total de cada produto e o envia para o e-commerce.

Outro ponto interessante é que o modelo de produto que a plataforma de e-commerce recebe é universal no entanto o ERP de cada marca (Fiat, Jeep e Citroën) possui tabelas distintas para representar seus produtos. Isso fez com que fossem criadas diversas entidades do Doctrine ORM. Os registros são lidos no banco de dados correspondente, transformados em um Produto da base local e por sua vez em um ProdutoMKX para o envio à loja.

Neste caso em específico não foram necessários parâmetros explícitos porque todas as bases são lidas na sequência. No entanto foram necessárias as 6 configurações do banco de dados. No momento do parse a conexão do Doctrine é sobrescrita temporariamente por cada uma das 5 configurações das concessionárias. Conforme a conexão no loop, são chamadas as entidades correspondentes, passando por um data binding e gerando um Produto da base local. Quando o processo termina lança o gatilho para que os recém atualizados produtos da base local sejam criados ou atualizados na loja MKX.

Vantagens e desvantagens

Unificação da sincronização. 3 marcas com 5 bases de dados e um mix de cerca de 20 mil produtos aptos à estarem na plataforma de e-commerce são sincronizados num curto período de tempo.

Ainda não encontrei desvantagem neste case. Isso porque ainda está em processo de finalização e até o momento tudo vem correndo bem. O item mais difícil até o momento foi conectar com bases SQL Server em um servidor Linux Debian, no mais, mais um projeto desafiador.

 

Quais as principais vantagens da arquitetura Multi-tenant?

Simplicidade na manutenção: Uma vez que todos os clientes rodam sobre a mesma base você precisa se preocupar com dados de acesso de somente um server, configuração de somente um deploy e report de erros unificado.

Redução de custos: Ao invés de se ter diversas instâncias consumindo recursos, pode-se ter apenas uma em uma estrutura mais robusta e ainda assim com menor custo.

Evolução e segurança: Sempre que algo novo ou correção vai para produção todos os clientes se beneficiam. Em uma aplicação single-tenant o deploy teria de ser feito para cada uma das instâncias rodando.

 

Concluindo

A intenção deste artigo não é passar detalhes a fundo da parte de programação, mas sim explicar o que é multi-tenant, em que situações se aplicam e mostrar alguns cases em que a técnica foi bem empregada.

Em um futuro artigo pretendo expor mais detalhes, quem sabe até criando um exemplo de aplicação multi-tenant para que você consiga ver como na prática não é um bicho de sete cabeças. Obviamente que para quem nunca criou algo assim é uma situação um tanto complexa, mas depois de feito você percebe que não só o resulltado é simples, mas também a implementação.