Есть задача хранить профили игроков на своём сервере со своей инфраструктурой. Быстро их отдавать и принимать.
что бы вы использовали в качестве временного хранилища данных по 100КБ каждый пакет в количестве 50тыс штук с возможностью быстрой замены данных?
rabbitMQ конечно прекрасен, но врядли подойдёт, впрочем как и прочие очереди
колеблюсь между таблицей в памяти mysql, Redis и memcache
==== примерные цифры ===
один сейв - до 100КБ данных.
Средняя сессия - 5 минут.
Сейв прилетает скажем 3 раза в минуту.
онлайн - пусть 100тыс в сутки.
канал 1ГБит
допустим пиковый онлайн 10тыс. То есть в минуту они пришлют 30 тыс сейвов. По 500 записей в секунду. До 50 Мбайт получается. Итого на вход 400Мбит.
так же эти профили будут отдаваться периодически. Но там на много меньще цифры. Десятками в секунду в худшем случае. Ибо клиент кеширует.
===== история ====
когда-то давно это всё хозяйство хранилось в файлах, но с ростом уткнулось в нехватку inodes
потом это всё хранилось в mysql, но уткнулось в производительность.
пробовал clickhouse, но дико ненадёжная штука. Несколько раз падала при обновлении через apt update.
==== планы ====
сейчас я планирую разбить на сегменты.
1. принимаем профили и храним в памяти, перезаписывая более новыми данными.
2. после 10 минут неактивности профиль сохраняется в mysql
3. отдаётся либо из кеша, либо из mysql по ситуации.
Это 5 гигабайт данных. В принципе нет особой проблемы разместить их в памяти, если памяти достаточно.
Сейв прилетает скажем 3 раза в минуту.
При такой частоте сохранения мне представляется не особо критичным инцидент утраты самого последнего сэйва. тем более с учётом того, что это игрушка. И уж совсем с учётом фразы "2. после 10 минут неактивности профиль сохраняется в mysql".
В случае MySQL вполне себе решением может быть рабочая таблица ENGINE = Memory, прогреваемая при старте сервера из статической копии, и сливаемая в статическую копию по эвенту, скажем, раз в минуту, с автоштампом времени обновления в качестве маркера.
Akina, А вот что произойдёт, если таблица вдруг переполнится?
Либо mysql перестанет выполнять запросы, потому как память закончилась, либо новые данные не будут приходить.
Вероятно это нужно закладывать в решение, масштабируя время перемещения из кеша.
Redis то он скинет на диск и будет дальше существовать. Да чуть лагнёт, но не страшно мне думается.
namee, а какая работа с данными, просто получить и отдать? поиск, агрегация и прочее есть? а то можно просто вернуться к первоначальному варианту, но победить inode, взять другую ФС, сделать куча дешевых серверов под шарды.
А вот что произойдёт, если таблица вдруг переполнится?
Я не зря пишу: "... если памяти достаточно". То есть вариант переполнения должен быть невероятным событием, возможным исключительно как последствие критической либо алгоритмической ошибки клиентского программного обеспечения. Однако в этом случае статическая копия последнего корректного состояния данных всё одно никуда не денется.
Everything_is_bad, да получить и отдать. Но опять таки, смысла держать несколько железок, когда на одной всё работает большого нет. Буду каэш закладывать возможность горизонтальноо масштабирования, но как перспективу далёкого будущего.
Проверять просто почаще состояние, да резерв держать.
А что там проверять? если я верно догадываюсь, то сэйвы существуют в количестве 1 штука на юзера, то есть общее количество сэйвов не больше общего количества юзеров. Уник по юзеру на таблицу, и вот уже количество записей в ней хорошо так ограничено сверху. Плюс Memory таблицы не выносят всяких текстов и прочих блобов, значит, и максимальный размер одной записи так же фиксирован (правда, от души, ибо они ещё до кучи не выносят и строк динамической длины, делая их статическими по максимуму). Но в любом случае финальный объём памяти на таблицу хорошо известен, и будет расти только с ростом количества юзеров, да и ре-юз там достаточно эффективен. Так что требуемый объём расти будет вряд ли быстро, и время на отреагировать, если вдруг что, у вас будет. Серверная память опять же не миллионы стОит, были бы кровати на мамке.
Я имел ввиду, что конкретно там хранится, но если в целом предполагается что данные прям так будут храниться, то я совсем не понимаю в чем смысл использовать mysql тут, логичнее всего использовать условный redis, который будет каждый раз будет обновлять по ключу профиль. Есть еще minio s3, но тут вряд ли этот кейс. В целом можно посмотреть еще в сторону оптимизации самих профилей, если там не собирается гора статистики, то в целом непонятно зачем отправлять 100кб сжатых данных по 3 раза в минуту
calculator212, Так исторически сложилось. Игры у нас для мобилок и умеют сохранять только весь профиль целиком. Ловить конкретную точку выхода игрока со страницы довольно сложно. От того и частое сохранение прогресса на каждое подозрение о зкарытии окна.
только redis - ну не знаю. мне казалось что он nosql бд для хранения данных в памяти. Как он десятки миллионов записей хранить будет, и быстро ли управляться с ними- ещё одни грабли собирать не хочется.
calculator212, Вы немного запутались. Это один профиль весит ~100k профили копятся годами и их количество растёт стремительно. Старые неиспользуемые профили мы удаляем через полгода. Но примерно 10% играют по несколько лет.
. Старые неиспользуемые профили мы удаляем через полгода.
и
От того и частое сохранение прогресса на каждое подозрение о зкарытии окна.
А зачем хранить все профили за полгода(я не докапываюсь просто интересно)? В этом случае redis не стоит использовать. В таком случае возможно имеет смысл держать в памяти/БД 5-10 сейвов, а остальное складировать в архив на сервере
Игроки играют, ходят в гости к соседям, обмениваются подарками.
Это должно работать даже если друг покинул игру, а игрок у себя переустановил игру.
Да и восстановление прогресса должно работать после недели-другой перерыва.
Я сам ни раз делал длительные перерывы в играх.
Ну то всё детали.
В общем думаю redis + mysql меня выручат.
Всем большое спасибо! Очень приятно, а главное полезно поговорить порой с умными людьми :)