Передача данных между двумя серверами PostgreSQL
У меня есть два сервера PostgreSQL, один централизованный и один периферийный. Идея состоит в том, чтобы периферийный сервер накапливал данные от различных процессов, работающих на одной машине. Периодически (возможно, ежечасно или около того) данные отправляются с периферийного сервера на централизованный сервер. После подтверждения успешного сервера периферийный сервер будет стирать содержимое, чтобы поддерживать его реализацию как можно более легким.
Хотя изначально это довольно простой сценарий, в котором существует множество существующих решений, я уверен, что есть несколько факторов, которые ограничивают мои возможности:
Связь между периферийным и централизованным серверами может быть разорвана на несколько дней, и в этом случае он просто сохранит все данные и попытается вместо этого повторить следующую запланированную передачу с вдвое большим объемом данных.
Крайне важно, чтобы никакие записи не дублировались, поэтому важно, чтобы удаленные записи точно соответствовали переданным записям.
Вероятно, что во время передачи периферийный сервер накапливает дополнительные данные, поэтому удаление и повторное создание таблицы невозможно, поскольку это приведет к удалению некоторых записей, которые еще не были переданы.
Я смотрел на это с нескольких точек зрения и пришел к выводу, что я, скорее всего, пытаюсь изобрести колесо здесь, поскольку существуют различные методы, которые почти соответствуют моим потребностям. Поэтому я решил сделать несколько шагов назад, чтобы увидеть, какие предложения для этого сценария возникают. Мои вопросы тогда:
Какой метод перевода рекомендуется, если ссылка ненадежна?
Какие есть способы проверки перевода?
Как убедиться, что удаленная дата точно соответствует переданным данным, когда периферийная база данных все еще накапливает данные во время передачи?
Использование postgresql 9.4.9 в Debian.
Грубый набросок идеи:
Стол имеет
serial
столбец, который отслеживает идентификатор записи.pg_dump
данные в файл. Вышеупомянутый серийный номер используется в имени файла, в основном "это содержит все записи изX
и кY
"dumpfile копируется на централизованный сервер через rsync или тому подобное.
Централизованный сервер загружает данные и каким-то образом отправляет подтверждение обратно на периферийный сервер, содержащий серийный номер. Попробуйте повторить это несколько раз, чтобы дубликаты не передавались позже.
периферийный сервер уничтожает все данные, относящиеся к проверенным сериалам.
Какие-нибудь мысли?
1 ответ
Ваш предложенный подход является разумной отправной точкой, но ошибочным в первом пункте. Вы подразумеваете, что serial
столбец предлагает некоторую надежную границу упорядочения. Это не так.
- Txn 1 начинается
- Txn 2 начинается
- Txn 1 получает серийный номер 4
- Txn 2 получает серийный номер 5
- Txn 2 фиксирует
- Txn 3 начинается
- Txn 3 копирует данные
- Txn 3 замечает, что наибольшее подтвержденное значение равно 5
- Txn 1 фиксирует
- Txn 3 удаляет все данные с идентификатором <= 5
К сожалению. Txn 3 удалил id=4, но он не был бы скопирован. Этот конкретный случай исправляется с помощью txn3 SERIALIZABLE
, но если вместо этого Txn3 фиксирует, а некоторые другие tx txn4 выполняет удаление, проблема возвращается.
Чтобы быть в безопасности, вы должны добавить барьер где-то между 5 и 7, где вы LOCK TABLE ... IN EXCLUSIVE MODE
и ждать, пока замок не будет получен. Это гарантирует, что нет выдающихся записей, все совершено. Теперь вы можете верить, что никакое значение ниже, чем наибольшее значение, не может быть зафиксировано позже.
Из другого (недавно начатого) xact, вы тогда pg_export_snapshot
,
После экспорта снимка вы можете откатить действие xact, принявшее блокировку, и позволить продолжить запись.
Оставьте xact, который экспортировал снимок, открытым. Передать идентификатор снимка pg_dump
с --snapshot
, поэтому он сбрасывает данные точно с той точки виртуального времени, когда вы знаете самый высокий зафиксированный идентификатор. Вы должны держать xact с открытым снимком, пока дамп не завершится, но запись может продолжаться в это время.
Теперь вы можете безопасно DELETE FROM ... WHERE id < x
для значения x
Вы подняли глаза, удерживая замок. Вы знаете, что из-за экспортированного снимка вы ничего не сделали с более высоким ID. И вы знаете, из-за блокировки, что вы не пропустите ничего, что фиксирует позже с более низким ID.
Кажется сложным?
Вместо этого я предлагаю использовать функции логического декодирования PostgreSQL. Инструмент pglogical, который использует логическое декодирование, имеет функции, которые делают то, что вы хотите сделать, относительно легко; это избавляет от проблем с упорядочением и гарантирует, что строки реплицируются ровно один раз. Это легко настроить для репликации вставок, но не для удаления, так что вы можете просто DELETE FROM mytable
время от времени.
(Конечно, я являюсь частью команды разработчиков для pglogical и связанного с ним инструмента BDR, поэтому я предвзято).
Основная проблема, с которой вы, вероятно, столкнетесь, заключается в том, что вам придется сохранять больше данных, потому что вам нужно сохранить WAL, а не только содержимое таблицы. (Технически вы можете на самом деле DELETE
данные, как только это INSERT
и он будет хорошо копироваться, но вы, вероятно, не захотите этого делать). Так что, если дисковое пространство является проблемой, вы можете предпочесть подход дампа. Но в pglogical3 появятся некоторые значительные улучшения, которые устранят эту проблему.