O multi-tenancy é uma evolução natural para boa parte das aplicações. Startups e seus produtos precisam dele para seu modelo SaaS, empresas e seus sistemas o querem para o reuso de código. Essa palestra irá mostrar técnicas e modelos para a aplicação de multi-tenancy, e erros comuns no processo.
2. Sobre o palestrante
Co-fundador e CTO da LQDI Digital
Projetos para empresas como Porto Seguro, Nestlé,
Ticket, Editora FTD, Tishman Speyer e Ambev
13 anos trabalhando com PHP
Desde a época que o PHPClasses era a onda :)
Aryel Tupinambá
3. Single tenant
Um único "cliente" para a
aplicação
Forma tradicional, instalada
no servidor do cliente
Faz sentido quando a
aplicação é um PROJETO
4. Agora com mais um cliente… e
mais outro...
Seu PROJETO se tornou um PRODUTO
Diversos clientes usando a mesma
aplicação
Estruturas separadas para cada novo
cliente
Nada é compartilhado; tudo é isolado
5. E agora, como faço...
… atualizações de segurança?
… correção de bugs?
… features novas para todo mundo?
E o espaço que toda essa galera ocupa?
E o custo que tudo isso gera?
6. Arquitetura multi-tenant
Tenant = inquilino
Uma única aplicação para vários clientes
Uma estrutura comum entre os clientes
As benfeitorias servem para todos
A customização de um cliente não
interfere nos demais, nem previne que ele
utilize da estrutura comum
7. Principais desafios
Como segmentar a
base de dados para
cada cliente?
Como segmentar os
arquivos enviados?
Como fica o código
fonte da aplicação?
Como ficam as
customizações?
Como lidamos com
updates e novas
features?
Como podemos
customizar as
funcionalidades da
aplicação?
Como permitir que
atualizações e novas
features não sejam
impedidas por
customizações?
DATA STORAGE CODEBASE CUSTOMIZAÇÃO
8. Não existe escolha certa ou errada!
O que existe são escolhas que fazem mais sentido para determinados cenários.
10. Três formatos mais comuns
Data storage
Instâncias separadas
Bancos de dados separadas
Banco de dados compartilhado
Cada cliente possui uma instância do seu SGDB (MySQL,
Postgres, Mongo, etc), com seus dados isolados.
Mais isolado
Mais compartilhado
Cada cliente tem um banco de dados (ou schema)
diferente, na mesma instância
Todos os clientes estão na mesma base de dados; o cliente
é identificado por meio de uma coluna nas tabelas
(tenantID)
Referência / diagramas: Microsoft - https://msdn.microsoft.com/en-us/library/aa479086.aspx
11. Data storage
Instâncias separadas
Bancos de dados separadas
Banco de dados compartilhado
Mais isolado
Mais compartilhado
Todos os clientes estão na mesma base de dados; o cliente
é identificado por meio de uma coluna nas tabelas
(tenantID)
Referência / diagramas: Microsoft - https://msdn.microsoft.com/en-us/library/aa479086.aspx
12. Data storage
Instâncias separadas
Bancos de dados separadas
Banco de dados compartilhado
Mais isolado
Mais compartilhado
Cada cliente tem um banco de dados (ou schema)
diferente, na mesma instância
Referência / diagramas: Microsoft - https://msdn.microsoft.com/en-us/library/aa479086.aspx
13. Data storage
Instâncias separadas
Bancos de dados separadas
Banco de dados compartilhado
Mais isolado
Mais compartilhado
Cada cliente possui uma instância do seu SGDB (MySQL,
Postgres, Mongo, etc), com seus dados isolados.
Referência / diagramas: Microsoft - https://msdn.microsoft.com/en-us/library/aa479086.aspx
16. Data storage
Instâncias separadas
Bancos de dados separadas
Banco de dados compartilhado
Sugestão de uso:
- Aplicações com pouca ou nenhuma
variabilidade / customização
- Aplicações em que a principal
customização é visual
- Aplicações com alto número de usuários
(500k+)
Mais isolado
Mais compartilhado
17. Data storage
Sugestão de uso:
- Aplicações em que deve haver maior
flexibilidade para customização
- Aplicações em que a infra-estrutura
sempre será responsabilidade sua
- Planos baseados em volume de consumo
ou performance
Instâncias separadas
Bancos de dados separadas
Banco de dados compartilhado
Mais isolado
Mais compartilhado
18. Data storage
Sugestão de uso:
- Projetos em que a separação física do hardware se
faz necessária (instalações on-premises, compliance
corporativo ou governamental, decisões de
performance);
- Alta disparidade no volume de dados ou de acessos
entre clientes (quando alguns clientes consomem
demais)
- Quando você precisa monitorar o consumo
individual de hardware para cada cliente (e seu SGDB
não faz isso por database/schema)
Instâncias separadas
Bancos de dados separadas
Banco de dados compartilhado
Mais isolado
Mais compartilhado
19. - Em regra geral, a FLEXIBILIDADE necessária deve ser o fator decisório
- Customizar funcionalidades pode ser um desafio quando você tem um modelo
de dados fixo
- Use o pattern de "migrations" e "seeds" para criar e manter o database schema
- Você não necessariamente precisa escolhar um único modelo para todos os
dados da aplicação
Data storage
25. Codebase
- Dois cenários: uma instância para todos, ou uma instância por tenant
app cliente1.app.com
código fonte
cliente2.app.com
cliente3.app.com
config 1
config 2
config 3
cliente1.app.com
código fonte
config 1
cliente2.app.com
código fonte
config 2
cliente3.app.com
código fonte
config 3
custom code
Uma instância para todos
Uma instância por cliente
26. Codebase
- Uma instância para todos
- Atualizações são sincronizadas sem custo ou esforço
- Nenhum ou pouquíssimo "housekeeping" necessário
- Não é muito flexível para customizações
- Mais fácil de escalar quando o padrão de consumo de todos os clientes é semelhante
app
código fonte
cliente1.app.com
cliente2.app.com
bigcorp.app.com
config 1
config 2
config 3
27. Codebase
- Uma instância para todos
- Atualizações são sincronizadas sem custo ou esforço
- Nenhum ou pouquíssimo "housekeeping" necessário
- Não é muito flexível para customizações
- Mais fácil de escalar quando o padrão de consumo de todos os clientes é semelhante
app
código fonte
cliente1.app.com
cliente2.app.com
bigcorp.app.com
config 1
config 2
config 3
Nginx sitesvia DB, cachedGit repository
28. Codebase
- Uma instância por cliente
- Atualizações não são sincronizadas, exceto se automatizadas
- Necessário um trabalho de "housekeeping" para manutenção das instâncias
- Bastante flexível para customizações
- Qualquer cliente pode ter sua versão da aplicação "congelada"
- O código do próprio "core" da aplicação pode ser forkado e alterado a qualquer momento
(se em algum momento isso fizer sentido para o negócio)
bigcorp.app.com
código fonte
config 1
cliente1.app.com
código fonte
config 2
cliente2.app.com
código fonte
config 3
custom code
29. Codebase
- Uma instância por cliente
- Atualizações não são sincronizadas, exceto se automatizadas
- Necessário um trabalho de "housekeeping" para manutenção das instâncias
- Bastante flexível para customizações
- Qualquer cliente pode ter sua versão da aplicação "congelada"
- O código do próprio "core" da aplicação pode ser forkado e alterado a qualquer momento
(se em algum momento isso fizer sentido para o negócio)
bigcorp.app.com
código fonte
config 1
cliente1.app.com
código fonte
config 2
cliente2.app.com
código fonte
config 3
custom code
Git repo
.env files
30. Codebase
- Uma instância por cliente
- Atualizações não são sincronizadas, exceto se automatizadas
- Necessário um trabalho de "housekeeping" para manutenção das instâncias
- Bastante flexível para customizações
- Qualquer cliente pode ter sua versão da aplicação "congelada"
- O código do próprio "core" da aplicação pode ser forkado e alterado a qualquer momento
(se em algum momento isso fizer sentido para o negócio)
bigcorp.app.com
código fonte
config 1
cliente1.app.com
código fonte
config 2
cliente2.app.com
código fonte
config 3
custom code
Nginx sites + PHP-FPM pools
v1.4.0 v1.4.1 v1.4.0
31. Codebase
- De novo, o maior fator decisório aqui deve ser a FLEXIBILIDADE: o
quanto você espera que o código da aplicação se altere com
customizações de clientes?
- A escalabilidade, embora seja um desafio (e mereceria uma palestra a
parte), não deve ser dificultada em nenhum dos cenários, DESDE QUE
você automatize todos os processos e fique de olho na consistência
- Instâncias isoladas permitem que você escale clientes mais
"barulhentos" (alto volume) para hardware melhor
33. Variabilidade e customização
- O calcanhar de aquiles da arquitetura multi-tenant
- Requer bastante meditação sobre os requisitos
- Aqui é um dos melhores lugares onde design
patterns e uma arquitetura sã e consistente brilham
de verdade
- Vou falar sobre algumas técnicas e formatos
interessantes
34. Variabilidade e customização
Para configuração:
Para instâncias de código isoladas: um
arquivo de configuração (biblioteca DotEnv)
Para instâncias unificadas: parâmetros de
configuração no banco/repositório de tenant
data
.env
35. Variabilidade e customização
Para o data storage:
Migrations: funcionam como um controle de
versão do seu modelo de dados
A maioria dos frameworks/ORMs possuem
suporte built-in (Laravel, CakePHP, Doctrine), e há
libs standalone para outros formatos.
Sempre criar migrations "reversíveis", ou seja, que
possam sofrer rollback
36. Variabilidade e customização
Para o código / funcionalidade: EVENTS
Transação de negócio
(ex: novo pedido realizado)
Gerenciador de eventos
(via Framework, biblioteca
ou hand-made)
Sub-serviços do core app
Módulo customizado: NF-E
Envio de
e-mail para
o usuário
Registro no log
de atividade do
usuário
Geração de NF-E
Módulo customizado: Tracking
Registrar nova carga à entregar
dispatchEvent('order_created', $order);
37. Variabilidade e customização
Para o código / funcionalidade: EVENTS
Transação de negócio
(ex: novo pedido realizado)
Gerenciador de eventos
(via Framework, biblioteca
ou hand-made)
Sub-serviços do core app
Módulo customizado: NF-E
Envio de
e-mail para
o usuário
Registro no log
de atividade do
usuário
Geração de NF-E
Módulo customizado: Tracking
Registrar nova carga à entregar
dispatchEvent('order_created', $order);
CORE APP
CUSTOM CODE
38. return [
['Entregas','abc.delivery.index'],
['Configurar Frete','abc.delivery.config']
];
Variabilidade e customização
Renderizar menu
principal
Gerenciador de hookstriggerHook('render_menu');
return [['Pedidos','core.orders.index']];
return [['Estoque','core.inventory.index']];
Módulos do core app
Módulo de Pedidos
Módulo de Estoque
Custom code do cliente ABC
Módulo de Entregas
return [...];
Para o código / funcionalidade: HOOKS
43. Variabilidade e customização
Para o front-end / interface: SASS / Pré-compiladores
O PHP pode gerar seu config, e rodar o build
durante a atualização de um tenant
48. Variabilidade e customização
Automatize (se aplicável) o processo de provisionamento para novos clientes
Novo cliente cadastrado
Script / microservice de
PROVISIONAMENTO
Criar pasta no servidor e site no Nginx
Criar banco de dados
Gerar .env de configuração
Criar registro no DB de tenants
Cadastrar no Envoyer e realizar primeiro deploy
Gerar composer.json com Core + Custom code
Disparar e-mail para o cliente
Gerar config do Sass e compilar CSS final
Para infra-estrutura / deploy...
49. Variabilidade e customização
Automatize (se aplicável) o processo de provisionamento para novos clientes
Novo cliente cadastrado
Script / microservice de
PROVISIONAMENTO
Criar pasta no servidor e site no Nginx
Criar banco de dados
Gerar .env de configuração
Criar registro no DB de tenants
Cadastrar no Envoyer e realizar primeiro deploy
Gerar composer.json com Core + Custom code
Disparar e-mail para o cliente
Gerar config do Sass e compilar CSS final
Para infra-estrutura / deploy...
50. Variabilidade e customização
O custo e tempo para provisionamento interfere diretamente em um
KPI de negócio, o CAC (Custo de Aquisição de Cliente)
Provavelmente toda sua infra-estrutura pode ser administrada via API;
use isso a seu favor:
- Amazon EC2 e DigitalOcean tem APIs para provisionamento de
servidores
- Amazon S3 e Rackspace Cloud tem APIs para criação de novos
"buckets" de arquivos
- Amazon Route 51 e DigitalOcean tem APIs para gerenciar o DNS
(domínios customizáveis)
Para infra-estrutura / deploy...
51. TL;DR
Oriente sua arquitetura principalmente pela sua
necessidade de flexibilidade e customização
Mais customizável ➜ mais isolada
Mais uniforme ➜ mais compartilhada
Use as melhores práticas de SOLID, principalmente no
que diz respeito a Inversão de Dependência; a
arquitetura multitenant é provavelmente o melhor
use-case de substituição de implementações de uma
interface em runtime
52. TL;DR
Automatize TUDO que diz respeito a provisionamento,
deploy e housekeeping de infraestrutura: manutenção
manual de instâncias é uma eterna dívida técnica que
se acumula
TDD é PRIMORDIAL; lembre-se que em um ambiente
sincronizado, uma atualização impacta TODOS os seus
clientes