Розробка 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 тижнів залежно від кількості джерел і складності трансформацій.







