Локация и реальное время: соберите живой сервис близости + лидерборд
Практический проект: соберите поиск рядом по пространственному индексу (запрос соседних ячеек), канал push в реальном времени по региону и backend лидерборда на отсортированном множестве — затем докажите корректность ранга и близости тестами.
Прочитать, что нужно запрашивать соседние ячейки и держать ранг в отсортированном множестве — не то же, что собрать сервис, переживающий движущуюся нагрузку. Возьмите три примитива юнита — пространственный индекс, канал push по региону и отсортированное множество — и соберите небольшой, но реальный сервис локации и реального времени, затем докажите два свойства корректности, что вероятнее всего укусят: что близость находит соседа за границей и что ранг игрока верен среди миллионов.
Этот проект делает юнит операционным: вы реализуете запрос близости грубо-потом-точно, фанаут по региону, избегающий вещания, и движок ранга O(log n), затем пишете тесты, ловящие канонические баги — пропущенного соседа за границей и неверный глобальный ранг.
Соберите рабочий сервис локации и реального времени из трёх частей — запрос поиска рядом по пространственному индексу, канал push в реальном времени для движущихся сущностей по региону и лидерборд на отсортированном множестве — и докажите тестовым харнессом, что близость возвращает соседей за границей и что ранги (включая глобальный ранг при шардинге) корректны.
- Эндпоинт find-nearby, который на рандомизированных входах, включая точки у границ, возвращает ровно то же множество, что брутфорс-скан по расстоянию — демонстрируя, что запрос кольца соседей чинит проблему границы ячейки.
- Измеренный hit-rate кэша на перекошенной нагрузке чтения с однострочной заметкой, почему кэширование по ячейке окупается на read-heavy, медленно меняющихся данных о местах.
- Рабочее демо реального времени, где пинги движущейся сущности доходят лишь до подписчиков её текущей региональной ячейки (показано логом или счётчиком), с переключением подписки при пересечении границы и недоставкой локации не-другу.
- Лидерборд, чьи операции обновления, top-k, мой-ранг и окно бегут без полного скана, с ничьями, решёнными детерминированно составным score.
- Тест, доказывающий, что глобальный ранг при шардинге по диапазону очков равен брутфорс-отсортированному рангу для рандомизированных очков, плюс краткая заметка, как по-шардовые счётчики делают это O(шарды), а не кросс-шардовым сканом.
- Добавьте адаптацию к плотности: переключите горячую переполняющуюся ячейку на более мелкое разрешение (или дробление quadtree) и покажите падение числа кандидатов на запрос, удерживая задержку плотной зоны ограниченной.
- Добавьте крошечный компонент маршрутизации: постройте малый дорожный граф, сожмите его в иерархию и покажите, что двунаправленный поиск вверх возвращает тот же кратчайший путь, что наивный Dijkstra, раскрывая куда меньше узлов.
- Добавьте адаптивную частоту пинга в канал реального времени (медленнее при покое сущности, быстрее при движении) и измерьте снижение записей против фиксированного интервала при равной воспринимаемой свежести.
- Добавьте временны́е лидерборды (дневной / недельный / всё-время) как отдельные отсортированные множества и обсудите, как это уменьшает каждую доску и размазывает нагрузку записи.
- 01Какие три примитива собирает этот проект, и что демонстрирует каждый?
- 02Как доказать два свойства корректности, и почему именно эти два?
- 03Почему собирать все три вместе, а не по отдельности?
Этот проект превращает юнит локации и реального времени в рабочую систему из трёх примитивов. Часть близости реализует поиск грубо-потом-точно по пространственному индексу — достать ячейку плюс кольцо соседей, фильтровать по точному расстоянию и кэшировать по ячейке на read-heavy нагрузке — и доказывается корректной против брутфорс-скана включая точки у границ, тест, вскрывающий баг одной ячейки. Часть реального времени хранит движущиеся сущности с TTL по ключу региональной ячейки, публикует по ячейке по постоянному соединению, переподписывается при пересечении границ и проверяет фильтр дружбы на краю-подписчике, а не вещает. Часть лидерборда использует отсортированное множество для O(log n) обновления, top-k, мой-ранг и окна, с тайбрейкером в составном score, и шардит по диапазону очков, так что глобальный ранг — внутришардовый ранг плюс счёты более высоких шардов — доказывается против брутфорс-сортировки. Сборка всех трёх вместе делает объединяющий урок осязаемым: та же абстракция региональной ячейки — это поисковый индекс, ключ маршрутизации и ось партиционирования, а верная структура всегда следует паттерну доступа.
Что-то непонятно?
Задай вопрос по этому уроку. Вопросы анонимны и попадают напрямую автору — урок станет лучше.