Clusters elásticos no servidor flexível do Base de Dados do Azure para PostgreSQL

Os clusters elásticos no serviço Banco de Dados do Azure para PostgreSQL são uma oferta gerenciada da extensão de código aberto do Citus para o PostgreSQL que permite a fragmentação horizontal do PostgreSQL.

Embora o Citus seja apenas uma extensão, ele conecta várias instâncias do PostgreSQL. Quando implementa um servidor flexível Base de Dados do Azure para PostgreSQL com Citus, ele gere e configura múltiplas instâncias PostgreSQL como um único recurso. Ele também configura automaticamente os nós e os torna conhecidos para a extensão Citus.

Os clusters elásticos no serviço oferecem dois modelos de fragmentação: fragmentação baseada em linha e fragmentação baseada em esquema. Para saber mais, consulte a documentação open-source sobre modelos de sharding.

Architecture

Um cluster elástico consiste em um ou mais nós de servidores flexíveis do Base de Dados do Azure para PostgreSQL. Estas instâncias descobrem-se automaticamente e interligam-se para formar um cluster Citus. Os nós devem ser do mesmo nível de computação e armazenamento, e podes escalá-los uniformemente para cima ou para baixo para níveis superiores ou inferiores.

Os clusters elásticos usam instâncias de servidores flexíveis (chamados nós) para coordenar uns com os outros em uma arquitetura de "nada compartilhado". A arquitetura também permite que o banco de dados seja dimensionado, adicionando mais nós ao cluster.

Clusters elásticos usam servidores flexíveis (chamados nós) para coordenarem entre si numa arquitetura de nada partilhado . A arquitetura também permite que o banco de dados seja dimensionado adicionando mais nós ao cluster.

Ao contrário do Cosmos DB para PostgreSQL, os endereços dos nós não são expostos externamente. Se olhar para tabelas de metadados do Citus, como a pg_dist_node, poderá notar que todos os nós têm o mesmo endereço IP, tal como no exemplo 10.7.0.254, mas portas diferentes.

select nodeid, nodename, nodeport from pg_dist_node;
 nodeid |  nodename  | nodeport
--------+------------+----------
      1 | 10.7.0.254 |     7000
      2 | 10.7.0.254 |     7001
 
(2 rows)

Na infraestrutura do Azure, esses nós vivem em máquinas virtuais diferentes, mesmo que pareçam ser portas diferentes na mesma máquina.

Para saber mais sobre o Citus, consulte a documentação oficial do projeto open-source.

Por padrão, as tabelas e esquemas criados com o Citus não são distribuídos automaticamente entre o cluster. Você precisa decidir sobre um modelo de fragmentação e decidir distribuir esquemas ou decidir distribuir os dados da tabela com fragmentação baseada em linha.

Para cada consulta em tabelas distribuídas, o nó que recebe a consulta encaminha-a para um único nó ou paraleliza-a por vários nós. A decisão depende se os dados necessários residem em um único nó ou em vários. Com a fragmentação baseada em esquema, o coordenador roteia as consultas diretamente para o nó que hospeda o esquema. Em ambos os casos, na fragmentação baseada em esquema e na fragmentação baseada em linha, o nó decide o que fazer consultando as tabelas de metadados. Essas tabelas rastreiam a localização e a integridade dos nós e a distribuição de dados entre nós.

Depois que os dados são distribuídos usando um dos modelos de fragmentação, você pode se conectar a qualquer um dos nós para executar operações DML (Data Modification Language) (SELECT, UPDATE, INSERT, DELETE). Todos os nós contêm os metadados necessários para localizar os dados necessários para a consulta e são capazes de obtê-los para responder à consulta.

As operações DDL (Data Definition Language) e as operações em todo o cluster estão atualmente limitadas ao nó que detém a função de coordenador. Certifique-se de executar operações DDL e em todo o cluster conectando-se à porta 5432, em vez de usar a porta 7432.

Você pode expandir um cluster elástico adicionando novos nós e reequilibrando os dados nele. O rebalanceamento é uma operação online e não bloqueia cargas de trabalho em execução.

Fragmentos

A seção anterior descreveu como as tabelas distribuídas são armazenadas como fragmentos em nós de trabalho. Esta seção discute mais detalhes técnicos sobre esses fragmentos.

A pg_dist_shard tabela de metadados contém uma linha para cada fragmento de cada tabela distribuída no sistema. A linha faz corresponder um identificador de fragmento (shardid) a um intervalo de números inteiros num espaço de hash (shardminvalue, shardmaxvalue).

SELECT * from pg_dist_shard;
logicalrelid  | shardid | shardstorage | shardminvalue | shardmaxvalue
---------------+---------+--------------+---------------+---------------
 github_events |  102026 | t            | 268435456     | 402653183
 github_events |  102027 | t            | 402653184     | 536870911
 github_events |  102028 | t            | 536870912     | 671088639
 github_events |  102029 | t            | 671088640     | 805306367
 
 (4 rows)

Se o nó quiser determinar que fragmento contém uma linha de github_events, calcula o hash do valor da coluna de distribuição nessa linha. Em seguida, o nó verifica qual intervalo do fragmento contém o valor em hash. Os intervalos são definidos de modo a que a imagem da função hash seja a união disjunta.

Posicionamentos de estilhaços

Suponha que o estilhaço 102027 esteja associado à linha em questão. A linha é lida ou escrita em uma tabela chamada github_events_102027 em um dos trabalhadores. Ao utilizar a informação armazenada nas tabelas de metadados, a extensão determina qual trabalhador específico utilizar. O mapeamento de fragmento para trabalhador é conhecido como colocação de fragmento.

O nó reescreve consultas em fragmentos que se referem às tabelas específicas como github_events_102027 e executa esses fragmentos nos trabalhadores apropriados. Aqui está um exemplo de uma consulta executada nos bastidores para encontrar o nó que contém o fragmento com o identificador 102027.

SELECT
    shardid,
    node.nodename,
    node.nodeport
FROM pg_dist_placement placement
JOIN pg_dist_node node
  ON placement.groupid = node.groupid
 AND node.noderole = 'primary'::noderole
WHERE shardid = 102027;
┌─────────┬───────────┬──────────┐
│ shardid │ nodename  │ nodeport │
├─────────┼───────────┼──────────┤
│  102027 │ localhost │     5433 │
└─────────┴───────────┴──────────┘