O problema com o sharding é que o aplicativo precisa saber qual shard consultar. Geralmente, isso é feito dividindo algo como o cliente. Vou adaptar um dos meus posts antigos para usar como resposta.
Ao criar um aplicativo para muitos clientes, há duas maneiras comuns de criar o (s) banco (s) de dados:
- Opção A: Coloque todos os clientes no mesmo banco de dados
- Opção 2: criar um banco de dados por cliente
Colocando todos os clientes no mesmo banco de dados
É simples: basta adicionar uma tabela Client na parte superior do esquema, adicionar uma tabela ClientUsers para garantir que as pessoas apenas vejam seus próprios dados e lá vamos nós.
Benefícios desta abordagem:
Gerenciamento de esquema mais fácil. Quando os desenvolvedores implantam uma nova versão do aplicativo, eles apenas precisam fazer alterações de esquema em um banco de dados. Não há preocupações sobre diferentes clientes estarem fora de sincronia ou na versão errada.
Ajuste de desempenho mais fácil. Podemos verificar o uso e as estatísticas do índice em um único local, implementar melhorias facilmente e ver os efeitos imediatamente em todos os nossos clientes. Com centenas ou milhares de bancos de dados, até a menor alteração pode ser difícil de coordenar. Podemos verificar o conteúdo do cache do procedimento e saber com certeza quais consultas ou procedimentos armazenados são mais intensivos em todo o aplicativo, enquanto que, se estivermos usando bancos de dados separados por cliente, podemos ter um tempo de agregação de consulta mais difícil em diferentes planos de execução.
Mais fácil de criar uma API externa. Se precisarmos conceder acesso a todo o banco de dados para que terceiros construam produtos, isso será mais fácil se todos os dados estiverem em um único banco de dados. Se a API precisar lidar com o agrupamento de dados de vários bancos de dados em vários servidores, ela adicionará tempo de desenvolvimento e teste. (Por outro lado, essa coisa de “vários servidores” começa a sugerir uma restrição para o cenário de um banco de dados para governar todos: um banco de dados geralmente significa que toda a nossa carga afeta apenas um servidor de banco de dados.) No seu caso , com o PowerBI, ter todos em um banco de dados facilitará muito o gerenciamento de conexões.
Alta disponibilidade e recuperação de desastres mais fáceis. É muito, muito simples gerenciar o espelhamento de banco de dados, o envio de logs, a replicação e o cluster, se tudo o que precisamos nos preocupar é apenas um banco de dados. Podemos construir uma grande quantidade de infraestrutura rapidamente.
Colocando cada cliente em seu próprio banco de dados ou fragmento
Você ainda precisa de uma lista de clientes, mas agora ela se torna um diretório - para cada cliente, você também rastreia o fragmento em que vive. Na inicialização, seu aplicativo consulta essa tabela e a armazena em cache na RAM. Quando precisa de dados para um cliente, ele se conecta diretamente a esse fragmento (banco de dados e servidor).
Benefícios desta abordagem:
Restauração de cliente único mais fácil. Os clientes são sacos de carne não confiáveis. (Exceto os meus - são sacos de carne confiáveis.) Eles têm todos os tipos de momentos em que desejam recuperar todos os seus dados de volta a um ponto no tempo, e isso é uma grande dor na retaguarda se os dados forem misturados com outros dados do cliente nas mesmas tabelas. As restaurações em um cenário de banco de dados de cliente único são fáceis de matar: basta restaurar o banco de dados do cliente. Ninguém mais é afetado.
Exportação de dados mais fácil. Os clientes adoram colocar as mãos em seus dados. Eles querem a segurança de saber que podem obter seus dados a qualquer momento, evitando o temido cenário de dependência de fornecedores e desejam fazer seus próprios relatórios. Com os dados de cada cliente isolados em seu próprio banco de dados, podemos simplesmente fornecer uma cópia do backup de seu próprio banco de dados. Não precisamos criar APIs de exportação de dados.
Escalabilidade multi-servidor mais fácil. Quando nosso aplicativo precisa de mais energia do que podemos obter em um único servidor, podemos dividir os bancos de dados entre vários servidores. Também podemos distribuir a carga geograficamente, colocando os servidores na Ásia ou na Europa mais próximos dos clientes.
Ajuste de desempenho mais fácil por cliente. Se alguns clientes usam recursos ou relatórios diferentes, podemos criar um conjunto especializado de índices ou visualizações indexadas apenas para esses clientes, sem aumentar o tamanho dos dados de todos. Concedido, há algum risco aqui - ao permitir diferenças de esquema entre clientes, acabamos de tornar nossas implantações de código um pouco mais arriscadas e nosso gerenciamento de desempenho mais difícil.
Gerenciamento de segurança mais fácil. Desde que tenhamos bloqueado adequadamente a segurança com um usuário por banco de dados, não precisamos nos preocupar com o acesso do Cliente X aos dados do Cliente Y. No entanto, se apenas usarmos um único login para todos, não abordaremos realmente essa preocupação.
Janelas de manutenção mais fáceis. Em um ambiente global em que os clientes estão espalhados pelo mundo, é mais fácil colocar os clientes offline para manutenção, se pudermos fazê-lo em grupos ou zonas.
Qual é a certa para você?
Não há uma escolha certa: você precisa conhecer os pontos fortes e fracos da sua própria empresa. Vamos dar dois de meus clientes como exemplos.
A empresa A se destaca no ajuste de desempenho de hardware. Eles são realmente muito bons em extrair o último pedaço de desempenho do hardware e não se importam em substituir o hardware do SQL Server em um ciclo de 12 a 18 meses. (Eles atualizam os servidores da Web a cada 4-6 meses!) O calcanhar de Aquiles deles / delas é exigências extremas de conformidade e segurança. Eles têm necessidades de auditoria incríveis, e é mais fácil implementar controles à prova de balas em um único servidor, único banco de dados do que gerenciar esses requisitos em milhares de bancos de dados em dezenas de servidores. Eles escolheram um banco de dados, um servidor, muitos clientes.
A empresa 2 se destaca nas práticas de desenvolvimento. Gerenciar alterações de esquema e implantações de código em milhares de bancos de dados simplesmente não é um problema para eles. Eles têm clientes em todo o mundo e estão processando transações com cartão de crédito para esses clientes o tempo todo. Eles precisam da capacidade de distribuir a carga geograficamente e não querem substituir servidores ao redor do mundo a cada 12 ou 18 meses. Eles escolheram um banco de dados para cada cliente, e está valendo a pena quando começam a colocar SQL Servers na Ásia e na Europa para seus clientes offshore.
Mais uma consideração que ainda não vi em outras respostas.
Ter um design que permita muitos inquilinos em um único banco de dados dará flexibilidade posteriormente. Se as demandas de carregamento / expansão / segurança / localização geográfica sugerirem posteriormente que um inquilino deve ter um banco de dados separado, ele pode ser criado restaurando o banco de dados atual na nova instância. Os dados dos outros inquilinos ainda estão protegidos por quaisquer mecanismos existentes. Os dados agora obsoletos podem ser removidos aos poucos dos bancos de dados antigos e novos conforme o tempo permitir.
O contrário não é verdade. A consolidação de muitos bancos de dados de um inquilino exigirá consideravelmente mais trabalho.
fonte
Uma prática que facilita muito os modelos de vários inquilinos, mesmo que quebre a normalização *, é incluir uma coluna em todas as tabelas do inquilino. Você poderia chamá-lo de TenantID. Dessa forma, toda consulta executada no banco de dados pode filtrar o TenantID em todas as tabelas, e você pode usar o particionamento do banco de dados para isolar os dados de cada inquilino e acelerar as consultas alinhando partições. Muito mais fácil ter todos os inquilinos em um banco de dados dessa maneira.
* Nem sempre quebra a normalização, mas pode. Por exemplo, se você tiver uma
Person
e umaPersonAddress
tabela. APerson
tabela teráTenantID, PersonID
como chave primária. APersonAddress
tabela teráTenantID, PersonID, AddressTypeID
como chave primária o que estou sugerindo.Normalmente,
PersonID
isso seria suficiente, porque você poderia juntar isso de volta àPerson
mesa para encontrar oTenant
. Estou sugerindo que você carregueTenantID
avance para todas as tabelas subseqüentes, mesmo quando uma chave mais fina funcionaria.Entendi que transportar qualquer informação para uma tabela que pudesse ser derivada de outros dados era considerada uma quebra da normalização. Mas talvez o uso de teclas finas seja apenas uma prática recomendada.
fonte