Add-on к Авито. Стартап или пример архитектуры

от автора

Предыстория

Честно говоря, никогда ранее не покупал б/у вещи на досках объявлений. Но когда случился очередной экономический кризис и нужда заставила, пришлось обратить свое внимание на Авито.

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

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

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

Разделяя мнение Стивена Леви о свободном доступе к информации, было решено проанализировать Авито на предмет разработки собственного сервиса sravnito.ru с блэкджеком и всеми делами, а именно: с простым интерфейсом и бесплатным доступом.

На основании проведенного анализа были определены основные атрибуты объявления:

  • название
  • дата публикации
  • цена
  • местонахождение
  • телефонный номер (либо изображение номера, либо хэш от него, либо распознанное OCR значение)

Архитектура

Теперь непосредственно об архитектуре программного комплекса, на котором основан сервис поиска всех объявлений продавца:

Хранилище

В качестве хранилища для хранения объявлений и их скриншотов используется MySQL (Maria DB) с движком InnoDB.

В DB1 хранятся объявления с основными атрибутами. Для сокращения объема памяти, занимаемого данными, для текстовых полей используется тип VARCHAR, так как их длина разнится от объявления к объявлению. Ежедневно добавляется примерно полмиллиона строк, среди которых как сами объявления, так и логи и служебная информация. При такой динамике хранилище по праву можно будет относить к Big Data. Из особенностей настройки можно выделить следующие параметры:

max_heap_table_size = 512M innodb_buffer_pool_size = 3G 

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

CREATE TEMPORARY TABLE _temp_table ENGINE=MEMORY AS ( SELECT field FROM table WHERE key = i_key LIMIT i_limit); 

которая потом соединяется с другой:

SELECT table.* FROM table JOIN _temp_table ON table.field = _temp_table.field; 

В DB2 хранятся скриншоты объявлений как они выглядят для пользователя браузера. Перед записью скриншоты сжимаются в JPEG с quality = 5, что обеспечивает размер файла с изображением равный примерно 20Кб. Принято считать, что при размере BLOB не более 200Кб, производительность хранения файлов в MySQL ничем не уступает NoSQL-хранилищам, что позволяет оставаться в зоне комфорта реляционной СУБД со всеми ее преимуществами. Настолько сжатый скриншот, несмотря на минимальное качество изображения, позволяет пользователю убедиться, что заданное объявление действительно существовало, и разглядеть хотя бы схематично изображение товара.

Вся логика реализована в хранимых процедурах, чтобы инкапсулировать зависимый от структуры данных код в самой СУБД. Таким образом, клиенты СУБД имеют полномочия только для доступа к хранимым процедурам, которые являются идемпотентными. Как дополнительный плюс получаем отсутствие возможности осуществления SQL-инъекций.

API к хранилищу

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

import ( "database/sql" "encoding/json" "net/http" _ "github.com/go-sql-driver/mysql" ) 

Обрабатываются GET и POST запросы от клиентов и вызываются соответствующие хранимые процедуры БД DB1, DB2.

Загрузчики объявлений

Объявления загружаются с сайта Авито загрузчиками S(1)-S(N), написанными на Java с использованием библиотеки Selenium WebDriver. Получив с Авито атрибуты объявления и скриншот, загрузчик обращается к серверу M1 для передачи данных. Также реализована обратная связь для управления загрузчиками, которые периодически опрашивают сервер M1 на предмет команд, например «стоп», «старт».

Captcha

Для разгадывания капчи, которую иногда запрашивает Авито, существует сервер C1, по аналогии с сервером M1 реализованный на golang и предоставляющий RESTful API. Разгадывание капчи осуществляется двумя способами:

  • с помощью сервиса rucaptcha.com
  • вручную в приложении для Android

Для связи с rucaptcha.com используется их API. Для ручного разгадывания используется написанное на Java приложение Android, которое выводит изображение и принимает ответ. Сервер C1 принимает решение о перенаправлении капчи на rucaptcha.com или в приложение Android в зависимости от количества запросов, накопившихся в очереди. Получив разгадку капчи, сервер C1 отправляет ответ запросившему его загрузчику.

Мониторинг

По аналогии с приложением Android для разгадывания капчи, существует приложение для мониторинга. Приложение Android для мониторинга обращается к серверу M1, который в свою очередь обращается к БД где агрегируются логи, на основе которых можно судить о количестве загруженных объявлений, сбоях в работе и т.п.

Заключение

Дальнейшее развитие сервиса может быть таким:

  • Создание загрузчиков для других досок объявлений, что позволит делать кросс-поиск всех объявлений одного продавца
  • Использование комплекса для обработки других данных, например загрузка из соцсетей для поиска всех постов по имени аккаунта

И в том и в другом случае разработке подлежат только загрузчики, которые легко интегрируются с серверами M1 и C1. Доработка других частей системы не потребуется.

Если сделать API серверов M1, C1 публичным с авторизацией и добавить в структуру БД ключевое поле для разделения по клиентам, то можно предоставлять услугу по хранению данных и обработке капчи как SaaS. Данные клиента можно хранить в BLOB в виде JSON, доработав при этом БД с хранимыми процедурами и интерфейс API.

Что можно сказать о выбранных технологиях:

  • MySQL — классика жанра, без комментариев
  • Java — загрузчики можно запускать на кофеварках и холодильниках
  • golang — очень быстро разрабатываются микросервисы, легко деплоится путем копирования единственного бинарника на сервер

Буду признателен за комментарии и обсуждение.
ссылка на оригинал статьи https://habrahabr.ru/post/317598/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *