Параллельная обработка очереди базы данных
-
05-07-2019 - |
Вопрос
Существует небольшая система, в которой таблица базы данных является очередью на MSSQL 2005. Несколько приложений пишут в эту таблицу, а одно приложение читает и обрабатывает в FIFO-формате.
Я должен сделать его немного более продвинутым, чтобы иметь возможность создавать распределенную систему, в которой могут работать несколько приложений обработки. В результате должно получиться, что обрабатывающее приложение 2-10 должно работать, и они не должны мешать друг другу во время работы.
Моя идея - расширить таблицу очередей строкой, показывающей, что над ней уже работает процесс. Приложение обработки сначала обновит таблицу своим idetifyer, а затем запросит обновленные записи.
Так что-то вроде этого:
start transaction
update top(10) queue set processing = 'myid' where processing is null
select * from processing where processing = 'myid'
end transaction
После обработки он устанавливает в столбце обработки таблицы что-то еще, например, «выполнено» или что-то в этом роде.
У меня есть три вопроса об этом подходе.
Во-первых: это может работать в этой форме?
Второе: если это работает, эффективно ли это? Есть ли у вас другие идеи по созданию такого дистрибутива?
В-третьих: в MSSQL блокировка основана на строках, но после того, как количество строк заблокировано, блокировка распространяется на всю таблицу. Таким образом, второе приложение не может получить к нему доступ, пока первое приложение не освободит транзакцию. Насколько большим может быть выделение (top x), чтобы не блокировать всю таблицу, а только создавать блокировки строк?
Решение
Это будет работать, но вы, вероятно, обнаружите, что вы столкнетесь с блокировками или взаимоблокировками, когда несколько процессов пытаются прочитать или обновить одни и те же данные. Я написал процедуру, чтобы сделать именно это для одной из наших систем, которая использует интересную семантику блокировки, чтобы гарантировать, что этот тип работает без блокировок и тупиков, описанный здесь .
Другие советы
Этот подход кажется мне разумным и похож на тот, который я использовал в прошлом - успешно.
Кроме того, строка / таблица будет заблокирована только во время выполнения операций обновления и выбора, поэтому я сомневаюсь, что вопрос "строка против таблицы" действительно важен.
Если только затраты на обработку вашего приложения не будут настолько незначительными, чтобы быть незначительными, я бы оставил " top " низкая стоимость - возможно, всего 1. Конечно, это полностью зависит от деталей вашего приложения.
Сказав все это, я не администратор баз данных, и поэтому мне также будут интересны дополнительные экспертные ответы
Что касается вашего вопроса о блокировке. Вы можете использовать подсказку о блокировке, чтобы заставить ее блокировать только строки
update mytable with (rowlock) set x=y where a=b
Самая большая проблема с этим подходом состоит в том, что вы увеличиваете количество «обновлений» в таблице. Попробуйте сделать это, используя только один процесс (update + delete) и другие, вставляющие данные в таблицу, и вы обнаружите, что на уровне около миллиона записей он начинает разрушаться.
Я бы предпочел иметь одного потребителя для БД и использовать очереди сообщений для доставки данных обработки другим потребителям.