Интеграция A-Parser с Redis: продвинутое API
Сравнение с HTTP API
A-Parser Redis API был разработан для замены методов oneRequest
и bulkRequest
для более производительной реализации и поддержки дополнильных сценариев использования:
- в качестве сервера запросов и результатов выступает Redis
- возможность запрашивать результаты асинхронно или в блокирующем режиме
- возможность подключить множество парсеров(как на одном так и на разных серверах) для обработки запросов с единой точкой входа
- возможность задасть количество потоков для обработки запросов и просматривать логи работы
- возможность организации таймаутов на операции
- автоматический Expire невостребованных результатов
Предварительная настройка
В отличие от A-Parser HTTP API для использования Redis API необходимо предварительно настроить и запустить задание с парсером API::Server::Redis:
- установить и запустить сервер Redis (локально или удаленно)
- создать пресет настроек для парсера API::Server::Redis, указать:
Redis Host
иRedis Port
- адрес и порт Redis сервера, по умолчанию127.0.0.1
, порт6379
Redis Queue Key
- название ключа для обмена данными с A-Parser, по умолчаниюaparser_redis_api
, вы можете создавать раздельные очереди и обрабатывать их разными заданиями или разными копиями A-Parser'аResult Expire(TTL)
- время жизни результата в секунда, служит для автоматического контроля и удаления невостребованных результатов, по умолчанию3600
секунд (1 час)
- добавить задание с парсером API::Server::Redis
- в качестве запросов необходимо указать {num:1:N}, где N должно соответствовать числу потоков, указанному в задании
- вы можете также включить опцию ведения лога, таким образом будет доступна возможность просмотра лога по каждому запросу
Выполнение запросов
Работа Redis API основана на Redis Lists (списках), операции над списками позволяют добавлять в очередь неограниченной число запросов(ограничено оперативной памятью), а также получать результаты в блокирующем режиме с таймаутом (blpop) или в асинхронном режиме (lpop).
- все настройки, кроме
useproxy
,proxyChecker
иproxybannedcleanup
берутся из пресета вызываемого парсера +overrideOpts
- настройки
useproxy
,proxyChecker
иproxybannedcleanup
берутся из пресета API::Server::Redis +overrideOpts
Запрос добавляется в Redis командой lpush
, каждый запрос состоит из массива [queryId, parser, preset, query, overrideOpts, apiOpts]
сериализованного с помощью JSON
:
parser
,preset
,query
соответствует аналогичным для API запросаoneRequest
queryId
- формируется вместе с запросом, рекомендуем использовать порядковый номер из вашей базы или хороший рандом, по данному ID можно будет получить результатoverrideOpts
- переопределние настроек для пресета парсераapiOpts
- дополнительные параметры обработки API
redis-cli
Пример выполнения запросов, для тестирования можно использовать redis-cli
:
127.0.0.1:6379> lpush aparser_redis_api '["some_unique_id", "Net::HTTP", "default", "https://ya.ru"]'
(integer) 1
127.0.0.1:6379> blpop aparser_redis_api:some_unique_id 0
1) "aparser_redis_api:some_unique_id"
2) "{\"data\":\"<!DOCTYPE html><html.....
Различные кейсы
Асинхронная проверка наличия результата
lpop aparser_redis_api:some_unique_id
Вернет результат если он уже обработан или nil
если запрос еще в процессе обработки
Блокирующее получение результата
blpop aparser_redis_api:some_unique_id 0
Данный запрос будет блокирован до момента получения результата, вы также можете указать максимальный таймаут на получение результата, после чего команда вернет nil
Сохранение результатов в единую очередь
По умолчанию A-Parser сохраняет результат для каждого запроса под своим уникальным ключом aparser_redis_api:query_id
, что позволяет огранизовать многопоточную обработку, отправляя запросы и получая результаты отдельно для каждого потока
В некоторых случаях необходимо обрабатывать результаты в один поток по мере их поступления, в этом случае удобнее сохранять результаты в единую очередь результатов (ключ должен отличаться от ключа для запросов)
Для этого необходимо указать ключ output_queue
для apiOpts
:
lpush aparser_redis_api '["some_unique_id", "Net::HTTP", "default", "https://ya.ru", {}, {"output_queue": "aparser_results"}]'
Получение результата из общей очереди:
127.0.0.1:6379> blpop aparser_results 0
1) "aparser_results"
2) "{\"queryId\":\"some_unique_id\",\"results\":{\"data\":\"<!DOCTYPE html><html class=...
Пример реализации (кейс SpySERP)
Предположим мы создаем SaaS сервис, который производит оценку параметров доменов, для простоты мы будем проверять дату регистрации домена
Наш сервис состоит из 2-ух страниц:
/index.php
- лендинг страница, на которой расположена форма ввода домена/results.php?domain=google.com
- страница с результатами работы сервиса
Для улучшения пользовательского опыта мы хотим чтобы страницы нашего сервиса загружались моментально, а процесс ожидания данных выглядел естественным и отображался лоадер
При запросе к results.php
мы в первую очередь выполняем запрос в A-Parser Redis API, формируя уникальный request_id:
lpush aparser_redis_api '["request-1", "Net::Whois", "default", "google.com", {}, {}]'
После чего мы можем вывести страничку пользователю и отобразить лоадер на области отображения данных, за счет отсутсвия задержек ответ сервера будет ограничен только скоростью подключения Redis (обычно в пределах 10мс)
A-Parser начнет обработку запроса еще до того как браузер пользователя получит первый контент, после того как браузер подгрузит все необходимые ресурсы и скрипты, мы можем отобразить результат, для этого отправляем AJAX
запрос на получение данных:
/get-results.php?request_id=request-1
Скрипт get-results.php
выполняет блокирующий запрос к Redis с таймаутом 15 секунд:
blpop aparser_redis_api:request-1 15
И возвращает ответ сразу как только он будет получен от A-Parser, если мы получили нулевой результат по таймауту, то мы можем отобразить ошибку получения данных для пользователя
Таким образом, отправляя запрос в A-Parser при первом открытии страницы (/results.php
) мы сокращаем необходимое время ожидания данных для пользователя (/get-results.php
) на время, которое браузер пользователя тратит на ожидание контента, подгрузку скриптов и выполнение AJAX
запроса