Interagindo com dados usando vários bancos de dados / servidores

18

Todos os projetos com os quais tive que lidar até agora exigiram apenas um único banco de dados em um único servidor. Estou interessado em aprender mais sobre como os projetos que precisam ser dimensionados são movidos para vários bancos de dados e / ou servidores para ajudar a gerenciar a carga. Estou ciente da alta escalabilidade , mas estou particularmente interessado em alguns exemplos de código ou recursos adicionais em que poderia ler mais sobre o assunto.

Por exemplo:

  • Como as junções são construídas entre duas tabelas em vários bancos de dados? (Um exemplo de código aqui seria útil).
  • Existem estratégias especiais para rastrear quais tabelas estão em qual banco de dados?
  • O código do aplicativo precisa saber que um ou mais bancos de dados estão espalhados por vários servidores? Caso contrário, em que nível as solicitações são filtradas?
  • Quando é hora de ir além de uma configuração de 1 banco de dados / 1 servidor? Quão comum é fazer isso?
VirtuosiMedia
fonte
Esta pergunta pode ser melhor respondida em Administradores de banco de dados . Nada realmente errado com isso aqui, porém, então eu só vou verificar com os mods do DBA. Se for adequado lá, você gostaria que ele fosse migrado?
Adam Lear
@ AnnaLear - Eu acho que depende do tipo de respostas. Neste ponto, estou mais interessado no lado do aplicativo, então por enquanto, acho que pode ser melhor aqui.
VirtuosiMedia 8/11
@AnnaLear ack, concorde com o OP se quiser um código específico do aplicativo.
precisa saber é o seguinte

Respostas:

13

Ok, vamos dividir:

  • Como as junções são construídas entre duas tabelas em vários bancos de dados? (Um exemplo de código aqui seria útil).

Isso é bem direto. Os Objetos SQL possuem de uma a quatro partes:

Servername.databasename.schemaname.tablename

Se todas as suas tabelas estiverem no mesmo servidor no mesmo banco de dados, com o mesmo proprietário / esquema, você poderá ignorar as três primeiras partes e usar o que está mais acostumado:

Select a.*,b.* from 
tableA a inner join 
tableB b on a.col1=b.col1

Se uma de suas tabelas estiver em um banco de dados diferente e ambas usarem o esquema padrão para seus bancos de dados, basta adicionar o banco de dados à segunda tabela:

Select a.*,b.* from 
tableA a inner join 
databaseC..tableB b on a.col1 = b.col1

Se você estiver em um terceiro banco de dados diferente de qualquer um dos que você está consultando, use os dois nomes de banco de dados explicitamente:

Select a.*,b.* from 
databaseD..tableA a inner join 
databaseC..tableB b on a.col1 = b.col1

Se você acabar usando diferentes esquemas e / ou proprietários, poderá adicioná-los em:

Select a.*,b.* from 
databaseD.john.tableA a inner join 
databaseC.accounting.tableB b on a.col1 = b.col1

Por fim, se você for muito cuidadoso e tiver um bom motivo, poderá ingressar em uma tabela (geralmente pequena) em outro servidor:

Select a.* from 
databaseD.john.TableA a inner join 
ATLANTA.databaseC.accounting.tableB b on a.col1 = b.col1
  • Quando é hora de ir além de uma configuração de 1 banco de dados / 1 servidor? Quão comum é fazer isso? Existem estratégias especiais para rastrear quais tabelas estão em qual banco de dados?

Vou combinar esses dois porque eles vão juntos. Você geralmente quase sempre está bem em começar com a suposição de que um servidor de banco de dados e um servidor é suficiente até que suas restrições de design / negócios / técnicas o forcem a usar mais.

Portanto, para responder à sua segunda pergunta primeiro, como você geralmente tem um motivo para ter bancos de dados separados, deve ser bastante óbvio conhecer o design do seu sistema onde algo está.

Quanto a quando / por que é necessário ir além de um único banco de dados. Geralmente, é uma mistura de regras de negócios, políticas e / ou razões técnicas.

Por exemplo, onde trabalho, temos 16 bancos de dados espalhados por 4 servidores. Temos um MainDB, ImageDB, referencetableDB, HighvolumeTransactionDB, ReportingDB, StagingDB, ProcessingDB, ArchiveDB, FinancialDB. Para dar alguns exemplos de por que eles são diferentes:

  • FinancialDB, informações confidenciais
  • DB de imagem, diferentes requisitos específicos de armazenamento e recuperação
  • ReferênciaDB, baixa transação, alta leitura
  • O ReportingDB, leitura muito alta, precisa ser restaurado / replicado para vários outros ambientes, ao contrário de muitos outros dados
  • StagingDB, nada permanente, apenas um tempdb reforçado que temos mais controle sobre
  • O MainDB faz interface com todos os outros bancos de dados, mas precisa de backups diferenciais, então ... dividimos o
  • As tabelas HighVolumeTransaction (que são relativamente transitórias) para seu próprio banco de dados para manter o tamanho razoável do backup.
  • Arquivar, muitos dos mesmos dados de Principal e de Relatórios, mas com períodos de retenção mais longos e consultas mais difíceis, aprofundando os dados. Se isso ainda fosse combinado com Principal / Relatórios, atrapalhava nosso sistema.

O código do aplicativo precisa saber que um ou mais bancos de dados estão espalhados por vários servidores? Caso contrário, em que nível as solicitações são filtradas?

Em um sentido amplo, eles provavelmente o fazem. No mínimo, eles precisam saber em qual servidor estão apontando na cadeia de conexão do banco de dados. Processamento, geração de relatórios, principal etc.

A partir daí, eles precisam de um contexto de banco de dados para executar. Geralmente, esse seria o mais usado para o aplicativo, talvez até o original do banco de dados / um servidor dias do aplicativo. Você PODE ter o aplicativo alternar explicitamente o contexto do banco de dados em todas as chamadas, mas isso dificulta o ajuste do banco de dados sem alterar o aplicativo.

A abordagem usual (ou pelo menos a MY usual) é sempre acessar por um ou talvez dois bancos de dados principais.

Em seguida, crie visualizações em outros bancos de dados conforme necessário, combinados com a interface com o banco de dados através de procedimentos armazenados.

Então, para ilustrar:

Digamos que você deseja obter as informações demográficas, dados de vendas e saldo de crédito de um cliente, distribuídos por três tabelas originalmente todas no MainDB.

Então você escreve uma chamada a partir do seu aplicativo:

Select c.ClientName, c.ClientAddress, s.totalSales,f.CreditBlance from
Clients c join Sales s on c.clientid = s.clientid inner join AccountReceivable f on 
c.clientid=f.clientid where c.clientid = @clientid

Impressionante. No entanto, agora, sempre que alterar um nome de coluna ou renomear / mover uma tabela, você deverá atualizar o código do aplicativo. Em vez disso, fazemos duas coisas:
criar clientes, vendas, visualizações de contas a receber (você não usaria o Select *, mas estou demonstrando aqui)

Use MainDB
GO
Create view v_Clients as select * from Clients
Create view v_Sales as select * from Sales
Create view v_AccountReceivable as select * from AccountReceivable
Go

Em seguida, também criaríamos um procedimento armazenado, spGetClientSalesAR

Create proc spGetClientSalesAR @clientID int
as
Select c.ClientName as ClientName, 
       c.ClientAddress as ClientAddress, 
       s.totalSales as TotalSales, 
       f.CreditBlance as CreditBalance 
from
v_Clients c join v_Sales s 
    on c.clientid = s.clientid 
inner join v_AccountReceivable f 
    on c.clientid=f.clientid 
where c.clientid = @clientid

E faça com que seu aplicativo ligue para isso.

Agora, desde que eu não mude a interface nesse proc armazenado, posso fazer praticamente qualquer coisa que precise fazer no banco de dados de back-end para aumentar ou diminuir a escala.

No extremo, eu poderia até tornar meu MainDB antigo apenas um monte de procedimentos e visualizações armazenados em shell, de modo que, por baixo das visualizações que criamos, parecesse o seguinte:

Create view v_Clients as select * from ServerX.DatabaseY.dbo.Clients
Create view v_Sales as select * from ServerQ.DatabaseP.dbo.Sales
Create view v_AccountReceivable as select * from ServerJ.DatabaseK.dbo.AccountReceivable

E seu aplicativo nunca saberia a diferença (assumindo canais rápidos e dados bem preparados, entre outras coisas).

Obviamente, isso é extremo e eu mentiria se dissesse que tudo foi planejado dessa maneira, mas o uso de procedimentos / visualizações armazenados, mesmo que você o faça durante a refatoração, permitirá muita flexibilidade à medida que o aplicativo cresce a partir de um humilde banco de dados / servidor. começando.

TetonSig
fonte
TetonSig - Obrigado pela resposta. Não consegui voltar à pergunta a tempo de conceder a você a recompensa completa (eu estava viajando), mas criei uma nova recompensa para a pergunta e poderei conceder a você em 24 horas.
VirtuosiMedia
Uau, obrigada. Obrigado. Foi muito divertido responder à pergunta.
TetonSig
5

A principal maneira que encontrei vários servidores de banco de dados no mundo da web (desde que a pergunta foi marcada como PHP) são configurações nas quais havia um banco de dados 'mestre' (gravação) e, em seguida, um ou mais bancos de dados 'escravos' (leitura) replicados . As gravações de banco de dados são executadas no banco de dados 'mestre'. O conteúdo desse banco de dados é replicado para os servidores 'escravos' quase em tempo real. As consultas - relatórios particularmente intensivos - são executadas em um dos bancos de dados 'slave' para transferir a carga para esses servidores. Lembre-se de que essa configuração específica é melhor para aplicativos que têm muitas leituras, mas não muitas gravações. Não é de forma alguma a única maneira de organizar as coisas.

GrandmasterB
fonte
3

Como as junções são construídas entre duas tabelas em vários bancos de dados? (Um exemplo de código aqui seria útil).

Eles não são. Os bancos de dados NoSQL não fazem "junções" e, mesmo que você possa fazer uma junção SQL entre servidores RDBMS, não gostaria se valorizasse o desempenho (cf. falácias da computação distribuída ).

Existem estratégias especiais para rastrear quais tabelas estão em qual banco de dados?

Em um banco de dados relacional / SQL, o particionamento normalmente é feito dentro dos limites de um único servidor / banco de dados, usando arquivos diferentes colocados em discos diferentes. Quase por definição, uma solução de dimensionamento horizontal significa que todos os bancos de dados têm todas as tabelas e você tem algum tipo de espelhamento transacional, replicação ou solução personalizada de consistência eventual para garantir que todos os dados cheguem ao seu destino.

Se você estiver realmente dividindo o banco de dados logicamente e não apenas fisicamente, os mapeamentos definidos no seu DAL ou ORM declararão quais tabelas estão em qual banco de dados.

Os bancos de dados NoSQL são uma mistura de soluções de particionamento. Às vezes, são as "tabelas" (ou mais comumente, as "coleções") que são particionadas. Outras vezes, são as "linhas" (ou "documentos"). Em alguns casos, na verdade, são as colunas , como em um banco de dados orientado a colunas como o HBase. Depende totalmente da tecnologia que você está usando. A única coisa que todos têm em comum é que o próprio mecanismo mantém o controle de tudo, então tudo o que você precisa fazer é solicitar um documento ou linha.

Obviamente, isso pressupõe que você esteja realmente usando os recursos de sharding e não apenas criando um monte de bancos de dados diferentes. Se você estiver fazendo o último, estará por sua conta.

O código do aplicativo precisa saber que um ou mais bancos de dados estão espalhados por vários servidores? Caso contrário, em que nível as solicitações são filtradas?

Se eles são bancos de dados lógicos diferentes , sim. Se eles forem distribuídos apenas fisicamente , não - assumindo que o banco de dados específico ofereça suporte nativo ao sharding ou você use uma solução de balanceamento de carga (para bancos de dados SQL). Também assumindo que todas as suas operações são sem estado; se você quiser dimensionamento horizontal, precisará renunciar ao ACID.

Quando é hora de ir além de uma configuração de 1 banco de dados / 1 servidor? Quão comum é fazer isso?

É hora de otimizar tudo o que é possível em um servidor e ainda não conseguir obter desempenho suficiente devido a restrições na carga de E / S. Se você precisar fazer a pergunta, é muito cedo.

Observe que os problemas de desempenho em um produto RDBMS decente (Oracle, SQL Server) são mais frequentes devido ao design inadequado, à indexação ruim, às consultas ruins, à contenção de bloqueios e assim por diante; esses produtos podem ser dimensionados verticalmente em um grau ridículo. Então, novamente, você deve considerar "ir além de uma configuração de 1 banco de dados / 1 servidor" quando tiver certeza absoluta de que seus problemas de desempenho são causados ​​por limitações de hardware e não apenas por um design / implementação abaixo da média.

Ou, suponho, outro motivo pelo qual algumas pessoas mudam para bancos de dados distribuídos é quando não estão dispostas a pagar muito (ou qualquer) dinheiro em taxas de licenciamento e desejam abandonar o SQL como uma opção consciente para negociar o baixo custo pelo aumento da complexidade de aplicativos. Razão totalmente válida se você é uma startup de software, mas geralmente não é aplicável no setor corporativo.

Aaronaught
fonte
+1 - Eu realmente não estava considerando o NoSQL, mas isso é útil da mesma forma. Obrigado.
VirtuosiMedia
1

Existem três tipos principais de configurações de replicação para bancos de dados:

  • Senhor de escravos
  • Master-Master
  • Consenso

Exemplo de mestre-escravo: Mestre do MySQL + escravos do MySQL, MongoDB

Exemplo Master-Master: CouchDB, Cassandra, Riak

Exemplo de consenso: ScalienDB

...para nomear alguns.

Estes têm características diferentes. As configurações mestre-escravo permitem que os nós escravos alcancem o mestre em sua taxa máxima enquanto atendem solicitações de leitura muito rapidamente, enquanto o servidor mestre é responsável pela integridade dos dados. Como todas as gravações vão para o mestre, nunca há contenção de bloqueio porque um único gravador relativamente lento está bloqueando muitos leitores, mas, por outro lado, os servidores escravos são eventualmente consistentes e você não obtém as garantias de isolamento de transação que você teria. de ler apenas do mestre. (leitura adicional; ACID vs BASE, níveis de isolamento de transação, replicação de banco de dados, MVCC / isolamento: captura instantânea, replicação transacional)

O mestre-mestre sempre permite gravações, para que você tenha várias autoridades sobre o que é verdade. Isso pode ou não ser um problema, dependendo do que o aplicativo está fazendo, mas se você escrever dados conflitantes, poderá obter vários resultados na próxima vez que ler a chave / linha / coluna que precisará mesclar com a lógica do aplicativo e salve de volta no banco de dados. (leitura adicional: teorema do CAP, replicação CouchDB, replicação Riak, hash consistente, Bitcask e StormDB, quorum-w / MongoDB na divisão de rede, estratégias de resolução de mesclagem)

Os bancos de dados baseados em consenso com replicação entre nós, como Scalien, sempre seriam consistentes nas gravações, mas com o custo de trocar várias mensagens antes de ACK a gravação. Isso não é muito problemático se você possui uma ethernet rápida e não precisa gravar em disco antes do ACKing, o que não será necessário se seu mínimo de três servidores estiverem em racks de servidores diferentes com fontes de alimentação separadas (uma morre; os outros dois certificam-se de que foram salvos no disco). (leitura adicional; PAXOS, PAXOS COMMIT, confirmação de duas fases com transações distribuídas, confirmação de três fases)

Outras leituras adicionais: (livro: 'Elements of Distributed Computing', relógios vetoriais, vetores de versão, vetores matriciais, relógios lógicos, algoritmo de padaria, relógios de árvore com intervalo, atores e programação e reatores reativos, memória transacional de software, transatores, AKKA, Stact, falácias da computação distribuída, protocolos de fofocas, extensões do protocolo anti-entropia de Cassandra, tabelas de hash distribuídas, documentos sobre a fusão de dados em um ambiente distribuído, arquitetura ZooKeeper, apresentação InfoQ em "protocolo assíncrono", arquitetura HBase, artigo MapReduce, artigo Amazon Dynamo que iniciou todo o cluster NoSQL, enfileiramento, alta disponibilidade do rabbitmq)

Espero ter dado um pouco de reflexão :). Você pode me seguir no twitter @henrikfeldt se quiser tweets sobre essas coisas também.

Henrik
fonte
1

OK, então aqui está outro ponto de vista sobre escalabilidade.

Vamos discutir o que significa coisas serem dados, o que significa ter comportamento e o que significa ter lógica de aplicativo.

Normalmente, quando alguém se aventura na terra dos aplicativos empresariais e similares, fica exposto à idéia de camadas. Obviamente, as camadas estão espalhadas por todo o lado nos computadores, como na pilha de rede (modelo ISO), nos gráficos (Photoshop) ou na SOA (os serviços podem chamar irmãos ou filhos, mas nunca pais).

No entanto, o tipo específico de estratificação que foi abusado, independentemente do que já foi o da 'GUI', 'Business Logic Layer' e depois 'Data Access Layer'. Quero dizer, sim, a ideia é boa em princípio, como o comunismo é bom em princípio, mas na realidade não é.

Vamos dar uma olhada no porquê. O argumento que vou usar é sobre acoplamento; pontos de uma camada que toca pontos em outra camada. Sempre que você começa a criar um aplicativo em camadas de n-camada, também conhecido como modo de negócios padrão no qual as pessoas entram, elas criam muitos pontos de contato entre as camadas.

No fundo, a idéia é que as camadas são intercambiáveis; mas eles não são! Por quê? Por causa de todo o acoplamento do site de chamada.

Em vez disso, veja por que a rede está dissociada! Porque a interface é um fluxo de bytes em um ponteiro de arquivo único que aponta para um soquete aberto! Todas as camadas nos modelos ISO são como o padrão de design chamado 'cadeia de responsabilidade' é a orientação a objetos! Cada camada envolve a camada subjacente, sem conhecer a semântica dos dados nessa camada subjacente.

À medida que um pacote de dados caminha em direção a sinais elétricos Ethernet e brutos na parte inferior, ele é continuamente envolvido por camadas que apenas conhecem seu próprio envelope de mensagem específico, seu próprio 'lote de bytes' que ele pode enviar; e nada mais. Não é necessário alterar os caminhos de chamada, dependendo do conteúdo do pacote.

Compare isso com a n-camada, na qual você teria que alterar o caminho das camadas da aplicação em uma 'chamada' atravessando suas camadas no caminho para o banco de dados - por exemplo, 'clientes de ouro' são polimorficamente um superconjunto de 'clientes normais' e assim, porque usamos 'tabela por subclasse', precisamos saber sobre isso agora que os dados (entidade) estão atravessando as camadas; tanto na chamada "camada de lógica de negócios" quanto na camada de dados que realmente está economizando.

Não é escalável nem ideal do ponto de vista da computação.

Por que não é escalável? Como a arquitetura está acoplada, e você ainda está dentro do mesmo banco de dados antigo que estava tentando expandir para muitos nós! Mas, como você precisa de ACID para isso, essa e uma terceira entidade (objeto de dados) precisam deles em um único banco de dados que realiza transações!

Bem, assim com aquele discurso retórico; que outras maneiras existem?

Bem, existe o odiado acrônimo chamado 'SOA', ou seja, arquitetura orientada a serviços. Obviamente, os Tomas Erls do mundo gostariam de implementar todas as suas camadas, mas com XML e SOAP.

Por todos os motivos acima, este é o caminho errado, porque você se acoplaria a esses proxies XML, assim como se acopla às camadas de aplicativos, conforme explicado acima.

Em vez disso, use as mensagens e deixe o que implementa a funcionalidade para elas, ouça-as. Sua superfície de serviço se torna uma lista de mensagens que você pode enviar e você não acoplou suas operações à fachada de serviço; e você nem precisa saber qual aplicativo ou terminal implementa essas operações, porque tudo o que você está fazendo é publicar uma mensagem de que algum outro mecanismo de roteamento encaminhará para o consumidor correto!

Como você separou as fachadas de serviço das operações reais que deseja executar, agora você pode adicionar vários serviços; de fato, é assim que a Netflix faz. Dê uma olhada nessas apresentações: http://www.slideshare.net/adrianco/global-netflix-platform . http://www.slideshare.net/adrianco/global-netflix-platform . Eles são bons!

Henrik
fonte
0

Há um novo banco de dados SQL (ACID) na versão beta que possui propriedades de escala elástica. Há um programa beta gratuito em andamento agora e sugiro que você dê uma olhada, chamado NuoDB.

Aparentemente, ele supera facilmente o MySQL, mesmo em uma única máquina de encadeamento, mas escala felizmente para mais de 70 instâncias em determinados benchmarks.

Dibbeke
fonte
Uma única discussão? Como é então uma referência relevante?
Henrik