Figura 26.1. Armazenamento compartilhado usando NAS (network attached storage)
A comutação (failover) [146] em armazenamento compartilhado evita a sobrecarga de sincronização por existir apenas uma única cópia da base de dados. É usado um único conjunto de discos [147], compartilhado por vários servidores. Se o servidor de banco de dados primário falhar, o servidor secundário poderá montar o armazenamento e iniciar o banco de dados como se estivesse se recuperando de uma falha no servidor de banco de dados. Isto permite uma comutação rápida (failover) sem perda de dados.
A funcionalidade de hardware compartilhado é comum em dispositivos de armazenamento de rede. Também é possível usar um sistema de arquivos de rede, embora seja necessário tomar cuidado para que o sistema de arquivos tenha o comportamento POSIX completo (veja NFS). Uma limitação significativa desse método é que, se o conjunto de discos falhar, ou se tornar corrompido, os servidores primário e secundário não vão funcionar. Outro problema é que o servidor secundário nunca deve acessar o armazenamento compartilhado enquanto o servidor primário estiver em execução.
Figura 26.2. Replicação do sistema de arquivos usando DRBD
Uma versão modificada da funcionalidade de hardware compartilhado é a replicação do sistema de arquivos, em que todas as alterações em um sistema de arquivos são espelhadas em um sistema de arquivos residente em outro computador. A única restrição é que o espelhamento deve ser feito de forma a garantir que o servidor secundário tenha uma cópia consistente do sistema de arquivos — especificamente, as escritas no servidor secundário devem ser feitas na mesma ordem daquelas no servidor primário. O DRBD (Distributed Replicated Block Device) é uma solução popular de replicação de sistema de arquivos para o Linux.
Figura 26.3. Tipos de replicação no PostgreSQL
Os servidores em-espera Warm-standby e Hot-standby podem ser mantidos atualizados pela leitura de um fluxo de registros de escrita antecipada (WAL). Se o servidor primário falhar, o servidor em-espera conterá quase todos os dados do servidor primário, podendo ser rapidamente transformado no novo servidor de banco de dados primário. Pode ser síncrono ou assíncrono, mas só pode ser feito para todo o servidor de banco de dados.
O servidor em-espera pode ser implementado usando o envio de registros de escrita antecipada (WAL) baseado em arquivo (Servidores em-espera de envio de WAL), ou por fluxo (veja Replicação por fluxo), ou uma combinação dos dois. Para obter informações sobre hot-standby, veja Servidor em-espera ativo (Hot Standby).
A replicação lógica permite que um servidor de banco de dados envie um fluxo de modificações de dados para outro servidor. A replicação lógica do PostgreSQL constrói um fluxo de modificações de dados lógicos do WAL. A replicação lógica permite a replicação de modificações de dados por tabela. Além disso, um servidor que está publicando suas próprias alterações também pode subscrever alterações de outro servidor, permitindo que os dados fluam em várias direções. Para obter mais informações sobre replicação lógica, veja Replicação lógica. Por meio da interface de decodificação lógica (Logical Decoding), as extensões de terceiros também podem fornecer uma funcionalidade semelhante.
Uma configuração de replicação baseada em gatilho normalmente encadeia as instruções de modificação de dados de um servidor primário específico. Operando por tabela, o servidor primário envia as alterações de dados (normalmente) de forma assíncrona para os servidores secundários. Os servidores secundários podem executar as instruções que recebem enquanto o servidor primário está em execução, e podem permitir algumas alterações de dados locais, ou mesmo atividade de escrita. Esta forma de replicação é geralmente usada para gerir grandes consultas analíticas, ou do tipo de armazém de dados.
O Slony-I é um exemplo desse tipo de replicação, com granularidade por tabela e suporte para vários servidores secundários. Como atualiza o servidor secundário de forma assíncrona (em lotes), existe a possibilidade de perda de dados durante a comutação de servidores (failover).
Figura 26.4. Middleware em arquitetura cliente-servidor
Com o middleware [148] de replicação baseado em SQL, um programa intercepta todas as instruções SQL e as envia para um ou para todos os servidores. Cada servidor opera de forma independente. As instruções de leitura/escrita devem ser enviadas a todos os servidores, para que cada servidor realize as alterações. Mas instruções de leitura-apenas podem ser enviadas para somente um servidor, permitindo que a carga de trabalho de leitura seja distribuída entre eles
Se as instruções forem simplesmente transmitidas sem modificação,
funções como random(),
CURRENT_TIMESTAMP e sequências podem ter
valores diferentes em servidores diferentes.
Isto acontece porque cada servidor opera de forma independente,
e porque são transmitidas as instruções SQL
em vez dos dados modificados.
Se isto for inaceitável, o middleware,
ou a aplicação, deve determinar estes valores de uma única fonte e,
em seguida, usar estes valores em instruções de escrita.
Também deve-se tomar cuidado para que todas as transações sejam
efetivadas ou desfeitas em todos os servidores, talvez usando a
efetivação de duas fases (PREPARE TRANSACTION
e COMMIT PREPARED).
O Pgpool-II e o Continuent Tungsten
são exemplos desse tipo de replicação.
Para servidores que não estão conectados regularmente, ou têm conexões de comunicação lentas, como laptops ou servidores remotos, manter a consistência dos dados entre os servidores é um desafio. Usando a replicação multi-mestre assíncrona cada servidor funciona de forma independente, e se comunica periodicamente com os outros servidores para identificar transações conflitantes. Os conflitos podem ser resolvidos por usuários ou regras de resolução de conflitos. Bucardo é um exemplo desse tipo de replicação.
Na replicação multi-mestre síncrona, cada servidor pode aceitar
instruções de escrita, e os dados modificados são transmitidos
do servidor original para todos os outros servidores antes de
cada transação ser efetivada.
A atividade intensa de escrita pode causar travamento excessivo e
atrasos de efetivação, levando a um desempenho ruim.
As instruções de leitura podem ser enviadas para qualquer servidor.
Algumas implementações usam disco compartilhado para reduzir
a sobrecarga de comunicação.
A replicação multi-mestre síncrona é melhor para cargas de trabalho
principalmente de leitura, embora sua grande vantagem seja que
qualquer servidor pode aceitar solicitações de escrita —
não há necessidade de particionar cargas de trabalho entre
servidores primários e secundário e, como as alterações de dados
são enviadas de um servidor para outro, não há problema com funções
não determinísticas como random().
O PostgreSQL não oferece este tipo de replicação, embora a efetivação em duas-fases do PostgreSQL (PREPARE TRANSACTION e COMMIT PREPARED) possa ser usada para implementar isto no código da aplicação ou no middleware.
A Tabela 26.1 e a Tabela 26.2 resumem os recursos das várias soluções listadas acima.
Tabela 26.1. Matriz de funcionalidades de alta disponibilidade, balanceamento de carga e replicação (I)
| Funcionalidade | Armazenamento compartilhado | Replicação do sistema de arquivos | Envio de WAL | Replicação lógica |
|---|---|---|---|---|
| Exemplos populares | NAS | DRBD | replicação nativa por fluxo | replicação nativa lógica, pglogical |
| Método comum | armazenamento compartilhado | blocos de disco | WAL | decodificação lógica |
| Nenhum hardware especial necessário | ✓ | ✓ | ✓ | |
| Permite vários servidores primários | ✓ | |||
| Sem sobrecarga no primário | ✓ | ✓ | ✓ | |
| Sem espera por vários servidores | ✓ | com sync inativo | com sync inativo | |
| Falha no primário nunca perde dados | ✓ | ✓ | com sync ativo | com sync ativo |
| As réplicas aceitam instruções de leitura-apenas | com “hot-standby” | ✓ | ||
| Granularidade por tabela | ✓ | |||
| Resolução de conflito não é necessária | ✓ | ✓ | ✓ |
Tabela 26.2. Matriz de funcionalidades de alta disponibilidade, balanceamento de carga e replicação (II)
| Funcionalidade | Replicação baseada em gatilho | Middleware baseado em SQL | Replicação multi-mestre assíncrona | Replicação multi-mestre síncrona |
|---|---|---|---|---|
| Exemplos populares | Londiste, Slony | pgpool-II | Bucardo | |
| Método comum | linhas da tabela | SQL | linhas da tabela | linhas da tabela e bloqueios de linha |
| Nenhum hardware especial necessário | ✓ | ✓ | ✓ | ✓ |
| Permite vários servidores primários | ✓ | ✓ | ✓ | |
| Sem sobrecarga no primário | ✓ | |||
| Sem espera por vários servidores | ✓ | ✓ | ||
| Falha no primário nunca perde dados | ✓ | ✓ | ||
| As réplicas aceitam instruções de leitura-apenas | ✓ | ✓ | ✓ | ✓ |
| Granularidade por tabela | ✓ | ✓ | ✓ | |
| Resolução de conflito não é necessária | ✓ | ✓ | ✓ |
Existem algumas soluções que não se enquadram nas categorias acima:
O particionamento de dados divide as tabelas em conjuntos de dados. Cada conjunto pode ser modificado por apenas um servidor. Por exemplo, os dados podem ser particionados por escritórios, como Florianópolis e Belém, com um servidor em cada escritório. Se forem necessárias instruções combinando dados de Florianópolis e Belém, a aplicação pode consultar os dois servidores, ou pode ser usada uma replicação primário/secundário para manter uma cópia de leitura-apenas dos dados do outro escritório em cada servidor.
Muitas das soluções acima permitem que vários servidores lidem com várias consultas, mas nenhuma permite que uma única consulta use vários servidores para concluir mais rapidamente. Esta solução permite que vários servidores trabalhem simultaneamente em uma única consulta. Geralmente, isto é feito dividindo os dados entre os servidores, e fazendo com que cada servidor execute sua parte da consulta e retorne os resultados a um servidor central, onde os resultados são combinados e devolvidos ao usuário. Isto pode ser implementado usando o conjunto de ferramentas PL/Proxy.
Também deve-se notar que, como o PostgreSQL é um software de código aberto e facilmente estendido, várias empresas adotaram o PostgreSQL e criaram soluções comerciais de código fechado com recursos próprios de failover, replicação e balanceamento de carga. Estas soluções não são discutidas aqui.
[146] fail over: Em um sistema de computador, significa comutar automaticamente para um componente sobressalente, de backup, ou alternativo, quando outro falha. TheFreeDictionary (N. T.)
[147] RAID é um meio de se criar um subsistema de armazenamento composto por vários discos individuais, com a finalidade de ganhar segurança – por meio da redundância de dados – e desempenho. Wikipédia – RAID (N. T.)
[148] middleware: software que serve como intermediário entre o software de sistemas e uma aplicação. TheFreeDictionary (N. T.)