Как распараллелить обновление данных для миллиона пользователей за ограниченное время?
Что проверяют
Умеете ли вы начать с оценки, а не с ThreadPoolExecutor. Миллион пользователей за час это около 280 обновлений в секунду, и упор почти всегда будет в базу или внешний API, а не в Python. Следом обычно спрашивают, что будет, если процесс упадёт на середине.
Как отвечать
Сначала посчитайте: объём, окно времени, где узкое место. Потом стройте решение по слоям:
- пачки вместо одиночных запросов: миллион отдельных
UPDATEупрётся в сетевые задержки. Быстрее загрузить изменения черезCOPYво временную таблицу и сделать одинUPDATE ... FROMна пачку, либо использоватьexecutemany; - нарезка по ключу: делить по
idчерез keyset (WHERE id > last_id ORDER BY id LIMIT N), а не черезOFFSET, который дорожает с каждой страницей; - воркеры: пачки раздаются через очередь (Celery, RQ, Dramatiq или
multiprocessing.Pool). Для IO-bound кода хватит потоков илиasyncio, для CPU-bound нужны процессы: GIL не даёт потокам считать параллельно; - ограничение параллелизма: число воркеров подбирают под пул соединений базы и лимиты API, а не под число ядер. Держать нагрузку помогают
asyncio.Semaphoreи размер пула; - идемпотентность и прогресс: повторная обработка пачки не должна портить данные, а отметка обработанного (колонка
updated_at, таблица чекпоинтов) позволяет продолжить после сбоя, а не начинать сначала; - ретраи с backoff для временных ошибок и отдельный список упавших пачек для разбора.
В конце скажите, как проверите результат: скорость по метрикам, лог по пачкам, сверка количества обновлённых строк.
Где спотыкаются
Отдают миллион идентификаторов в executor.map. Он сразу ставит в очередь все задачи, память растёт, а ошибку по отдельному пользователю поймать неудобно.
Ставят 500 потоков «для скорости» и кладут базу: соединения кончаются, блокировки растут, и итог выходит медленнее, чем с двадцатью воркерами.
Забывают про падение на середине. Без чекпоинтов и идемпотентности перезапуск означает либо повтор всего миллиона, либо двойное применение изменений.