Conversa aleatória sobre o sub-banco de dados e a tabela de rotinas distribuídas

Como se trata de "Classificação sobre o sub-banco de dados e a subtabela", precisamos determinar sobre o que queremos falar e sobre o que não falar.

  1. Em primeiro lugar, não discutimos a implementação e o código-fonte da estrutura de subtabela de sub-banco de dados específica, que não é o escopo de nossa discussão.
  2. Estamos discutindo ideias, principalmente discutindo as rotinas de como dividir o banco de dados e a tabela, quais são as armadilhas e que experiência você tem, mas não discutiremos os detalhes específicos. Claro, minhas próprias habilidades são limitadas, mas eu só espero ser capaz de atrair outros.
  3. Devemos deixar claro que o sub-banco de dados e a subtabela não é uma solução mágica , é apenas uma maneira de economizarmos quando o desempenho autônomo do MySQL não é suficiente. Para o chefe, ele quer economizar custos, mas também apoiar o negócio e fornecer desempenho estável e durável.

Os programadores exercem sua engenhosidade, quebram a cabeça, dia após dia de trabalho árduo e prática e, finalmente, produzem duas maneiras principais:

  1. O modo integrado do agente usa um pacote jar para integrar em nosso código. O código usa regras de roteamento e chaves de fragmentação para dividir o banco de dados e as tabelas, que é um modo integrado.
  2. O modo cs (modo cliente-servidor) fornece um componente de três partes, como mycat, o modo proxy em sharding-sphere, semelhante ao mycat; há centralização e a alta disponibilidade dos componentes de três partes precisa ser garantida .

Se houver uma seleção técnica melhor, preferiríamos não sub-biblioteca e subtabela, porque é uma solução complicada em si. É apenas um compromisso. NewSQL e bancos de dados comerciais são mais adequados (por exemplo, Oracle, na maioria dos cenários, o desempenho é suficiente, mas o custo é alto).

Se um dia houver um novo SQL excelente e econômico, como oceanbase, tidb, podemos basicamente dizer adeus ao sub-banco de dados e à subtabela.

A razão pela qual escolhemos usar o banco de dados e a estratégia de tabela é fundamentalmente porque, por um lado, nosso custo de uso não pode ser muito alto; por um lado, o desempenho do banco de dados DB independente não é suficiente; por outro Por outro lado, newSQL é atualmente imaturo e muito caro. Não ouse usá-lo.

Existem muitos fabricantes de sub-bibliotecas e subtabelas, ricas estruturas de código aberto, comunidades e casos maduros, por isso adotamos,

A razão direta é que Ali está na plataforma. Nosso ethos doméstico é que eu uso o que Ali usa e como Ali o faz. Sigo a tendência muito a sério. Minha ideia é que ainda temos algumas visões futuras de nossa própria tecnologia, e é melhor não confiar em Ali, apenas na tecnologia.

Dito isso, voltamos ao assunto e começamos a olhar para o problema.

1. É normal fazer apenas subtabelas? Ainda tem que dividir a mesa e dividir a biblioteca, se for dividida então a biblioteca está em vários servidores? Como considerar isso

Eu quero dizer, ou olhar para a escala dos negócios , apenas para ver a escala atual das operações, mas também olhar para o futuro 3 - 5 anos de tendências de negócios.

Quando se trata de seleção de tecnologia, nosso objetivo é escolher sempre a mais adequada para o negócio atual, o menor custo, o maior lucro e a adequada é o melhor.

A melhor solução que escolhemos é aquela que a equipa técnica apenas pode acolher. Se a seleção não for mais adequada para o desenvolvimento de negócios atual, você pode alterar para um mais adequado. Esta é a lei inevitável do desenvolvimento das coisas.

Ou então o negócio não evoluiu para um patamar superior, já é GG, então é certo, não desperdice dinheiro para comprar instalações melhores, apenas pare com a perda;

Ou então, o plano atual não chega mesmo, mudamos um conjunto de mais poderoso, embora vá custar mais dinheiro, agradar mais pessoas, mas isso não está em nossa mente, nosso propósito Em si mesmo, ele apoia o desenvolvimento de negócios através de arquitetura técnica adequada e um código melhor.

O resumo de uma frase é que, como você precisa gastar dinheiro, gaste-o.

Discussão por cena

Uma imagem vale mais que mil palavras. Vejamos esses dois cenários separadamente.

Para  cenários de análise de dados offline

Apenas a subtabela é suficiente, porque você é usado principalmente para analisar os dados, e os dados após os dados de análise podem ser excluídos. As tarefas assíncronas excluem vários meses / dias de dados.

Conversa aleatória sobre o sub-banco de dados e a tabela de rotinas distribuídas

 

Para  sistemas de negócios em tempo real

Se for um sistema de negócios 2C distribuído, que precisa transportar uma grande quantidade de tráfego, é recomendável   considerar o banco de dados e a tabela .

Conversa aleatória sobre o sub-banco de dados e a tabela de rotinas distribuídas

 

Pré-requisitos para sub-biblioteca, volume de negócios estimado

A premissa do sub-banco de dados e subtabela é estimar o volume de negócios. Fornecemos um valor empírico, que não representa o mais adequado, mas é apenas uma análise qualitativa:

QPS 500-1000以下,   那么采用主从读写分离,基本上足够支撑业务了;

QPS 1000-10000,考虑分布分表是一个比较合适的事情 

12000TPS 30000QPS 32库 1024表 
1000多万 16000QPS 16库512表

Essencialmente: O sub-banco de dados e a subtabela são uma venda única.O design inicial é muito importante e determina a dificuldade de expansão posterior e migração de dados. No projeto preliminar, há uma grande probabilidade de precisarmos planejar para os próximos 3-5 anos. No curto prazo, precisamos planejar para 1-2 anos. De acordo com o plano, determine se devemos dividir o banco de dados e a tabela, bem como quantas bibliotecas e tabelas.

Voltando ao problema em si, isso depende principalmente do volume de negócios atual e da taxa de crescimento do volume de negócios.

Com base nessas dimensões, fornecemos um conjunto de fórmulas:

某年数据增量M = (1 + 数据年增速K)^ n  * 初始数据量 N

第一年增量 M1 = (1+k)   * N 
第二年增量 M2 = (1+K)^2 * N
第三年增量 M3 = (1+K)^3 * N

三年数据总量 M' = N + m1 + m2 + m3

Vamos calcular com uma única tabela contendo 10 milhões de dados. Existem várias tabelas no total. Atualmente, não é necessariamente 1000w, mas 2000w-5000w é bom. Em primeiro lugar, este é um valor empírico e, em segundo lugar, é necessária uma análise quantitativa.

A análise quantitativa requer teste de pressão. Precisamos usar uma instância de biblioteca para realizar o teste de estresse para sua configuração online. Sob esta configuração, sem afetar a taxa de transferência do sistema, a capacidade máxima de um único medidor é um link seguro., O que pode nos guiar bem na fase inicial de design .

Em seguida, discutimos, quando precisamos sub-banco de dados, devemos garantir que cada banco de dados é uma instância independente?

Não, ainda temos que analisar questões específicas em detalhes.

Se for um ambiente de desenvolvimento, ou seja, para desenvolver uma biblioteca para RD escrever código, então vários conjuntos de bibliotecas podem ser usados ​​em uma máquina. Afinal, o ambiente de desenvolvimento não tem simultaneidade e é usado no máximo para desenvolvimento. desde que não seja usado para teste de estresse, não há problema.

Se for um ambiente online, além de implantar a biblioteca em várias máquinas, você também deve considerar a separação de leitura e gravação e a alta disponibilidade da biblioteca. A principal diferença entre online e offline é que existem requisitos de alta disponibilidade online, mas não offline .

Pense na diferença entre os dois, a diferença está no controle de custos .

Concluímos que, quando queremos implantar o banco de dados em uma instância de máquina, isso depende do cenário, do custo e se precisamos dele. Analise questões específicas.

2. Como gerar chaves de roteamento? O algoritmo do floco de neve pode ser usado? Se a chave primária do banco de dados original é auto-crescente, não há restrição de negócios exclusiva, se após a migração, como os dados originais podem ser roteados no sub-banco de dados e subtabela?

boa pergunta.

Em primeiro lugar, como gerar a chave de roteamento?

Essencialmente, esta é uma questão de como implementar um emissor distribuído confiável . Só falamos sobre ideias, porque podemos falar sobre isso, mas faz muito tempo para falarmos sozinhos.

Ideias:

Para algumas estruturas, eles têm seu próprio gerador de chave primária, como o algoritmo SnowFlake da classe shardingSphere / ShardingJDBC;

  1. UUID: formato de string, realmente único, mas de baixa legibilidade, difícil de fazer cálculos matemáticos, não intuitivo, relativamente longo e ocupa um grande espaço
  2. SNOWFLAKE: Pode ser usado, ou pode ser usado para melhorar o Leaf, o próprio Leaf é um conjunto completo de emissores de números distribuídos, e também possui garantia de alta disponibilidade.

Claro, existem outras maneiras:

Como você já fez o sub-banco de dados e a subtabela, há uma grande probabilidade de que seu sistema também seja distribuído, portanto, usar a numeração em processo não é a maneira ideal.

Se você deseja simplesmente implementar um serviço de emissão de número distribuído, podemos usar o incremento de redis para implementar um conjunto de emissor ou usar o id único de autoincremento do banco de dados para fazê-lo, mas ainda precisamos desenvolvê-lo para implementar um sistema de emissão de números.

Basta usar a imagem anterior para expressar seus pensamentos. Este conteúdo será escrito em um artigo separado posteriormente.

Conversa aleatória sobre o sub-banco de dados e a tabela de rotinas distribuídas

 

Resumindo, em essência, esta é uma questão de como implementar um emissor distribuído confiável.

Portanto, a questão de depender de um mecanismo específico de emissão de número distribuído não precisa ser complicada, basta prestar atenção à seleção final e fazer mais trade-offs.

3. Se for um único banco de dados e não houver chave de roteamento e a chave primária for usada como identificador exclusivo, como posso jogar com o sub-banco de dados e a tabela?

É muito simples. Qual é o seu identificador exclusivo original? Você pode usar isso após a subtabela do sub-banco de dados.

No entanto, como não há chave de atributo de negócios, é recomendável adicionar uma chave primária natural do atributo de negócios após a migração de dados, e há uma grande probabilidade de que você precise configurar novas regras de roteamento.

O processo específico é:

  1. Migrar dados
  2. Altere a configuração de roteamento para especificar uma nova regra de consulta, regras de roteamento para sub-bancos de dados e subtabelas
  3. Altere o código para incluir o código CRUD no código, como o código contido no DAO e no repositório, e adicione regras de roteamento ao código. Simplificando, você ainda pode usar o id original para realizar consultas, inserções e exclusões, mas principalmente O ponto da mudança é que você precisa ter uma regra de roteamento.

Dizemos que o núcleo da migração do banco de dados para a tabela independentemente da tabela: para garantir a integridade dos dados, o código deve ser refatorado, é difícil ter um programa abrangente que não precise alterar o código, podemos apenas comprometer e reduzir o grau de complexidade.

O ID da chave primária original foi migrado para o novo sub-banco de dados e subtabela do banco de dados. Não é mais contínuo, mas precisa ser exclusivo. A chave primária de incremento automático na nova tabela do banco de dados ainda precisa ter, mas não há atributo de negócios O motivo para sub-banco de dados Depois que a tabela é dividida, uma chave primária de incremento automático é necessária, que é principalmente para melhorar a eficiência de inserção e consulta. Através da árvore de índice de chave primária, de volta à operação da tabela.

É equivalente ao fato de que você originalmente usou o ID de incremento automático para ter atributos de negócios. Aqui está uma digressão, tente não usar a chave primária de incremento automático para representar o significado do negócio .

3. Como escolher a chave de fragmento

Nossa resposta ainda não pode dar uma afirmação precisa, só posso dizer que temos que escolher de acordo com as necessidades do cenário de negócios.

Isso é muito geral, vamos expressá-lo por meio de alguns exemplos.

对于用户表,使用用户唯一标识, 如:userId作为分片键;
对于账户表,使用账户唯一标识,如:accountId作为分片键;
对于订单表,使用订单唯一标识, 如:orderId作为分片键;
对于商家相关信息表,使用商家唯一标识, 如:merchantId作为分片键;
......

Se quisermos verificar o pedido de um usuário, devemos usar userId para ir para a tabela de roteamento e inserir o pedido na tabela de pedidos para garantir que todos os pedidos de um usuário possam ser distribuídos em um fragmento da tabela. Isso pode evitar a introdução de transações distribuídas.

Se dissermos que a dimensão não é o usuário, mas outras dimensões, por exemplo, queremos consultar os pedidos de todos os usuários de um determinado estabelecimento comercial .

Então, devemos usar o merchantId do comerciante para armazenar uma cópia dos dados. Ao rotear, use o ID do comerciante para rotear. Contanto que seja um pedido do usuário deste comerciante, nós o gravamos na tabela de pedidos do comerciante. Depois, para o pedido a que o comerciante pertence, nós Ele pode ser obtido a partir de um fragmento.

Use um diagrama para expressar a descrição acima claramente:

Para os usuários, a função da chave de fragmentação é a seguinte:
usertable.png

Para comerciantes, a função da chave de
fragmento é a seguinte: merchanttable.png

Portanto, nossa conclusão é: devemos escolher de acordo com os requisitos do cenário de negócios, analisar os problemas específicos em detalhes e tentar garantir que nenhuma transação distribuída seja introduzida para melhorar a eficiência da consulta.

Além disso, para a abordagem convencional, se você precisar de consultas complexas, seja de gravação dupla com base em dimensões diferentes, ou poderá consultar diretamente introduzindo um método heterogêneo, como o uso de pesquisa elástica ou hive.

4. Ao inserir dados em lotes, ele irá inserir em cada sub-banco de dados, seja para fazer transações distribuídas em negócios reais

A terceira questão mais ou menos também mencionou a resposta a esta questão.

No processo de implementação de sub-banco de dados e tabela, devemos tentar evitar a introdução de transações distribuídas .

Porque a partir da terceira pergunta acima, você verá que se tivermos uma chave de roteamento, o problema é muito mais simples. Na maioria dos casos, não precisamos introduzir transações distribuídas, mas será doloroso se não o fizermos.

Para inserções fora de ordem e a necessidade de garantir cenários transacionais de inserção, transações distribuídas são necessárias. Mas isso é muito ineficiente e inapropriado.

Em primeiro lugar, não há muitos cenários para a inserção fora de ordem. Em segundo lugar, se forem introduzidas transações distribuídas, a força das transações não é pequena e tem um impacto significativo no desempenho da inserção. Não é a melhor maneira.

Minha sugestão é fazer isso com base na consistência eventual. Caso contrário, a introdução de transações distribuídas afetará muito a eficiência e aumentará a complexidade do sistema. Acho que o objetivo do nosso sistema de design é que não precisamos de soluções complicadas. Se você tem tempo para tomar chá, por que não fazer outra coisa.

Portanto, a conclusão desta questão é: tente evitar transações distribuídas, se você tem que introduzi-las, você precisa minimizar o escopo e a intensidade das transações. Por meio de compromisso, considere mais sobre a viabilidade do esquema. O
desempenho é muito importante. Pode ser feito sem transações distribuídas. Como fazê-lo é por meio de eventual consistência.

No entanto, se você disser "Não consigo evitar transações distribuídas, o que devo fazer". Em seguida, use-o, se não for necessário, não aumente a entidade. Se você tiver que usar, é só usar, nada a dizer.

5. Se houver muitas tabelas em uma biblioteca, e uma tabela for dividida em tabelas, como colocar as tabelas sem dividir as tabelas e as tabelas? É atribuído a uma determinada biblioteca no ramo?

Essencialmente: Este é um problema de distribuição de dados de sub-banco de dados e subtabela e dados de sub-banco de dados e subtabela.

Na verdade, o middleware para sub-bancos de dados e subtabelas geralmente tem funções correspondentes. Essa função é frequentemente chamada de regras de roteamento padrão . Como você a entende?

Ou seja, para essas tabelas sem sub-bancos de dados e subtabelas, as regras de roteamento padrão são  suficientes, de forma que sempre será roteado para o DataSource padrão.

É equivalente a uma lista de permissões. Encontre a documentação do middleware para ver como as regras de roteamento padrão são configuradas. Basicamente, o middleware considera esse problema. Para o ShardingSphere, um exemplo de configuração é o seguinte:

CustomerNoShardingDBAlgorithm
    default-table-strategy: (缺省表分区策略)
        complex:
        sharding-columns: db_sharding_id
        algorithm-class-name: com.xxx.XxxClass
    tables:
        ops_account_info: (必须要配置这个,才能使用缺省分表策略)
        actual-data-nodes: db-001.ops_account_info

Para dar um exemplo detalhado, por exemplo:

Quando um serviço é um sub-banco de dados no banco de dados original (por exemplo, o banco de dados do usuário é dividido em user01 e user02), isso força as tabelas não distribuídas a serem roteadas para um determinado banco de dados (por exemplo, rotear as não distribuídas tabelas para user01)?

A essência mencionada aqui é: Regras de roteamento padrão, só precisamos configurar algumas tabelas para seguir as regras de roteamento padrão. Por exemplo, agora temos a tabela de usuário, tabela de pedido e tabela de configuração. Entre elas, a tabela de usuário e o pedido sub-banco de dados subtabela e config não tem sub-banco de dados e subtabela.

Então, só precisamos colocar a tabela de configuração na biblioteca 0, 1 biblioteca, 2 biblioteca da biblioteca do usuário, em qualquer lugar,

Depois de colocá-lo no lugar, precisamos apenas configurar as regras de roteamento padrão no arquivo de configuração do sub-banco de dados e do middleware da subtabela, e especialmente configurar a tabela de configuração, basta verificar a tabela de configuração e ir para a biblioteca especificada.

Outros são semelhantes, desde que haja tal demanda, adicione a configuração correspondente.

Você deve informar explicitamente ao middleware quais tabelas não seguem as regras de roteamento e onde essas tabelas são colocadas.
É melhor colocá-las em uma biblioteca com uma pequena quantidade de solicitação ou você pode construir uma biblioteca separadamente. A biblioteca coloca tabelas que não executam subtabelas de sub-banco de dados
e não configura regras de roteamento para serem feitas; na verdade, ainda são as regras de roteamento padrão.

Por que você faz isso? Qual é a intenção?

Meu entendimento é: a razão pela qual dividimos o banco de dados e as tabelas é porque a solicitação é muito grande e a simultaneidade precisa ser reduzida; e para as tabelas com baixa frequência de solicitação, podemos usar a tabela sem dividir o banco de dados e a tabela ou usá-lo em uma única tabela, então podemos apenas configurá-lo como a regra de roteamento padrão.

8. Processo de migração de dados e como garantir a consistência dos dados

Em um resumo simples, a migração de dados depende da gravação dupla dos dados; a consistência dos dados depende da verificação da integridade dos dados.

Para a migração, temos as seguintes etapas:

Conversa aleatória sobre o sub-banco de dados e a tabela de rotinas distribuídas

 

  1. Modifique o código primeiro, adicione o código da subtabela de sub-banco de dados de gravação dupla; vá online
  2. Inicie a gravação dupla de dados, dados incrementais síncronos; gravação dupla, o objetivo principal é recuperar os dados em tempo real, um prazo para a quantidade total de dados síncronos, para garantir que os dados após esse tempo estejam completos (no ao mesmo tempo, por meio de verificação de integridade de dados assíncrona O programa verifica a integridade dos dados, mas se pudermos garantir a confiabilidade da escrita dupla, essa comparação pode ser feita ou não. É melhor fazê-lo)
  3. Sincronize a quantidade total de dados históricos e verifique a integridade dos dados; geralmente, a quantidade total de dados é sincronizada e não precisa ser gravada de forma síncrona. O motivo é que a gravação síncrona tem um alto grau de acoplamento de código e um impacto sobre o sistema. Portanto, geralmente escrevemos de maneira assíncrona e esse processo é ilustrado no texto a seguir;
  4. Remova o código de gravação dupla e consulte a lógica completa do sub-banco de dados e subtabela;
    por meio da chave, mude para o sub-banco de dados de leitura / gravação completa e a lógica da subtabela após a sincronização de dados completa ser concluída. Neste momento, a lógica antiga não tem roteamento de solicitação. Precisamos apenas encontrar uma janela de liberação para desligar a lógica antiga. Neste momento, a linha foi completamente migrada para o fluxo de código do sub-banco de dados e subtabela.

Enfim, quero dizer que devemos voltar, devemos retornar, devemos retornar! ! !

Link original: http://wuwenliang.net/2021/01/09/ Rotinas distribuídas: Discutindo o Sub-banco de dados e a Subtabela /

Se você acha que este artigo é útil para você, pode seguir minha conta oficial e responder à palavra-chave [Entrevista] para obter uma compilação de pontos de conhecimento do núcleo de Java e um pacote de presente para entrevista! Existem mais artigos técnicos e materiais relacionados para compartilhar. Deixe que todos aprendam e progridam juntos!

Acho que você gosta

Origin blog.csdn.net/weixin_48182198/article/details/112436867
Recomendado
Clasificación