Перейти к содержанию

Data Storager

data-storager (в коде и переменных окружения также встречается историческое имя es-storager) — микросервис, который читает данные из реляционных баз Webim и переносит их в поисковый кластер (Elasticsearch или OpenSearch) и в ClickHouse. Исходные записи в meta-БД и базах pro сервис не изменяет.

Компонент не входит в основной пакет Webim Server. Его выдаёт техническая поддержка вместе с инструкцией по установке конкретной поставки. Статья описывает архитектуру, настройки и типовые операции, которые нужно знать администратору hosted-инсталляции.

Связанные материалы:

Как устроен сервис

Один процесс producer раз в три минуты просматривает список аккаунтов и публикует в общий топик Apache Kafka задание DiscoverAndStoreRequest (имя аккаунта). Несколько независимых consumer-процессов читают тот же топик и каждый делает свою работу:

meta-БД (таблица accountkeyvalue)
        │  раз в 3 минуты
        ▼
   producer  ──►  топик Kafka (DISCOVER_AND_STORE_CHATS_TOPIC)
                       │
          ┌────────────┼────────────────────┐
          ▼            ▼                    ▼
 subscriber-chats   subscriber-stats   subscriber-report-stats (опционально)
          │            ▼                    ▼
          ▼       ClickHouse           ClickHouse
 Elasticsearch /   (статистика v2,     (отчётный стор)
 OpenSearch        базы webim_stats_*)

Маркеры прогресса и список временно «заблокированных» аккаунтов хранятся в Redis. Благодаря этому consumer-ы можно запускать, останавливать и масштабировать независимо, не теряя позицию переноса.

Сервис не получает содержимое чатов из Kafka: в топике только триггер. Данные consumer читает сам из баз pro.

Компоненты

Компонент Роль Обязателен
producer Планировщик: один экземпляр на весь контур. Не запускайте отдельный producer на каждый consumer. Да
subscriber-chats Индексация тредов, сообщений, посетителей, оценок и опросов в Elasticsearch / OpenSearch. Для поиска в истории
subscriber-stats Наполнение ClickHouse для Статистики версии 2. Для статистики v2 через storager
subscriber-report-stats Отдельный ETL в отчётный ClickHouse (виджеты статистики и дашборда поверх HTTP API). Если используете отчётный HTTP API
stats.py HTTP-приложение (FastAPI): служебные эндпоинты, метрики, при включении — API отчётов и статика виджетов. Да, если нужны /health, /metrics или отчётный API
dashboard-realtime Периодический снимок «живых» показателей дашборда в Redis. Только для realtime-дашборда
subscriber-chat-states, subscriber-periods Индексация истории состояний чата и периодов онлайна операторов в поисковый кластер. По необходимости поставки

Функции

  • индексация истории чатов и связанных объектов в Elasticsearch / OpenSearch;

  • индексация истории состояний чатов и периодов онлайна операторов в тот же кластер — опционально, отдельными компонентами subscriber-chat-states и subscriber-periods;

  • перенос статистических данных в ClickHouse для Статистики версии 2;

  • инкрементальное обновление по триггерам из Kafka;

  • опциональный отчётный HTTP API и встраиваемые виджеты статистики / дашборда;

  • публикация метрик Prometheus и проверка состояния.

Что должно быть в инфраструктуре

Перед запуском согласуйте с поддержкой и подготовьте:

  • Apache Kafka (и права на чтение/запись общего топика; по умолчанию имя топика — es-discover-and-store-chats, 2 партиции);

  • Redis — маркеры, кэш и список аккаунтов, для которых недавно произошла ошибка обработки;

  • meta-БД Webim (MySQL или PostgreSQL) — таблица accountkeyvalue;

  • базы pro каждого индексируемого аккаунта (MySQL или PostgreSQL);

  • кластер Elasticsearch или OpenSearch, если нужен поиск в истории;

  • ClickHouse, если нужна статистика v2 и/или отчётный API;

  • файл геоданных Sypex Geo по пути GEO_DB_PATH (если в поставке используется определение страны в статистике).

Версии смежных продуктов см. в требованиях к ПО сервера. Типовая поставка сервиса рассчитана на Python 3.10.

Какие аккаунты обрабатываются

producer собирает список аккаунтов из двух источников и отбрасывает те, что временно попали в Redis-множество storager.failed_accounts (после ошибки обработки; срок — 15 минут).

Маркер в meta-БД (основной способ)

В таблицу accountkeyvalue добавьте строку с ключом es_storager_key. Значение должно посимвольно совпадать с переменной ES_KEY_VALUE в .env того инстанса data-storager, который должен обрабатывать аккаунт. Так несколько инстансов сервиса могут делить аккаунты между собой.

Пример для MySQL:

INSERT INTO accountkeyvalue (`accountname`, `key`, `value`)
VALUES ('shop', 'es_storager_key', '1.0');

Подробнее о маркере — в статье Подключение Elasticsearch или OpenSearch.

Список в .env

Переменная PRODUCE_FOR_ACCOUNTS — имена аккаунтов через запятую. Такие аккаунты producer обрабатывает даже без строки es_storager_key в meta-БД:

PRODUCE_FOR_ACCOUNTS=shop,support

Подключение к базе pro

По умолчанию URL берётся из PRO_DATABASE_DEFAULT_URL, имя базы подставляется из PRO_DATABASE_TEMPLATE (плейсхолдер {account_name}).

Если имя аккаунта не совпадает с ключом подключения (другой хост или другое имя базы), задайте в meta-БД ключ pro_db_connection_key. Сервис ищет переменную окружения DATABASE_CONNECTION_<NAME>_URL, где <NAME> — значение ключа в верхнем регистре.

INSERT INTO accountkeyvalue (`accountname`, `key`, `value`)
VALUES ('shop', 'pro_db_connection_key', 'db1');
DATABASE_CONNECTION_DB1_URL=mysql+aiomysql://webim_service:PASSWORD@db.example.local:3306/{database}

Внимание

Если pro_db_connection_key задан, а соответствующей переменной DATABASE_CONNECTION_<NAME>_URL нет, сервис молча использует PRO_DATABASE_DEFAULT_URL. При неверном ключе это выглядит как ошибка «Unknown database» в логах consumer, а аккаунт периодически попадает в failed_accounts.

Глубина первого переноса в поисковый кластер

Если маркеров в Redis ещё нет, subscriber-chats ограничивает «назад» по ключам в accountkeyvalue. Приоритет у es_store_since.

Ключ Смысл Формат значения
es_store_since Фиксированная дата начала индексации YYYY-MM-DDTHH:MM:SS+TZ, например 2026-01-01T00:00:00+03:00
es_store_period Глубина от текущего момента микросекунды, например 2592000000000 — 30 суток

Для subscriber-stats (ClickHouse статистики v2) при отсутствии маркера глубина по умолчанию — последние 30 дней (начало суток). Маркеры этого контура в Redis живут 7 суток: если процессы не работали дольше, прогресс сбрасывается, и перенос снова начнётся с этой границы.

Сетевые требования

HTTP-порт веб-приложения задаётся STATS_WEB_PORT (по умолчанию 8000/tcp), адрес прослушивания — STATS_BIND_IP (по умолчанию 0.0.0.0). Прямой доступ из интернета к этому порту, как правило, не нужен: откройте его только для внутренней сети, балансировщика и системы мониторинга.

На том же порту:

  • /health — проверка: если в Redis есть аккаунты из failed_accounts, ответ будет с кодом 500;

  • /metrics — метрики Prometheus веб-приложения;

  • /static/… и /reports… — при включённом отчётном контуре.

Каждый Faust-воркер (producer, consumer-ы) дополнительно поднимает HTTP-сервер метрик на порту PROMETHEUS_PORT (по умолчанию 9090). Если несколько воркеров запущены на одном хосте без изоляции портов, назначьте им разные значения.

Для hosted-инсталляции на узле с сервисом нужны следующие направления (порты — значения по умолчанию; актуальные смотрите в .env).

Направление Назначение Порт/протокол Примечание
Входящие HTTP веб-приложения STATS_WEB_PORT (8000/tcp) /health, /metrics, при необходимости отчётный API
Входящие Метрики воркеров PROMETHEUS_PORT (9090/tcp) Сбор Prometheus с процессов Faust
Исходящие meta-БД и базы pro 3306/tcp или 5432/tcp Сервис читает данные напрямую из СУБД, не через HTTPS бэкенда
Исходящие Redis порт из REDIS_CACHE_LOCATION Маркеры и кэш
Исходящие Elasticsearch / OpenSearch 9200/tcp Запись индексов истории
Исходящие ClickHouse 9000/tcp (native); при необходимости 8123/tcp (HTTP) Статистика v2 и/или отчётный стор
Исходящие Apache Kafka порт брокера Публикация и чтение заданий
Исходящие Sentry 443/tcp Только если задан SENTRY_DSN

Если data-storager и Speller стоят на одном хосте без сетевой изоляции, назначьте им разные HTTP-порты.

Переменные окружения

Сервис настраивается через .env (или эквивалент в оркестраторе). Полный шаблон поставляется вместе с компонентом. Ниже — параметры, которые нужно согласовать при развёртывании.

Ядро и Kafka

Переменная Назначение
KAFKA_BROKER Адрес брокера Apache Kafka.
DISCOVER_AND_STORE_CHATS_TOPIC Имя общего топика заданий.
ES_KEY_VALUE Значение маркера es_storager_key в meta-БД.
PRODUCE_FOR_ACCOUNTS Дополнительный список аккаунтов через запятую.
BATCH_SIZE Размер пакета при чтении БД и записи в поисковый кластер.
LOGGING_LEVEL, LOGGING_FORMAT Уровень и формат логов.
SENTRY_DSN, SENTRY_ENV Опциональная отправка ошибок в Sentry.
DEFAULT_TZ Часовой пояс по умолчанию.
GEO_DB_PATH Путь к файлу Sypex Geo.
DEFAULT_HIDDEN_COUNTRIES Страны, скрываемые в статистике.

Базы данных

Переменная Назначение
META_DATABASE_URL Подключение к meta-БД. Для MySQL — префикс mysql+aiomysql://, для PostgreSQL — postgresql+asyncpg:// (схема meta задаётся параметром schema=).
PRO_DATABASE_TEMPLATE Шаблон имени базы pro, например webim_service_pro_{account_name}.
PRO_DATABASE_DEFAULT_URL URL по умолчанию; плейсхолдер {database} заменяется именем из шаблона.
DATABASE_CONNECTION_<NAME>_URL Именованные подключения для pro_db_connection_key.
REDIS_CACHE_LOCATION URL Redis, например redis://redis.example.local:6379/2.

Поисковый кластер

Переменная Назначение
SEARCH_ENGINE_TYPE elasticsearch или opensearch.
SEARCH_ENGINE_URLS URL узлов кластера (через запятую). Допустимы устаревшие имена ELASTIC_URLS, ELASTIC_USER, ELASTIC_PASSWORD, ELASTIC_INDEX_TEMPLATE.
SEARCH_ENGINE_USER, SEARCH_ENGINE_PASSWORD Учётная запись кластера. Нужны права на работу с индексами.
SEARCH_ENGINE_INDEX_TEMPLATE Шаблон имён индексов, например {account}-{object}.
ES_INDEX_VERSION Суффикс версии в ключах маркеров Redis.

На стороне Webim Server подключение к тому же кластеру задаётся в /etc/webim/db.json и параметрах account config elasticsearch_history / elasticsearch_threadprocessor — см. Подключение Elasticsearch или OpenSearch.

ClickHouse статистики v2

Переменная Назначение
STATS_DATABASE_TEMPLATE Шаблон имени базы, по умолчанию webim_stats_{account_name}.
STATS_DATABASE_DEFAULT_URLS URL реплик ClickHouse через запятую. Список трактуется как реплики одной и той же копии данных. Не указывайте здесь разные шарды: запись уйдёт на один узел, а чтение увидит неполные данные.

HTTP и мониторинг

Переменная Назначение
STATS_BIND_IP Адрес прослушивания веб-приложения (по умолчанию 0.0.0.0).
STATS_WEB_PORT HTTP-порт (по умолчанию 8000).
PROMETHEUS_PORT Порт метрик Faust-воркера (по умолчанию 9090).

Отчётный HTTP API (опционально)

Эти переменные нужны, если в поставке включены виджеты статистики / дашборда (subscriber-report-stats и stats.py).

Переменная Назначение По умолчанию
REPORT_CH_URLS URL одного экземпляра (или реплик) отчётного ClickHouse. —
REPORT_CH_DATABASE_TEMPLATE Имя общей базы отчётов на все аккаунты (без плейсхолдера {account_name}: изоляция — колонкой account_name). —
REPORT_STATS_MAX_AGE_DAYS Глубина хранения отчётных данных, дни. Уменьшение значения при следующем populate удалит более старые строки. 730
REPORTS_MAX_RANGE_DAYS Максимальная ширина одного запроса отчёта, дни; 0 — без ограничения. 31
REPORT_SCAN_LOOKBACK_DAYS Запас вниз по дате создания треда при скане; 0 — полное чтение таблицы. 90
REPORTS_REQUIRE_SIGNATURE Требовать подписанный токен. В промышленной среде оставляйте True. True
REPORTS_SIGNING_SECRET Секрет HMAC (≥ 32 символов), только на сервере. При включённой подписи и коротком секрете веб-приложение не стартует. —
REPORTS_SIGNING_SECRET_PREVIOUS Предыдущий секрет на время ротации. —
REPORTS_MAX_TOKEN_TTL_DAYS Потолок остаточного срока токена; 0 — без ограничения. 0
REPORTS_CORS_ORIGINS Origin страниц, с которых браузер может читать API (через запятую). Это не замена токену. *
REPORTS_RATE_LIMIT / REPORTS_RATE_LIMIT_WINDOW Лимит запросов на IP и окно в секундах; 0 в лимите — выключить. 120 / 60
REPORTS_TRUST_PROXY_HEADER Брать IP клиента из X-Forwarded-For. Включайте только за прокси, который сам выставляет заголовок. False
DASHBOARD_REALTIME_UPDATE_INTERVAL Интервал живого опроса дашборда, сек. 15
DASHBOARD_PREV_PERIODS_UPDATE_INTERVAL Интервал исторического опроса дашборда, сек. 60

N.B.

База отчётного контура создаётся администратором заранее. Процесс ETL не выполняет CREATE DATABASE. Пользователю ClickHouse нужны права на таблицы этой базы, включая DDL и мутации (CREATE TABLE / VIEW, DROP, ALTER, OPTIMIZE, TRUNCATE — уточняйте по поставке).

Масштабирование и отказоустойчивость

  • producer — ровно один экземпляр на контур.

  • Consumer-ы масштабируются по числу партиций топика (в типовой конфигурации — 2). Все экземпляры одного consumer должны использовать общий Redis.

  • Веб-приложение stats.py можно поставить за прокси в нескольких процессах.

  • Отчётный ClickHouse: в REPORT_CH_URLS перечисляйте только реплики. Если кластер шардирован и реплик нет, указывайте один узел: несколько шардов в этом списке разнесут запись и испортят отчёты без явной ошибки в логе.

  • Источник истины для чатов — базы pro. Поисковый кластер и ClickHouse — производные витрины: после потери витрины данные можно перезалить (см. ниже).

Эксплуатация

Команды выполняются через CLI Faust. В Docker подставьте имя контейнера вашей поставки, например:

docker exec -it es-storager-subscriber-chats-1 faust -A subscriber_chats -l info health

Поиск (subscriber-chats)

Задача Команда
Проверить связь с кластером поиска faust -A subscriber_chats -l info health
Сбросить список failed_accounts в Redis faust -A subscriber_chats -l info reset
Поставить задание на индексацию аккаунта faust -A subscriber_chats -l info indexchats --account_name=shop
Проиндексировать один тред faust -A subscriber_chats -l info indexchat --account_name=shop --chat_id=<id>
Состояние маркеров faust -A subscriber_chats -l info info --account_name=shop
Сбросить маркеры (переиндексация с начала глубины) faust -A subscriber_chats -l info refresh --account_name=shop
Удалить индекс аккаунта faust -A subscriber_chats -l info drop --account_name=shop
Обновить mapping индекса faust -A subscriber_chats -l info mapping --account_name=shop

Статистика v2 (subscriber-stats)

Даты: %d-%m-%Y или %d-%m-%YT%H:%M:%S.

faust -A subscriber_stats -l info populate --account_name=shop --from=01-01-2026 --to=31-01-2026
faust -A subscriber_stats -l info nextstep --account_name=shop
faust -A subscriber_stats -l info refresh --account_name=shop

refresh сбрасывает маркеры всех storager-ов статистики v2 и запускает пересчёт.

Для «дыр» в ClickHouse, которые наполняет Chat Backend, по-прежнему можно использовать скрипт populate_clickhouse.sh — см. Перенос данных в ClickHouse.

Отчётный контур (subscriber-report-stats)

faust -A subscriber_report_stats -l info migrate_schema --account_name=shop
faust -A subscriber_report_stats -l info populate --account_name=shop --from=01-01-2026 --to=31-01-2026
faust -A subscriber_report_stats -l info refresh --account_name=shop
faust -A subscriber_report_stats -l info purge --account_name=shop

Схема таблиц создаётся идемпотентно при первом событии по аккаунту; migrate_schema прогревает её заранее. Очистка старше REPORT_STATS_MAX_AGE_DAYS выполняется автоматически не чаще раза в сутки (можно вызвать purge вручную).

Отчётный HTTP API и встраивание

Если в поставке включён отчётный контур, веб-приложение отдаёт:

Метод Путь Назначение
GET /reports Один отчёт (report, start, end; необязательно department, locale, category_id)
GET /reports/list Список отчётов
GET /reports/filters Значения фильтров и граница хранения min_date
GET /l/o/current-stats Данные дашборда (realtime=true или false)

Авторизация: параметр token (подписанный токен). В режиме разработки при REPORTS_REQUIRE_SIGNATURE=False допускается account_name — в промышленной среде не используйте.

Токен несёт имя аккаунта и срок действия, подписывается HMAC-SHA256 секретом REPORTS_SIGNING_SECRET. Бэкенд страницы-хоста выпускает новый токен на каждый рендер с коротким TTL. Отдельного отзыва токенов нет: экстренно отзывают все токены ротацией секрета (REPORTS_SIGNING_SECRET_PREVIOUS на время перекрытия). Формат токена и примеры реализации на PHP / Node.js / Python входят в поставку компонента (файл report_storager/EMBED.md).

Виджеты подключаются одним тегом (скрипт сам догружает недостающие стили и библиотеки). Origin API по умолчанию совпадает с origin скрипта; при другом origin задайте его на странице. Для кросс-доменных запросов со страниц Webim Server укажите эти origin в REPORTS_CORS_ORIGINS.

Лимит REPORTS_MAX_RANGE_DAYS отклоняет слишком широкий период кодом 400 (range_too_wide), а не сужает его молча. Частотный лимит (429) не затрагивает /health, /metrics и /static. Если Redis недоступен, частотный лимитер пропускает запрос (fail-open): это защита от нагрузки, а не авторизация.

Логирование и мониторинг

Логи пишутся в стандартный вывод процесса.

Метрики воркеров (имена с префиксом es_storager_) включают счётчики проиндексированных и неуспешных чатов, маркеры прогресса, число опубликованных заданий. На отчётном API: report_storager_auth_rejected (причины отказа видны в метке, в HTTP-ответе всегда общий 401) и report_storager_rate_limited.

N.B.

При инфраструктурной ошибке (нет базы, таймаут СУБД) счётчик неуспешных чатов может вырасти сразу на величину BATCH_SIZE, хотя документы в кластер ещё не отправлялись. Ориентируйтесь также на логи и на отсутствие роста es_storager_indexed_chats.

Типовые проблемы

Симптом Что проверить
Аккаунт не обрабатывается Есть es_storager_key = ES_KEY_VALUE или имя в PRODUCE_FOR_ACCOUNTS; аккаунт не в failed_accounts (reset)
Ошибка «Unknown database» pro_db_connection_key и наличие DATABASE_CONNECTION_<NAME>_URL; иначе используется PRO_DATABASE_DEFAULT_URL
Нет связи с поиском faust -A subscriber_chats -l info health; URL, учётная запись, сеть до 9200/tcp
Нужно переиндексировать историю refresh или drop + indexchats
В статистике v2 дыра за период populate у subscriber_stats и/или populate_clickhouse.sh
Отчёты пустые / 500 Доступен ли ClickHouse по REPORT_CH_URLS; создана ли схема (migrate_schema); эмитит ли producer аккаунт
401, «Ссылка устарела» Истёк или неверно подписан токен; секрет на хосте и в сервисе совпадает
Фронт не загружает отчёты REPORTS_CORS_ORIGINS; прокси до STATS_WEB_PORT
Realtime-дашборд пустой Запущен dashboard-realtime; недавно открывали дашборд этого аккаунта

data-storager обеспечивает перенос данных из баз Webim в поисковый кластер и ClickHouse. Для работы нужны Kafka, Redis, доступ к meta-БД и базам pro, согласованный маркер es_storager_key / ES_KEY_VALUE и (по задачам инсталляции) кластер поиска и ClickHouse.