Создание поисковой системы, безусловно, не самая простая задача. Чтобы пользователь мог быстро получить релевантный ответ на свой запрос, вы должны непрерывно добывать данные с веб-страниц и индексировать их содержимое. Главная цель при реализации — избежать чрезмерной сложности инфраструктуры, сохранив гибкость решения. Какой же должна быть при этом архитектура? Ответ на этот вопрос не очевиден. В этой статье мы расскажем о бессерверной поисковой системе, способной масштабироваться с целью обхода и индексирования крупных сайтов.
Простейшая поисковая система состоит из двух основных компонентов:
Поисковый робот (или веб-скрейпер) — программа для извлечения и хранения онлайн-контента
Поисковый индекс — в нем ищутся ответы на поисковые запросы
Поисковый робот
Возможно, вы уже читали статью Поисковый робот на базе бессерверной архитектуры. В этой статье Дзидас Мартинайтис (Dzidas Martinaitis) рассказывает о двух возможных вариантах бессерверных архитектур для реализации поискового робота на базе инфраструктуры AWS. Функции AWS Lambda предоставляют простой и экономичный способ обхода сайтов. Здесь, однако, нужно оговориться: у Lambda-функции из-за тайм-аута время обхода оказывалось ограничено 15 минутами. Можно справиться с этим ограничением и создать бессерверный поисковый робот, который сможет масштабироваться для обхода крупных сегментов сети.
В стандартном алгоритме поискового робота используется очередь URL-адресов для обхода. Вот что делает робот:
берет URL-адрес из очереди;
заходит на страницу по этому URL-адресу;
извлекает все URL-адреса, которые сможет найти на странице;
помещает в очередь те адреса, которые не посещал раньше;
повторяет предыдущие шаги до тех пор, пока очередь URL-адресов не станет пустой.
Даже если мы распараллелим обход URL-адресов, все равно для более крупных сайтов есть вероятность превысить 15-минутный лимит.
Структура алгоритма работы поискового робота
Система AWS Step Functions — это оркестратор бессерверных функций. Она позволяет выстроить последовательность из одной или нескольких функций AWS Lambda, чтобы получился более длительный по времени рабочий процесс. Данный алгоритм работы поискового робота можно разбить на этапы, за каждый из которых будет отвечать отдельная Lambda-функция. Затем из отдельных шагов можно построить конечный автомат (также его называют машиной состояний) под управлением системы AWS Step Functions.
Ниже показан вариант структуры конечного автомата для реализации подобного поискового алгоритма:
1. ReadQueuedUrls читает любые непосещенные URL-адреса из нашей очереди. 2. QueueContainsUrls? проверяет, остались ли необойденные URL-адреса. 3. CrawlPageAndQueueUrls берет URL-адрес из очереди, посещает его и записывает все вновь обнаруженные URL-адреса в очередь. 4. CompleteCrawl — когда в очереди не остается URL-адресов, работа завершается.
Каждая часть алгоритма может теперь быть реализована как отдельная Lambda-функция. Теперь уже весь процесс не регламентируется 15-минутным тайм-аутом — данное ограничение будет применяться к каждому отдельному шагу.
В тех случаях, где ранее, возможно, использовалась очередь в памяти, теперь потребуется очередь URL-адресов, которая будет сохраняться при переходе от одного шага к другому. Как вариант, можно передавать очередь на вход и выход в каждом шаге. Однако здесь вы можете столкнуться с ограничением на ввод-вывод для функций AWS Step Functions. Чтобы этого избежать, можно представить очередь в виде таблицы Amazon DynamoDB, и тогда каждая Lambda-функция сможет писать в нее или читать из нее данные. Очередь требуется только на время обхода сайта. Это означает, что вы можете создать таблицу DynamoDB в самом начале выполнения и удалить ее после завершения работы поискового робота.
Вертикальное масштабирование
Если обходить интернет по одной странице за раз, процесс индексирования будет не очень быстрым. В системе AWS Step Functions можно использовать Map state для запуска шага CrawlPageAndQueueUrls с целью добычи данных с нескольких URL-адресов одновременно. Однако не стоит бомбардировать сайт тысячами параллельных запросов. Вместо этого можно взять фиксированный набор URL-адресов из очереди на шаге ReadQueuedUrls.
Важное ограничение, которое следует учитывать при работе с AWS Step Functions — это максимальный размер истории выполнения. Чтобы не упереться в этот потолок, используйте рекомендуемое в данном случае разделение рабочих объемов между несколькими исполнениями рабочего процесса. Это можно сделать, проверив общее число URL-адресов, посещаемых при каждой итерации. Если порог при этом будет превышен, можно запустить выполнение новых функций AWS Step Functions — и продолжить обход страниц.
Система AWS Step Functions предлагает встроенную поддержку обработки ошибок и повторных попыток выполнения. Таким образом, ваш поисковый робот становится более устойчив к сбоям.
Вот как будет выглядеть наш итоговый конечный автомат после масштабирования:
Этот автомат включает те же начальные шаги, что и предыдущий (1-4), но к ним добавляются еще два дополнительных шага (5 и 6), которые позволяют разделить рабочий процесс на несколько исполнений автомата.
Поисковый индекс
Развертывание масштабируемой, эффективной и полнотекстовой поисковой системы, способной предоставлять релевантные результаты — задача сложная и сопряженная с дополнительными операционными расходами. Здесь может помочь Amazon Kendra — это полностью управляемый сервис, в котором не нужно самостоятельно настраивать никаких серверов. Поэтому данная система идеально подходит для нашего сценария. Amazon Kendra поддерживает работу с HTML-документами. Это означает, что вы можете хранить необработанный HTML-код с просмотренных веб-страниц в рамках Простого сервиса хранения данных от Amazon (S3). Amazon Kendra обеспечит функционал поиска, основанный на методах машинного обучения, и ваши пользователи смогут быстро получить релевантные результаты по своим поисковым запросам.
Однако в Amazon Kendra есть ограничения на количество хранимых документов и объем запросов в день. Если пользователи часто обращаются к вашему сервису, можно приобрести дополнительные пакеты обрабатываемых запросов или хранимых документов.
На шаге CrawlPageAndQueueUrls содержимое страницы, которую посещает робот, записывается в хранилище S3. При этом также пишутся метаданные, позволяющие Amazon Kendra ранжировать или предоставлять результаты поиска. После завершения обхода робот может запустить задание синхронизации источника данных, чтобы убедиться, что индекс остается актуальным.
Если вы используете Amazon Kendra в своем решении, стоит обратить внимание на используемую тарифную модель. Применяемая единица тарификации — «индекс в час», поэтому система больше подходит для крупномасштабных корпоративных систем, чем для компактных личных проектов. В начале работы рекомендуем обратить внимание на бесплатный тариф Amazon Kendra для разработчиков.
Общая архитектура
Для отслеживания истории обхода веб-страниц можно добавить еще одну таблицу DynamoDB. Вот какая архитектура получилась у нашего решения:
Образец реализации этой архитектуры через Node.js опубликован на GitHub.
В этом примере Lambda-уровень формирует двоичный код Chromium (используя chrome-aws-lambda). При этом используется библиотека Puppeteer для извлечения содержимого и URL-адресов с посещенных веб-страниц. Инфраструктура определяется при помощи комплекта разработки AWS Cloud Development Kit (CDK), который автоматизирует процесс предоставления ресурсов для облачных приложений с помощью AWS CloudFormation.
Используемый в примере компонент Amazon Kendra опционален. Можно ограничиться развертыванием бессерверного поискового робота.
Выводы
Если использовать полностью управляемые сервисы AWS, то создание бессерверного интернет-робота и поисковой системы уже не будет выглядеть такой уж неподъемной задачей как в самом начале. Мы изучили варианты параллельного выполнения заданий по обходу сайтов, а также масштабирования интернет-робота при помощи функций AWS Step Functions. Чтобы получить значимые результаты запросов к неструктурированному контенту, извлеченному с сайтов, мы задействовали Amazon Kendra. При этом нам удалось избежать операционных накладных расходов, сопровождающих создание поискового индекса с нуля. Здесь можно ознакомиться с примером кода и глубже погрузиться в реализацию этой архитектуры.
Если вам интересна экосистема Serverless-сервисов и все, что с этим связано, заходите в наше сообщество в Telegram, где можно обсудить serverless в целом.