Разработка ETL-процессов для 1С-Битрикс
Стандартный импорт через административную панель 1С-Битрикс хорошо работает для разовой загрузки каталога. Для регулярной синхронизации с внешними источниками — ERP, 1С, складскими системами, маркетплейсами — нужны полноценные ETL-процессы с трансформацией данных, обработкой ошибок и мониторингом. Иначе через месяц окажется, что 3% товаров имеют неверные остатки, а никто об этом не знает.
Архитектура ETL для Битрикс
ETL (Extract, Transform, Load) на базе 1С-Битрикс строится вокруг нескольких слоёв:
Extract — получение данных из источника. Источники бывают:
- Файлы (CSV, XML, JSON, YML) — по FTP/SFTP или HTTP
- REST API внешних систем (1С, SAP, Salesforce)
- БД напрямую (MySQL, MSSQL, PostgreSQL) через PDO
- Очереди сообщений (RabbitMQ, Kafka)
Transform — приведение данных к структуре Битрикса: маппинг полей, нормализация форматов, валидация.
Load — запись в Битрикс через D7 API или прямые SQL-запросы для высоких объёмов.
Загрузка товаров: производительность
Для загрузки товаров через стандартный API Битрикса используем \Bitrix\Iblock\ElementTable и CCatalogProduct. При загрузке 10 000+ товаров — ключевые настройки:
// Отключаем ненужные обработчики на время импорта
define('STOP_STATISTICS', true);
define('NO_AGENT_STATISTIC', 'Y');
define('DisableEventsCheck', true);
// Отключаем поисковый индекс — перестроим в конце
\CSearch::DisableIndex();
// Загрузка элемента инфоблока
$el = new \CIBlockElement();
$result = $el->Add([
'IBLOCK_ID' => CATALOG_IBLOCK_ID,
'NAME' => $item['name'],
'CODE' => $item['code'],
'ACTIVE' => 'Y',
'PROPERTY_VALUES' => [
'VENDOR_CODE' => $item['vendor_code'],
'WEIGHT' => $item['weight'],
],
]);
При объёме > 50 000 элементов прямой вызов CIBlockElement::Add деградирует из-за каскада событий и обновления поиска. Переходим на прямые INSERT в таблицы b_iblock_element, b_iblock_element_property, b_catalog_product с последующим полным перестроением индексов.
Инкрементальная синхронизация
Полная перезапись каждые N часов — дорого. Инкрементальный ETL работает только с изменёнными записями:
// Фиксируем момент начала синхронизации
$syncStartTime = new \Bitrix\Main\Type\DateTime();
// Запрашиваем из источника только изменённые с прошлой синхронизации
$changedItems = $source->getChangedSince($this->getLastSyncTime());
// После успешной синхронизации обновляем метку
$this->setLastSyncTime($syncStartTime);
Таблица для хранения состояния синхронизации:
CREATE TABLE etl_sync_state (
source_name VARCHAR(64) PRIMARY KEY,
last_sync_at TIMESTAMP,
last_sync_status VARCHAR(16), -- success/error/running
records_processed INTEGER,
errors_count INTEGER
);
Трансформация данных
Трансформация — самая сложная часть: у каждого источника своя модель данных. Типичные задачи:
Маппинг категорий: в источнике может быть плоский список с полем parent_id, в Битриксе — дерево разделов. Нужно строить дерево, сопоставлять по коду или создавать с сохранением маппинга external_id → iblock_section_id.
Нормализация цен: источник может давать цену с НДС, без НДС, в разных валютах. Нужно пересчитывать с учётом курсов, хранить в правильный тип цены.
Очистка HTML: описания из 1С часто содержат нечитаемое форматирование. Прогоняем через DOMDocument, удаляем нежелательные теги.
Дедупликация: если источник не гарантирует уникальность артикулов — нужна логика объединения дублей.
Обработка ошибок на уровне строк
ETL-процесс не должен останавливаться из-за одной невалидной записи:
foreach ($items as $item) {
try {
$transformed = $this->transform($item);
$this->load($transformed);
$this->stats->incrementSuccess();
} catch (\Bitrix\Main\ArgumentException $e) {
// Ошибка валидации данных — логируем и продолжаем
$this->logger->warning('Validation failed', [
'external_id' => $item['id'],
'error' => $e->getMessage(),
]);
$this->stats->incrementError($item['id'], $e->getMessage());
} catch (\Exception $e) {
// Неожиданная ошибка — логируем, но продолжаем
$this->logger->error('Load failed', ['item' => $item['id'], 'error' => $e->getMessage()]);
$this->stats->incrementError($item['id'], $e->getMessage());
}
}
После синхронизации — отчёт: сколько создано, обновлено, пропущено с ошибками. Если ошибок > 5% — алерт.
Управление памятью при больших объёмах
PHP при обработке 100 000 записей легко исчерпывает память. Правила:
- Читаем данные порциями (chunk), не загружаем весь файл в массив
- Используем генераторы для итерации по CSV/XML
- Явно вызываем
unset()после обработки порции - Сбрасываем ORM-кеш Битрикса:
\Bitrix\Main\ORM\Data\DataManager::cleanCache() - Следим за
memory_get_usage()— при приближении к лимиту пишем в лог
// Генератор для чтения большого CSV
function readCsvChunks(string $file, int $chunkSize = 500): \Generator {
$handle = fopen($file, 'r');
$header = fgetcsv($handle);
$chunk = [];
while (($row = fgetcsv($handle)) !== false) {
$chunk[] = array_combine($header, $row);
if (count($chunk) >= $chunkSize) {
yield $chunk;
$chunk = [];
}
}
if ($chunk) yield $chunk;
fclose($handle);
}
Агенты vs Cron vs Очередь
Агенты Битрикса (b_agent) — для небольших задач (до 1000 записей за запуск). Запускаются при обращении к сайту, нестабильны при низком трафике.
Cron — надёжнее для регулярных синхронизаций. Скрипт запускается независимо от трафика:
*/30 * * * * php -f /var/www/bitrix/etl/sync_products.php >> /var/log/etl.log 2>&1
Очередь (RabbitMQ/Redis Queue) — для event-driven ETL, когда источник публикует события изменений. Позволяет обрабатывать высокочастотные изменения без потерь.
Мониторинг ETL
| Метрика | Источник | Алерт |
|---|---|---|
| Время последней успешной синхронизации | etl_sync_state |
> N часов от расписания |
| Доля ошибочных записей | Лог синхронизации | > 5% |
| Время выполнения синхронизации | Лог | Превышение планового окна |
| Расхождение количества записей | Сравнение источника и Битрикса | > 1% |
Этапы разработки
| Этап | Содержание | Срок |
|---|---|---|
| Анализ источников | Структура данных, форматы, расписание | 3–5 дней |
| Коннекторы Extract | Подключение к источникам, получение данных | 1 неделя |
| Трансформация | Маппинг, нормализация, валидация | 1–2 недели |
| Загрузка в Битрикс | API или прямые SQL, оптимизация производительности | 1–2 недели |
| Обработка ошибок и мониторинг | Логирование, алерты, отчёты | 3–5 дней |
| Тестирование | Нагрузочные тесты, граничные случаи | 1 неделя |
Суммарно: 6–12 недель в зависимости от количества источников и сложности трансформаций.







