Я недавно провалил собеседование при приеме на работу, плохо ответив на простой вопрос: как такие сайты, как LinkedIn, эффективно показывают расстояние отношения (1/2/3) от вас до каждого человека, отображаемого на странице (например, в результатах поиска людей, списке людей, работающих в компании и т. д.)?
Я получил существенную «хитрость» решения: поиск «расстояния от меня» - обычная операция (например, 20x + на одной странице, 100 на сеанс входа в систему), так что вы можете выполнить часть «расстояния от меня до X», кэшировать его, а затем повторно использовать этот частичный результат в кэше много раз, чтобы сделать другие операции намного более дешевыми. Я также предположил, что частичным результатом, вероятно, будут мои соединения второго уровня, потому что «кэшировать все соединения 3-го уровня» будет слишком дорого в оперативной памяти и ЦП.
Но, пытаясь преобразовать это понимание в решение, я придумал неуклюжий ответ, заключающийся в создании постоянных кэшей соединений 2-го уровня для всех на сайте (что было бы чрезвычайно дорого в обслуживании и сложным в обслуживании), и я сделал необъяснимый обходной путь в использовании Bloom Filters способом, который не имел большого технического смысла. Я бы не взял себя на работу после такого ответа!
Позже, когда я подумал о проблеме без давления интервью, нависшего над моей головой, я нашел более разумный ответ.
Создайте очень быстрый способ получения соединений первого уровня для каждого из пакетов идентификаторов пользователей (размер пакета до ~ 1000?). Это, вероятно, означает выделенный кластер серверов с большим количеством оперативной памяти, который может кэшировать соединения 1-го уровня всей сети в памяти. К счастью, 50 миллионов членов х ср. 100 подключений на элемент x 4 байта на идентификатор элемента = <25 ГБ для кэширования в ОЗУ, что выполнимо с помощью недорогого оборудования. И количество изменений в день будет ниже 1%, поэтому поддерживать кеш в актуальном состоянии не так уж сложно. (Обратите внимание, что реляционная база данных, вероятно, будет плохим выбором для реализации этого кэша, поскольку шаблон доступа «много случайных операций ввода-вывода» снижает производительность реляционной БД.) </p>
когда пользователь входит в систему, кэширует его соединения 2-го уровня, выбирая соединения 1-го уровня для каждого соединения 1-го уровня, и вставляет хеш-таблицу (ключ = идентификатор 2-го уровня, значение = массив 1-го уровня. уровень соединений, которые соединяют вас). Также кешируйте ваши соединения первого уровня, чтобы вы могли откатить и 1-й, и 2-й уровни с помощью одного обратного вызова на ваш удаленный сервер кеша. Идентификаторы пользователей легко разбиваются, поэтому распределенный кеш, такой как memcached, может хорошо работать для этого.
для любого идентификатора пользователя, чтобы определить, находится ли он в вашей «сети» и какое отношение он имеет к вам (1-й, 2-й, 3-й), выполните следующие действия:
- если идентификатор находится в соединениях первого уровня, остановитесь.
- попробуйте найти идентификатор в вашей кэшированной таблице соединений 2-го уровня. Если найдено, верните массив соединений, которые вас соединяют.
- Извлеките соединения первого уровня идентификатора и повторите шаг # 2 для каждого из них. Объедините все результаты в один массив и верните их.
- рефакторинг в пакетную реализацию («посмотрите на расстояние от меня до N разных пользователей»), так что вы можете получить все удаленные результаты с шага № 3 без необходимости делать N удаленным вызовы.
Но я уверен, что есть лучшие ответы на это. Что твое? Если вам нужны дополнительные проблемы, попробуйте смоделировать ситуацию в интерактивном режиме (не можете искать решения в Интернете).
Обратите внимание, что вопрос был об оптимальном решении, независимо от , как LinkedIn на самом деле делает это сегодня , который я посмотрел после того, как написал свой собственный ответ выше.