Что я пытаюсь сделать
Я занимаюсь разработкой веб-службы, которая работает в нескольких экземплярах сервера, все из которых обращаются к одной и той же СУБД (PostgreSQL). Хотя база данных необходима для постоянства, она содержит очень мало данных, поэтому каждый экземпляр сервера имеет кэш всех данных. Кроме того, приложение действительно простое в том, что оно только когда-либо вставляет новые строки в довольно простые таблицы и выбирает эти данные по расписанию из всех экземпляров сервера (без обновлений или изменений ... только вставки и чтения).
Как это в настоящее время реализовано
В основном у меня есть таблица, которая выглядит примерно так:
id BIGSERIAL,
creation_timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
-- further data columns...
Сервер делает что-то подобное каждые пару секунд (псевдокод):
get all rows with creation_timestamp > lastMaxTimestamp
lastMaxTimestamp = max timestamp for all data just retrieved
insert new rows into application cache
Проблема, с которой я сталкиваюсь
Приложение пропускает определенные строки при обновлении кэшей. Я проанализировал проблему и выяснил, что проблема вызвана следующим образом:
- один экземпляр сервера создает новую строку в контексте транзакции. Идентификатор для новой строки извлекается из связанной последовательности (id = n), и устанавливается creation_timestamp (со значением ts_1).
- другой сервер делает то же самое в контексте другой транзакции. Новая строка в этой транзакции получает id = n + 1 и creation_timestamp ts_2 (где ts_1
- транзакция 2 завершается до транзакции 1
- , когда один из серверов выполняет «выбрать все» строки с creation_timestamp> lastMaxTimestamp ". Он получает строку n + 1, но не n1. Он устанавливает для lastMaxTimestamp значение ts_2.
- транзакция 1 завершается
- , и через некоторое время сервер из шага 4 снова выполняет «выбрать все строки с creation_timestamp> lastMaxTimestamp». Но поскольку lastMaxTimestamp = ts_2 и ts_2> ts_1, строка n никогда не будет считываться на этом сервере.
Примечание: CURRENT_TIMESTAMP имеет одинаковое значение во время транзакции, то есть время начала транзакции.
Таким образом, приложение получает несогласованные данные в свой кэш и не может получать новые строки на основе метки времени вставки ИЛИ на основе идентификатора последовательности. Уровни изоляции транзакций в действительности ничего не меняют в ситуации, так как проблема в сущности создается завершением транзакции 2 до транзакции 1.
Мой вопрос
Я что-то упустил? Я думаю, что должен быть простой способ получить все новые строки СУБД, но я не могу найти простое решение ... по крайней мере, простое решение, которое является последовательным. Обширная блокировка (например, таблиц) не будет приемлемой из-за соображений производительности. Простая попытка обеспечить получение всех идентификаторов из этой последовательности кажется а) сложным решением и б) не может быть легко осуществлена, поскольку могут произойти откаты во время транзакций (что приведет к тому, что идентификаторы последовательности не будут использоваться).
У кого-нибудь есть решение?