Abordagens de fragmentação do MySQL?

88

Qual é a melhor abordagem para Sharding tabelas MySQL. As abordagens que consigo pensar são:

  1. Fragmentação de nível de aplicativo?
  2. Fragmentação na camada de proxy do MySQL?
  3. Servidor de pesquisa central para fragmentação?

Você conhece algum projeto ou ferramenta interessante nesta área?

Sheki
fonte

Respostas:

115

A melhor abordagem para fragmentar tabelas MySQL é não fazer isso, a menos que seja totalmente inevitável.

Quando você está escrevendo um aplicativo, geralmente deseja fazê-lo de uma forma que maximize a velocidade, a velocidade do desenvolvedor. Você otimiza para latência (tempo até a resposta estar pronta) ou rendimento (número de respostas por unidade de tempo) apenas quando necessário.

Você particiona e atribui partições a diferentes hosts (= fragmento) apenas quando a soma de todas essas partições não cabe mais em uma única instância do servidor de banco de dados - a razão para isso ser gravações ou leituras.

O caso de gravação é a) a frequência de gravações está sobrecarregando os discos dos servidores permanentemente ou b) há muitas gravações em andamento, de forma que a replicação fica permanentemente atrasada nesta hierarquia de replicação.

O caso de leitura para fragmentação é quando o tamanho dos dados é tão grande que o conjunto de trabalho deles não cabe mais na memória e as leituras de dados começam a atingir o disco em vez de serem atendidas da memória na maior parte do tempo.

Somente quando você tiver que fragmentar, faça isso.


No momento em que você fragmenta, está pagando por isso de várias maneiras:

Muito do seu SQL não é mais declarativo.

Normalmente, em SQL, você informa ao banco de dados quais dados deseja e deixa para o otimizador transformar essa especificação em um programa de acesso a dados. Isso é uma coisa boa, porque é flexível e porque escrever esses programas de acesso a dados é um trabalho enfadonho que prejudica a velocidade.

Com um ambiente fragmentado, você provavelmente está juntando uma tabela no nó A com os dados no nó B, ou tem uma tabela maior do que um nó, nos nós A e B e está juntando dados dela com os dados que estão nos nós B e C. Você está começando a escrever resoluções de junção baseadas em hash do lado do aplicativo manualmente para resolver isso (ou está reinventando o cluster MySQL), o que significa que você acaba com muito SQL que não é mais declarativo, mas expressa a funcionalidade SQL de uma forma procedural (por exemplo, você está usando instruções SELECT em loops).

Você está incorrendo em muita latência de rede.

Normalmente, uma consulta SQL pode ser resolvida localmente e o otimizador conhece os custos associados aos acessos ao disco local e resolve a consulta de uma forma que minimiza os custos para isso.

Em um ambiente fragmentado, as consultas são resolvidas executando acessos de valor-chave em uma rede para vários nós (esperançosamente com acessos de chave em lote e não pesquisas de chave individuais por viagem de ida e volta) ou empurrando partes da WHEREcláusula para os nós onde eles podem ser aplicado (isso é chamado de 'pushdown de condição') ou ambos.

Mas, mesmo no melhor dos casos, isso envolve muito mais viagens de ida e volta da rede do que uma situação local, e é mais complicado. Especialmente porque o otimizador MySQL não sabe nada sobre latência de rede (Ok, o cluster MySQL está lentamente ficando melhor nisso, mas para o MySQL vanilla fora do cluster isso ainda é verdade).

Você está perdendo muito poder expressivo do SQL.

Ok, isso provavelmente é menos importante, mas as restrições de chave estrangeira e outros mecanismos SQL para integridade de dados são incapazes de abranger vários fragmentos.

O MySQL não tem API que permite consultas assíncronas em bom estado de funcionamento.

Quando os dados do mesmo tipo residem em vários nós (por exemplo, dados do usuário nos nós A, B e C), as consultas horizontais geralmente precisam ser resolvidas em todos esses nós ("Encontre todas as contas de usuário que não foram conectadas por 90 dias ou mais"). O tempo de acesso aos dados cresce linearmente com o número de nós, a menos que vários nós possam ser solicitados em paralelo e os resultados agregados à medida que chegam ("Mapa-Redução").

A pré-condição para isso é uma API de comunicação assíncrona, que não existe para o MySQL em bom estado de funcionamento. A alternativa são muitas bifurcações e conexões nos processos infantis, que é visitar o mundo do chupar na passagem de temporada.


Depois de iniciar a fragmentação, a estrutura de dados e a topologia de rede tornam-se visíveis como pontos de desempenho para seu aplicativo. Para ter um desempenho razoavelmente bom, seu aplicativo precisa estar ciente dessas coisas, e isso significa que realmente apenas a fragmentação no nível do aplicativo faz sentido.

A questão é mais se você deseja fragmentar automaticamente (determinar qual linha vai para qual nó por meio de hash de chaves primárias, por exemplo) ou se deseja dividir funcionalmente de forma manual ("As tabelas relacionadas à história do usuário xyz vão para este mestre, enquanto as tabelas relacionadas a abc e def vão para esse mestre ").

O sharding funcional tem a vantagem de que, se feito corretamente, é invisível para a maioria dos desenvolvedores na maioria das vezes, porque todas as tabelas relacionadas à sua história de usuário estarão disponíveis localmente. Isso permite que eles ainda se beneficiem do SQL declarativo pelo maior tempo possível e também incorrerá em menos latência de rede porque o número de transferências entre redes é mínimo.

O sharding funcional tem a desvantagem de não permitir que uma única tabela seja maior que uma instância e requer atenção manual de um designer.

O sharding funcional tem a vantagem de ser feito com relativa facilidade em uma base de código existente, com várias alterações que não são muito grandes. http://Booking.com fez isso várias vezes nos últimos anos e funcionou bem para eles.


Tendo dito tudo isso, olhando para sua pergunta, acredito que você está fazendo as perguntas erradas ou estou interpretando mal a sua definição de problema.

Isotopp
fonte
2
Esta é uma boa resposta. Mas quero salientar que a fragmentação é realmente necessária apenas para aplicativos de alto volume e é provável que estejam gerando algum tipo de receita. Um aplicativo de sharding de terceiros tratará de todas as preocupações que você tiver com junções, transações de cross-shard etc. E se você conseguir um bom, manterá a integridade de um banco de dados "relacional". Outros aplicativos, você está certo, simplesmente transformarão seu banco de dados em um par de valores-chave e, assim, frustrarão o propósito do SQL.
chantheman
3
Ainda não encontrei um aplicativo de fragmentação, comercial ou não, que consiga esconder o fato de que os dados agora estão espalhados pela rede e sujeitos a latência ou inconsistência devido à falta de esperas induzidas por latência. Se você estiver fragmentando, seu aplicativo notará e exigirá alterações. Você pode muito bem estar no controle disso sozinho. Não há bala de prata, mas há muito óleo de cobra.
Isotopp
1
Você deve verificar o dbShards. Ele é escalonado melhor do que linearmente de acordo com o número de "fragmentos" que você adicionar. Você exigirá muito poucas, se houver, alterações no lado do aplicativo e, sim, seu aplicativo não sabe a diferença. Ele apenas envia e recebe transações da mesma forma que faria com ODBC ou JDBC. dbShards também permite dicas de shard se você quiser mais controle sobre uma transação. Você pode dizer ao dbShards exatamente de qual fragmento deseja ler ou escrever.
chantheman
1
@Gigala bem, gastar tempo compondo uma resposta bem definida como essa, independente da abrangência, também não é necessário, mas estou feliz que tenha sido feito, pois essa resposta se mostrou útil para mim. Não desencoraje os usuários a não "pensar fora da caixa" ao responder.
mewm de
12
  1. Fragmentação de nível de aplicativo: dbShards é o único produto que conheço que faz "fragmentação com reconhecimento de aplicativo". Existem alguns bons artigos no site. Apenas por definição, a fragmentação com reconhecimento de aplicativo será mais eficiente. Se um aplicativo souber exatamente para onde ir com uma transação sem ter que procurá-la ou ser redirecionado por um proxy, isso por si só será mais rápido. E a velocidade costuma ser uma das principais preocupações, se não a única, quando alguém está investigando a fragmentação.

  2. Algumas pessoas "fragmentam" com um proxy, mas, a meu ver, isso anula o propósito de fragmentar. Você está apenas usando outro servidor para informar às suas transações onde encontrar os dados ou onde armazená-los. Com a fragmentação por reconhecimento de aplicativo, seu aplicativo sabe onde ir sozinho. Muito mais eficiente.

  3. Este é o mesmo que # 2, na verdade.

chantheman
fonte
O dbShards está em uso na produção em algum lugar? também não é open source.
Sheki
Além disso, as abordagens 2 e 3 podem ser diferentes se o proxy pesquisar com base em um hash em vez do banco de dados ou de um armazenamento.
sheki
1
dbShards está em produção com uma variedade de clientes, mas não, não é um software livre. Não acho que você encontrará um bom produto de fragmentação de código aberto. E sim, você está correto que um hash poderia ser usado como uma consulta, mas nesse caso você ainda terá que dar mais uma "parada" para colocar sua transação no banco de dados. É por isso que a fragmentação com "reconhecimento de aplicativo" quase sempre será mais rápida.
chantheman
Mas, como eu disse, se você conseguir um aplicativo de fragmentação que mantenha a integridade dos relacionamentos, estará em boa forma. Menciono dbShards porque é o único que conheço que o faz. E desde que isso aconteça, ele dimensiona suas velocidades de gravação e leitura linearmente. Você adiciona 4 "fragmentos" ou divide seu servidor MySQL em 4 e ele será executado 4 vezes mais rápido.
chantheman
7

Você conhece algum projeto ou ferramenta interessante nesta área?

Vários novos projetos neste espaço:

  • citusdata.com
  • spockproxy.sourceforge.net
  • github.com/twitter/gizzard/
btcbb
fonte
5

Shard-Query é uma solução de fragmentação baseada em OLAP para MySQL. Ele permite que você defina uma combinação de tabelas fragmentadas e não fragmentadas. As tabelas não fragmentadas (como tabelas de pesquisa) podem ser unidas livremente a tabelas fragmentadas, e as tabelas fragmentadas podem ser unidas umas às outras, desde que as tabelas sejam unidas pela chave de fragmento (sem fragmentos cruzados ou junções self que cruzam os limites dos fragmentos). Por ser uma solução OLAP, o Shard-Query geralmente tem tempos de resposta mínimos de 100 ms ou menos, mesmo para consultas simples, portanto, não funcionará para OLTP. O Shard-Query foi projetado para analisar conjuntos de big data em paralelo.

Soluções de fragmentação de OLTP também existem para MySQL. Soluções de código fechado incluem ScaleDB , DBShards . A solução OLTP de código aberto inclui JetPants , Cubrid ou Flock / Gizzard (infraestrutura do Twitter).

Justin Swanhart
fonte
3

Nível de aplicação, é claro.

A melhor abordagem que já encontrei neste livro

MySQL de alto desempenho http://www.amazon.com/High-Performance-MySQL-Jeremy-Zawodny/dp/0596003064

Breve descrição: você pode dividir seus dados em várias partes e armazenar aproximadamente 50 partes em cada servidor. Isso o ajudará a evitar o segundo maior problema de fragmentação - o rebalanceamento. Basta mover alguns deles para o novo servidor e tudo ficará bem :)

Eu recomendo fortemente que você compre e leia a parte "escalonamento do mysql".

Andrey Frolov
fonte
O livro que você recomendou tem 8 anos ... ele cobre fragmentação relevante para as tecnologias de hoje?
raffian
1
Ele cobre algumas abordagens básicas para dimensionar o mysql. AFAIK nada mudou no escalonamento do mysql. As técnicas de fragmentação e replicação no mesmo nível de aplicativo são amplamente usadas hoje em dia.
Andrey Frolov
Posso estar errado, mas tenho feito muitas pesquisas sobre isso na semana passada e parece que o próprio mySQL fez muitas mudanças nos últimos 8 anos, especialmente em relação ao particionamento e cache. Há uma nova versão que saiu este ano: amazon.com/High-Performance-MySQL-Optimization-Replication/dp/… Não li, mas acho que cobre os novos modelos de replicação disponíveis.
NateDSaint
4
Livros .. por que não explicar aqui.
DDD
2

Em 2018, parece haver uma solução nativa do MySql para isso. Na verdade, existem pelo menos 2 - InnoDB Cluster e NDB Cluster (há uma versão comercial e uma versão da comunidade).

Como a maioria das pessoas que usam o MySql Community Edition estão mais familiarizadas com o mecanismo InnoDB, isso é o que deve ser explorado como primeira prioridade. Ele suporta replicação e particionamento / fragmentação fora da caixa e é baseado no roteador MySql para diferentes opções de roteamento / balanceamento de carga.

A sintaxe para a criação de suas tabelas precisaria ser alterada, por exemplo:

    CREATE TABLE t1 (col1 INT, col2 CHAR(5), col3 DATETIME) PARTITION BY HASH ( YEAR(col3) );

(este é apenas um dos quatro tipos de particionamento )

Uma limitação muito importante:

As chaves externas InnoDB e o particionamento MySQL não são compatíveis. Tabelas InnoDB particionadas não podem ter referências de chave estrangeira, nem podem ter colunas referenciadas por chaves estrangeiras. As tabelas InnoDB que têm ou são referenciadas por chaves estrangeiras não podem ser particionadas.

yuranos
fonte
Esteja ciente de que PARTITION BY HASH(YEAR...)irá verificar todas as partições se você tiver um intervalo de datas. Que nojo.
Rick James