База данных
Этот документ описывает требования к 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 модели |
analyzer | Read-only потребитель данных CDR; отдельная роль используется только в per-service модели |
grafana_ds | Read-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-dbRunbook: миграция 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 диапазона и проверкой, что новые записи не будут сдвинуты или удалены.
Таблица доступов#
| Owner | Grants |
|---|---|
portal | USAGE/CREATE на public, search_path=public; grafana_ds получает read-only доступ к объектам portal, если роль отличается |
grafana | Создает и владеет схемой grafana, search_path=grafana |
billing | USAGE/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 удаляются отдельной контролируемой процедурой.