Привет! Меня зовут Максим Панфилов, я ИТ-предприниматель. Мой основной бизнес – студия разработки, которой больше 10 лет. Мы специализируемся на создании ИТ-проектов для бизнеса из ниши стройматериалов, товаров для дома и инженерных систем.

В начале мы делали сайты на 1С-Битрикс. Сейчас в команде по-прежнему сохранилась эта компетенция, но в основном мы разрабатываем веб-приложения с подходом Sinlge Page Application: на беке Symfony или Node.js, на фронте – Vue / Nuxt.

Одной ногой в Битриксе, другой – в Single Page Application
Одной ногой в Битриксе, другой – в Single Page Application

К сожалению, у клиентов на рынке по-прежнему большой спрос на разработку на 1С-Битрикс как CMS. От крупных компаний к нам приходят запросы с обязательным требованием по использованию Битрикса. Условия сотрудничества хорошие, поэтому мы соглашаемся.

Однако на стороне клиентов всё чаще понимают ограничения Битрикса и соглашаются на то, чтобы расширять его другими технологиями. Один из таких проектов – сайт крупнейшего производителя кабеленесущих систем с каталогом продукции.

В основе проекта заложен Битрикс, но для выборки блока с аналогами и аксессуарами в карточке товара стандартных возможностей CMS было недостаточно.

Блок с подборкой аксессуаров в карточке товара
Блок с подборкой аксессуаров в карточке товара

Поэтому для реализации этой подборки мы выделили агрегацию данных в отдельный сервис на Symfony + MongoDB.

В этой статье расскажу, как это было и с какими сложностями мы столкнулись.

Фильтрация и агрегация большой базы данных

На проекте в базе товаров больше 80 тыс. товаров, и дальше планируется увеличение до 250 тыс.

У товаров есть набор различных характеристик, причём они разного вида:

  • есть базовый справочник общих характеристик,

  • могут дополняться свои характеристики для группы товаров.

Всего сейчас в таблице БД больше 1 миллиона записей связок «товар — характеристика».

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

Мы уже успешно разрабатывали похожие функции на другом проекте, который был написан на Symfony с базой MongoDB. Там мы реализовали сложную фильтрацию, подборку «Аналогов и Аксессуаров», сборку комплектов и не только.

Чтобы использовать ценный опыт, для нового проекта мы решили сделать отдельный сервис, который возьмет на себя все заботы по фильтрации и агрегации данных и снимет нагрузку с Битрикса.

Для реализации сервиса выбрали Symfony с базой данных MongoDB и придумали схему взаимодействия с Битриксом.

Схема взаимодействия сервиса на Symfony с CMS Битрикс и внешними системами
Схема взаимодействия сервиса на Symfony с CMS Битрикс и внешними системами

Данные из Битрикса передаются через очередь RabbitMQ, тогда как запросы на фильтрацию и агрегацию отправляются по HTTP внутри локальной сети.

Средства взаимодействия Битрикса и сервиса успешно прошли проверку. Проблем с передачей больших объемов данных и скоростью обработки запросов не возникло.

Но работа с данными из основной системы Битрикса оказалась сложнее, чем мы предполагали.

Мы воспринимали наш сервис как независимый элемент, что привело к недостаточной проработке вопросов хранения данных на стороне Битрикса и вызвало ряд сложностей.

Обмен данными

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

Система хранения данных на стороне Битрикса была разработана до внедрения сервиса и не предусматривала необходимости обмена данными.

Первоначально мы полагали, что оптимальным решением будет оставить схему хранения и обработки данных «Аналогов и Аксессуаров» на стороне Битрикса без изменений.

Схема хранения данных до внедрения сервиса
Схема хранения данных до внедрения сервиса

Первое пробное предложение для Битрикса по получению данных было слишком оптимистичным.

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

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

В итоге отказались от денормализации в данных и пришли к универсальному виду сообщения для отправки в очередь.

Параметры сообщения в очередь:

  • timestamp - string, метка времени создания сообщения

  • entity - string, сущность с которой связанно событие

  • action - string, тип события

  • message - string, данные события

Вот так это выглядит в JSON:

{
    "timestamp": "1720771159",
    "entity": "b_iblock_section",
    "action": "update",
    "message": {}
}

Обработка очереди на стороне сервиса

Из нашего опыта и общих правил работы с RabbitMQ мы вынесли важный момент: RabbitMQ не любит, когда в очереди накапливается много сообщений.

При накоплении большого количества сообщений, RabbitMQ потребляет много памяти, упирается в лимиты и умирает.

Здесь простое решение — быстро обрабатывать то, что пришло в очередь. Спасибо, Кэп :) 

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

Мы организовали промежуточное хранилище и отдельный документ с отдельной таблицей в реляционной БД.

Так мы:

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

  • упростили обработку данных. Само хранилище организовано так, что при сохранении происходит отсеивание ошибочных данных и возможных дублей.

  • настроили приоритеты. Данные могут приходить разрозненно, например на момент обработки свойств, у нас может не быть товара, для которого эти свойства пришли. Поэтому мы сначала обрабатываем базовые данные, которые нужны для связей в других.

Такая схема усложнила разработку, но полностью себя окупила — в разы упростились этапы тестирования и отладки сервиса.

Опасения, что обработка будет медленной, не оправдались. Если целостность данных не нарушена, все обрабатывалось очень быстро. Но если всё- таки происходило нарушение целостности данных в Битрикс, это замедляло процесс, но не останавливало его.

Хранение данных на стороне сервиса

Это был самый трудный и важный этап проектирования. Весь успех зависел от схемы хранения данные в MongoDB. Ошибки на этом этапе отражались бы на всём функционале сервиса.

Одна из сильных сторон MongoDB — денормализация данных. Например, в данных товара можно сложить все его свойства в виде вложенной конструкции. Одним запросом фильтровать товары, получать список их свойств со значениями для выбранной локали.

Перед нами стояла задача — преобразовать данные из Битрикса в удобную схему для фильтрации и выборок.

Например, вот какие правила выборки были для «Аналогов» или «Аксессуаров»:

  1. Активность разделов. Мы не должны отдавать товар, если он лежит в неактивном разделе, или неактивный один из родительских разделов.

  2. Локаль (языковая версия сайта) раздела. Мы не должны отдавать товар, если он лежит в разделе, который не доступен для выбранной локали.

  3. Активность товаров. Мы должны отдавать только активные товары-аналоги.

  4. Локаль товара. Мы должны отдавать товары-аналоги, которые доступны для выбранной локали.

  5. Пагинация.

«Аналогом» или «Аксессуаром» может быть не только товар, но и целый раздел товаров.

Эти правила работают и для формирования списка разделов «Аналогов» или «Аксессуаров», и для списка самих «Аналогов» или «Аксессуаров».

Разработчики могут представить себе все сложности, которые придётся пережить на реляционной базе. Но для MongoDB с её подходами к выборке данных это простая задача

Схема отлично показала себя при дальнейшей реализации фильтрации и агрегации данных:

Часть итоговой структуры данных в MongoDB
Часть итоговой структуры данных в MongoDB

Сложности в разработке

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

Сильно упрощал работу наш большой опыт с MongoDB.

На стороне Битрикса основной проблемой было хранение и обновление данных по «Аналогам» и «Аксессуарам». Поначалу решили работать с тем, что есть. 

В итоге потеряли целостность: у данных в Битриксе менялись id при обработке новой выгрузки. Это усложнило процесс обработки данных в сервисе, нужно было исключать логические дубли данных. Страдала хронология отправки данных. Сначала могло прийти удаление, а потом создание этих же данных.

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

Корень проблемы — мы проектировали системы отдельно, делали упор только на общую схему обмена данных, но это был не совсем верный подход. Как это разрешили? 

Мы помним, что сервис является неотъемлемой частью всей системы и подчиняется Битриксу. Битрикс, в этой системе:

  • источник данных,

  • инициатор передачи данных,

  • инициатор запроса агрегации,

  • выполняющий компенсирующие действия, если что-то пошло не так.

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

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

Сервису стало проще обрабатывать данные. Это положительно сказалось на скорости обработки.

Итоги

Мы получили ценный опыт в проектировании сервиса, который расширяет функции основной системы.

Связка Битрикс и Symfony + MongoDB может приносить хороший результат. Запросы в локальной сети ходят быстро. MongoDB легко справляется с большими объемами данных.

Есть и альтернативные варианты решения задачи: можно было использовать связку Битрикс + Sphinx или Elasticsearch, и мы работали с таким системами.

Но в нашем случае Symfony + MongoDB — дешевле в разработке за счёт использования большого опыта и знаний.

Реализация прозрачна, легко расширяема и имеет большой потенциал для развития.

И это только начало для проекта. В сервисе уже готовится фасетный фильтр товаров, для которого мы планируем использовать надстройку из Symfony и MongoDB над CMS 1С-Битрикс.


Если у вас были похожие задачи совмещения Битрикса с другими технологиями, поделитесь в комментариях, как вы их решили :)

Комментарии (9)


  1. Mausglov
    03.12.2024 11:48

    Разработчики могут представить себе все сложности, которые придётся пережить на реляционной базе

    И дальше показана схема, для реализации которой в РСУБД я не вижу никаких сложностей.

    поделитесь в комментариях, как вы их решили

    Вы сами не делитесь ( в статье только общие слова), но ожидаете, что делиться будут с Вами?


    1. mpanfilov Автор
      03.12.2024 11:48

      Привет! Спасибо за внимание к нашей публикации!

      И дальше показана схема, для реализации которой в РСУБД я не вижу никаких сложностей.

      Мы не говорим, что это не возможно. Мы только рассказали про то, как использовали свой опыт не в РСУБД для упрощения этой конкретной задачи.

      Вы сами не делитесь ( в статье только общие слова), но ожидаете, что делиться будут с Вами?

      В статье постарались рассказать о том, как решили сложности совмещения Битрикса с другими технологиями для решения локальной задачи – постарались рассказать верхнеуровнево об архитектуре решения.

      Подскажите, чего вам именно не хватило в статье, чтобы вы посчитали, что мы поделились своим опытом? Нам важно, чтобы учесть это в будущих публикациях.


  1. Zivaka
    03.12.2024 11:48

    По интернет-магазинам только с DIY работаете сферой? Есть похожая задача по Битриксу и новым технологиям, как раз в поисках исполнителя)


    1. mpanfilov Автор
      03.12.2024 11:48

      Как я написал в тексте, если проект интересный, мы не против посотрудничать) написал вам в лс


      1. Zivaka
        03.12.2024 11:48

        "Пользователь mpanfilov запретил личные сообщения" :)


      1. Zivaka
        03.12.2024 11:48

        Можно в телеге по нику)


        1. mpanfilov Автор
          03.12.2024 11:48

          связались)


  1. mihacoder
    03.12.2024 11:48

    Миллион записей - это как бы немного. У нас 100 млн, обходимся просто postgresql.


    1. mpanfilov Автор
      03.12.2024 11:48

      Точно, объемы данных сами по себе – не проблема для реляционок. Подскажите, был ли у вас опыт разработки аналогичного сервиса фильтрации и подборок на PostgreSQL? Если да, то как делали, с помощью Elasticsearch или по-другому?