База данных

Этот документ описывает требования к PostgreSQL для SmartCPD, актуальную модель ролей и SQL-скрипты поставки.

Базовые требования#

  • Поддерживаемая СУБД: PostgreSQL.
  • Поддерживаемая версия: 14+.
  • Мультиплексоры и connection pooler-решения типа pgbouncer в текущей версии SmartCPD не поддерживаются.
  • Подготовка, установка, отказоустойчивость, эксплуатация, мониторинг, backup и restore PostgreSQL находятся в зоне ответственности Заказчика.

Для SmartCPD обязательно задаётся параметр DB_TZ — IANA timezone, в которой интерпретируются значения времени БД без информации о часовом поясе, например Europe/Moscow. Значение должно соответствовать timezone, использовавшейся при записи исторических данных, и оставаться согласованным при эксплуатации и миграции. В SmartCPD 6.0 timezone БД (SMARTCPD_DB_TZ, передаваемая сервисам как DB_TZ) должна точно совпадать с timezone запуска контейнеров (SMARTCPD_TZ). Setup проверяет это соответствие и не позволяет сгенерировать или развернуть конфигурацию с разными значениями.

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

Разделение данных в SmartCPD 6.0#

В SmartCPD 6.0 исходные данные вызовов и расчетные данные биллинга разделены между разными сервисами:

  • cdr-collector владеет исходными CDR, разметкой и историей детекций в БД;
  • billing-server владеет тарифами, назначениями тарифов, тарифными окнами и расчетными фактами вызовов;
  • portal-api владеет основными объектами портала;
  • Grafana хранит собственную конфигурацию в отдельной схеме grafana;
  • SIPCapture/HOMER при включении соответствующего контура использует отдельную схему homer.

Новый billing-server не хранит исходные CDR и отдельную таблицу stats. Расчетные факты биллинга создаются на основании данных, полученных от cdr-collector, и не заменяют исходные CDR. Отдельный целевой пользователь БД markup в SmartCPD 6.0 не требуется: объекты CDR и разметки принадлежат владельцу контура cdr-collector. При обновлении с 5.x мигратору могут потребоваться учетные данные исходного legacy-пользователя markup.

При обновлении с SmartCPD 5.x legacy-таблицы могут временно сосуществовать с новыми объектами. Удалять их можно только после завершения и проверки миграции в соответствии с документом «Обновление SmartCPD».

Модель доступа#

SmartCPD использует единый bootstrap flow, поддерживающий две модели учетных записей: общую и per-service. Модель выбирается в smartcpd-setup.sh; SQL-скрипты поставки поддерживают обе модели.

Независимо от выбранной модели используются:

  • БД SmartCPD, по умолчанию smartcpd;
  • учетная запись основных объектов портала;
  • отдельная учетная запись конфигурационной БД Grafana;
  • обязательная логическая учетная запись биллинга: общая с порталом либо выделенная.

Имена пользователей и пароли задаются при прохождении setup. В production-сценарии не следует использовать тестовые значения из локального DB-образа.

Общая учетная запись#

В общей модели одна учетная запись используется для объектов portal-api, billing-server, cdr-collector, AMD, analyzer и datasource Grafana. Учетная запись конфигурационной БД Grafana остается отдельной.

На уровне 02-dbo-grants.sql незаданные роли amd, analyzer, grafana_ds и cdr автоматически заменяются ролью портала. Роль billing должна быть передана явно; setup подставляет для нее роль и пароль портала.

Роли sipcapture и pds не получают fallback к порталу и создаются только при включении соответствующих контуров.

Учетные записи per-service#

В модели per-service setup запрашивает отдельные учетные записи для:

  • billing-server;
  • AMD;
  • cdr-collector;
  • analyzer;
  • datasource Grafana.

Учетная запись billing-server должна быть выделенной и не может совпадать с учетными записями других сервисов. 02-dbo-grants.sql применяет права по владельцам объектов и пропускает выдачу прав, если получатель и владелец совпадают.

Схемы#

  • public — рабочая схема SmartCPD.
  • grafana — схема внешнего сервиса Grafana, создается если задан DB_GRAFANA_USER.
  • homer — схема SIPCapture/HOMER, создается если задан DB_SIPCAPTURE_USER.

Роли#

РольНазначение
portalВладелец основных объектов портала и общая сервисная роль в модели с одной учетной записью
grafanaВладелец схемы grafana с конфигурацией Grafana
billingВладелец тарифов и расчетных объектов billing-server; совпадает с portal в общей модели и изолирован в per-service модели
amdПотребитель и писатель данных CDR; отдельная роль используется только в per-service модели
analyzerRead-only потребитель данных CDR; отдельная роль используется только в per-service модели
grafana_dsRead-only datasource-пользователь Grafana для объектов портала и CDR; отдельная роль используется только в per-service модели
cdrВладелец объектов cdr-collector, включая CDR и разметку; в общей модели совпадает с portal
sipcaptureОпциональный владелец схемы homer
pdsОпциональный read-only потребитель CDR и объектов homer.hep_*

Административные роли:

РольНазначение
dboОпциональная роль владельца и администратора БД
dbadminОпциональная login-роль с наследуемым membership в dbo
readonlyОпциональная роль с pg_read_all_data
dbreaderОпциональная login-роль с наследуемым membership в readonly

Скрипты поставки#

Актуальный набор скриптов:

  • db/postgres/sql/00-sa-create-db-once.sql — создает БД.
  • db/postgres/sql/01-sa-users.sql — создает роли/пользователей, настраивает passwords/login, role memberships, owner БД и системные role grants.
  • db/postgres/sql/02-dbo-grants.sql — применяет CONNECT, schemas, search_path, default privileges и object grants.

В каталоге исходного репозитория этим файлам соответствует путь db/sql; в собранной setup-поставке используется публичный путь db/postgres/sql.

Старые раздельные скрипты 10/12/20/... и restore-скрипты больше не используются.

00-sa-create-db-once.sql выполняется только при первоначальном создании БД. Скрипты 01-sa-users.sql и 02-dbo-grants.sql являются идемпотентными и применяются при первичной подготовке и при обновлениях, изменяющих набор ролей или прав.

Требуемые полномочия:

  • 00-sa-create-db-once.sql — право создания БД;
  • 01-sa-users.sql — создание и изменение ролей, выдача membership и изменение владельца БД;
  • 02-dbo-grants.sql — выполнение от владельца целевой БД, superuser либо роли, способной выполнять SET ROLE в роли владельцев объектов.

CLI#

SQL-скрипты обращаются ко всему набору psql-переменных DB_*. Даже неиспользуемые параметры необходимо передать как пустые значения. Ниже приведен полный пример общей модели учетных записей. Команды предполагают, что подключение администратора PostgreSQL уже настроено через параметры psql, переменные окружения или .pgpass.

scpd_db_vars=(
  -v "DB_NAME=smartcpd"
  -v "DB_DBO_ROLE="
  -v "DB_DBO_ROLE_PASSWORD="
  -v "DB_DBA_USER="
  -v "DB_DBA_PASSWORD="
  -v "DB_READONLY_ROLE="
  -v "DB_READONLY_PASSWORD="
  -v "DB_READER_USER="
  -v "DB_READER_PASSWORD="
  -v "DB_PORTAL_USER=smartcpd"
  -v "DB_PORTAL_PASSWORD=<portal_password>"
  -v "DB_GRAFANA_USER=grafana"
  -v "DB_GRAFANA_PASSWORD=<grafana_password>"
  -v "DB_BILLING_USER=smartcpd"
  -v "DB_BILLING_PASSWORD=<portal_password>"
  -v "DB_AMD_USER="
  -v "DB_AMD_PASSWORD="
  -v "DB_ANALYZER_USER="
  -v "DB_ANALYZER_PASSWORD="
  -v "DB_GRAFANA_DS_USER="
  -v "DB_GRAFANA_DS_PASSWORD="
  -v "DB_CDR_USER="
  -v "DB_CDR_PASSWORD="
  -v "DB_SIPCAPTURE_USER="
  -v "DB_SIPCAPTURE_PASSWORD="
  -v "DB_PDS_USER="
  -v "DB_PDS_PASSWORD="
)

psql -v ON_ERROR_STOP=1 -d postgres \
     -v DB_NAME=smartcpd \
     -f db/postgres/sql/00-sa-create-db-once.sql

psql -v ON_ERROR_STOP=1 -d postgres "${scpd_db_vars[@]}" \
     -f db/postgres/sql/01-sa-users.sql

psql -v ON_ERROR_STOP=1 -d smartcpd "${scpd_db_vars[@]}" \
     -f db/postgres/sql/02-dbo-grants.sql

Для модели per-service в массиве необходимо задать отдельные имена и пароли в DB_BILLING_*, DB_AMD_*, DB_ANALYZER_*, DB_GRAFANA_DS_* и DB_CDR_*. Для опциональных контуров аналогично задаются DB_SIPCAPTURE_* и DB_PDS_*.

Если используются административные роли, в том же массиве задаются:

  • DB_DBO_ROLE и при необходимости DB_DBO_ROLE_PASSWORD;
  • DB_DBA_USER и DB_DBA_PASSWORD для отдельного администратора с membership в dbo;
  • DB_READONLY_ROLE и при необходимости DB_READONLY_PASSWORD;
  • DB_READER_USER и DB_READER_PASSWORD для отдельного read-only пользователя.

Локальный контейнер PostgreSQL#

DB-образ из репозитория предназначен для разработки и тестирования. Production setup SmartCPD использует заранее подготовленный PostgreSQL Заказчика и не разворачивает этот контейнер в stack.

При первичной инициализации локального volume контейнер выполняет 00 -> 01 -> 02. Значения portal/portal, billing/billing и grafana/grafana являются только локальными defaults образа и не должны использоваться в production.

docker build -f db/Dockerfile --target dev -t smartcpd-db .

docker run --rm \
  -e POSTGRES_PASSWORD=postgres \
  -p 5432:5432 \
  smartcpd-db

Runbook: миграция cdr-collector#

Перед запуском разовой миграции cdr-collector оператор должен явно задать через DB_TZ timezone, в которой были записаны исторические legacy timestamps без информации о часовом поясе. Она не обязана совпадать с TZ контейнера мигратора: DB_TZ определяет интерпретацию переносимых данных, а TZ — локальное время выполнения контейнера.

Полная команда запуска мигратора в Docker, требуемые учетные данные и порядок обновления приведены в документе «Обновление SmartCPD». Ниже зафиксированы только требования к часовому поясу и проверке временных данных.

Для инсталляций, где исторические CDR timestamps хранились как локальное время без timezone, обычно требуется:

DB_TZ=Europe/Moscow

Критичность DB_TZ#

DB_TZ является критичным параметром миграции.

Запуск миграции без явно проверенного DB_TZ не поддерживается. Неверное значение может привести к тому, что legacy timestamps без timezone будут интерпретированы как время в неправильной зоне, например как UTC вместо Europe/Moscow.

Последствия:

  • calldate, end и связанные timestamps в целевой таблице CDR могут быть сдвинуты на величину разницы timezone;
  • партиции будут созданы с границами, соответствующими выбранной timezone policy;
  • отчеты, фильтры по времени, markup matching по времени и сверка с legacy-данными могут давать неверные результаты;
  • построенные индексы не исправляют проблему, так как ошибка находится в самих перенесенных timestamp values.

Это не косметическая ошибка. Если миграция выполнена с неверным DB_TZ, данные времени в целевой БД следует считать потенциально некорректными до проверки.

Проверка после миграции#

После миграции нужно сравнить несколько известных звонков в legacy-источнике и целевой таблице cdr_cdr по устойчивому идентификатору (sip_trace_id, call_id или другому доступному идентификатору).

Проверяется как минимум:

  • calldate;
  • end;
  • попадание записи в ожидаемый локальный день/месяц;
  • результаты выборки через UI/API по ожидаемому диапазону времени.

Если целевые timestamps отличаются от legacy-значений на постоянный timezone offset, миграция выполнена с неправильным DB_TZ.

Исправление#

Если миграция выполнялась в подготовительном окне и новые CDR-записи еще не поступали в целевую БД, правильное действие — повторить миграцию с пересозданием целевой схемы:

/app/cdr-collector-migrator full --with-stats --recreate

Перед повторным запуском необходимо задать корректный DB_TZ.

Если после миграции целевая БД уже принимала новые CDR-записи, --recreate использовать нельзя без отдельного плана сохранения данных: он удалит целевые таблицы и новые записи. В этом случае требуется отдельная repair-процедура с явным ограничением migrated диапазона и проверкой, что новые записи не будут сдвинуты или удалены.

Таблица доступов#

OwnerGrants
portalUSAGE/CREATE на public, search_path=public; grafana_ds получает read-only доступ к объектам portal, если роль отличается
grafanaСоздает и владеет схемой grafana, search_path=grafana
billingUSAGE/CREATE на public, search_path=public; в per-service модели доступ определяется ownership и другим сервисным ролям grants не выдаются; в single-user модели доступ объединен с portal общей ролью
cdrВладеет объектами CDR и разметки; pds, analyzer, grafana_ds получают SELECT; amd получает SELECT/INSERT/UPDATE
sipcaptureСоздает и владеет схемой homer; pds получает USAGE на homer и SELECT на homer.hep_*

Default privileges настраиваются тем же правилом для будущих объектов соответствующего owner.

Скрипт применяет только минимально необходимые grants и не отзывает ранее выданные права. Если установка обновляется с более широкой исторической моделью доступа, лишние grants удаляются отдельной контролируемой процедурой.

Дата формирования

Powered by Altuera