Безопасно ли присоединять таблицу "pg_locks" в производственном коде? - PullRequest
1 голос
/ 14 февраля 2020

У меня есть таблица типа очереди t1, содержащая данные, упорядоченные по меткам времени. Один из его столбцов - внешний ключ ext_id. У меня есть ряд работников, которые обрабатывают строки из t1 и удаляют их после выполнения своей работы. Результатом процесса является добавление строк в другую таблицу t2. t2 также ссылается на ext_id, но в этом случае отношение является уникальным: если строка, указывающая на конкретный ext_id, уже существует, я хочу обновить ее вместо вставки.

Пока один работник обрабатывает Задача данных довольно проста. Когда в игру вступают несколько рабочих, на помощь приходит условие SKIP LOCKED: каждый поток блокирует строку, которую он обрабатывает, и делает ее невидимой для других потоков. Предложение SKIP LOCKED гарантирует, что потоки не мешают друг другу с точки зрения исходной таблицы t1. Проблема в том, что они все еще могут попытаться одновременно вставить строки в таблицу t2. Поскольку существует ограничение уникальности t2, это может привести к ошибке, если несколько работников выберут t1 строк с общим ext_id. Так как ограничение вызывает ошибку, я могу просто повторить попытку обработки определенной строки, но тогда я теряю гарантию порядка обработки (не говоря уже о том, что управление потоком на основе исключений выглядит как серьезный анти-шаблон).

Я рассмотрел добавление вспомогательная таблица «синхронизации» (назовем ее sync), которая будет содержать запись для каждого ext_id, обрабатываемого в данный момент. Затем обработка усложняется: мне нужно зафиксировать sync вставку строки перед тем, как фактически начать обработку, чтобы другие потоки могли использовать эту информацию для выбора t1 строк, которые безопасны для обработки. t1 выбор строки может присоединиться к вспомогательной таблице и соответствовать первой строке, в которой ext_id отсутствует в таблице sync. Возможно, что параллельные потоки будут выбирать последовательные строки и пытаться вставить строки синхронизации, указывающие на один и тот же ext_id. Если это произойдет, мне нужно повторить t1 выбор строки.

Второй подход решает параллельную обработку конфликтующих t1 строк и гарантирует, что порядок строк поддерживается (в пределах разделов, определенных значениями ext_id). Чего она не может решить, так это грязной структуры управления потоком, основанной на неудачных вставках.

PostgreSQL предоставляет механизм консультативных блокировок, который позволяет создавать специфичные для приложения c пользовательские журналы синхронизации c.

Цитата из документация по явной блокировке :

Например, общепринятым использованием консультативных блокировок является эмуляция пессимистических c стратегий блокировки, типичных для так называемого «плоского файла» системы управления данными. Хотя флаг, хранящийся в таблице, можно использовать для той же цели, консультативные блокировки быстрее, избегают раздувания таблиц и автоматически очищаются сервером в конце сеанса.

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

Это намного лучше, но в некоторых случаях он запрещает подгруппе работников выполнять свои задачи одновременно и заставляет их ждать выполнения задач в последовательности. Вместо того чтобы ждать, эти работники могут попытаться получить другую строку: то, что решение на основе sync решается путем исключения t1 строк с использованием внешнего соединения.

После этого длинного введения, наконец, возникает вопрос:

Существующие консультативные блокировки можно проверить, запросив pg_locks view. Это представление может быть объединено как регулярное отношение в запросах. Соблазнительно присоединиться к нему при получении следующей строки t1, чтобы исключить строки, которые в настоящее время не могут быть обработаны из-за существующей блокировки. Поскольку pg_locks не является обычной таблицей, я сомневаюсь, что этот подход безопасен.

Это так?

...