Блог /

Как подгружать 4,5 млн товаров от более чем 60 офферов. Или пробуем CPA с Admitad

Не наживы ради, а эксперимента для, решили мы попробовать CPA в рамках нашего студийного вечернего хобби-исследования. И вот что из этого получилось:

Чё за эксперимент?

А эксперимент простой: узнать и сравнить предел мощностей, удобство программирования и быстродействие CMS 1C Битрикс и индивидуальной разработки на фреймворке (CakePHP), решая одну и ту же задачу: ежесуточная выгрузка большого количества товаров и поддержание их актуальности по срокам/доступности.

Что значит "большого количества" товаров? Это сколько вообще? 10 тыщ? 100 тыщ? 500 тыщ? Цифру нам тоже предстояло узнать. 

Железо

Сравнивать естественно надо на железе с одинаковыми характеристиками. Мы любим vscale.io и в рамках данного эксперимента все сайты работают на их серверах с характеристиками:

4 ГБ RAM 
60 ГБ SSD 
2 CPU

Средние такие показатели, ничего особенного. Обычно на подобных серверах живут и неплохо себя чувствуют сайты с каталогом товаров в 50к и посещаемостью 2-3к в сутки.

Так, вот не надо только придираться, мы говорим про средние показатели. Конечно тут дельта довольно большая.

Где брать данные? Откуда столько товаров получить?

И тут мы задумались о том, где же взять товаров, да еще чтобы они обновлялись бы, снимались с активности, добавлялись. Короче, живой каталог. Думали и придумали: будем искать интернет-магазины с партнерскими программами, которые выдают своим партнерам фид данных своего каталога. Но как искать? Ходить и стучаться в контакты к ним? Вот так вот позвонить или написать в М-Видео, и они прям такие "О, ребята, да мы вас ждали сидели, ну наконец-то!". Нет конечно. И тут мы нагуглили, что существует много площадок-агрегаторов партнерских программ. Стали выбирать и остановились на Admitad.

Почему Admitad?

Да нипочему. Так получилось. Говняных отзывов про ребят полно, равно как и про другие агрегаторы. Просто исходили из того, кто самый крупный. А Admitad еще и интернэйшнл. И отчеты у них интересные. И курсы у них какие-никакие, и бложик живой такой. В общем постоянно развиваются, обучают веб-мастеров, привлекают рекламодателей. На первый взгляд нам понравилось. Поэтому пошли туда. Да и шли мы вообще за информацией, а не заработком, и на его счет иллюзий не питали, так как к CPA у нас отношение предвзятое.

Что такое CPA и почему к нему у нас предвзятое отношение. Было?

Если ты в курсе что это такое, то есть те кто нет. Этот раздел для них. А ты, умник, мотай дальше. 

Итак, CPA. Только, чур, не по-русски читай. Латинские буквы. И означают они "Cost Per Action" — что в переводе звучит как "оплата за действие". 

Модель простая: рекламодатель (оффер) платит тебе за заранее оговоренное действие, которое должен совершить пользователь, которого ты привел. Чтобы отследить, что именно ты привел этого пользователя, оффер выдает реферальную ссылку, в которой вшит идентификатор партнера (веб-мастера). 

Какое это может быть действие? В основном это совершение заказа на сайте оффера

Почему отношение к этой модели у нас так себе? Да потому что очень ничего в данной цепочке контролирует веб-мастер. Очень много где можно его на@&?ть (<-- тут "нагреть"). Вот оффер сообщает "заказ был отменен пользователем". И как ты проверишь? Или клик был, переход пользователь по твоей ссылке совершил, а заказа нет. А чего его нет? Вдруг оффер жульничает?

В общем тут вопросов больше чем ответов. И решать эти вопросы призвана третья сторона: в нашем случае это ребята из Admitad. Они становятся между оффером и веб-мастером, контролируя те самые Action'ы, Per которые тебе должны Cost.

Но даже они не избавляют на 100% от проблемы упущенных заказов. Да, есть в Admitad инструмент "Потерянные заказы". И я на себе даже проверил как это работает. Но, увы, ничего из этого не вышло. А история такая. Есть магазин ОРМАТЕК, который продает товары для сна. И есть я, которому нужен был самый простенький матрас. Решил поспать) Так вот, перехожу я по партнерской ссылке с ВДВрус.ру, делаю заказ, и жду такой радостный свои 100 рублей. Проходит день, неделя. Я получил свой матрасик, а в Адмитаде пусто. Пишу в поддержку, мол, где же? Говорят: "воспользуйтесь нашим инструментом потерянные заказы". Иду туда, пишу. Через примерно месяц мне отвечает ОРМАТЕК что заказ был осуществлен в результате перехода из другого источника, то есть не по реферальной ссылке. Ну как таак то вообще? Я уже в себе засомневался, что я сделал не так. Увы, такие ситуации возникают. И сколько их, одному Богу известно. Думаю что много, т.к. шанс самому наткнуться на такое минимален, по идее.

Не будем о грустном) Давайте дальше:

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

А так выглядит главная страница личного кабинета в Admitad:

График удобный, показывает динамику за последние 30 дней по кликам, действиям и заработку. Но нужно иметь в виду что партнерские ссылки лучше реализовывать на js, т.к. даже указание rel="nofollow" не избавляет от "роботных" переходов.

На каких сайтах тестируемся?

Бэбикам.ру на 1С Битрикс редакции "Бизнес"

Жил да был наш давнишний домен bebikam.ru. А еще мы вообще-то золотые партнеры 1С Битрикс. И нам положена студийная лицензия редакции "Бизнес". Отлично, решили мы, это судьба и надо пробовать. Добавили площадку в Admitad и набрали офферов. Сначала выбирали офферы без модерации. Выгрузили примерно тысяч 40 товаров. Потом пошли пробоваться к офферам с модерацией. И процентов 80 нам одобрили заявки. Надо сказать что есть офферы, которые уже !месяца три все еще думают брать нас или нет (или не думают а подзабили просто на обработку заявок?). А есть кто на следующий день уже отмодерировал заявку.

ВДВрус.ру на фреймворке CakePHP

Один из самых давних наших клиентов, сайт vdvrus.ru — это доска объявлений и магазинов. И почему бы не совместить полезное с еще более полезным? Пришли мы к ВДВрус и говорим: "Готовы запустить на сайте раздел с мегатоннами товаров, которые будут выступать в качестве альтернативы объявлениям.". "А давайте" говорят.

Там мы получили две площадки и смогли параллельно работать над одной и той же задачей в рамках нашего эксперимента. Как это выглядит с технической стороны? Нюансов сильно много, но мы попробуем обрисовать в общих чертах:

Техническая реализация

Бэбикам.ру

Тут у нас Битрикс. Битрикс — он хороший, большой, универсальный и надежный. Действительно лучший в сегменте среди конкурентов. Но за счет своей универсальности требует много ресурсов. Использовать Битрикс — во многих случаях оправданное и хорошее решение. 

Концепция построения каталога такова: мы хотим взять столько офферов сколько получится, и слить в единую структуру категорий и подкатегорий все предложения офферов. И это было, если не ошибкой, то уж точно граблями, которые мы сами себе же и постелили. Почему? На то есть несколько причин:

  1. Офферы очень по-разному раскладывают товары по категориям. У кого-то, например, всего один уровень. Просто "Детские авто-кресла". А другие эту категорию раскрывают в подкатегориях "С 0 до 2 лет", "С 2 до 5 лет" и т.д. Вот тут и начинаются косяки: если мы покажем в нашем каталоге подкатегорию "С 0 до 2 лет" и пользователь в нее перейдет, то он не увидит предложения от оффера, который не детализируется так сильно. Теперь ты понимаешь муки выбора.. 
  2. Офферы меняют структуру выгружаемого каталога. И начинай сначала: см. п. 1.
  3. Есть пересекающиеся "непересекающиеся" объединения. Это если один оффер слил "Перчатки и шарфы", а "Шапки отдельно". А второй решил что "Шапки, варежки, перчатки" это няшно. И надо расщепить нерасщепимое и впихнуть невпихуемое.

Ладно, с горем пополам мы все-таки структуру осилили. Нужен механизм выгрузки. Ничего готового в Битриксе нет. Да нигде пока нет. Поэтому пишем сами. Логика такова:

  • Раз в сутки подгружаем фид с данными к себе на диск. Почему раз в сутки? Потому что чаще фиды не обновляются. Почему к себе? Потому что читать файл фида весом 3Гб по ссылке очень неустойчивое мероприятие. Все намного предсказуемее, когда файл фида лежит в локальной директории на сервере и точно известно, что он сейчас не будет перезаписываться, сетевое соединение не оборвется и все стабильно;
  • Формируем "очередь" из офферов. Запускаем процесс обработки фида раз в 10 минут. Он ищет из очереди первого кандидата на обработку: оффер, который дольше всех не обновлялся. И начинает процесс, блокируя сам себя до окончания обработки оффера, чтобы никаких параллельно выполняемых задач не возникало;
  • Раз в сутки запускаем скрипт, который ищет товары, обновленные последний раз трое суток назад. Такая ситуация возникает, когда в фиде товар пропадает. Это значит что он не в наличии и надо бы его убрать из каталога.

В итоге мы подключились к 31-му офферу и выгрузили 150 000 товаров. И начались торр-мо-зза. Банально не хватает оперативки для того чтобы выстроить дерево категорий и подкатегорий, характеристик товаров. Загрузка страниц разделов происходила в среднем за 3-4 секунды, а могла и дольше. Это сильно долго и не продакшн реади, и не юзер френдли ни разу. Композитный кеш помогал, но не сильно. Посещаемость сайта была... да можно сказать что ее и не было) 40-50 человек за сутки. 

Со стороны выгрузки товаров тоже было не все гладко: очень по-долгу обрабатывались фиды, сервер падал с нехваткой памяти и вообще не кайф. В итоге мы пришли к оптимальной цифре товаров, отказавшись от некоторых офферов. Сейчас это примерно 80 000 товаров. Именно с таким количеством все работает комфортно: и выгрузка успевает и Sphinx не падает, а выдает вполне себе хороший морфологический поиск. 

ВДВрус.ру

А тут наш любимый CakePHP. И поиск уже не на Sphinx а на ElasticSearch. И взялись мы за этот проект аккурат после Бэбикам, то есть уже находившись по одним граблям изрядно, решили пройтись по другим. Здесь было принято стратегическое решение: делаем собственные изолированные витрины подключаемых офферов. То есть даже не пытаемся все товары от всех офферов слить в единую структуру. Просто раскладываем все отдельно.

И какое же это счастье, когда нет ничего лишнего, и ты сам проектируешь структуру БД исходя из задачи. Тогда парсинг — одно удовольствие. Быстрее чем это происходит в Бэбикам на 1С Битрикс раз так в 50. Серьезно. Но это и логично: в своей разработке мы решаем одну узкую задачу. В Битриксе же, в силу его универсальности и многофункциональности, при добавлении товара в базу происходит еще очень большое количество смежных процессов, которые требуют времени на выполнение.

Здесь мы сразу решили строить выдачу товаров на ElasticSearch. И это, прямо скажем, стало залогом успеха. Попробуйте ка на больших объемах посчитать количество товаров в категориях с учетом подкатегорий и отсортировать в порядке убывания, уложившись в 50 миллисекунд. Едва ли это возможно на голом MySQL, ведь всем известно насколько дорого обходятся COUNT с JOIN'ами и дополнительными условиями выборки. ElasticSearch же делает это неприлично быстро.

Еще на ВДВрус мы захотели поиск в каждой категории. Зашел ты в М-видео в категорию "Ноутбуки", и прям там тебе морфологический поиск. И легко это реализовали. Причем с фильтром по диапазону цен "от" и "до".

Ну и вишенка на торте: поиск. Быстрый поиск по всем товарам всех магазинов. Который позволит найти самый дешевый Iphone 11 среди всех офферов. Поиск — это то место, где встречаются все подходящие под запрос товары из витрин различных офферов.

Выгрузку мы также написали с нуля, но пользуясь полученным в Бэбикам опытом. Разбор файлов происходит путем чтения "по кускам" при помощи XMLReader. Сначала товары складываются в базу MySQL, а затем попадают в индекс ElasticSearch в независимой задаче "Индексирование", которая запускается каждые две минуты и берет пачку непроиндексированных или измененных товаров размером не более 5000 штук.

И начали мы подавать заявки офферам. Справедливости ради, надо отметить, что сайт ВДВрус был намного более интересен офферам, поскольку с посещаемостью у него неплохо: в среднем 2600 посетителей в сутки. В итоге мы набрали аж 60 штук офферов. И это не предел, в Адмитаде есть еще) Но нам хватило данного объема чтобы начать наращивать базу товаров. 

Итак, самое интересное. Поехали. 100 тыщ товаров: на ура! Страницы открываются меньше чем за секунду. 500 тыщ: никаких изменений, полет нормальный! 1 млн. товаров. Да ладно?! 2 млн. товаров.. 3 млн. Вообще класс! За сутки вся очередь офферов успевает преспокойненько пройти по обработке. Максимум, достигнуты нами: 4 660 000 товаров

И тут уже мы почувствовали задержку на главной странице: вместо привычных 1.2-1.5 сек она вдруг начала прогружаться за 2.5 сек. Но это вполне себе нормально, с учетом того что происходит: обрабатываются все категории всех 60-ти офферов, считается кол-во товаров в каждой из них, складывается рекурсивно до верхнего уровня, сортируется и выводится. И все это "по-офферно". И да, мы понимаем что это мало информативная страница, и оно того не стоит. И в ближайших планах сделать ее поинтереснее и полезнее. Данная структура изжила себя.

И поиск начал долго думать на высокочастотных запросах. Тут уж мы смириться не смогли и пошли оптимизировать. И все дело оказалось в нюансах построения запроса к ElasticSearch, а именно к агрегации товаров по офферам и категориям. Удалось оптимизироваться настолько, что стало еще быстрее чем в самом начале, со 100 000 товаров :)

Как это индексируется поисковиками?

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

Описания товаров

Основная проблема конечно же состоит в том, что офферы скупы на качественные описания товаров. Видимо считают, что они будут конкурировать с их сайтом, что не гуд. А прорабатывать отдельные описания для партнерки не хотят. Хорошим примером оффера, который предоставляет качественные описания, является MyToys. Именно благодаря текстам товары данного оффера хорошо индексируются и конвертируются в продажи.

Стартовые метрики сайта

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

Посещаемость и быстродействие

Покажем это наглядно. Вот как развивалась история с посещаемостью на Бэбикам.ру:

А вот как это происходило с разделом "Товары" на ВДВрус.ру:

Видно что на Бэбикам.ру с первого месяца до последнего мы нарастили посещаемость в четыре раза. А с 0 посетителей до 2118 в месяц мы добрались спустя 9 месяцев после запуска.

На ВДВрус.ру темпы роста не так впечатляют. Зато посещаемость радует. Но это пока что всего лишь 3,5 месяца работы раздела с витринами товаров.

По быстродействию ситуация следующая:

Это график скорости загрузки на ВДВрус.ру

А это график Бэбикам.ру

Как видим, на ВДВрус.ру мы вышли из секунды по времени до начала отрисовки страницы. До загрузки DOM проходит 2.7 сек. Львиную долю на себя забирает главная страница с товарами, т.к. там все наши офферы со своей структурой: эту инфу трудно собрать и довольно много нодов в HTML структуре получается. Но главную мы уже решили изменить на более интересную и информативную.

Бебикам.ру, в принципе, показывает адекватное время до отрисовки. Однако время до загрузки DOM в 5.5 секунд это долговато. И не забываем, что товаров там всего ничего: 80к. На ВДВрус.ру их, на момент написания статьи, уже 4.5 млн.

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

Что по SMM?

Понятно что SMM нужно, хотя бы в базовом своем варианте: регулярные посты в группах. Но чтобы ухаживать за всем этим хозяйством, добавляя посты вручную, нужны ресурсы. А у нас их нет. Нам есть чем заняться. Поэтому мы написали бота, который делает выборку случайного товара по определенному фильтру, и постит в соц сети по расписанию. Особого эффекта на продажах не ощутили, но поисковикам активность в соц. сетях явно нравится. 

Сколько удалось заработать?

Не так много чтобы говорить об этом серьезно, но на удивление не так уж и мало. Ну то есть не совсем ничего :) Мы даже задумались "А что если заняться этой темой более плотно?".

Какие планы на будущее?

Вот так обычный эксперимент привел нас к новому необычному гемору) Это интересная тема. И у нас уже появилась куча идей по развитию сервисов для пользователей: мы уже запустили программу лояльности и раздел с обзорами товаров на ВДВрус.ру. А Бебикам мы все-таки пересадим на индивидуальную разработку. В общем, будем пробовать и обязательно напишем, если получится что-то дельное.

P.S.

И еще кое-что: параллельно с запуском раздела товаров на ВДВрус.ру мы запустили аналогичный сайт ВсемТовар.ру с нуля. И, если раздел с товарами на ВДВрус.ру вышел на среднюю суточную посещаемость в 600 посетителей, но ВсемТовар.ру до сих пор сидит в песочнице и на сайт заходят 2-3 посетителя в сутки. Вылезет ли он из песочницы? Сколько для этого понадобится времени? Будем посмотреть!

Заказать разработку