Мы давно ничего не писали в наш блог и возвращаемся с рассказом о нашем новом проекте: Relap.io (relevant pages).

Мы запустили рекомендательный B2B-сервис Relap.io полтора года назад. Он облегчает жизнь редакции и читателям СМИ. В будние дни Relap.io обслуживает 15 млн уников и выдаёт 30 миллиардов рекомендаций в месяц.

Сейчас Relap.io крупнейшая рекомендательная платформа в Европе и Азии.

image


Зачем нужен Relap.io


В зависимости от поведения пользователя мы подбираем статьи, которые будут ему интересны. Выглядит это как блок «Читать также» или «Вам будет интересно»:

Сейчас сервисом пользуются РИА Новости, AdMe, COUB, TJournal, Лайфхакер и другие медиа. Виджеты Relap.io установлены на более чем 1000 сайтов. 50 из них — миллионники (1 млн и более уникальных посетителей в сутки).

Relap.io начался с простенькой беты. Мы взяли рекомендательные алгоритмы Surfingbird и адаптировали их для сторонних площадок.

Из чего сделан Relap.io



image

Каждую секунду на сервера Relap.io от пользователей поступает 15 000 http-запросов. Из них:
  • 10К статика: изображения для виджетов, стили, статический js.
  • 5К динамика: сбор сигналов, формирующих обучающее множество и формирование блоков рекомендаций.



Когда мы создавали архитектуру у нас было 2 требования:
  • она должна выдерживать высокие нагрузки;
  • масштабироваться.


Бэкенд — это два сервера с большим количеством памяти и объёмными SSD в RAID1. На них стоит PostgreSQL свежей версии, на одном сервере — мастер, на втором — слейв.

Рабочие лошадки — сервера поскромнее. Они принимают запросы из внешнего мира. На двух из них стоят Nginx-ы, которые балансируются друг с другом просто по DNS. Они раскидывают запросы. Их ловят перловые FCGI-воркеры.

FCGI-приложение построено таким образом, что отказ PostgreSQL не приводит к мгновенному отказу всего сервиса, у нас есть примерно 10 минут на устранение фатальных неисправностей. Даже если автоматическое переключение на реплику не спасло ситуацию.

Эти же сервера выполняют и другие роли — на них крутится бОльшая часть очередей, выполняющих в оффлайне всё, что можно делать в оффлайне; инстансы memcached и Redis, крон-скрипты.

Особняком стоят сервера, которые формируют рекомендациями. Для всех, кроме команды математиков, это более-менее чёрная коробка. Туда FCGI и очереди кидают данные, а они в ответ вставляют в PostgreSQL свежие рекомендации, посчитанные по разным алгоритмам, для каждой активной ссылки в базе. Ключевые слова — Hadoop, Spark, Elasticsearch как сторадж, толстый слой Java.

Коду остаётся только забирать готовое, накладывать некоторое фильтрование. Его мы стараемся делать минимальным и максимум фильтровать на этапе генерации и сортировки.

Всё что можно обвешано кешами. Кеш PostgreSQL в памяти, дисковый кеш, мемкешед или redis, где он удобнее, несколько видов кеширования прямо внутри процесса.

Почему все так?


PostgreSQL — самая полнофункциональная open-source база данных. Предсказуемая, стабильная, популярная. Nginx — куда лучше выдерживает масштабирование нагрузки, чем Apache.

MySQL или Apache более популярны, но нам кажется, что выбирать их для новых проектов можно только на shared-хостинге, где больше ничего нет. Или если вы очень хорошо умеете их готовить и масштабировать.

Выбирать shared-хостинг для нового проекта можно, только если вы заранее знаете, что рост ему не грозит. Тогда технологии стоит выбирать уже по принципу «а людей с какими знаниями я найду дешевле и быстрее всего» — это, скорее всего, люди со знанием PHP, MySQL и Apache. Замкнутый мир проектов на shared-хостингах.

Hadoop взяли потому, что особого опыта ни с одним из подобных решений у команды не было. А это некий стандарт в обработке больших данных. Здесь мы просто шли за всеми.

Ещё нам было нужно отдельное хранилище данных для Hadoop-а — PostgreSQL не подходил. Для этого мы выбрали, как ни странно, Elasticsearch, получив заодно полнотекстовый поиск и возможность строить алгоритмы, его использующие. Впрочем, это оказалось неправильным решением. Он может быстро все индексировать и находить, но не отдавать большие объёмы данных.

В следующей серии расскажем, как мы решали эту проблему.

Где хостится Relap.io


С ростом нагрузки перед нами вставала проблема выбора надёжного хостинг-провайдера. Сейчас мы хостимся на Servers.com. Они достаточно мощные, чтобы выдержать нагрузку 900 000 запросов в минуту. Это не пиковые нагрузки, а нормальное состояние в будние дни.

В прошлом году мы несколько раз меняли датацентр. Сначала был ДЦ Славянский. Там до сих пор хостится Surfingbird.ru.

Потом в марте 2015 переехали на Hetzner. Тогда мы выдавали 2К рекомендаций в секунду. При последнем переезде на Servers.com было 6К в секунду. Сейчас 15K.

Интеграция Relap.io на сайт:


Как виджет
Коробочное решение. Пользователь ставит наш код в head страницы, на которой должен быть виджет. Выбирает тип виджета и собирает дизайн во встроенном конструкторе. Формирование рекомендаций и фронтенд полностью происходит на нашей стороне. Так к Relap.io подключено большинство площадок. Например, Лайфхакер.

Через jsonp api
Площадка получает описание нашего api. Мы отдаём большой пакет рекомендаций, а площадка фильтрует их уже на своей стороне и подставляет в дизайн. Интеграция через JSONP API позволяет использовать кастомные элементы: историческое количество просмотров, лайков и любую другую информацию о ссылке. Таким способом к Relap.io подключены, например, AdMe или COUB.

В последующих статьях мы подробно расскажем о технологиях, алгоритмах машинного обучения и инфраструктуре сервиса. Задавайте вопросы в комментариях — обязательно ответим на них в следующих публикациях.

Комментарии (39)


  1. drakmail
    19.02.2016 15:23
    +3

    Здесь всё на самом деле стандартно, интересно как раз как и на основе чего формируются рекомендации и насколько они лучше обычной выдачи последних материалов, например


    1. recompileme
      19.02.2016 15:46

      А что больше интересует техническая сторона вопроса, как обсчитывать тысячи хитов в секунду и не загнуться или какая математика лежит в основе?



  1. Heckfi
    19.02.2016 15:49
    +1

    Рекомендации формируются персонально для каждого пользователя или на страницу?


    1. Skaurus
      19.02.2016 18:27

      Помножьте количество страниц на количество пользователей. Так жить невозможно. Генерировать рекомендации в таких объёмах на лету — тоже.
      Но для каждого пользователя есть минимальная кастомизация — учитываются уже просмотренные статьи, например. Планируем продолжать такую аккуратную кастомизацию, которую ненакладно делать прямо в процессе выдачи рекомендаций.


  1. chizh_andrey
    19.02.2016 15:58
    +1

    Чем Servers.com лучше Hetzner.de в вашем случае?


    1. Skaurus
      19.02.2016 18:23

      Как минимум у Hetzner узкий канал между стойками, да и в интернет не фонтан. Нам нужно больше гигабита и там и там :) Так что когда выросли из стойки — стали искать, куда переехать.


  1. ShadowsMind
    19.02.2016 17:08
    +2

    *Тут должна быть картинка про то как рисовать сову*
    Начало было хорошее, а потом все скатилось непонятно куда. Не думаю, что людям на хабре надо объяснять почему shared-хостинг не подходит для подобных проектов. Да и без сравнения PostgreSQL/MySQL и Nginx/Apache тоже можно было обойтись.(тем более без упоминания реальных юзкейсов, в духе «нам надо было хранить json и PostgreSQL нам подошел лучше» (с) ).
    Надеюсь в следующих статьях объем будет побольше и поинтереснее, т.к. куча вопросов по поводу Вашей архитектуры:
    1. Почему Perl?
    2. Почему Redis для очередей?
    3. Про то как Spark используете.


    1. Skaurus
      19.02.2016 18:09
      +1

      1. Выбор Perl обусловлен тем, что у нас уже была сильная команда перловиков. На самом деле, конечно, можно использовать любой популярный для веб-разработки язык (даже PHP).
      2. В своё время для Surfingbird переписали Resque от твиттера на перл. Нам понравилось — работает хорошо, проблем нет. На новый проект взяли то же самое.


      1. DoctorChaos
        19.02.2016 21:54

        Допустить ремарку «даже php» очень непрофессионально с вашей стороны.
        Хотя, перловикам простительно быть не в курсе, что актуальная версия php уже 7 а не 4.


        1. Pink
          19.02.2016 22:04

          Не воспринимайте так серьезно эту шутку)


        1. Skaurus
          20.02.2016 01:52

          Я слежу за трендами всей индустрии, и про развитие PHP в курсе :)


  1. ealekseev
    19.02.2016 17:08

    Что нужно, чтобы подключиться к Вам через jsonp api ?


    1. Skaurus
      19.02.2016 18:12

      Для начала объяснить, зачем :) Стараемся обходиться виджетами. И оказаться сайтом с высокой посещаемостью.


      1. ealekseev
        19.02.2016 18:35

        Ну как минимум потому, что виджеты не совсем вписываются в дизайн :) Они конечно настраиваемые, но пока недостаточно.
        Высокая для Вас — это от скольки в сутки?


        1. Skaurus
          19.02.2016 19:46

          При посещаемости от 20к уников в сутки мы сделаем вам ваш собственный дизайн, и это тоже бесплатно.
          Ну вот сейчас JSONP стоит на Adme и Coub-е ;)


          1. ealekseev
            20.02.2016 10:59
            -1

            А если 19900 в пиковый день недели договоримся? :)


            1. Pink
              20.02.2016 14:34

              давайте попробуем. пишите в личку


  1. vgray
    19.02.2016 17:45

    Что нужно, чтобы подключиться к Вам через jsonp api ?

    тоже интерисует этот вопрос, с кем связываться? чтобы получить стоимость этой услуги?

    Вы можете давать рекомендации только по сайту в целом "Популярное сейчас..." или также можете давать рекомендации по каждой странице "Похожие статьи ...." ?


    1. Skaurus
      19.02.2016 18:13

      Это бесплатно, как и весь наш сервис. Рекомендации у каждой страницы свои.


  1. negodnik
    20.02.2016 01:34

    Как построена монетизация? :)


    1. Skaurus
      20.02.2016 01:51

      Площадки, разместившие наш виджет, при желании могут согласиться размещать в виджете помимо рекомендаций рекламу. Доходы от рекламы делятся между нами и площадкой, по умолчанию — пополам.
      Мы ну вообще бесплатны и зарабатываем, только помогая зарабатывать другим :)


      1. negodnik
        20.02.2016 01:57

        Ещё вопрос назрел. У вас почти в чистом виде content based recommendation, за исключением учета прочитанных юзером. А как — в двух словах — вы тогда строите рекомендации? По ключевым словам плюс времени публикации, как-то так?


        1. Skaurus
          20.02.2016 14:10

          Алгоритмов много. Вплоть до того, что для каких-то сайтов могут быть модификации специально для них.
          Вместе это работает примерно как на surfingbird — алгоритмы выстроены в цепочку, пытаемся взять из одного, не нашли достаточно — идём в следующий.
          Основной — на самом деле item to item.


          1. negodnik
            20.02.2016 15:46

            Как реализовано исключение прочтенного юзером из рекомендаций? Где вы храните прочтенные юзером ссылки и в какой момент это условие срабатывает? И как вообще работает отслеживание уника, если отключен прием third party cookies?


            1. Skaurus
              20.02.2016 15:57

              Пока что — в куках, и, соответственно, без них никак не работает.


              1. negodnik
                20.02.2016 16:12

                В виджете ни чего не выводится при этом? Или какой-то запасной вариант?


                1. Skaurus
                  20.02.2016 16:14

                  Выводится. item to item же основной алгоритм, я писал выше.


                  1. negodnik
                    20.02.2016 16:19

                    Это понятно, но ведь в случае item-item все равно нужна матрица user/item? Ведь нужно понять, что еще читали юзеры, которые читали эту страницу. А в случае если кука на домен сервиса не будет отправляться, по юзерам просмотры не сгруппировать?


                    1. Skaurus
                      20.02.2016 16:33

                      Кука не будет отправляться у меньшинства, так что корреляцию между item-ами посчитать всё равно получится.
                      Показать посчитанную корреляцию можно кому угодно, хоть у него кук вообще нет.
                      Я ответил на ваш вопрос?


                      1. negodnik
                        20.02.2016 17:09
                        +1

                        Спасибо за ответы, я не подумал что большинство в данном случае спасает ситуацию.


          1. negodnik
            20.02.2016 15:56

            Поясню насчет отслеживания уника. Для создания матрицы item-user, где элемент это условно время, которое он провел на странице item, нужно идентифицировать уникального юзера, как вы это делаете с учетом third party cookies? По IP?


      1. negodnik
        20.02.2016 02:08
        +1

        Почитал на сайте «Мы собираем для каждого пользователя материалы на основе его поведения. На виджет Relap, кликают в 2 раза чаще, чем на блоки, собранные вручную.» Видимо, я не так понял коменты к этому посту :)


      1. merk
        20.02.2016 12:44

        Откровенно говоря, подозрительно выглядит позиция "Если хотите, то запускайте рекламу, а если не хотите рекламу — то пользуйтесь бесплатно". Это наводит на мысли, что вы можете использовать собранную информацию еще как-то в своих целях.

        Честно слово, если бы вы предлагали схему с выбором между бесплатным использованием с рекламой или платным использованием без рекламы, то было бы больше доверия :)

        В любом случае, у вас очень крутая идея!


        1. Skaurus
          20.02.2016 14:42

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


  1. Mixim333
    20.02.2016 16:56

    А что сейчас с https://relap.io/ — хотел воочию посмотреть, что из себя представляет, но ни страничка не открылась, ни ping'и не ходят? Хабраэффект?


    1. Pink
      20.02.2016 18:32

      нет, все ок, весь день все штатно


  1. xorax
    24.02.2016 00:43

    Вы не просчитывали AWS? Издержки получаются значительно выше?