У меня есть набор размером ~ 1M. Случайные предметы в наборе часто трогаются до грязи (~ 10к / м, с дублированием). Демон домработника стремится снова очистить грязные предметы, выполняя тяжелую задачу очистки для каждого грязного элемента (например, 1 минуту на каждую задачу). Часто во время задачи очистки связанный элемент снова затрагивается (что не имеет значения). Из-за характера задачи одновременное выполнение одновременных задач для одного и того же элемента не допускается.
Как правильно решить эту проблему? Чтобы лучше объяснить это, вот приблизительное представление о том, как это можно решить:
Простое решение 1:
«Грязный набор» отслеживает все затронутые элементы: элемент тронут, он добавлен в грязный набор. (например, на основе Redis, каждый элемент является ключом-значением в пространстве ha sh с именем «dirty-set»).
Несколько экземпляров демона housekeeper запускаются одновременно (например, экземпляр микросервиса) . Каждый демон-экономка пытается получить работоспособные предметы:
2.1. Просматривать до N элементов (в зависимости от объема задачи, которую он может поддерживать) из грязного набора.
2.2. Для каждого просматриваемого элемента попробуйте заблокировать его так, чтобы другие узлы этого не сделали (объяснено позже в пункте 4).
2.3. Удалите успешно заблокированные предметы из грязного набора.
Для каждого полученного предмета демон домработницы отправляет задачу. работа над предметом. (например, блокировка на основе Redis: Redlock или блокировка на основе MongoDB: выделенная коллекция с уникальным индексом)
Наивное решение 2:
Подобно решению 1, но используйте таблица / коллекция базы данных для реализации как грязного набора, так и блокировки. Например, с MongoDB - это коллекция со схемой вроде {itemId: string, dirty: boolean, lock: timestamp}. Исходя из этого, «добавить в грязный набор» представляет собой простую запись без блокировки, которая обновляет грязное поле до значения «истина», «заглянуть, удалить из грязного и заблокировать» станет переходом БД (запрос N dirty = true и non -locked, обновить грязное поле до false и обновить блокировку).
Решение 2 кажется более интегрированным. Однако он имеет высокочастотную запись в БД (добавление грязного набора), чего следует избегать.
Какое решение этой проблемы может быть лучше?