Все привет, тематика автозапчасти. Данных ежедневно льется 20 млн в clickhouse.
На основе данных есть скрипт который считает данные и строит отчет.
Столкнулся с тем что если выбрать большой период и попробовать посчитать данные то процесс занимает очень большое время. Что я сделал уже:
1. Получаю группы уникальных артикулов-брендов из выбранного диапазона времени, отправляю в rabbitMq в очередь.
2. Сообщений в очереди примерно 50к, каждое сообщение состоит из 100 артикулов-брендов, калькуляция занимает 40 сек.
3. Работает 10 консьюмеров, но с учетом этого разбор 50к сообщение длится 3 дня это если период отчета 10 дней. При периоде отчета 90 дней будет работать расчет 27 дней.
Пока закончились мысли как ускорится.
Сервер: 12th Gen Intel(R) Core(TM) i9-12900K 1Тб SSD, память 116g
Судя по описанию выборка из кликхауса не тормозит, а основное узкое место в коде т.к. разбор 100 товаров в течении 40 секунд это оочень долго, нужно пррыилировать код и смотреть что там тормозит
Если что-то тяжело считать батчем, его нужно считать в рантайме. Оно уже однажды попадало в кликхаус, а значит где-то есть точка где оно туда попадает, вот посредине надо замидлвариться и предварительную стату вести, я так мыслю.
Что до "10 консюмеров" - теоритически это 10 поднятых процессов, каждый из которых пока неизвестно что делает и где его можно затюнинговать.
Непонятно, что еще есть на машине. Даже на слабой машине даже обычный fpm, не то что прям рэббит движ - настраивается под 50 возможных процессов (это дефолтный конфиг если что). Точно 10 это достаточно?
На тему достаточности - сам скрипт тоже важно как написан. Если он подымает целый фреймворк а не состоит из 20-30 строк кода - может от увеличения числа скриптов все очень напряжется. Но чесслово - я запускал на винде не на серверной машине сотку консолей, каждая из которых что-то читала-писала, и ничего, сидел ютуб еще одновременно с этим смотрел. 10 это прям как-то мало. С другой стороны - если задача прям хардовая - то по скрипту на ядро - может и нормально.
Но хардовость задачи не раскрыта никак кроме "каждый день 20 лямов пишется, и я пытаюсь считать эти 20 лямов, чтобы агрегатить их в 100 строчек". Вместо того чтобы и агрегатить на уровне SQL запроса, и вообще делать это в момент записи сайд эффектом не влияющим на саму запись.
Еще можешь упереться в сам рэббит, там есть особенности. Попробуй сэмулировать свою же задачу в сильно меньшем количестве данных на обычном кроне. Как бы ты это делал если бы скрипт работал раз в минуту. Подключение крутых и быстро реагирующих штук для построения отчетов вычиткой из СУБД миллионов записей само по себе странная идея. То есть быстро реагирующий инструмент для редко но постоянно считаемых тяжелых задач.
На очень упрощенном уровне правильная очередь работает в режиме "накопи буффер из N или раз в M секунд выполни сколько скопилось даже если оно меньше чем N". То есть это крон + счетчик + менеджер процессов. Рэббит в свою очередь представляет собой буфер на 1 ячейку, которая всегда и немедленно передается на выполнение. Это прикольно, чтобы пользователи не ждали минуту, пока крон запустится, но для операций расчетов это вообще не важно. Другой вопрос, что рэббит это еще и приложение на порту/сокете, т.е. с доступом с нескольких машин, а крон это все таки штука на конкретной машине. Но обдумать можно.
Виталий Артемьев, походу 100 брэндов а не 100 товаров... Опять же зачем перевычитывать 20 лямов потом, может можно привязаться на сам момент записи где 20 лямов уже по сети проходят. Или агрегировать на самом sql или кликхаусе, чтобы туда-сюда 20 лямов не гонять. Много чего можно придумать, но кода нет и поэтому воздух сотрясаем.
Спасибо за предыдущие рекомендации, немного кокретики.
Консьюмер получает сообщение в котором находится 100 пар артикул+бренд, уникальных. Эти артикулы летят в КХ и извлекают ценовые предложения по данным парам артикул, бренд, кол-во, цена и данных много так как одна деталь каждый день может быть с разной ценой или кол-вом.
Консьюмер логирует в файл то что делает вот лог
[11/03/2024 15:23:48] [DEBUG] generate part report start, hash 000125dadae7fa7b2d1273bd3a1751bf [Context [] Extra []]
[11/03/2024 15:24:25] [DEBUG] execute success, 1 time: 37.32 [Context [] Extra []]
[11/03/2024 15:24:26] [DEBUG] calculatePart finish, hash 000125dadae7fa7b2d1273bd3a1751bf mem: 19.00 MB [Context [] Extra []]
[11/03/2024 15:24:26] [DEBUG] save results finish, hash 000125dadae7fa7b2d1273bd3a1751bf mem: 19.35 MB [Context [] Extra []]
[11/03/2024 15:24:26] [DEBUG] generate part report finish, time: 0.01 hash 000125dadae7fa7b2d1273bd3a1751bf mem: 19.33 MB [Context [] Extra []]
Запросы такого плана
SELECT * FROM partscanner_sheet_raw_log WHERE event_date >= '2023-12-01' AND event_date <= '2024-02-24' AND sheet_id IN (15,17,18,19,20,21,22,23,24,25,26,.........,255,256,257,258,259,260,261,262,263) AND type = 'info' AND upperUTF8(key) IN ('MAZ_54321310400601','..........'MAZ_54322704125','MAZ_54322801080') ORDER BY event_time ASC LIMIT 0,10000000
Кстати сейчас заглянул в лог, вижу ошибки такого плана
In StreamIO.php line 268:
fwrite(): Send of 21 bytes failed with errno=104 Connection reset by peer
Может действительно раббит барахлит, StreamIO.php - класс раббита php