Курс «Архитектура мессенджера» · Часть 2 · Соединение и доставка

Раздел 7. Статусы присутствия и индикаторы

Онлайн/офлайн, «был(а) в сети», «печатает…»; почему presence дорого масштабировать; что хранить, а что считать эфемерным.

«Онлайн», «был(а) в сети», «печатает…» — на вид мелочь, три строчки в интерфейсе. Но именно эта мелочь — одна из самых тяжёлых нагрузок в мессенджере. Парадокс, который любят раскручивать на интервью: маленький значок, огромная цена.

Общее название этих штук — статусы присутствия (по-английски presence).

Откуда система знает, кто онлайн

Это бесплатно достаётся из того, что мы уже построили в Разделе 3. Раз у каждого пользователя в сети есть живая связь с сервером соединений, то сам факт наличия этой связи и есть «онлайн».

Чтобы вовремя замечать обрыв, устройство и сервер обмениваются короткими сигналами «я жив» (их называют heartbeat). Идут сигналы — пользователь онлайн. Сигналы пропали, связь оборвалась — значит, офлайн. То есть отдельной «кнопки онлайн» нет: статус выводится из состояния соединения.

Почему присутствие — это дорого

Вот ключевая мысль раздела. Обычное сообщение — это «один раз одному человеку». А статус присутствия — это постоянный поток мелких обновлений, который надо рассылать многим сразу.

Смотри, что происходит. Статус Алисы интересен всем, кто прямо сейчас на неё «смотрит»: открыл с ней чат, видит её в списке контактов, состоит с ней в группе. Стоит Алисе изменить статус — и это изменение надо разослать всем наблюдателям. А теперь умножь: миллионы пользователей, у каждого десятки наблюдателей, и статусы меняются часто. Получается лавина крошечных событий.

Самый дорогой из всех — «печатает…». Он меняется по несколько раз в секунду, по смыслу живёт буквально пару секунд, и его надо мгновенно показать всем в чате (а в группе — всем участникам). Огромный объём микроскопических, быстро устаревающих сообщений.

Что хранить, а что выбросить

Раз присутствие — это в основном поток, а не архив, главный приём прост: не записывай в дорогое надёжное хранилище то, что устаревает через секунду. Разложим по полочкам:

  • «Печатает…» — чисто эфемерное. Эфемерное значит: живёт секунды, нигде надолго не хранится, потерять не страшно. В базу его не пишут вообще.
  • «Онлайн / офлайн» — почти эфемерное. Это текущее состояние; его держат в быстром хранилище в памяти (типа Redis — это база, которая живёт в оперативной памяти и потому очень быстрая), а не в долговременной базе.
  • «Был(а) в сети» (отметка времени последнего захода) — единственное, что стоит реально сохранить, и то компактно: одна метка времени на пользователя.

Как снижают нагрузку

Несколько приёмов, которые стоит назвать на доске:

  • Рассылать только тем, кто смотрит. Не слать статус всем подряд, а только тем, у кого прямо сейчас открыт чат или экран с этим пользователем. Нет наблюдателей — нет рассылки.
  • Агрегировать, а не слать каждое изменение. Не отправлять «печатает» на каждое нажатие клавиши — достаточно раз в пару секунд, и гасить по таймауту, если человек перестал печатать.
  • Разрешить статусу быть неточным. Присутствие можно делать «примерно»: если онлайн-статус на пару секунд соврёт, ничего страшного. Здесь точность сознательно приносят в жертву масштабу. Это прямое продолжение мысли из Раздела 2: для мессенджера доступность и масштаб важнее идеальной точности в каждый момент.

Главное одной фразой

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

Вопросы интервьюера (с разбором)

«Как сделать "печатает…" и онлайн-статус для миллионов?» Образец: «Онлайн-статус я не храню отдельно — он выводится из наличия живой связи на сервере соединений, обрыв ловлю по пропаже сигналов "я жив". "Печатает…" делаю чисто эфемерным: ничего не пишу в базу, агрегирую события (не на каждое нажатие, а раз в пару секунд) и гашу по таймауту. Рассылаю оба статуса только тем, кто сейчас реально смотрит на пользователя, а не всем подряд.»

«Почему присутствие — серьёзная нагрузка и как её снизить?» Образец: «Потому что это не одно сообщение одному человеку, а постоянный поток мелких обновлений, который надо размножать на всех наблюдателей; умножьте на миллионы пользователей и частые изменения — выходит лавина. Снижаю так: рассылка только активным наблюдателям, агрегация и таймауты вместо потока событий, хранение в быстрой памяти вместо надёжной базы и допущение небольшой неточности.»

«Что будет, если статус слегка "врёт"?» Образец: «Ничего критичного. Присутствие — приблизительная вещь, и небольшая задержка или неточность онлайн-статуса не ломает доставку сообщений. Это осознанный компромисс: я жертвую точностью присутствия ради масштаба, потому что само сообщение всё равно доставится надёжно отдельным механизмом.»


#мессенджер #присутствие #онлайн-статус #печатает #эфемерные-данные #подготовка-к-интервью