25.1. Сравнение различных решений

Отказоустойчивость на разделяемых дисках

Отказоустойчивость на разделяемых дисках позволяет избежать избыточности синхронизации путём задействования только одной копии базы данных. Она использует единственный дисковый массив, который разделяется между несколькими серверами. Если основной сервер БД откажет, резервный сервер может подключиться и запустить базу данных, что позволит восстановить БД после аварии. Это обеспечивает быстрое переключение без потери данных.

Функциональность разделяемого оборудования обычно реализована в сетевых устройствах хранения. Так же возможно применение сетевой файловой системы, особое внимание следует уделить тому, чтобы поведение системы полностью соответствовало POSIX (см. Подраздел 17.2.1). Существенное ограничение этого метода состоит в том, что в случае отказа или порчи разделяемого дискового массива оба сервера: ведущий и резервный — станут нерабочими. Другая особенность — резервный сервер никогда не получает доступ к разделяемым дискам во время работы ведущего.

Репликация на уровне файловой системы (блочного устройства)

Видоизменённая версия функциональности разделяемого оборудования представлена в виде репликации на уровне файловой системы, когда все изменения в файловой системе отражаются в файловой системе другого компьютера. Единственное ограничение: синхронизация должна выполняться методом, гарантирующим целостность копии файловой системы на резервном сервере — в частности, запись на резервном сервере должна происходить в том же порядке, что и на главном. DRBD является популярным решением на основе репликации файловой системы для Linux.

Трансляция журнала транзакций

Серверы тёплого и горячего резерва могут так же поддерживаться актуальными путём чтения потока записей из журнала изменений (WAL). Если основной сервер отказывает, резервный содержит почти все данные с него и может быть быстро преобразован в новый главный сервер БД. Это можно сделать синхронно или асинхронно, но может быть выполнено только на уровне сервера БД целиком.

Резервный сервер может быть реализован с применением трансляции файлов журналов (см. Раздел 25.2), или потоковой репликации (см. Подраздел 25.2.5), или их комбинацией. За информацией о горячем резерве обратитесь к Разделу 25.5.

Репликация главный-резервный на основе триггеров

При репликации главный-резервный все запросы, изменяющие данные, пересылаются главному серверу. Главный сервер, в свою очередь, асинхронно пересылает изменённые данные резервному. Резервный сервер может обрабатывать запросы только на чтение при работающем главном. Такой резервный сервер идеален для обработки запросов к хранилищам данных.

Slony-I является примером подобного типа репликации, действующей на уровне таблиц, и поддерживает множество резервных серверов. Так как обновления на резервных серверах происходят асинхронно (в пакетах), возможна потеря данных во время отказа.

Репликация запросов в среднем слое

В схеме с репликацией запросов в среднем слое, средний слой перехватывает каждый SQL-запрос и пересылает его на один или все серверы. Каждый сервер работает независимо. Модифицирующие запросы должны быть направлены всем серверам, чтобы каждый из них получал все изменения. Но читающие запросы могут быть посланы только на один сервер, что позволяет перераспределить читающую нагрузку между всеми серверами.

Если запросы просто перенаправлять без изменений, функции подобные random(), CURRENT_TIMESTAMP и последовательности могут получить различные значения на разных серверах. Это происходит потому что каждый сервер работает независимо, а эти запросы неизбирательные (и действительно не изменяют строки). Если такая ситуация недопустима, или средний слой, или приложение должно запросить подобные значения с одного сервера, затем использовать его в других пишущих запросах. Другим способом является применения этого вида репликации совместно с другим традиционным набором репликации главный-резервный, то есть изменяющие данные запросы посылаются только на главный сервер, а затем применяются на резервном в процессе этой репликации, но не с помощью реплицирующего среднего слоя. Следует иметь в виду, что все транзакции фиксируются или прерываются на всех серверах, возможно с применением двухфазной фиксации (см. PREPARE TRANSACTION и COMMIT PREPARED). Репликацию такого типа реализуют, например Pgpool-II и Continuent Tungsten.

Асинхронная репликация с несколькими главными серверами

Если серверы не находятся постоянно в единой сети, как например, ноутбуки или удалённые серверы, обеспечение согласованности данных между ними представляет проблему. Когда используется асинхронная репликация с несколькими главными серверами, каждый из них работает независимо и периодически связывается с другими серверами для определения конфликтующих транзакций. Конфликты могут урегулироваться пользователем или по правилам их разрешения. Примером такого типа репликации является Bucardo.

Синхронная репликация с несколькими главными серверами

При синхронной репликации с несколькими главными серверами каждый сервер может принимать запросы на запись, а изменённые данные передаются с начального сервера всем остальным, прежде чем транзакция будет подтверждена. Если запись производится интенсивно, это может провоцировать избыточные блокировки, что приводит к снижению производительности. На самом деле производительность при записи часто бывает хуже, чем с одним сервером. Запросы на чтение также могут быть обработаны любым сервером. В некоторых конфигурациях для более эффективного взаимодействия серверов применяются разделяемые диски. Синхронная репликация с несколькими главными серверами лучше всего работает, когда преобладают операции чтения, хотя её большой плюс в том, что любой сервер может принимать запросы на запись — нет необходимости искусственно разделять нагрузку между главным и резервными серверами, а так как изменения передаются от одного сервера другим, не возникает проблем с недетерминированными функциями вроде random().

PostgreSQL не предоставляет данный тип репликации, но так как PostgreSQL поддерживает двухфазное подтверждение транзакции (PREPARE TRANSACTION и COMMIT PREPARED) такое поведение может быть реализовано в коде приложения или среднего слоя.

Коммерческие решения

Так как PostgreSQL обладает открытым кодом и легко расширяется, некоторые компании взяли за основу PostgreSQL и создали коммерческие решения с закрытым кодом со своими реализациями свойств отказоустойчивости, репликации и балансировки нагрузки.

Таблица 25-1 итоговая таблица возможностей различных решений приведена ниже.

Таблица 25-1. Таблица свойств отказоустойчивости, балансировки нагрузки и репликации

ТипОтказоустойчивость через разделяемые дискиРепликация файловой системыТрансляция журнала транзакцийРепликация главный-резервный на основе триггеровРепликация запросов в среднем слоеАсинхронная репликация с несколькими главными серверамиСинхронная репликация с несколькими главными серверами
Наиболее типичная реализацияNASDRBDПотоковая репликацияSlonypgpool-IIBucardo 
Метод взаимодействияразделяемые дискидисковые блокиWALСтроки таблицыSQLСтроки таблицыСтроки таблицы и блокировки строк
Не требуется специального оборудования 
Допускается несколько главных серверов    
Нет избыточности главного сервера    
Нет задержки при нескольких серверах без синхр.  
Отказ главного сервера не может привести к потере данныхс синхр.  
Резервный сервер принимает читающие запросы  с горячим резервом
Репликация на уровне таблиц    
Не требуется разрешение конфликтов  

Несколько решений, которые не подпадают под указанные выше категории:

Секционирование данных

При секционировании таблицы расщепляются на наборы данных. Каждый из наборов может быть изменён только на одном сервере. Например, данные могут быть секционированы по офисам, например, Лондон и Париж, с сервером в каждом офисе. В случае необходимости обращения одновременно к данным Лондона и Парижа, приложение может запросить оба сервера, или может быть применена репликация главный-резервный для предоставления копии только для чтения в другом офисе для каждого из серверов.

Выполнение параллельных запросов на нескольких серверах

Многие из указанных выше решений позволяют обрабатывать несколько запросов на нескольких серверах, но ни один из них не может обрабатывать один запрос с применением нескольких серверов для уменьшения общего времени выполнения. Подобное решение позволяет нескольким серверам обрабатывать один запрос одновременно. Такое обычно достигается путём разделения данных между серверами, обработкой на сервере своей части запроса с возвратом результата на центральный сервер. Там данные проходят окончательную обработку и возвращаются пользователю. Pgpool-II предоставляет такую возможность. Так же это может быть реализовано с применением набора средств PL/Proxy.