dima74 / factorio-servers-statistics

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Терминология

  • GameId == уникальный game_id

  • HostId == уникальный server_id

  • ServerId == последовательность GameId (имеющих одинаковый HostId), предположительно образующих один «сервер»

  • Обычный хост — такой HostId, что в любой момент времени ему соответствует не более одной GameId (то есть на нём запущено не более одной factorio). При этом в ответе /get-games иногда для такого HostId может встречаться несколько GameId (причина: кеширование — если хост перестаёт отправлять heartbeat, то бекенд /get-games забывает его только через ~10 минут).

  • Мультихост — не обычный хост

Комментарии

  • Для обычных хостов HostId и ServerId должны образовывать биекцию
  • ServerId нам нужно задавать самим, будем использовать обычный счётчик, начиная с 1

Хранилище

  • Будем хранить отдельно информацию о играх (GameId) и серверах (ServerId)
  • Игры будем хранить просто как HashMap<GameId, Game>
  • ...

Game

  • Содержит prev_game_id

Хранение строк

  • Все строки одного типа (тип — например, «имя игрока», «описание игры», «название игры») будем хранить в одной большой строке, с разделителем — нулевым символом
  • В структурах (Game, ...) вместо строк храним индекс начала части строки в большой строке
  • При добавлении новой строки просто добавляем её в конец (не проверяя, существует ли она уже)
  • Периодически (каждый раз после рестарта dyno, например, или мб чаще) удаляем дубликаты в больших строках
  • Теги (массив строк) склеиваем в одну строку по разделителю \x02
  • Моды: название и версию храним также как остальные строки, сам список модов храним просто как вектор пар

Объединение игр с одним ServerId (расчёт prev_game_id)

Обычный хост

  • перезапуск: игра с таким HostId исчезает и через несколько минут появляется снова (с новым game_id)
  • перезапуск с наложением: как перезапуск, только после появления нового game_id старый тоже присутствует несколько минут (из-за особенностей кеширования)
  • приостановка: как перезапуск, только разница может составлять часы/дни/недели
  • потеря соединения: как перезапуск/приостановка, но game_id сохраняется

Мультихост

  • все сценарии обычного хоста для любого подмножества игр, в любом временном порядке (в том числе одновременно)
  • добавление новой игры/игр
  • удаление игры/игр

Наивный алгоритм объединения

Нас интересуют два события: появления или исчезновение game_id При появлении/исчезновении game_id добавляем HostId в список на «отложенное объединение» Через ~20 минут после последнего события появлении/исчезновении game_id производим объединение:

  • объединяем два множества: {game_id, соответствующие HostId} для t=now и t=(now - 20minutes)
  • не рассматриваем game_id, которые как были так и остались
  • количество рассматриваемых game_id было и осталось не больше одного ⇒ всё однозначно
  • иначе пытаемся объединять по game_name и game_host (в частности game_port)

Приостановка

Данный алгоритм не учитывает «приостановку». Поэтому дополнительно будем хранить для подходящих HostId последний ему соответствующий game_id. HostId является походящим если это обычный хост или если к моменту когда данный хост последний раз был онлайн ему соответствовал ≤1 game_id как минимум 24 часа.

...

В теории игры могут перемещаться между мультисерверами. Например, игры с названием factorioX.xzwq.net, где X ∈ [1, 9]. Игры с X ∈ [4, 9] образуют мультисервер (совпадает server_id), игры 1, 2 и 3 являются обычными (у каждой уникальный server_id). Хотя все игры хостятся в одном месте (в host_address отличается только порт, хост совпадает). Однако это какой-то совсем крайний случай, поэтому не будем его рассматривать.

Сохранение данных в Яндекс.Облако

  • Состояние сохраняется каждые 10 минут и также при получении сигнала SIGTERM
  • Все состояния хранятся в папке states-hourly/, с именами вида H.bin.<compression>, где H = floor(T / 3600), где T — unix time в секундах
  • Причины такого формата хранения:
    • просто применять алгоритм удаления ненужных бекапов (так как все бекапы уже пронумерованы)
    • если приложение сломается, то матожидание длительности потерянного состояния равно 1час / 2 = 30минут
  • Тип сжатия файла с состоянием:
    • для последнего бекапа --- lz4 (самое быстрое, а у heroku всего 30 секунд timeout на завершение dyno)
    • для бекапов --- xz (сжимает лучше всего)
    • подробности в [various/analyze_compressions_methods]
    • при старте dyno бекапы в формате lz4 будут конвертироваться в xz

Главная страница

Текущие сервера:

  • Топ-10 серверов по числу игроков которые сейчас онлайн
  • Топ-10 серверов по убыванию game_time_elapsed

Все сервера:

  • Топ-10 серверов по максимальному числу игроков онлайн одновременно
  • ...
  • Топ-10 по человеко-часам за день/неделю/месяц/всё время

Другие страницы

  • табличка 7 на 24 с цветовой градацией — число игроков в соответствующее время (думаю даже более полезно для конкретного сервера, а не суммарно)
  • такой же график числа игроков как на странице сервера, но для суммарного числа игроков на всех серверах
  • график числа серверов с определённой версией (0.17/0.16) в зависимости от времени

Комментарии для полученных данных (особенности/странности/и т.д.)

  • В промежутке 4-13 января 2020 зафиксировано примерно 5500 игр с именем "Fboys game" (с различным game_id). Каждая игра длилась примерно 2-3 минуты. Всё это время игры находились

About


Languages

Language:Rust 72.4%Language:Vue 13.6%Language:Python 6.5%Language:TypeScript 6.2%Language:Shell 0.7%Language:HTML 0.5%Language:JavaScript 0.1%