Searchanise: нюансы и сложности разработки умного поиска
В этой статье поговорим об архитектуре быстрого высоконагруженного приложения на примере сервиса Searchanise. Это облачный сервис, включающий в себя умный поиск, рекомендательную систему, навигацию и инструменты повышения конверсии внутри интернет-магазинов.
О развитии функциональности сервиса
В качестве ядра сервиса был использован поисковый движок, угадывающий запрос по первым введённым символам, а также исправляющий ошибки и предлагающий актуальные подсказки. Сам поиск поначалу сопровождался виджетом, в котором отображались продукты с фотографиями, стоимостью, указанием остатка на складе, а также рейтингом. Кроме того, дополнительно показывались контентные страницы и категории, релевантные поисковому запросу.
По мере развития сервиса в нём появились: — рекомендательные блоки; — фильтры; — страница результатов; — промоинструменты; — мерчендайзинг; — аналитика.
Архитектура
Главное в любой системе — это архитектура. Что касается Searchanise, то он хостится на десяти железных серверах. Используется KVM-виртуализация, где создано маленькое облако, в котором находится более 50 виртуалок. На одном железе располагается около шести серверов, причём каждый из них решает свою задачу: кто-то лишь хранит статистику, а кто-то принимает запросы. Есть отдельные серверы для панели администратора и индексации. Больше всего именно поисковых серверов — 30, т. к. системе Sphinx для организации быстрого поиска необходимо много памяти.
В тот момент, когда пользователь устанавливает модуль, он тем самым регистрируется на сервере, после чего начинает отправлять поисковые данные. Эти данные поступают в очередь, а оттуда — в базы данных. Когда импорт данных заканчивается, команда на индексацию поступает в очередь индексации. Что касается обработчиков очереди API, то они расположены на десяти серверах, в то время как обработчики индексации — на 19-ти.
Довольно необычно сделаны очереди: они реализованы в Redis посредством LUA-скриптов и встроенных в Redis типов данных. Таким образом удалось часть логики переложить в очередь и получить очереди, распараллеливаемые по нужным условиям. Такие очереди способны повторять ошибочные запросы лишь фиксированное число раз, а при падении обработчика потеря данных не происходит.
Для каждой конкретной регистрации создаётся своя база (на момент написания материала их было более 10 тысяч). Да, такое решение не является стандартным, зато у него есть несомненный плюс — базы реально изолируются. Согласитесь, что удалить такую базу намного проще и быстрее, чем заниматься вычисткой информации из таблиц. Вдобавок к этому, решается проблема торможения индекса, которая возникает при добавлении или частой работе с обновлениями базы. Нельзя не сказать и то, что если базы отделены, у нас не возникает проблем с шардированием. То есть просто раскладывается определенное количество баз на каждый MySQL-сервер.
Что касается приложения для Shopify, то оно написано на Erlang. Этот язык оказался весьма быстрым и удобным для решения задач параллельного программирования. В частности, его использование позволяет поддерживать тысячи магазинов, осуществляя по несколько миллионов запросов к API. К слову, Shopify имеет очень развитый API, с которым возможно делать почти всё. В результате была сделана индексация, отслеживание обновлений и статусов магазинов и т. п. Само приложение изолировано — это сделано для соблюдения общей монолитной структуры и сохранения единого API для всех платформ.
Теперь о метриках. Они собираются со всех серверов с помощью Zabbix. Чрезвычайно удобно — знать, что с сервером происходит, насколько он загружен. Кроме того, в Zabbix настроены триггеры на различные «внештатные» ситуации — когда что-то идёт не так, приходит уведомление на почту и в Slack.
Работа со Sphinx
За счёт Sphinx и проведённой оптимизации скорость поиска сервиса Searchanise значительно превысило конкурирующие предложения. Например, сервис без проблем поддерживает 500 тысяч продуктов в поиске при ежедневной обработке порядка 15 миллионов поисковых запросов.
Да, у Sphinx, есть проблемы, многие их которых удалось обойти. Многие, но не все: Sphinx периодически падает, и поделать с этим пока ничего нельзя. Для подстраховки приходится один индекс держать на 2-х серверах: если Sphinx упадёт на одном, обслуживание запросов обеспечит второй.
Тестирование
Unit-тестирование не используется, ведь если система быстро развивается, поддерживать unit-тесты в актуальном состоянии — значит существенно тормозить процесс разработки.
При этом все метрики проверяются самописными короткими тестами, плюс используются функциональные тесты для API. Так как API является фиксированным, тесты часто менять не приходится. Да и вообще, в данном случае функциональное тестирование эффективнее, чем регулярная правка unit-тестов под постоянно меняющиеся требования.
Виджеты
На ряде платформ результаты поиска отображаются в дизайне платформы. Кроме того, на некоторых платформах поиск показывается в JS-виджетах. Управление всем этим осуществляется через встраиваемую админку, которая тоже представляет собой JS-виджет.
Вообще, для системы виджетов предусмотрено большое число всевозможных настроек. Все они обновляются почти в реальном времени (оказываются у клиента в течение 10–20 секунд). У аналогичных конкурирующих сервисов этот показатель достигает 10–15 минут, как говорится, результат налицо.
Файлы виджетов хранятся на Amazon S3, но раздаются они не напрямую, а посредством CDN. Точнее, KeyCDN — это недорого, прекрасно работает, плюс изменения быстро актуализируются, а IP-адреса не заблокированы ни в одной из стран мира.
Выводы
Благодаря использованию системы Sphinx, был построен сервис поиска для множества пользователей и с обеспеченной себестоимостью почти в 10 раз ниже, чем у конкурирующих компаний. Правда, Sphinx из коробки не очень удобен. Это проявляется, например, при попытках использовать его со множеством индексов и при организации на его основе распределённого сервиса. В результате пришлось преодолеть множество сложностей и придумать ряд уникальных решений — только тогда удалось наладить процесс индексации, распараллеливания и faleover.
За материал выражается благодарность Дмитрию Сухоносову, руководителю разработки в Searchanise.