open atlas
↑ К треку
Разборы System Design SDC · 04 · 07

Локация и реальное время: читаем код и конфиг

Читаем реальный гео-код, конфиг маршрутизации pub/sub, настройку движка маршрутизации и команды отсортированного множества Redis, затем рассуждаем: баг одной ячейки, взрыв вещания, ловушка пересжатия и запрос ранга O(n).

SDC Senior ◷ 14 min
Уровень
ОсновыJuniorMiddleSenior

Баги этих систем живут в коде, не в прозе: запрос, читающий одну ячейку, публикация, идущая всем, настройка маршрутизации, пере-предобрабатывающая на каждый тик трафика, запрос ранга, который сканирует. Читай каждый сниппет, прогоняй в голове и выбирай ответ, на который подписался бы senior-инженер.

Практикуй петлю дизайн-ревью: найди паттерн доступа в коде, сопоставь его с верной структурой и выбери изменение, которое арифметика/архитектура реально поддерживают.

Сниппет 1 — запрос близости

def nearby(lat, lng, radius_m):
    cell = h3.geo_to_h3(lat, lng, res=9)         # собственная ячейка пользователя
    candidates = store.get_by_cell(cell)         # лишь эта одна ячейка
    return [p for p in candidates
            if haversine(lat, lng, p.lat, p.lng) <= radius_m]
Викторина

В чём баг nearby() и как его починить?

Сниппет 2 — публикатор локаций

def on_ping(user_id, lat, lng):
    store.set(user_id, (lat, lng), ttl=30)
    for conn in all_connections:          # каждый подключённый клиент
        conn.send({"user": user_id, "lat": lat, "lng": lng})
Викторина

При 2 млн пингов/с этот цикл плавит кластер. Структурный фикс?

Сниппет 3 — настройка движка маршрутизации

def update_traffic(edge_id, new_travel_time):
    graph.set_weight(edge_id, new_travel_time)
    graph.build_contraction_hierarchy()   # бежит на каждое обновление трафика
    return graph
# вызывается ~тысячи раз в секунду из потока зондов
Викторина

Почему это катастрофа и какая архитектура верна?

Сниппет 4 — запрос ранга

-- ранг игрока на лидерборде
SELECT COUNT(*) + 1 AS rank
FROM scores
WHERE score > (SELECT score FROM scores WHERE player_id = :id);
-- вызывается на игрока, миллионы опрашивают свой ранг
Викторина

Почему этот запрос плохо масштабируется и что его заменяет?

Вспомните перед уходом
  1. 01
    Два кодовых запаха, сигналящих о баге близости или фанаута, и их фиксы?
  2. 02
    Почему пере-сжатие на каждое обновление трафика неверно, и почему SQL-запрос ранга медлен — что заменяет каждое?
Итог

Каждый сбой этого юнита виден в коде и структурен, не деталь тюнинга. Запрос близости, читающий одну ячейку, пропускает место за границей — запрашивай кольцо соседей и фильтруй по точному расстоянию. Обработчик локаций, шлющий каждый пинг всем соединениям — квадратичное вещание — публикуй по региональной ячейке и фильтруй на краю-подписчике. Движок маршрутизации, перестраивающий contraction hierarchy на каждый тик трафика — невозможно на континентальном масштабе — раздели структуру и веса, чтобы трафик накладывался живьём. А SQL-запрос ранга (COUNT(*) WHERE score > mine) — это скан O(n) на опрашивающего — заменяй отсортированным множеством, чей ZREVRANKO(log n). Senior-привычка одна каждый раз: читай паттерн доступа из кода, затем выбирай структуру данных или маршрутизацию под него — никогда версию, что прячет O(n) или пересчёт на горячем пути.

Что-то непонятно?

Задай вопрос по этому уроку. Вопросы анонимны и попадают напрямую автору — урок станет лучше.

хоткеи развернуть
поиск
K
пред. пьеса
k
след. пьеса
j
тиры
t
это меню
?
sources3
expand
  1. 01
  2. 02
  3. 03

Trademarks belong to their respective owners. Editorial reference only.