Нужна помощь в вопросе т.к. понимаю, что текущая реализация максимально неэффективна, и хотелось бы посмотреть на задачу с другой стороны.
Сервис занимается сбором статистики активности пользователей (простейшей), сохраняем user_id, app_id (web/mobile/ios/android, etc), date. Сохраняем "отметку" только один раз с уникальным индексом, для того, что бы лишний раз не непрягать СУБД - делаем отметку в Redis, что "отметка" была проставлена. В кабинете статистику обновляем раз в 3-5 минут (сохраняем уже агрегированные данные в другой бд).
Суть вопроса в том, что в последнее время пользовательская активность выросла и часто бывает, что Redis не успевает сохранить строку, как идет 2-3 попытки записи. Возможное решение вопроса - сохранять куда-то эти данные и как-то их сохранять в базу весь пулл раз в 1-2 минуты, но как это сделать более "нормально"? Учитывая, что уникальных юзеров бывает больше 1 миллиона в сутки
1) что бы лишний раз не дергать PostgreSQL, запрос к redis "стоит" сильно меньше.
2) обязательные: [user_id => Int, app_id => Int, date => Date], если юзер заходит с помощью браузера: [browser_name => text, browser_version => text]
3) ~1K
Ivan Palamarchuk,
1. Я б попробовал подергать - в зависимости от железа может и вытянуть
2. Уберите редис - пишите nginx'ом в текстовый лог
3. Requests Per Second?
Миллион пользователей в сутки - это 11 запросов в секунду - копейки для postgresql на хоть сколько либо нормально настроенном железе, никакой Redis вам не нужен.
Окей, учитываем, что пользователи приходят неравномерно в течение дня плюс есть запросы на дублирующий insert, но в любом случае простой
INSERT ... ON CONFLICT DO NOTHING
вам абсолютно достаточно.
Поддерживаю - даже на простецком RAID10 из HDD с нормальным выданным объёмом памяти несколько сотен транзакций в секунду для постгреса не особенно напряжный режим, а уж если активно используемые таблицы положить в отдельный таблеспейс, располагающийся на SSD, то вообще.
В общем, есть подозрение, что узкое место - не СУБД (либо она неоптимально настроена).
Откуда вы взяли, что их несколько сотен? Примерно 1 тысяча запросов в секунду к одному сервису, постоянно делать INSERT, учитывая, что в 99.9% запись в базу делать не нужно. Странное решение, в общем.
1 тысяча запросов в секунду к одному сервису, ... 99.9% запись в базу делать не нужно
То есть отсылается информация о пользователе, отсылаются 1000 rps к сервису в секунду, но писать из них нужно только 1 из тысячи, потому что остальные дублируются?
Ivan Palamarchuk, ну окей, допустим, сервис действительно настолько популярен, что пользовательскую активность обычные меры оптимизации уже не выдерживают. Тогда, наверное, он достаточно велик и настала пора для:
Шардирования СУБД
Перехода на СУБД, часто используемые данные которой хранятся не на диске, а в памяти
Найма специалиста по балансировке нагрузки
Странно всё-таки, что вы полагаете узким местом именно СУБД. Не верю, что такое количество запросов - это не следствие кривой архитектуры приложения или неверно выбранного стека технологий.
Ivan Palamarchuk,
То есть в идеальном случае до базы доходит 1 rps, но, поскольку ваш самодельный кэш с редисом неидеален, то получаем попыток записи в 2-3 раза больше, т.е. 2-3 rps. Так еще раз, а чем проблема?
Отдельный вопрос, конечно, что вы такое делаете с редисом, что он "не успевает сохранить строку".
terrier, это скорее не RPS, а 2-3 запроса в секунду на одного юзера. На Redis тоже большая нагрузка идет, но сейчас не об этом. Я пришел сюда посоветоваться, как бы вы сохраняли отложено такую информацию? Где хранили, как читали и пр. Напрямую с PG вообще нет смысла работать.
Ivan Palamarchuk,
Понимаете, в чем дело, у вас тут все спрашивают конкретные цифры rps, потому что это определяющая информация для выбора решения. И, похоже вы сами их не очень представляете. Но видно, что нагрузка небольшая и если вы ради сервиса с 1000 rps построите кластер на 15-ти машинах с кафкой, кассандрой и хадупом - это будет печальный исход. Postgres + redis, нормальная система, почему бы нет. Так что на вашем месте я бы:
- померил реальную нагрузку на сервис, на redis, на postgres и уяснил бы, где реально узкое место
- починил код, работающий с redis. Вы с ним что-то принципиально не так делаете, если он у вас "не успевает сохранить строку"
- настроил существующие системы по-нормальному
Если бы у вас было 100х от текущей нагрузки, то было бы разумно сначала быстро в некую очередь сообщений, а на другом конце разгребать ее уже не задерживая прием/передачу, но пока у вас 1000 rps и, насколько я понимаю, в пределах полугигабайта данных в день, повторюсь, нужно настроить существующие системы.