Лучшие практики для многопоточной обработки записей базы данных - PullRequest
14 голосов
/ 18 февраля 2009

У меня есть один процесс, который запрашивает таблицу для записей, где PROCESS_IND = 'N', выполняет некоторую обработку, а затем обновляет PROCESS_IND до 'Y'.

Я бы хотел разрешить запуск нескольких экземпляров этого процесса, но не знаю, как лучше всего избегать проблем с параллелизмом.

С чего мне начать?

Ответы [ 5 ]

10 голосов
/ 20 февраля 2009

Шаблон, который я бы использовал, выглядит следующим образом:

  • Создайте столбцы «lockedby» и «locktime», которые являются идентификатором потока / процесса / машины и отметкой времени соответственно (идентификатор машины вам понадобится при разделении обработки между несколькими машинами)
  • Каждая задача будет выполнять запрос, такой как:

    ОБНОВЛЕНИЕ стабильной задачи SET lockedby = (мой идентификатор), locktime = now () ГДЕ заблокированная блокировка равна NULL ORDER BY ID LIMIT 10

Где 10 - «размер партии».

  • Затем каждая задача выполняет SELECT, чтобы выяснить, какие строки «заблокированы» для обработки, и обрабатывает эти
  • После того, как каждая строка завершена, вы устанавливаете lockby и locktime обратно в NULL
  • Все это делается в цикле столько раз, сколько существует.
  • Задание cron или запланированное задание периодически сбрасывает «заблокированный» любой ряд, чье время блокировки слишком давно, так как оно предположительно было выполнено в результате зависания или сбоя задачи. Кто-то другой тогда заберет их

LIMIT 10 специфичен для MySQL, но я думаю, что другие базы данных имеют эквиваленты. ORDER BY является импортом, чтобы избежать недетерминированности запроса.

4 голосов
/ 19 февраля 2009

Хотя я понимаю намерение, я бы не согласился с тем, чтобы немедленно перейти к блокировке на уровне строк. Это сократит ваше время отклика и может даже ухудшить вашу ситуацию. Если после тестирования вы столкнулись с проблемами параллелизма с APL, вам следует сначала сделать итеративный переход к блокировке «datapage»!

Чтобы правильно ответить на этот вопрос, потребовалась бы дополнительная информация о структуре таблицы и задействованных индексах, но для более подробного объяснения.

DOL, блокировка datarow использует намного больше блокировок, чем блокировка всех страниц / уровней страниц. Затраты на управление всеми блокировками и, следовательно, уменьшение доступной памяти из-за запросов на большее количество структур блокировок в кеше снизят производительность и компенсируют любые выигрыши, которые вы можете получить, перейдя на более параллельный подход.

Протестируйте свой подход без перемещения сначала в APL (все блокировки страниц «по умолчанию»), а затем, если обнаружены проблемы, переместитесь в DOL (сначала страница данных, а затем datarow). Помните, что при переключении таблицы в режим DOL все ответы в этой таблице становятся немного хуже, таблица занимает больше места, и таблица становится более подверженной фрагментации, которая требует регулярного обслуживания.

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

2 голосов
/ 18 февраля 2009

Вы должны включить row level locking в таблице с:

CREATE TABLE mytable (...) LOCK DATAROWS

Тогда вы:

  • Начать транзакцию
  • Выберите строку с опцией FOR UPDATE (которая заблокирует ее)
  • Делай, что хочешь.

Никакой другой процесс не может ничего сделать с этой строкой, пока транзакция не завершится.

P. S. Некоторые упоминают о накладных расходах, которые могут возникнуть в результате использования LOCK DATAROWS.

Да, есть накладные расходы, хотя я вряд ли назвал бы это проблемой для такой таблицы.

Но если вы переключитесь на DATAPAGES, вы можете заблокировать только одну строку на PAGE (2k по умолчанию), и процессы, строки которых находятся на одной странице, не смогут работать одновременно.

Если мы говорим о таблице, в которой одновременно заблокировано несколько десятков строк, то вряд ли произойдет заметное снижение производительности.

Для такого дизайна гораздо важнее параллелизм процесса.

1 голос
/ 19 февраля 2009

Наиболее очевидный способ - это блокировка. Если ваша база данных не имеет блокировок, вы можете реализовать ее самостоятельно, добавив поле «Заблокировано».

Некоторые из способов упростить параллелизм - это рандомизировать доступ к необработанным элементам, поэтому вместо конкуренции по первому элементу они распределяют доступ случайным образом.

0 голосов
/ 19 февраля 2009

Преобразование процедуры в один оператор SQL и обработка нескольких строк в виде одного пакета. Вот как должны работать базы данных.

...