Документация Postgres Pro Shardman 14.18.2

ООО «Постгрес Профессиональный»

The PostgreSQL Global Development Group

Авторские права © 2021-2025 ООО «Постгрес Профессиональный»

Авторские права © 1996-2025 The PostgreSQL Global Development Group

Глава 1. Начало работы с Shardman

Shardman — это распределённая система управления базами данных (СУБД) на основе PostgreSQL, реализующая сегментирование. Сегментированием называется принцип проектирования баз данных, при котором строки таблицы хранятся отдельно друг от друга в разных БД, потенциально управляемых разными экземплярами СУБД. Основная задача Shardman — повысить эффективность выполнения запросов к сегментированным распределённым БД и упростить управление ими.

В данной главе представлена вводная информация о распределённой СУБД Shardman.

1.1. Что такое Shardman

В современных компаниях, в веб-приложениях с большой нагрузкой размер баз данных непрерывно растёт. Приспособиться к таким изменениям можно, только используя горизонтальное масштабирование. Распределённая СУБД Shardman предназначена для обеспечения горизонтального масштабирования баз данных OLTP (online transaction processing, обработка транзакций в реальном времени) при строгом соответствии требованиям ACID.

Shardman обладает следующими преимуществами и улучшениями совместимости:

Строгие гарантии ACID.

Совместимость с Postgres Pro Enterprise.

Сертификаты четвёртого уровня доверия и четвёртого класса безопасности.

Поддержка одновременной работы нескольких кластеров.

Прозрачное горизонтальное масштабирование без необходимости перехода к NoSQL.

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

Поддержка до 100 узлов кластера.

Высокая степень доступности с поддержкой режимов ведущего и резервного, синхронного решения для обеспечения отказоустойчивости и асинхронного решения для минимального влияния на производительность системы.

Поддержка статистики планирования и выполнения всех операторов SQL.

Утилиты для выявления наиболее ресурсоёмких операций в базе данных.

Инструменты для достижения настоящего уровня изоляции REPEATABLE READ в распределённой системе.

Возможность работать с кластером как с единой СУБД.

Инструменты горячего резерва и резервного копирования и восстановления для поддержки полного и инкрементального копирования с журналированием.

Восстановления на момент времени (PITR).

Потоковая репликация.

Создание кластера с высокой доступностью с несколькими ведущими узлами при помощи специальных утилит.

Стандарт ANSI.

Массивы SQL.

Хранимые процедуры.

Хранение и обработка большого объёма данных.

Полнотекстовый поиск.

Покрывающие индексы.

Индексы B-дерево, хеш, GiST, GIN, SP-GiST, BRIN.

Процедурные языки Perl и Python.

Интерфейсы для работы с C++, Ruby, C, ODBC Perl, Python, Tcl и Java.

Кодировки EUC, UTF-8 и Mule.

Адаптивная оптимизация запросов.

Сжатая файловая система.

Доступ к данным на сторонних серверах PostgreSQL с помощью postgres_fdw, в частности: Microsoft Active Directory, MySQL, Oracle, Postgres Pro Enterprise.

Мониторинг длительных запросов с помощью модуля pg_query_state.

Встроенный агент мониторинга.

Неограниченное количество записей и индексов, максимальный размер таблицы — 32 ТБ, максимальный размер атрибута — 1 ГБ, максимальное количество атрибутов — 1600.

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

Безопасное хранение паролей.

Тонкая настройка очистки памяти.

1.2. Область применения

Shardman обеспечивает горизонтальное масштабирование со всеми преимуществами единой базы данных. Приложения могут использовать любой узел для доступа к распределённой базе данных и работать в основном так же, как и с одним экземпляром PostgreSQL. Тем не менее, по сути это распределённая система, в которой существуют определённые правила проектирования схемы и написания запросов. Основное направление внедрения — локализация данных и вычислений.

Следующие свойства базы данных или рабочей нагрузки указывают на потенциальную необходимость перехода на распределённую систему:

Рабочий набор данных не помещается в оперативную память одного сервера. В сегментированных системах общий объём оперативной памяти может быть гораздо больше.

Операции технического обслуживания, например очистка, занимают слишком много времени. Shardman сразу использует секционированные таблицы, поэтому операции обслуживания можно распараллеливать по узлам и секциям таблиц.

Слишком большое количество сеансов чтения для одного экземпляра PostgreSQL. Shardman позволяет распределять сеансы чтения по кластеру и очень эффективно обрабатывать внутренние соединения с помощью мультиплексирующего транспорта.

Интенсивные операции записи. Сегментированные системы могут работать со значительно большим общим количеством дисковых операций ввода-вывода в секунду.

Запросы с интенсивной вычислительной нагрузкой на процессор. Shardman позволяет распределить вычисления по узлам и сократить время выполнения сложных запросов.

Использовать Shardman нецелесообразно в следующих случаях:

Вертикальное масштабирование экономически и технически возможно.

Модель данных и рабочая нагрузка требуют большого количества межсегментных транзакций.

Сложная аналитика, в частности объединение сегментированных таблиц в условиях отсутствия ключа сегментирования.

Развёртывание кластера типа Multi-DC/Multi-region.

1.3. Быстрый запуск

Shardman состоит из следующих программных компонентов:

СУБД PostgreSQL 14 с набором изменений.

Расширение Shardman.

Инструменты и службы управления, включая встроенный менеджер stolon для обеспечения отказоустойчивости.

Конфигурации Postgres Pro Shardman и stolon хранятся в кластере etcd, поэтому можно использовать существующий или развернуть новый простой кластер etcd с одним узлом.

Демон shardmand контролирует конфигурацию кластера Shardman и управляет кластерами stolon, которые обеспечивают отказоустойчивость сегментов. Общая конфигурация Shardman (shardmand, stolon) хранится в кластере etcd.

В настоящее время пакеты Shardman доступны для следующих ОС:

Ubuntu 20.04/22.04

Debian 10/11/12

Red Hat Enterprise Linux 7/8/9

РЕД ОС 7.3/7.3.1/7.3.2

Альт 9/10

Astra Linux «Смоленск» 1.7

1.3.1. Конфигурация кластера

Предположим, есть три узла для развёртывания Postgres Pro Shardman: один будет использоваться для кластера etcd с одним узлом, а два других — для кластера Postgres Pro Shardman с двумя узлами.

Допустим, у нас есть следующие имена узлов и IP-адреса:

192.0.1.1 etcd  - кластер etcd с одним узлом
192.0.1.20 sdm01 - первый узел Shardman
192.0.1.21 sdm02 - второй узел Shardman

Характеристики каждого узла: 4Gb RAM, 20GB HDD, 2CPU и ОС Ubuntu 22.04.

1.3.2. Подготовка

1.3.2.1. Добавление имён узлов в /etc/hosts

Этот шаг следует выполнить на всех узлах.

sudo /bin/sh -c 'cat << EOF >> /etc/hosts
192.0.1.1 etcd
192.0.1.20 sdm01
192.0.1.21 sdm02
EOF'

1.3.2.2. Синхронизация по времени

Этот шаг следует выполнить на всех узлах.

Установите и запустите демон chrony на всех узлах.

sudo apt install -y chrony

По умолчанию chrony получает время с доступных серверов в Интернете или с локального сервера времени. Проверить доступные серверы времени можно следующим образом:

chronyc sources
MS Name/IP address         Stratum Poll Reach LastRx Last sample
===============================================================================
^? 192.0.1.100                   1   6     7     1    -98us[  -98us] +/-   11ms
^* time.cloudflare.com           3   6     7     1   +139us[ +163us] +/-   11ms
^+ tms04.deltatelesystems.ru     1   6     7     1   -381us[ -357us] +/-   17ms

Желательно синхронизировать время с вашим сервером или локальным сервером для кластера. Для этого внесите в конфигурацию chrony следующие изменения:

cat /etc/chrony/chrony.conf

server 192.0.1.100 iburst
keyfile /etc/chrony.keys
driftfile /var/lib/chrony/chrony.drift
log tracking measurements statistics
logdir /var/log/chrony

systemctl restart chrony

Проверьте, что демон chrony подключён к нужному серверу.

chronyc sources
MS Name/IP address         Stratum Poll Reach LastRx Last sample
===============================================================================
^? 192.0.1.100                   8   6    17    37    +14us[  +70us] +/-  161us
chronyc tracking
Reference ID    : 0A80000C (ntp.local)
Stratum         : 9
Ref time (UTC)  : Wed Nov 15 11:58:52 2023
System time     : 0.000000004 seconds slow of NTP time
Last offset     : -0.000056968 seconds
RMS offset      : 0.000056968 seconds
Frequency       : 10.252 ppm fast
Residual freq   : -2.401 ppm
Skew            : 364.419 ppm
Root delay      : 0.000455358 seconds
Root dispersion : 0.010503666 seconds
Update interval : 2.1 seconds
Leap status     : Normal

1.3.3. Развёртывание кластера etcd с одним узлом

Рекомендуем также ознакомиться с Развёртывание кластера etcd с несколькими узлами.

Установите следующие пакеты:

sudo apt install -y vim curl

Чтобы подключить репозиторий Postgres Pro Shardman, выполните следующие шаги:

Запустите указанные скрипты:

curl -fsSL -u "<user>:<password>" https://repo.postgrespro.ru/sdm/sdm-14/keys/pgpro-repo-add.sh > pgpro-repo-add.sh
chmod +x pgpro-repo-add.sh

Откройте файл pgpro-repo-add.sh и укажите пароль от репозитория в переменной PASSWORD.

Запустите sudo pgpro-repo-add.sh.

Установите пакеты etcd-sdm:

sudo apt install -y etcd-sdm

Укажите значения переменных окружения в соответствующем файле:

sudo vim /etc/default/etcd-sdm
ETCD_NAME=etcd
ETCD_LISTEN_CLIENT_URLS=http://0.0.0.0:2379
ETCD_ADVERTISE_CLIENT_URLS=http://192.0.1.1:2379
ETCD_MAX_SNAPSHOTS=5
ETCD_MAX_WALS=5
ETCD_AUTO_COMPACTION_MODE=periodic
ETCD_AUTO_COMPACTION_RETENTION=5m
ETCD_QUOTA_BACKEND_BYTES=6442450944
ETCD_DATA_DIR=/var/lib/etcd-sdm/sdm-14

Этот файл будет загружен при запуске etcd.

Очистите каталог данных etcd:

sudo rm -rf /var/lib/etcd-sdm/sdm-14/*

Перезапустите службу etcd-sdm:

sudo systemctl restart etcd-sdm

Для локального пользователя добавьте путь /opt/pgpro/sdm-14/bin в переменную окружения PATH:

echo "export PATH=$PATH:/opt/pgpro/sdm-14/bin" >> ~/.bashrc
source ~/.bashrc

Проверьте правильность конфигурации etcd:

etcdctl endpoint --endpoints=http://192.0.1.1:2379 status health -w table
+------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------------------------------+
|        ENDPOINT        |        ID        | VERSION | DB SIZE | IS LEADER | IS LEARNER | RAFT TERM | RAFT INDEX | RAFT APPLIED INDEX |             ERRORS             |
+------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------------------------------+
| http://192.0.1.1:2379 | 9324a99282752a09 |   3.5.9 |  2.1 GB |      true |      false |        14 |   91459207 |           91459207 |  memberID:10602785869456026121 |
|                        |                  |         |         |           |            |           |            |                    |                 alarm:NOSPACE  |
+------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------------------------------+

Кластер etcd с одним узлом правильно сконфигурирован и готов обрабатывать запросы.

Чтобы предотвратить раздувание при интенсивном использовании etcd, добавьте команду дефрагментации в cron:

sudo sh -c '
{ crontab -l; echo "@hourly /opt/pgpro/sdm-14/bin/etcdctl defrag"; }
| crontab'

1.3.4. Развёртывание узлов Shardman

Добавьте репозиторий Postgres Pro Shardman на каждом узле:

Задайте пользователя и пароль, как описано в Подразделе 1.3.3.

Запустите указанные скрипты:

curl -fsSL -u "<user>:<password>" https://repo.postgrespro.ru/sdm/sdm-14/keys/pgpro-repo-add.sh > pgpro-repo-add.sh | bash
chmod +x pgpro-repo-add.sh

Откройте файл pgpro-repo-add.sh и укажите пароль от репозитория в переменной PASSWORD.

Запустите pgpro-repo-add.sh.

Установите пакеты (на каждом узле):

  sudo apt update
  sudo apt install -y postgrespro-sdm-14-server postgrespro-sdm-14-client postgrespro-sdm-14-contrib postgrespro-sdm-14-libs pg-probackup-sdm-14  shardman-services shardman-tools

Предположим, выбранное имя кластера — cluster0. Следующий шаг — поместить переменные окружения Shardman в каталог /etcd/shardman (на каждом узле):

sudo sh -c 'cat << EOF > /etc/shardman/shardmand-cluster0.env
SDM_CLUSTER_NAME=cluster0
SDM_LOG_LEVEL=info
SDM_STORE_ENDPOINTS=http://etcd:2379
EOF'

Файл и каталог создаются с помощью команды sudo, однако в дальнейшем shardmanctl её не использует, поэтому доступ к файлу с переменными окружения отсутствует. Для получения доступа необходимо добавить переменные в систему через export или дать пользователю права доступа к файлу и каталогу.

Для локального пользователя добавьте путь /opt/pgpro/sdm-14/bin в переменную окружения PATH и экспортируйте переменную SDM_STORE_ENDPOINTS:

echo "export PATH=$PATH:/opt/pgpro/sdm-14/bin" >> ~/.bashrc
echo "export SDM_STORE_ENDPOINTS=http://etcd:2379" >> ~/.bashrc
source ~/.bashrc

Сгенерируйте пример конфигурации с помощью утилит Shardman (только на одном узле).

  shardmanctl config generate > spec.json

На этом шаге можно внести некоторые изменения в спецификацию (конфигурацию) кластера, например изменить пароль или параметр PostgreSQL shared_buffers и так далее.

1.3.5. Инициализация кластера Shardman

Осталось несколько последних шагов. Сначала инициализируйте конфигурацию кластера в etcd (только на одном [любом] узле).

  shardmanctl init -f spec.json

Ожидается такой результат:

  2023-04-18T12:30:03.043Z	DEBUG	cmd/common.go:100	Waiting for metadata lock...
  2023-04-18T12:30:03.048Z	DEBUG	cluster/cluster.go:365	DataDir is not specified, setting to default /var/lib/pgpro/sdm-14/data

Включите и запустите службу shardmand (на каждом узле):

  sudo systemctl enable --now shardmand@cluster0
  sudo systemctl status shardmand@cluster0

  ● shardmand@cluster0.service - deployment daemon for shardman
       Loaded: loaded (/lib/systemd/system/shardmand@.service; enabled; vendor preset: enabled)
       Active: active (running) since Tue 2023-04-18 12:28:18 UTC; 2min 13s ago
         Docs: https://github.com/postgrespro/shardman
     Main PID: 618 (shardmand)
        Tasks: 10 (limit: 4571)
       Memory: 32.0M
          CPU: 422ms
       CGroup: /system.slice/system-shardmand.slice/shardmand@cluster0.service
               └─618 /opt/pgpro/sdm-14/bin/shardmand --cluster-name cluster0 --system-bus --user postgres

1.3.6. Добавление узлов в кластер Shardman

На этом шаге предполагается, что все предыдущие шаги выполнены успешно: кластер etcd работает нормально, время на всех узлах синхронизировано, и демон запущен на sdm01 и sdm02. На последнем шаге выполняется команда shardmanctl:

  shardmanctl nodes add -n sdm01,sdm02 \
             --cluster-name cluster0 \
             --log-level debug

Ожидается такой результат:

  2023-04-18T12:43:11.300Z	DEBUG	cmd/common.go:100	Waiting for metadata lock...
  2023-04-18T12:43:11.306Z	INFO	cluster/store.go:277	Checking if shardmand on all nodes have applied current cluster configuration
  ✓ Waiting for shardmand on node sdm01 to apply current configuration: success 0.000s
  ✓ Waiting for shardmand on node sdm02 to apply current configuration: success 0.000s
  2023-04-18T12:43:11.307Z	INFO	add/case.go:112	Initting Stolon instances...
  2023-04-18T12:43:11.312Z	INFO	add/case.go:170	Waiting for Stolon daemons to start... make sure shardmand daemons are running on the nodes
  ✓ Waiting for Stolon daemons of rg clover-1-sdm01: success 31.012s
  ✓ Waiting for Stolon daemons of rg clover-1-sdm02: success 0.012s
  2023-04-18T12:43:42.336Z	INFO	add/case.go:187	Adding repgroups...
  ✓ waiting rg 1 config apply: done 7.014s
  2023-04-18T12:43:49.444Z	DEBUG	broadcaster/worker.go:33	start broadcaster worker for repgroup id=1
  2023-04-18T12:43:49.453Z	DEBUG	broadcaster/worker.go:51	repgroup 1 connect established
  2023-04-18T12:43:49.453Z	DEBUG	commands/addrepgroup.go:575	waiting for extension lock...
  2023-04-18T12:43:49.453Z	DEBUG	commands/addrepgroup.go:137	Loading schema into replication group rg 1
  ...
  2023-04-18T12:44:25.665Z	DEBUG	rebalance/service.go:528	wait all tasks finish
  2023-04-18T12:44:25.666Z	DEBUG	broadcaster/worker.go:75	finish broadcaster worker for repgroup id=1
  2023-04-18T12:44:25.666Z	DEBUG	broadcaster/worker.go:75	finish broadcaster worker for repgroup id=2
  2023-04-18T12:44:25.666Z	INFO	add/case.go:221	Successfully added nodes sdm01, sdm02 to the cluster

Сообщение «Successfully added nodes sdm01, sdm02 to the cluster» (Узлы sdm01, sdm02 успешно добавлены в кластер) означает, что всё в порядке и узлы sdm01 и sdm02 работают нормально.

1.3.7. Проверка состояния кластера Shardman

Проверьте состояние узлов кластера:

  shardmanctl status
  ┌──────────────────────────────────────────────────────────────────────────────────────────────────┐
  │                                        == STORE STATUS ==                                        │
  ├───────────┬──────────────────────────────────────────┬─────────────────────┬─────────────────────┤
  │   STATUS  │                  MESSAGE                 │  REPLICATION GROUP  │         NODE        │
  ├───────────┼──────────────────────────────────────────┼─────────────────────┼─────────────────────┤
  │  Warning  │ Store has only one member, consider      │                     │                     │
  │           │ deploying store cluster                  │                     │                     │
  └───────────┴──────────────────────────────────────────┴─────────────────────┴─────────────────────┘
  ┌─────────────────────────────────────────────────────────────────────────────────────────────────┐
  │                                      == TOPOLOGY STATUS ==                                      │
  ├───────────┬─────────────────────────────────────────┬─────────────────────┬─────────────────────┤
  │   STATUS  │                 MESSAGE                 │  REPLICATION GROUP  │         NODE        │
  ├───────────┼─────────────────────────────────────────┼─────────────────────┼─────────────────────┤
  │   CROSS   │ Topology placement policy is CROSS      │                     │                     │
  └───────────┴─────────────────────────────────────────┴─────────────────────┴─────────────────────┘
  ┌─────────────────────────────────────────────────────────────────────────────────────────────────┐
  │                                      == METADATA STATUS ==                                      │
  ├───────────┬─────────────────────────────────────────┬─────────────────────┬─────────────────────┤
  │   STATUS  │                 MESSAGE                 │  REPLICATION GROUP  │         NODE        │
  ├───────────┼─────────────────────────────────────────┼─────────────────────┼─────────────────────┤
  │     OK    │ Metadata is OK                          │                     │                     │
  └───────────┴─────────────────────────────────────────┴─────────────────────┴─────────────────────┘
  ┌─────────────────────────────────────────────────────────────────────────────────────────────────┐
  │                                      == SHARDMAND STATUS ==                                     │
  ├───────────┬─────────────────────────────────────────┬─────────────────────┬─────────────────────┤
  │   STATUS  │                 MESSAGE                 │  REPLICATION GROUP  │         NODE        │
  ├───────────┼─────────────────────────────────────────┼─────────────────────┼─────────────────────┤
  │     OK    │ shardmand on node sdm01 is OK           │                     │        sdm01        │
  ├───────────┼─────────────────────────────────────────┼─────────────────────┼─────────────────────┤
  │     OK    │ shardmand on node sdm02 is OK           │                     │        sdm02        │
  └───────────┴─────────────────────────────────────────┴─────────────────────┴─────────────────────┘
  ┌─────────────────────────────────────────────────────────────────────────────────────────────────┐
  │                                  == REPLICATION GROUP STATUS ==                                 │
  ├───────────┬─────────────────────────────────────────┬─────────────────────┬─────────────────────┤
  │   STATUS  │                 MESSAGE                 │  REPLICATION GROUP  │         NODE        │
  ├───────────┼─────────────────────────────────────────┼─────────────────────┼─────────────────────┤
  │     OK    │ Replication group clover-1-sdm01 is OK  │    clover-1-sdm01   │                     │
  ├───────────┼─────────────────────────────────────────┼─────────────────────┼─────────────────────┤
  │     OK    │ Replication group clover-1-sdm02 is OK  │    clover-1-sdm02   │                     │
  └───────────┴─────────────────────────────────────────┴─────────────────────┴─────────────────────┘
  ┌──────────────────────────────────────────────────────────────────────────────────────────────────┐
  │                                        == MASTER STATUS ==                                       │
  ├───────────┬──────────────────────────────────────────┬─────────────────────┬─────────────────────┤
  │   STATUS  │                  MESSAGE                 │  REPLICATION GROUP  │         NODE        │
  ├───────────┼──────────────────────────────────────────┼─────────────────────┼─────────────────────┤
  │     OK    │ Replication group clover-1-sdm01 master  │    clover-1-sdm01   │      sdm01:5432     │
  │           │ is running on sdm01:5432                 │                     │                     │
  ├───────────┼──────────────────────────────────────────┼─────────────────────┼─────────────────────┤
  │     OK    │ Replication group clover-1-sdm02 master  │    clover-1-sdm02   │      sdm02:5432     │
  │           │ is running on sdm02:5432                 │                     │                     │
  └───────────┴──────────────────────────────────────────┴─────────────────────┴─────────────────────┘
  ┌──────────────────────────────────────────────────────────────────────────────────────────────────┐
  │                                      == DICTIONARY STATUS ==                                     │
  ├───────────┬──────────────────────────────────────────┬─────────────────────┬─────────────────────┤
  │   STATUS  │                  MESSAGE                 │  REPLICATION GROUP  │         NODE        │
  ├───────────┼──────────────────────────────────────────┼─────────────────────┼─────────────────────┤
  │     OK    │ Replication group clover-1-sdm01         │    clover-1-sdm01   │                     │
  │           │ dictionary is OK                         │                     │                     │
  ├───────────┼──────────────────────────────────────────┼─────────────────────┼─────────────────────┤
  │     OK    │ Replication group clover-1-sdm02         │    clover-1-sdm02   │                     │
  │           │ dictionary is OK                         │                     │                     │
  └───────────┴──────────────────────────────────────────┴─────────────────────┴─────────────────────┘

1.3.8. Подключение к кластеру Shardman

Для подключения к кластеру получите строку подключения на любом узле кластера (sdm01 или sdm02):

  shardmanctl getconnstr

  dbname=postgres host=sdm01,sdm02 password=!!!CHANGE_ME!!! port=5432,5432 user=postgres

Затем попробуйте подключиться:

  psql -d 'dbname=postgres host=sdm01,sdm02 password=!!!CHANGE_ME!!! port=5432,5432 user=postgres'

  psql (14.7)
  Type "help" for help.

  postgres=#

1.3.9. Создание сегментированных таблиц

Создайте сегментированную таблицу и проверьте, всё ли работает корректно.

  postgres=# create table x(id int primary key, t text) with (distributed_by='id',num_parts=2);
  CREATE TABLE

  postgres=# \d
                   List of relations
    Schema |  Name   |       Type        |  Owner
   --------+---------+-------------------+----------
    public | x       | partitioned table | postgres
    public | x_0     | table             | postgres
    public | x_1_fdw | foreign table     | postgres
   (3 rows)

  postgres=# \d x_0
    Table "public.x_0"
    Column |  Type   | Collation | Nullable | Default
   --------+---------+-----------+----------+---------
    id     | integer |           | not null |
    t      | text    |           |          |
   Partition of: x FOR VALUES WITH (modulus 2, remainder 0)
   Indexes:
       "x_0_pkey" PRIMARY KEY, btree (id)

  postgres=# \d x_1_fdw
                   Foreign table "public.x_1_fdw"
   Column |  Type   | Collation | Nullable | Default | FDW options
  --------+---------+-----------+----------+---------+-------------
   id     | integer |           | not null |         |
   t      | text    |           |          |         |
  Partition of: x FOR VALUES WITH (modulus 2, remainder 1)
  Server: shardman_rg_2
  FDW options: (table_name 'x_1')

  postgres=# insert into x values (1,'t'),(2,'t'),(3,'t');
  INSERT 0 3

  postgres=# select * from x_0;
   id | t
  ----+---
    1 | t
    2 | t
  (2 rows)

  postgres=# select * from x_1_fdw;
   id | t
  ----+---
    3 | t
  (1 row)

Всё работает так, как и ожидалось.

1.3.10. Пример: развёртывание кластера etcd с несколькими узлами

В примере используются следующие серверы:

192.0.1.1 etcd1
192.0.1.2 etcd2
192.0.1.3 etcd3

Установите необходимые пакеты на каждом сервере:

sudo apt install -y vim curl

Для подключения к репозиторию запустите на каждом сервере следующую команду:

sudo curl -fsSL https://repo.postgrespro.ru/sdm/sdm-14/keys/pgpro-repo-add.sh | bash

Установите пакеты etcd-sdm на каждом сервере:

sudo apt install -y etcd-sdm

Для каждого сервера отредактируйте файл со списком переменных окружения, заменив местозаполнители в угловых скобках конкретными значениями:

sudo vim /etc/default/etcd-sdm
ETCD_NAME=<hostname>
ETCD_LISTEN_PEER_URLS=http://0.0.0.0:2380
ETCD_LISTEN_CLIENT_URLS=http://0.0.0.0:2379
ETCD_ADVERTISE_CLIENT_URLS=http://<host ip address>:2379
ETCD_INITIAL_ADVERTISE_PEER_URLS=http://<host ip address>:2380
ETCD_INITIAL_CLUSTER_TOKEN=etcd-cluster-1
ETCD_INITIAL_CLUSTER_STATE=new
ETCD_MAX_SNAPSHOTS=5
ETCD_MAX_WALS=5
ETCD_AUTO_COMPACTION_MODE=periodic
ETCD_AUTO_COMPACTION_RETENTION=5m
ETCD_QUOTA_BACKEND_BYTES=6442450944
ETCD_DATA_DIR=/var/lib/etcd-sdm/sdm-14
ETCD_INITIAL_CLUSTER=etcd1=http://<ip etcd1>:2380,etcd2=http://<ip etcd2>:2380,etcd3=http://<ip etcd3>:2380

Этот файл будет загружен при запуске etcd со своими собственными параметрами запуска на каждом сервере.

Очистите каталог данных etcd:

sudo rm -rf /var/lib/etcd-sdm/sdm-14/*

Перезапустите службы etcd-sdm на каждом сервере:

sudo systemctl restart etcd-sdm

Для локального пользователя добавьте путь /opt/pgpro/sdm-14/bin в переменную окружения PATH:

echo "export PATH=$PATH:/opt/pgpro/sdm-14/bin" >> ~/.bashrc
source ~/.bashrc

Проверьте правильность конфигурации etcd:

etcdctl member list -w table
+------------------+---------+-------+----------------------------+----------------------------+------------+
|        ID        | STATUS  | NAME  |         PEER ADDRS         |        CLIENT ADDRS        | IS LEARNER |
+------------------+---------+-------+----------------------------+----------------------------+------------+
|  318be6342e6d9ac | started | etcd1 | http://192.0.1.1:2380      | http://192.0.1.1:2379      |      false |
| 9e49480544aedb89 | started | etcd2 | http://192.0.1.2:2380      | http://192.0.1.2:2379      |      false |
| bb3772bfa22482d7 | started | etcd3 | http://192.0.1.3:2380      | http://192.0.1.3.4:2379    |      false |
+------------------+---------+-------+----------------------------+----------------------------+------------+
$ etcdctl --endpoints=http://192.0.1.1:2380,http://192.0.1.2:2380,http://192.0.1.3:2380 endpoint status health  -w table
+----------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
|          ENDPOINT          |        ID        | VERSION | DB SIZE | IS LEADER | IS LEARNER | RAFT TERM | RAFT INDEX | RAFT APPLIED INDEX | ERRORS |
+----------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
| http://192.0.1.1:2380      |  318be6342e6d9ac |   3.5.9 |  5.7 MB |      true |      false |        13 |     425686 |             425686 |        |
| http://192.0.1.2:2380      | 9e49480544aedb89 |   3.5.9 |  5.7 MB |     false |      false |        13 |     425686 |             425686 |        |
|  http://192.0.1.3:2380     | bb3772bfa22482d7 |   3.5.9 |  5.7 MB |     false |      false |        13 |     425686 |             425686 |        |
+----------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
-------+

Кластер etcd правильно сконфигурирован и готов обрабатывать запросы.

Чтобы предотвратить раздувание при интенсивном использовании etcd, добавьте команду дефрагментации в cron:

sudo { crontab -l; echo "@hourly /opt/pgpro/sdm-14/bin/etcdctl defrag"; } | crontab

Последняя строка с границами кластера etcd:

etcd1=http://<ip etcd1>:2380,etcd2=http://<ip etcd2>:2380,etcd3=http://<ip etcd3>:2380

Её следует указать в файле конфигурации /etc/shardman и в качестве параметра --store-endpoints shardmanctl.

Глава 2. Управление

2.1. Службы кластера

Конфигурация кластера Shardman хранится в etcd. Службы кластера Shardman организованы как службы systemd. Демон настройки Shardman shardmand отслеживает конфигурацию кластера и управляет экземплярами PostgreSQL посредством интегрированного менеджера stolon. У каждого узла есть одна служба shardmand, которая обычно называется shardmand@CLUSTER_NAME.service. Здесь ИМЯ_КЛАСТЕРА — это имя кластера Shardman, по умолчанию cluster0.

Каждый shardmand включает в себя несколько интегрированных процессов stolon keeper и stolon sentinel.

С каждым зарегистрированным экземпляром СУБД связан процесс stolon keeper, который напрямую управляет этим экземпляром PostgreSQL. Процесс keeper запускает, останавливает, инициализирует и синхронизирует экземпляры PostgreSQL в зависимости от необходимого состояния кластера stolon.

С каждым зарегистрированным экземпляром СУБД связан процесс stolon sentinel. Для каждой группы репликации процессы stolon sentinel выбирают так называемого лидера среди таких существующих процессов. Этот лидер принимает решения о необходимом состоянии кластера (например, какой процесс keeper должен стать новым ведущим при сбое). При выборе нового ведущего сервера в группе репликации лидер выбирает процесс keeper с минимальной задержкой. Когда все реплики синхронны, keeper с максимальным приоритетом выбирается новым ведущим, даже если ведущий сервер в группе репликации «жив». Shardman использует только синхронные реплики (в противном случае существует вероятность потери данных при сбое узла).

shardmand — это модуль systemd, его журналы записываются в journald. Ознакомиться с его работой можно, используя команду journalctl. Например, чтобы получить все журналы с 2023-05-09 10:00 для службы shardmand кластера cluster0, можно использовать следующую команду:

                 $ journalctl -u shardmand@cluster0 --since '2023-05-09 10:00'

Чтобы задать уровень детализации журнала для всех служб Shardman, укажите SDM_LOG_LEVEL в файле конфигурации shardmand.

2.2. Масштабирование кластера

Архитектура Shardman позволяет масштабировать кластер, не прерывая его работу. В этом разделе описывается, как добавить дополнительные узлы в кластер Shardman, чтобы повысить производительность/масштабируемость запросов. Если кластер Shardman не соответствует ожиданиям по производительности или ёмкости хранилища, можно добавить в кластер новые узлы.

2.2.1. Добавление и удаление узлов

Тип конфигурации определяет, как узлы добавляются в кластер и где будут располагаться реплики. Shardman поддерживает два типа конфигураций: режим перекрёстной репликации (cross) и режим ручной топологии (manual). Параметр PlacementPolicy в sdmspec.json позволяет выбрать поведение кластера и поддерживает два соответствующих значения: cross и manual. По умолчанию используется cross. Например:

                    {
                        "PlacementPolicy": "cross",
                        "Repfactor": 1,
                        ...
                    }

2.2.1.1. Перекрёстная репликация

Для добавления новых узлов в кластер Shardman используется команда shardmanctl nodes add. С политикой размещения cross узлы добавляются в кластер звеньями. Каждый узел в звене запускает основной экземпляр СУБД и реплики других узлов звена. Количество реплик определяется параметром конфигурации Repfactor. Таким образом, каждое звено состоит из Repfactor + 1 узлов и может выдержать потерю Repfactor узлов. Пример создания кластера из четырёх узлов с Repfactor=1 и перекрёстной репликацией показан ниже:

                        $ shardmanctl --store-endpoints http://etcd1:2379,http://etcd2:2379,http://etcd3:2379 init -f sdmspec.json
                        $ shardmanctl --store-endpoints http://etcd1:2379,http://etcd2:2379,http://etcd3:2379 nodes add -n n1,n2,n3,n4

Посмотрите на топологию кластера:

                         $ shardmanctl --store-endpoints http://etcd1:2379,http://etcd2:2379,http://etcd3:2379 cluster topology

Ожидается такой результат:

                        ┌─────────────────────────────────────────────────────────────────────┐
                        │             == REPLICATION GROUP clover-1-n1, RGID - 1 ==           │
                        ├─────────────────────────┬─────────────────┬─────────────────────────┤
                        │           HOST          │       PORT      │          STATUS         │
                        ├─────────────────────────┼─────────────────┼─────────────────────────┤
                        │            n1           │       5432      │         PRIMARY         │
                        ├─────────────────────────┼─────────────────┼─────────────────────────┤
                        │            n2           │       5433      │         STANDBY         │
                        └─────────────────────────┴─────────────────┴─────────────────────────┘
                        ┌─────────────────────────────────────────────────────────────────────┐
                        │             == REPLICATION GROUP clover-1-n2, RGID - 2 ==           │
                        ├─────────────────────────┬─────────────────┬─────────────────────────┤
                        │           HOST          │       PORT      │          STATUS         │
                        ├─────────────────────────┼─────────────────┼─────────────────────────┤
                        │            n1           │       5433      │         STANDBY         │
                        ├─────────────────────────┼─────────────────┼─────────────────────────┤
                        │            n2           │       5432      │         PRIMARY         │
                        └─────────────────────────┴─────────────────┴─────────────────────────┘
                        ┌─────────────────────────────────────────────────────────────────────┐
                        │             == REPLICATION GROUP clover-2-n3, RGID - 1 ==           │
                        ├─────────────────────────┬─────────────────┬─────────────────────────┤
                        │           HOST          │       PORT      │          STATUS         │
                        ├─────────────────────────┼─────────────────┼─────────────────────────┤
                        │            n3           │       5432      │         PRIMARY         │
                        ├─────────────────────────┼─────────────────┼─────────────────────────┤
                        │            n4           │       5433      │         STANDBY         │
                        └─────────────────────────┴─────────────────┴─────────────────────────┘
                        ┌─────────────────────────────────────────────────────────────────────┐
                        │             == REPLICATION GROUP clover-2-n4, RGID - 2 ==           │
                        ├─────────────────────────┬─────────────────┬─────────────────────────┤
                        │           HOST          │       PORT      │          STATUS         │
                        ├─────────────────────────┼─────────────────┼─────────────────────────┤
                        │            n3           │       5433      │         STANDBY         │
                        ├─────────────────────────┼─────────────────┼─────────────────────────┤
                        │            n4           │       5432      │         PRIMARY         │
                        └─────────────────────────┴─────────────────┴─────────────────────────┘

Для удаления узлов из кластера Shardman используется команда shardmanctl nodes rm. Эта команда удаляет из кластера звенья, содержащие указанные узлы. Последнее звено в кластере не может быть удалено. Любые данные (например, секции сегментированных отношений) в удалённых группах репликации переносятся в оставшиеся группы репликации с использованием логической репликации, а все ссылки на удалённые группы репликации (включая определения сторонних серверов) удаляются из метаданных оставшихся групп репликации. На последнем этапе обновляются метаданные в etcd.

                       $ shardmanctl --store-endpoints http://etcd1:2379,http://etcd2:2379,http://etcd3:2379 nodes rm -n n3

Посмотрите на топологию кластера:

                         $ shardmanctl --store-endpoints http://etcd1:2379,http://etcd2:2379,http://etcd3:2379 cluster topology

Вывод команды выглядит так:

                        ┌─────────────────────────────────────────────────────────────────────┐
                        │             == REPLICATION GROUP clover-1-n1, RGID - 1 ==           │
                        ├─────────────────────────┬─────────────────┬─────────────────────────┤
                        │           HOST          │       PORT      │          STATUS         │
                        ├─────────────────────────┼─────────────────┼─────────────────────────┤
                        │            n1           │       5432      │         PRIMARY         │
                        ├─────────────────────────┼─────────────────┼─────────────────────────┤
                        │            n2           │       5433      │         STANDBY         │
                        └─────────────────────────┴─────────────────┴─────────────────────────┘
                        ┌─────────────────────────────────────────────────────────────────────┐
                        │             == REPLICATION GROUP clover-1-n2, RGID - 2 ==           │
                        ├─────────────────────────┬─────────────────┬─────────────────────────┤
                        │           HOST          │       PORT      │          STATUS         │
                        ├─────────────────────────┼─────────────────┼─────────────────────────┤
                        │            n1           │       5433      │         STANDBY         │
                        ├─────────────────────────┼─────────────────┼─────────────────────────┤
                        │            n2           │       5432      │         PRIMARY         │
                        └─────────────────────────┴─────────────────┴─────────────────────────┘

2.2.1.2. Ручная топология

В режиме ручной топологии для добавления основного узла в кластер используется команда shardmanctl nodes add, добавляющая список узлов в кластер в качестве основных узлов с отдельной группой репликации для каждого ведущего узла. Создайте кластер с тремя ведущими узлами и ручной топологией (PlacementPolicy=manual в sdmspec.json):

                        $ shardmanctl --store-endpoints http://etcd1:2379,http://etcd2:2379,http://etcd3:2379 init -f sdmspec.json
                        $ shardmanctl --store-endpoints http://etcd1:2379,http://etcd2:2379,http://etcd3:2379 nodes add -n n1,n2,n3

Чтобы посмотреть на топологию кластера, используйте команду shardmanctl cluster topology:

                         $ shardmanctl --store-endpoints http://etcd1:2379,http://etcd2:2379,http://etcd3:2379 cluster topology

Ожидается такой результат:

                        ┌────────────────────────────────────────────────────────────────────────┐
                        │              == REPLICATION GROUP clover-1-n1, RGID - 1 ==             │
                        ├──────────────────────────┬──────────────────┬──────────────────────────┤
                        │           HOST           │       PORT       │          STATUS          │
                        ├──────────────────────────┼──────────────────┼──────────────────────────┤
                        │            n1            │       5432       │          PRIMARY         │
                        └──────────────────────────┴──────────────────┴──────────────────────────┘
                        ┌────────────────────────────────────────────────────────────────────────┐
                        │              == REPLICATION GROUP clover-2-n2, RGID - 2 ==             │
                        ├──────────────────────────┬──────────────────┬──────────────────────────┤
                        │           HOST           │       PORT       │          STATUS          │
                        ├──────────────────────────┼──────────────────┼──────────────────────────┤
                        │            n2            │       5432       │          PRIMARY         │
                        └──────────────────────────┴──────────────────┴──────────────────────────┘
                        ┌────────────────────────────────────────────────────────────────────────┐
                        │              == REPLICATION GROUP clover-3-n3, RGID - 3 ==             │
                        ├──────────────────────────┬──────────────────┬──────────────────────────┤
                        │           HOST           │       PORT       │          STATUS          │
                        ├──────────────────────────┼──────────────────┼──────────────────────────┤
                        │            n3            │       5432       │          PRIMARY         │
                        └──────────────────────────┴──────────────────┴──────────────────────────┘

Добавьте узлы n4, n5, n6 в качестве реплик, используя команду shardmanctl shard add:

                        $ shardmanctl --store-endpoints http://etcd1:2379,http://etcd2:2379,http://etcd3:2379 shard --shard clover-1-n1 add -n n4
                        $ shardmanctl --store-endpoints http://etcd1:2379,http://etcd2:2379,http://etcd3:2379 shard --shard clover-2-n2 add -n n5
                        $ shardmanctl --store-endpoints http://etcd1:2379,http://etcd2:2379,http://etcd3:2379 shard --shard clover-3-n3 add -n n6

В режиме ручной топологии один узел можно добавить более чем в одну группу репликации.

В результате получится следующая конфигурация кластера:

                        ┌─────────────────────────────────────────────────────────────────────┐
                        │             == REPLICATION GROUP clover-1-n1, RGID - 1 ==           │
                        ├─────────────────────────┬─────────────────┬─────────────────────────┤
                        │           HOST          │       PORT      │          STATUS         │
                        ├─────────────────────────┼─────────────────┼─────────────────────────┤
                        │            n1           │       5432      │         PRIMARY         │
                        ├─────────────────────────┼─────────────────┼─────────────────────────┤
                        │            n4           │       5432      │         STANDBY         │
                        └─────────────────────────┴─────────────────┴─────────────────────────┘
                        ┌─────────────────────────────────────────────────────────────────────┐
                        │             == REPLICATION GROUP clover-2-n2, RGID - 2 ==           │
                        ├─────────────────────────┬─────────────────┬─────────────────────────┤
                        │           HOST          │       PORT      │          STATUS         │
                        ├─────────────────────────┼─────────────────┼─────────────────────────┤
                        │            n2           │       5432      │         PRIMARY         │
                        ├─────────────────────────┼─────────────────┼─────────────────────────┤
                        │            n5           │       5432      │         STANDBY         │
                        └─────────────────────────┴─────────────────┴─────────────────────────┘
                        ┌─────────────────────────────────────────────────────────────────────┐
                        │             == REPLICATION GROUP clover-3-n3, RGID - 3 ==           │
                        ├─────────────────────────┬─────────────────┬─────────────────────────┤
                        │           HOST          │       PORT      │          STATUS         │
                        ├─────────────────────────┼─────────────────┼─────────────────────────┤
                        │            n3           │       5432      │         PRIMARY         │
                        ├─────────────────────────┼─────────────────┼─────────────────────────┤
                        │            n6           │       5432      │         STANDBY         │
                        └─────────────────────────┴─────────────────┴─────────────────────────┘

Для удаления реплики запустите команду shardmanctl shard rm. Например:

                        $ shardmanctl --store-endpoints http://etcd1:2379,http://etcd2:2379,http://etcd3:2379 shard --shard clover-1-n1 rm -n n4

Для удаления ведущего сервера сначала запустите команду shardmanctl shard switch, чтобы переключить ведущий сервер на реплику; затем удалите старый ведущий сервер.

                        $ shardmanctl --store-endpoints http://etcd1:2379,http://etcd2:2379,http://etcd3:2379 shard --shard clover-1-n1 switch --new-primary n4

2.3. Перебалансировка данных

2.3.1. Автоматическая перебалансировка данных

По умолчанию используется режим автоматической перебалансировки. Процесс перебалансировки запускается автоматически после добавления узлов (по умолчанию, если не задан параметр --no-rebalance) или перед удалением узла. Перебалансировку также можно запустить вручную. Суть процесса перебалансировки заключается в равномерном распределении секций для каждой сегментированной таблицы между группами репликации.

Процесс перебалансировки для каждой сегментированной таблицы итерационно определяет группу репликации с максимальным и минимальным количеством секций и создаёт задание на перемещение одной секции в группу репликации с минимальным количеством секций. Этот процесс повторяется, пока соблюдается условие max - min > 1. Для перемещения секций используется логическая репликация. Секции совместно размещённых таблиц перемещаются совместно с секциями сегментированных таблиц, на которые они ссылаются.

Важно помнить, что max_logical_replication_workers должно быть довольно большим, так как процесс перебалансировки использует до max(max_replication_slots, max_logical_replication_workers, max_worker_processes, max_wal_senders)/3 параллельных потоков. На практике можно использовать max_logical_replication_workers = Repfactor + 3 * task_num (task_num — количество параллельных заданий перебалансировки).

Чтобы выполнить перебалансировку сегментированных таблиц в кластере cluster0 вручную, выполните следующую команду (где etcd1, etcd2, etcd3 — это узлы кластера etcd):

                    $ shardmanctl --store-endpoints http://etcd1:2379,http://etcd2:2379,http://etcd3:2379 rebalance

Если процесс завершается ошибкой, необходимо вызвать команду shardmanctl cleanup с параметром --after-rebalance.

2.3.2. Ручная перебалансировка данных

Бывают случаи, когда необходимо определённым образом разместить секции сегментированных таблиц по узлам кластера. Для выполнения этой задачи в Shardman поддерживается режим ручной перебалансировки данных.

Как это работает:

Получите список сегментированных таблиц с помощью команды shardmanctl tables sharded list. Вывод будет примерно следующим:

$ shardmanctl shardmanctl tables sharded list

Sharded tables:

public.doc
public.resolution
public.users

Запросите информацию о выбранных сегментированных таблицах. Пример:

$ shardmanctl shardmanctl tables sharded info -t public.users

Table public.users

Partitions:

Partition    RgID     Shard                            Master
0            1        clover-1-shrn1                   shrn1:5432
1            2        clover-2-shrn2                   shrn2:5432
2            3        clover-3-shrn3                   shrn3:5432
3            1        clover-1-shrn1                   shrn1:5432
4            2        clover-2-shrn2                   shrn2:5432
5            3        clover-3-shrn3                   shrn3:5432
6            1        clover-1-shrn1                   shrn1:5432
7            2        clover-2-shrn2                   shrn2:5432
8            3        clover-3-shrn3                   shrn3:5432
9            1        clover-1-shrn1                   shrn1:5432
10           2        clover-2-shrn2                   shrn2:5432
11           3        clover-3-shrn3                   shrn3:5432
12           1        clover-1-shrn1                   shrn1:5432
13           2        clover-2-shrn2                   shrn2:5432
14           3        clover-3-shrn3                   shrn3:5432
15           1        clover-1-shrn1                   shrn1:5432
16           2        clover-2-shrn2                   shrn2:5432
17           3        clover-3-shrn3                   shrn3:5432
18           1        clover-1-shrn1                   shrn1:5432
19           2        clover-2-shrn2                   shrn2:5432
20           3        clover-3-shrn3                   shrn3:5432
21           1        clover-1-shrn1                   shrn1:5432
22           2        clover-2-shrn2                   shrn2:5432
23           3        clover-3-shrn3                   shrn3:5432

Переместите секцию в новый сегмент, как показано ниже:

$ shardmanctl --log-level debug tables sharded partmove -t public.users --partnum 1 --shard clover-1-shrn1

2023-07-26T06:00:36.900Z        DEBUG   cmd/common.go:105       Waiting for metadata lock...
2023-07-26T06:00:36.936Z        DEBUG   rebalance/service.go:256        take extension lock
2023-07-26T06:00:36.938Z        DEBUG   broadcaster/worker.go:33        start broadcaster worker for repgroup id=3
2023-07-26T06:00:36.938Z        DEBUG   broadcaster/worker.go:33        start broadcaster worker for repgroup id=2
2023-07-26T06:00:36.938Z        DEBUG   broadcaster/worker.go:33        start broadcaster worker for repgroup id=1
2023-07-26T06:00:36.951Z        DEBUG   broadcaster/worker.go:51        repgroup 3 connect established
2023-07-26T06:00:36.951Z        DEBUG   broadcaster/worker.go:51        repgroup 2 connect established
2023-07-26T06:00:36.952Z        DEBUG   broadcaster/worker.go:51        repgroup 1 connect established
2023-07-26T06:00:36.952Z        DEBUG   extension/lock.go:35    Waiting for extension lock...
2023-07-26T06:00:36.976Z        INFO    rebalance/service.go:276        Performing move partition...
2023-07-26T06:00:36.977Z        DEBUG   broadcaster/worker.go:33        start broadcaster worker for repgroup id=3
2023-07-26T06:00:36.978Z        DEBUG   broadcaster/worker.go:33        start broadcaster worker for repgroup id=2
2023-07-26T06:00:36.978Z        DEBUG   broadcaster/worker.go:33        start broadcaster worker for repgroup id=1
2023-07-26T06:00:36.987Z        DEBUG   broadcaster/worker.go:51        repgroup 1 connect established
2023-07-26T06:00:36.989Z        DEBUG   broadcaster/worker.go:51        repgroup 2 connect established
2023-07-26T06:00:36.992Z        DEBUG   broadcaster/worker.go:51        repgroup 3 connect established
2023-07-26T06:00:36.992Z        DEBUG   rebalance/service.go:71 Performing cleanup after possible rebalance operation failure
2023-07-26T06:00:37.077Z        DEBUG   broadcaster/worker.go:75        finish broadcaster worker for repgroup id=3
2023-07-26T06:00:37.077Z        DEBUG   broadcaster/worker.go:75        finish broadcaster worker for repgroup id=1
2023-07-26T06:00:37.077Z        DEBUG   broadcaster/worker.go:75        finish broadcaster worker for repgroup id=2
2023-07-26T06:00:37.082Z        DEBUG   rebalance/service.go:422        Rebalance will run 1 tasks
2023-07-26T06:00:37.095Z        DEBUG   rebalance/service.go:452        Guessing that rebalance() can use 3 workers
2023-07-26T06:00:37.096Z        DEBUG   rebalance/job.go:352    state: Idle     {"worker_id": 1, "table": "users", "partition num": 1, "source rgid": 2, "dest rgid": 1, "kind": "move"}
2023-07-26T06:00:37.111Z        DEBUG   rebalance/job.go:352    state: ConnsEstablished {"worker_id": 1, "table": "users", "partition num": 1, "source rgid": 2, "dest rgid": 1, "kind": "move"}
2023-07-26T06:00:37.171Z        DEBUG   rebalance/job.go:352    state: WaitInitCopy     {"worker_id": 1, "table": "users", "partition num": 1, "source rgid": 2, "dest rgid": 1, "kind": "move"}
2023-07-26T06:00:38.073Z        DEBUG   rebalance/job.go:347    current state   {"worker_id": 1, "table": "users", "partition num": 1, "source rgid": 2, "dest rgid": 1, "kind": "move", "state": "WaitInitialCatchup"}
2023-07-26T06:00:38.073Z        DEBUG   rebalance/job.go:352    state: WaitInitialCatchup       {"worker_id": 1, "table": "users", "partition num": 1, "source rgid": 2, "dest rgid": 1, "kind": "move"}
2023-07-26T06:00:38.084Z        DEBUG   rebalance/job.go:347    current state   {"worker_id": 1, "table": "users", "partition num": 1, "source rgid": 2, "dest rgid": 1, "kind": "move", "state": "WaitFullSync"}
2023-07-26T06:00:38.084Z        DEBUG   rebalance/job.go:352    state: WaitFullSync     {"worker_id": 1, "table": "users", "partition num": 1, "source rgid": 2, "dest rgid": 1, "kind": "move"}
2023-07-26T06:00:38.108Z        DEBUG   rebalance/job.go:347    current state   {"worker_id": 1, "table": "users", "partition num": 1, "source rgid": 2, "dest rgid": 1, "kind": "move", "state": "Committing"}
2023-07-26T06:00:38.108Z        DEBUG   rebalance/job.go:352    state: Committing       {"worker_id": 1, "table": "users", "partition num": 1, "source rgid": 2, "dest rgid": 1, "kind": "move"}
2023-07-26T06:00:38.254Z        DEBUG   rebalance/job.go:352    state: Complete {"worker_id": 1, "table": "users", "partition num": 1, "source rgid": 2, "dest rgid": 1, "kind": "move"}
2023-07-26T06:00:38.258Z        DEBUG   rebalance/service.go:583        Produce and process tasks on destination replication groups...
2023-07-26T06:00:38.258Z        DEBUG   rebalance/service.go:594        Produce and process tasks on source replication groups...
2023-07-26T06:00:38.258Z        DEBUG   rebalance/service.go:606        wait all tasks finish
2023-07-26T06:00:38.258Z        DEBUG   rebalance/service.go:531        Analyzing table public.users in rg 1    {"table": "public.users", "rgid": 1, "action": "analyze"}
2023-07-26T06:00:38.573Z        DEBUG   rebalance/service.go:531        Analyzing table public.users in rg 2    {"table": "public.users", "rgid": 2, "action": "analyze"}
2023-07-26T06:00:38.833Z        DEBUG   broadcaster/worker.go:75        finish broadcaster worker for repgroup id=1
2023-07-26T06:00:38.833Z        DEBUG   broadcaster/worker.go:75        finish broadcaster worker for repgroup id=2
2023-07-26T06:00:38.833Z        DEBUG   broadcaster/worker.go:75        finish broadcaster worker for repgroup id=3

В этом примере секция номер 1 таблицы public.users будет перемещена в сегмент clover-1-shrn1.

После ручного перемещения секции сегментированной таблицы автоматическая перебалансировка данных отключается для этой таблицы и всех совместно размещённых с ней таблиц.

Для получения списка таблиц с отключённой автоматической перебалансировкой, выполните команду shardmanctl table sharded norebalance. Пример:

$ shardmanctl tables sharded norebalance

public.users

Для включения автоматической перебалансировки данных для выбранной сегментированной таблицы, выполните команду shardmanctl tables sharded rebalance, как показано в примере ниже:

$ shardmanctl tables sharded rebalance -t public.users

2023-07-26T07:07:00.657Z        DEBUG   cmd/common.go:105       Waiting for metadata lock...
2023-07-26T07:07:00.687Z        DEBUG   broadcaster/worker.go:33        start broadcaster worker for repgroup id=1
2023-07-26T07:07:00.687Z        DEBUG   broadcaster/worker.go:33        start broadcaster worker for repgroup id=2
2023-07-26T07:07:00.687Z        DEBUG   broadcaster/worker.go:33        start broadcaster worker for repgroup id=3
2023-07-26T07:07:00.697Z        DEBUG   broadcaster/worker.go:51        repgroup 1 connect established
2023-07-26T07:07:00.698Z        DEBUG   broadcaster/worker.go:51        repgroup 2 connect established
2023-07-26T07:07:00.698Z        DEBUG   broadcaster/worker.go:51        repgroup 3 connect established
2023-07-26T07:07:00.698Z        DEBUG   extension/lock.go:35    Waiting for extension lock...
2023-07-26T07:07:00.719Z        DEBUG   rebalance/service.go:381        Planned moving pnum 21 for table users from rg 1 to rg 2
2023-07-26T07:07:00.719Z        INFO    rebalance/service.go:244        Performing rebalance...
2023-07-26T07:07:00.720Z        DEBUG   broadcaster/worker.go:33        start broadcaster worker for repgroup id=1
2023-07-26T07:07:00.720Z        DEBUG   broadcaster/worker.go:33        start broadcaster worker for repgroup id=2
2023-07-26T07:07:00.720Z        DEBUG   broadcaster/worker.go:33        start broadcaster worker for repgroup id=3
2023-07-26T07:07:00.732Z        DEBUG   broadcaster/worker.go:51        repgroup 3 connect established
2023-07-26T07:07:00.732Z        DEBUG   broadcaster/worker.go:51        repgroup 1 connect established
2023-07-26T07:07:00.734Z        DEBUG   broadcaster/worker.go:51        repgroup 2 connect established
2023-07-26T07:07:00.734Z        DEBUG   rebalance/service.go:71 Performing cleanup after possible rebalance operation failure
2023-07-26T07:07:00.791Z        DEBUG   broadcaster/worker.go:75        finish broadcaster worker for repgroup id=1
2023-07-26T07:07:00.791Z        DEBUG   broadcaster/worker.go:75        finish broadcaster worker for repgroup id=2
2023-07-26T07:07:00.791Z        DEBUG   broadcaster/worker.go:75        finish broadcaster worker for repgroup id=3
2023-07-26T07:07:00.795Z        DEBUG   rebalance/service.go:422        Rebalance will run 1 tasks
2023-07-26T07:07:00.809Z        DEBUG   rebalance/service.go:452        Guessing that rebalance() can use 3 workers
2023-07-26T07:07:00.809Z        DEBUG   rebalance/job.go:352    state: Idle     {"worker_id": 1, "table": "users", "partition num": 21, "source rgid": 1, "dest rgid": 2, "kind": "move"}
2023-07-26T07:07:00.823Z        DEBUG   rebalance/job.go:352    state: ConnsEstablished {"worker_id": 1, "table": "users", "partition num": 21, "source rgid": 1, "dest rgid": 2, "kind": "move"}
2023-07-26T07:07:00.880Z        DEBUG   rebalance/job.go:352    state: WaitInitCopy     {"worker_id": 1, "table": "users", "partition num": 21, "source rgid": 1, "dest rgid": 2, "kind": "move"}
2023-07-26T07:07:01.886Z        DEBUG   rebalance/job.go:347    current state   {"worker_id": 1, "table": "users", "partition num": 21, "source rgid": 1, "dest rgid": 2, "kind": "move", "state": "WaitInitialCatchup"}
2023-07-26T07:07:01.886Z        DEBUG   rebalance/job.go:352    state: WaitInitialCatchup       {"worker_id": 1, "table": "users", "partition num": 21, "source rgid": 1, "dest rgid": 2, "kind": "move"}
2023-07-26T07:07:01.904Z        DEBUG   rebalance/job.go:347    current state   {"worker_id": 1, "table": "users", "partition num": 21, "source rgid": 1, "dest rgid": 2, "kind": "move", "state": "WaitFullSync"}
2023-07-26T07:07:01.905Z        DEBUG   rebalance/job.go:352    state: WaitFullSync     {"worker_id": 1, "table": "users", "partition num": 21, "source rgid": 1, "dest rgid": 2, "kind": "move"}
2023-07-26T07:07:01.932Z        DEBUG   rebalance/job.go:347    current state   {"worker_id": 1, "table": "users", "partition num": 21, "source rgid": 1, "dest rgid": 2, "kind": "move", "state": "Committing"}
2023-07-26T07:07:01.932Z        DEBUG   rebalance/job.go:352    state: Committing       {"worker_id": 1, "table": "users", "partition num": 21, "source rgid": 1, "dest rgid": 2, "kind": "move"}
2023-07-26T07:07:02.057Z        DEBUG   rebalance/job.go:352    state: Complete {"worker_id": 1, "table": "users", "partition num": 21, "source rgid": 1, "dest rgid": 2, "kind": "move"}
2023-07-26T07:07:02.060Z        DEBUG   rebalance/service.go:583        Produce and process tasks on destination replication groups...
2023-07-26T07:07:02.060Z        DEBUG   rebalance/service.go:594        Produce and process tasks on source replication groups...
2023-07-26T07:07:02.060Z        DEBUG   rebalance/service.go:531        Analyzing table public.users in rg 2    {"table": "public.users", "rgid": 2, "action": "analyze"}
2023-07-26T07:07:02.060Z        DEBUG   rebalance/service.go:606        wait all tasks finish
2023-07-26T07:07:02.321Z        DEBUG   rebalance/service.go:531        Analyzing table public.users in rg 1    {"table": "public.users", "rgid": 1, "action": "analyze"}
2023-07-26T07:07:02.587Z        DEBUG   broadcaster/worker.go:75        finish broadcaster worker for repgroup id=3
2023-07-26T07:07:02.587Z        DEBUG   broadcaster/worker.go:75        finish broadcaster worker for repgroup id=2
2023-07-26T07:07:02.587Z        DEBUG   broadcaster/worker.go:75        finish broadcaster worker for repgroup id=1

Чтобы включить автоматическую перебалансировку данных для всех сегментированных таблиц, выполните команду shardmanctl rebalance с параметром --force.

$ shardmanctl rebalance --force

2.4. Анализ и очистка

Базы данных Shardman требуют периодического обслуживания, такого как очистка. Для многих инсталляций достаточно, чтобы очистка выполнялась демоном автоочистки. Как и при установке PostgreSQL, демон автоочистки автоматически запускает команды ANALYZE всякий раз, когда содержимое таблицы существенно изменяется. Когда ANALYZE запускается демоном автоочистки или вручную для всей базы данных, статистика из сторонних секций передаётся с удалённых узлов.

В процессе перебалансировки данные могут перемещаться или копироваться между узлами кластера. После этой операции все перемещённые объекты автоматически анализируются. Как обычно, собирается локальная статистика и статистика со сторонних серверов.

Примечание

Команда ANALYZE на уровне базы данных использует статистику, доступную на удалённых сегментах. Но такая статистика может отсутствовать, и недостаточно просто транслировать команду ANALYZE для обновления статистики на уровне кластера. Вместо этого можно использовать функцию shardman.global_analyze(). Она собирает статистику для сегментированных и глобальных таблиц.

Команду VACUUM для очистки всей базы данных можно транслировать, чтобы выполнить очистку всего кластера. Это можно сделать, если включён параметр конфигурации shardman.broadcast_ddl.

Примечание

Когда команда ANALYZE выполняется для глобальной таблицы, обновляется только статистика соответствующей локальной таблицы. При запуске ANALYZE для сегментированной таблицы обновляется статистика по локальным секциям, статистика по сторонним секциям передаётся с удалённых узлов, если она есть. Когда ANALYZE выполняется непосредственно для сторонней таблицы, а на удалённом узле нет статистики для соответствующей локальной таблицы, эта таблица анализируется удалённо. Затем статистика передаётся с удалённого узла.

Когда VACUUM запускается для сегментированной или глобальной таблицы, оператор транслируется. Для сегментированной таблицы очистка выполняется для всех секций.

2.5. Управление доступом

В кластере Shardman действует традиционная модель безопасности PostgreSQL, дополненная функциональностью распределённых СУБД. В этом разделе описана данная функциональность, а также даётся общее представление об управлении доступом в кластере Shardman.

2.5.1. Параметры инициализации кластера по настройке управления доступом

Параметры кластера Shardman, связанные с безопасностью, берутся из файла инициализации. Можно изменить их позднее, но это следует делать с осторожностью, помня, что в большинстве случаев любое изменение потребует перезапуска СУБД.

В кластере Shardman есть два специальных пользователя: администратор и пользователь репликации. Shardman и stolon управляют экземплярами СУБД через администраторов. Репликация между контролируемыми экземплярами СУБД осуществляется stolon через пользователей репликации.

Параметры безопасности в файле инициализации задают:

Методы аутентификации для администраторов и пользователей репликации — PgSuAuthMethod, PgReplAuthMethod.

Имена для администраторов и пользователей репликации — PgSuUsername, PgReplUsername

Пароли для администраторов и пользователей репликации — PgSuPassword, PgReplPassword

Правила в файле pg_hba.conf, используемые экземплярами СУБД — StolonSpec.pgHBA

Более подробно эти параметры рассматриваются в описании sdmspec.json.

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

Проверьте, что пользователь, который будет указан в PgReplUsername/PgSuUsername, имеет права REPLICATION/SUPERUSER во всех группах репликации в кластере, и укажите его действующий пароль в PgReplPassword/PgSuPassword.

Если всё верно, создайте дамп ключа etcd shardman/cluster0/data/cluster (здесь и далее имя кластера Shardman — cluster0). Например:

$ etcdctl --endpoints etcdserver:2379 get --print-value-only  shardman/cluster0/data/cluster |jq . > clusterdata.json

В этом примере создаётся дамп ключа data/cluster для кластера Shardman с именем cluster0 с сервера etcd etcdserver, принимающего подключения через порт 2379, дамп форматируется при помощи jq и сохраняется в файл clusterdata.json.

При необходимости отредактируйте дамп и сохраните его обратно в etcd:

$ cat clusterdata.json | etcdctl --endpoints etcdserver:2379 put shardman/cluster0/data/cluster

Изменение этих параметров приведёт к перезапуску СУБД.

В отличие от вышеуказанных параметров, параметр StolonSpec.pgHBA может быть изменён без перезапуска СУБД. Чтобы изменить его, выполните следующие действия:

Извлеките определение StolonSpec из shardman/cluster0/data/cluster, сохраните в какой-нибудь файл, измените при необходимости и обновите параметры кластера командой shardmanctl config update:

$ etcdctl --endpoints etcdserver:2379 get --print-value-only  shardman/cluster0/data/cluster | jq .Spec.StolonSpec . > stolonspec.json

Отредактируйте в файле stolonspec.json определение StolonSpec.pgHBA соответствующим образом, например:

"pgHBA": [
        "host all postgres 0.0.0.0/0 scram-sha-256",
        "host replication postgres 0.0.0.0/0 scram-sha-256",
        "host replication postgres ::0/0 scram-sha-256",
        "host all someuser 0.0.0.0/0 scram-sha-256"
      ],

Примените изменения, внесённые в файл stolonspec.json:

$ shardmanctl --store-endpoints etcdserver:2379 --cluster-name cluster0 config update -f stolonspec.json

2.5.2. Управление пользователями и ролями

Пользователи и роли в кластере Shardman — это обычные пользователи и роли PostgreSQL. Можно управлять ими отдельно на каждом сервере или глобально, используя DDL на уровне кластера. В Shardman также используются понятия глобальных пользователей и глобальных ролей. И только глобальные пользователи (или роли) могут создавать другие объекты Shardman и владеть ими на уровне кластера, такими как сегментированные или глобальные таблицы. Операции таких пользователей всегда выполняются одновременно на всех группах репликации. Например, когда глобальная роль включается в какую-то другую роль или удаляется, эта операция будет выполняться для всех групп репликации.

Можно создать глобального пользователя, используя оператор CREATE USER ... IN ROLE global, например:

CREATE USER someuser ENCRYPTED PASSWORD 'somepass' IN ROLE global;

При создании глобального пользователя Shardman автоматически создаёт сопоставление пользователя во всех группах репликации и предоставляет этому пользователю доступ ко всем сторонним серверам, входящим в существующие группы репликации. Поэтому при создании глобального пользователя нужно либо задать незашифрованный пароль, чтобы его можно было сохранить в пользовательском сопоставлении, либо вообще не задавать пароль. Глобальные роли (в том числе глобальные пользователи), для которых не задан пароль, не могут получить доступ к сторонним серверам. Однако глобальной роли можно выдать нужный набор разрешений, чтобы затем предоставлять их пользователям, включая их в эту роль. Кроме того, можно задать пароль для глобального пользователя позже.

Глобальных пользователей может создавать только пользователь с правом CREATEROLE на всех узлах кластера.

Операторы ALTER и DROP для глобальных пользователей транслируются всем группам репликации. Когда роль предоставляется глобальному пользователю, эта операция также транслируется. Переименование глобального пользователя не поддерживается, поскольку это делает недействительными пароли md5/scram-sha-256, хранящиеся в сопоставлениях пользователей.

Список глобальных пользователей хранится в таблице shardman.users.

Роль, заданная в PgSuUsername (обычно postgres), также создаётся как глобальная во время инициализации кластера. Однако роль, заданная в PgReplUsername, создаётся как локальная в каждой группе репликации.

Роль global зарезервирована и не может напрямую использоваться в кластере Shardman. Обратите внимание, что «global» является не фактически заданной ролью, а просто зарезервированным словом.

2.5.3. Управление разрешениями в сегментированных таблицах

В Shardman сегментированная таблица — это по сути секционированная таблица, где секции представляют собой либо локальные сегменты, либо сторонние таблицы, ссылающиеся на сегменты в других группах репликации.

Разрешения, установленные для сегментированной таблицы, транслируются для всех групп репликации и всех секций таблицы.

Когда в кластер добавляется новая группа репликации, клиент shardmanctl копирует схему из случайной существующей группы репликации в новую. Он также создаёт сторонний сервер для новой группы репликации во всех существующих группах репликации и пересоздаёт сторонние серверы в новых группах репликации. Разрешения для созданных сторонних серверов и сопоставления пользователей копируются со случайного стороннего сервера в существующей группе репликации. В новой группе репликации для каждой секции сегментированной таблицы shardmanctl создаёт стороннюю таблицу, ссылающуюся на существующий сегмент, и заменяет секцию этой сторонней таблицей. Позже некоторые из этих сторонних таблиц могут быть заменены на реальные таблицы. Это происходит на этапе перебалансировки команды shardmanctl nodes add, если перебалансировка включена. Данные для этих секций переносятся с существующих узлов с использованием логической репликации. Когда shardmanctl создаёт таблицы (или сторонние таблицы), он копирует разрешения из родительской таблицы. В родительской таблице уже должны быть правильные разрешения, поскольку они были скопированы из существующей группы репликации.

2.5.3.1. Примеры

Для выполнения команд в данном примере требуются права администратора.

Чтобы создать сегментированную таблицу и глобального пользователя, а затем предоставить ему доступ только для чтения к таблице, можно использовать следующие операторы:

CREATE USER someuser ENCRYPTED PASSWORD 'somepass' IN ROLE global;
CREATE TABLE pgbench_branches (
       bid integer NOT NULL PRIMARY KEY,
       bbalance integer,
       filler character(88)
)
WITH (distributed_by = 'bid', num_parts = 8);
GRANT SELECT ON pgbench_branches TO someuser;

Чтобы разрешить пользователю someuser доступ к кластеру Shardman, необходимо задать соответствующие параметры в pg_hba.conf (как было показано здесь).

Теперь предположим, что командой shardmanctl nodes add в кластер добавлено новое звено, например:

$ shardmanctl --store-endpoints http://etcdserver:2379 --cluster-name cluster0 nodes add -n newnode1,newnode2

В этом примере некоторые фрагменты таблицы pgbench_branches переносятся в новые группы репликации, и пользователю someuser выдаётся право SELECT для этой таблицы. Позже можно удалить пользователя someuser из всех групп репликации в кластере одной командой:

DROP USER someuser;

2.6. Резервное копирование и восстановление

В данном разделе рассматриваются основы резервного копирования и восстановления Shardman.

Для выполнения полного двоичного согласованного резервного копирования кластера Shardman в общий каталог или локальный каталог (при указании параметра --use-ssh) можно использовать команду backup инструмента shardmanctl, а для выполнения восстановления из этой резервной копии команду recover.

Также можно использовать команду probackup backup инструмента shardmanctl для выполнения полного согласованного двоичного резервного копирования кластера Shardman в репозиторий резервных копий на локальном узле или в S3-совместимом объектном хранилище и probackup restore для выполнения восстановления из любой резервной копии в репозитории.

Утилита PostgreSQL pg_probackup для создания согласованных полных и инкрементальных резервных копий была интегрирована в shardman-utils. Утилита shardman-utils использует подход pg_probackup для хранения резервных копий в предварительно созданном репозитории. Команды pg_probackup archive-get и archive-push используются для доставки журналов WAL в репозиторий резервных копий. В режимах резервного копирования и восстановления используется подключение по SSH без пароля между узлами кластера и узлом резервных копий.

Параметр конфигурации кластера Shardman enable_csn_snapshot должен иметь значение on. Этот параметр необходим для согласованности резервной копии кластера. Если этот параметр отключён, согласованное резервное копирование невозможно.

Для достижения согласованной видимости распределённых транзакций используется метод изоляции глобальных снимков на основе алгоритма физических часов. Точно так же можно получить согласованный снимок для резервных копий, при этом время, соответствующее глобальному снимку, должно быть сопоставлено с набором LSN для каждого узла. Такой набор согласованных LSN в кластере называется точкой синхронизации. Получив точку синхронизации и взяв из неё значения LSN для каждого узла в кластере, можно сделать резервную копию каждого узла, которая обязательно должна содержать это значение LSN. Также можно восстановить это значение LSN, используя механизм восстановления на момент времени (PITR).

Команды backup и probackup используют разные механизмы создания резервных копий. Команда backup использует стандартные утилиты pg_basebackup и pg_receivewal. Команда probackup использует утилиту pg_probackup и её параметры для создания резервной копии кластера. При любом использовании команд backup или probackup для восстановления имён узлов, заданных по имени хоста или IP-адресу, эти имена должны соответствовать тем, которые существовали на момент создания резервной копии.

2.6.1. Резервное копирование кластера с использованием pg_basebackup

В данном разделе рассматриваются основы резервного копирования и восстановления Shardman с использованием команды basebackup.

2.6.1.1. Требования

Для резервного копирования и восстановления кластера Shardman командой basebackup должны быть выполнены следующие требования:

Параметр конфигурации кластера Shardman enable_csn_snapshot должен иметь значение on. Этот параметр необходим для согласованности резервной копии кластера. Если этот параметр отключён, согласованное резервное копирование невозможно.

На каждом узле кластера Shardman утилиты Shardman должны быть установлены в каталог /opt/pgpro/sdm-14/bin.

На каждом узле кластера Shardman утилита pg_basebackup должна быть установлена в каталог /opt/pgpro/sdm-14/bin.

На каждом узле кластера Shardman должны быть созданы пользователь и группа пользователей операционной системы с именем postgres.

Должен быть настроен беспарольный доступ по SSH между узлами кластера Shardman для пользователя postgres операционной системы.

Если не указан флаг --use-ssh, все узлы кластера Shardman должны быть подключены к общему сетевому хранилищу, в котором должен быть создан каталог для резервных копий.

Если флаг --use-ssh указан, каталог для резервных копий можно создать в локальном хранилище на узле, где будет вызываться команда recover.

Пользователю postgres должен быть предоставлен доступ к каталогу с резервными копиями.

Утилита shardmanctl должна запускаться пользователем postgres операционной системы.

2.6.1.2. Резервное копирование с использованием pg_basebackup

shardmanctl выполняет задачу резервного копирования в несколько этапов.

Устанавливает необходимые блокировки в etcd, чтобы не допустить параллельные операции на уровне кластера.

Подключается к произвольной группой репликации и блокирует метаданные Shardman, чтобы не допустить изменения на сторонних серверах во время резервного копирования.

Создаёт слоты репликации в каждой группе репликации, чтобы гарантировать сохранение WAL-записей. Во время повторной синхронизации слоты репликации автоматически создаются на ведущем узле, если резервный узел отстаёт.

Выгружает метаданные Shardman, хранящиеся в etcd, в файл JSON в каталоге для резервных копий.

Для получения резервных копий из каждой группы репликации, параллельно запускает pg_basebackup, используя созданные слоты репликации.

Создаёт точку синхронизации и использует pg_receivewal для получения журналов WAL, созданных после завершения каждого выполнения базового резервного копирования (basebackup), до тех пор, пока не будут достигнуты LSN, извлечённые из точки синхронизации.

Исправляет неполные файлы WAL, созданные pg_receivewal, и создаёт файл описания резервной копии.

2.6.2. Восстановление кластера из резервной копии с использованием pg_basebackup

Можно восстановить резервную копию в том же кластере, где она находится, или в совместимом кластере. В данном случае совместимыми называются кластеры, которые используют одинаковые версии Shardman и имеют одинаковое количество групп репликации.

shardmanctl может выполнять либо полное восстановление, либо восстановление только метаданных. Восстановление только метаданных полезно, если возникают проблемы с экземпляром etcd, но данные СУБД не повреждены.

Во время восстановления только метаданных shardmanctl восстанавливает данные etcd из дампа, созданного во время резервного копирования.

Важно

Восстановление метаданных в несовместимом кластере может привести к катастрофическим последствиям, в том числе к потере данных, поскольку состояние метаданных может отличаться от фактической конфигурации. Не выполняйте восстановление метаданных, если после резервного копирования произошли изменения конфигурации кластера, например добавление или удаление узлов, даже если снова были добавлены те же узлы.

При восстановлении только схемы восстанавливает только информацию о схеме без данных. Это может быть полезно при большом объёме данных, и если схема нужна для тестирования или проверки.

Во время полного восстановления shardmanctl проверяет, соответствует ли количество групп репликации в целевом кластере количеству групп репликации в резервной копии. Это означает, что нельзя проводить восстановление в пустом кластере, а необходимо добавить столько же групп репликации, сколько было в кластере, резервная копия которого была создана.

shardmanctl probackup restore может восстановить полностью или частично работающий кластер из резервной копии, созданной на полностью или частично работающем кластере.

Также можно восстановить только один сегмент, используя параметр --shard.

shardmanctl выполняет полное восстановление в несколько этапов.

Устанавливает необходимые блокировки в etcd для предотвращения одновременных операций на уровне кластера и пытается назначить группы репликации при резервном копировании существующих групп репликации. Если это невозможно сделать (например, из-за несовместимости кластера), восстановления не происходит.

Восстанавливает часть метаданных etcd: конфигурацию кластера и части определений групп репликации.

Когда корректные метаданные восстановлены, выполняет stolon init в режиме инициализации PITR с RecoveryTargetName, для которого задано значение LSN точки синхронизации из файла резервной копии. DataRestoreCommand и RestoreCommand также берутся из файла с информацией о резервной копии.

Ожидает восстановления каждой группы репликации.

2.6.3. Резервное копирование кластера с использованием pg_probackup

В данном разделе рассматриваются основы резервного копирования и восстановления Shardman с использованием команды probackup.

Можно использовать команду probackup backup инструмента shardmanctl для выполнения двоичного резервного копирования кластера Shardman в репозиторий резервных копий на локальном (резервном) узле и probackup restore для выполнения восстановления из выбранной резервной копии. Поддерживаются полные и частичные (дельта) резервные копии.

2.6.3.1. Требования

Для резервного копирования и восстановления кластера Shardman командой probackup должны быть выполнены следующие требования:

Параметр конфигурации кластера Shardman enable_csn_snapshot должен иметь значение on. Этот параметр необходим для согласованности резервной копии кластера. Если этот параметр отключён, согласованное резервное копирование невозможно.

На узле резервного копирования утилиты Shardman должны быть установлены в каталог /opt/pgpro/sdm-14/bin.

На узле резервного копирования и на каждом узле кластера утилита pg_probackup должна быть установлена в каталог /opt/pgpro/sdm-14/bin.

На узле резервного копирования должны быть созданы пользователь и группа пользователей операционной системы с именем postgres.

Должен быть настроен беспарольный доступ по SSH между резервными узлами и узлами кластера Shardman для пользователя postgres операционной системы. Чтобы сделать это, на каждом узле:

Пользователь postgres должен создать подкаталог .ssh в каталоге /var/lib/postgresql и поместить туда ключи, необходимые для беспарольного подключения по SSH.

Для резервного копирования/восстановления довольно большого числа потоков, например 50 (-j=50, подробнее в Подразделе « backup »), для MaxSessions и MaxStartups необходимо задать значение 100 на резервном узле в файле /etc/ssh/sshd_config.

Примечание

Если для команды shardmanctl probackup задать число потоков больше 10 (параметр -j), то фактическое число SSH-соединений может превысить максимально допустимое число одновременных SSH-соединений на резервном узле и, следовательно, приведёт к ошибке «ERROR: Agent error: kex_exchange_identification: Connection closed by remote host» (ОШИБКА: Ошибка агента: kex_exchange_identification: Соединение закрыто удалённым сервером). Чтобы исправить ошибку, либо уменьшите количество потоков probackup, либо измените значение параметра конфигурации MaxStartups резервного узла. Если SSH настроен как служба xinetd на резервном узле, измените значение параметра конфигурации xinetd per_source, а не MaxStartups.

Можно отключить SSH для копирования данных, задав для параметра --storage-type значение mount или S3 (но для выполнения удалённых команд всё равно потребуется SSH). Это значение также будет автоматически использоваться в процессе восстановления.

Должен быть создан каталог для резервного копирования или корзина в S3-совместимом объектном хранилище.

Пользователю postgres должен быть предоставлен доступ к каталогу с резервными копиями.

Утилита shardmanctl должна запускаться пользователем postgres операционной системы.

На узле резервного копирования должна быть успешно выполнена подкоманда init для инициализации репозитория резервных копий.

На узле резервного копирования должна быть успешно выполнена подкоманда archive-command add для включения archive_command в каждой группе репликации для потоковой передачи WAL в инициированный репозиторий.

2.6.3.2. Процесс резервного копирования с использованием pg_probackup

shardmanctl выполняет задачу резервного копирования в несколько этапов.

Устанавливает необходимые блокировки в etcd, чтобы не допустить параллельные операции на уровне кластера.

Подключается к произвольной группой репликации и блокирует метаданные Shardman, чтобы не допустить изменения на сторонних серверах во время резервного копирования.

Выгружает метаданные Shardman, хранящиеся в etcd, в файл JSON в каталоге для резервных копий или в корзине в S3-совместимом объектном хранилище.

Для получения резервных копий из каждой группы репликации, параллельно запускает pg_probackup, используя сконфигурированный archive_command.

Создаёт точку синхронизации и получает значения LSN из структуры данных точки синхронизации для каждой группы репликации. Затем команда pg_probackup arhive-push используется для отправки журналов WAL, созданных после завершения резервного копирования, и файла WAL, в котором для каждой группы репликации присутствуют LSN точки синхронизации.

2.6.4. Восстановление кластера из резервной копии с использованием pg_probackup

Можно восстановить резервную копию в том же кластере, где она находится, или в совместимом кластере. В данном случае совместимыми называются кластеры, которые используют одинаковые версии Shardman и имеют одинаковое количество групп репликации.

Кроме того, возможно восстановить другие кластеры из той же резервной копии, если у этих кластеров одинаковая топология.

shardmanctl может выполнять либо полное восстановление, либо восстановление только метаданных, либо только схемы. Восстановление только метаданных полезно, если возникают проблемы с экземпляром etcd, но данные СУБД не повреждены.

Во время восстановления только метаданных shardmanctl восстанавливает данные etcd из дампа, созданного во время резервного копирования.

Важно

Восстановление метаданных в несовместимом кластере может привести к катастрофическим последствиям, в том числе к потере данных, поскольку состояние метаданных может отличаться от фактической конфигурации. Не выполняйте восстановление метаданных, если после резервного копирования произошли изменения конфигурации кластера, например добавление или удаление узлов, даже если снова были добавлены те же узлы.

При восстановлении только схемы восстанавливает только информацию о схеме без данных. Это может быть полезно при большом объёме данных, и если схема нужна для тестирования или проверки.

Во время полного восстановления shardmanctl проверяет, соответствует ли количество групп репликации в целевом кластере количеству групп репликации в резервной копии. Это означает, что нельзя проводить восстановление в пустом кластере, а необходимо добавить столько же групп репликации, сколько было в кластере, резервная копия которого была создана.

Также можно выполнить восстановление только одного сегмента, используя параметр --shard.

Также можно выполнить восстановление на определённый момент времени, используя параметр --recovery-target-time. В этом случае Shardman находит ближайшую точку синхронизации к указанной временной метке и предлагает выполнить восстановление по найденному значению LSN. Можно также указать параметр --wal-limit, чтобы ограничить количество обрабатываемых сегментов WAL.

shardmanctl выполняет полное восстановление в несколько этапов.

Устанавливает необходимые блокировки в etcd для предотвращения одновременных операций на уровне кластера и пытается назначить группы репликации при резервном копировании существующих групп репликации. Если это невозможно сделать (например, из-за несовместимости кластера), восстановления не происходит.

Восстанавливает часть метаданных etcd: конфигурацию кластера и части определений групп репликации.

Когда корректные метаданные будут на месте, выполняет stolon init в режиме инициализации PITR с RecoveryTargetName, имеющем значение LSN точки синхронизации из файла с информацией о резервной копии. DataRestoreCommand и RestoreCommand также берутся из этого файла. Эти команды генерируются автоматически на этапе резервного копирования, не рекомендуется вносить какие-либо изменения в файл, содержащий описание резервной копии кластера Shardman. При восстановлении кластера для каждой группы репликации файлы WAL, содержащие окончательное значение LSN для восстановления, будут автоматически запрашиваться из репозитория резервных копий с удалённого узла командой pg_probackup archive-get.

Ожидает восстановления каждой группы репликации.

Наконец, нужно снова включить archive_command.

При выполнении последовательного восстановления в PostgreSQL следует учитывать потенциальные конфликты линии времени в сегментах WAL (журнала предзаписи). Эта проблема обычно возникает при восстановлении базы данных из резервной копии, созданной в определённый момент времени. Если база данных продолжает работать и генерировать сегменты WAL после резервного копирования, эти новые сегменты WAL будут связаны с другой линией времени. Если во время восстановления система попытается воспроизвести сегменты WAL из другой линии времени — той, которая разошлась с точкой резервного копирования, — это может привести к несогласованности и конфликтам. Кроме того, после завершения восстановления в PostgreSQL настоятельно не рекомендуется восстанавливать базу данных на той же линии времени или на любой линии времени, предшествующей той, в которой была создана резервная копия.

2.6.5. Объединение резервных копий с помощью pg_probackup

При увеличении количества инкрементальных копий также увеличивается общий размер каталога резервных копий. Чтобы сэкономить дисковое пространство, можно объединить инкрементальные копии с их родительской полной резервной копией, выполнив команду объединения и указав идентификатор последней инкрементальной копии для объединения:

$ shardmanctl --store-endpoints http://etcd1:2379,http://etcd2:2379,http://etcd3:2379 probackup merge --backup-path backup_dir --backup-id backup_id

Эта команда объединяет резервные копии, принадлежащие к общей цепочке инкрементальных копий. Если указана полная копия, она объединяется с первой инкрементальной копией. Если указана инкрементальная копия, она объединяется с родительской полной копией вместе со всеми промежуточными инкрементальными копиями. После выполнения команды полная копия содержит все объединённые данные, а инкрементальные копии удаляются как ненужные. Таким образом, операция объединения по сути равнозначна удалению всех устаревших резервных копий из полной копии, но выполняется намного быстрее, особенно для больших объёмов данных. Это также позволяет сократить количество операций ввода-вывода и объём сетевого трафика при использовании pg_probackup в удалённом режиме.

Перед объединением pg_probackup проверяет все задействуемые резервные копии, чтобы удостовериться в их целостности. Можно посмотреть на текущее состояние резервной копии, выполнив команду show:

$ shardmanctl --store-endpoints http://etcd1:2379,http://etcd2:2379,http://etcd3:2379 probackup show --backup-path backup_dir

За дополнительной информацией обратитесь к этой главе.

2.6.6. Удаление резервных копий с помощью pg_probackup

Для удаления резервной копии, ставшей ненужной, выполните команду:

$ shardmanctl --store-endpoints http://etcd1:2379,http://etcd2:2379,http://etcd3:2379 probackup delete --backup-path backup_dir --backup-id backup_id

Эта команда удаляет резервную копию с указанным идентификатором backup_id вместе со всеми инкрементальными копиями, происходящими от этого backup_id, если они есть. Это позволяет удалить некоторые из последних инкрементальных резервных копий, не затрагивая базовую полную резервную копию и другие инкрементальные резервные копии, следующие за ней.

Для удаления старых файлов WAL, которые не нужны для восстановления резервных копий, воспользуйтесь ключом --delete-wal:

$ shardmanctl --store-endpoints http://etcd1:2379,http://etcd2:2379,http://etcd3:2379 probackup delete --backup-path backup_dir --backup-id backup_id --delete-wal

За дополнительной информацией обратитесь к этой главе.

2.7. Настройка безопасных подключений с помощью etcd

В этом разделе описывается как настроить безопасное подключение служб и утилит Shardman к хранилищу etcd.

etcd является критически важным компонентом кластера Shardman. Если злоумышленник получит доступ к хранилищу etcd, он получит полный контроль над всем кластером, включая доступ к СУБД с правами администратора. Для защиты кластера рекомендуется настроить проверку подлинности TLS между демонами etcd и службами Shardman.

Для этого можно использовать транспорт HTTPS с сертификатами, подписанными вашим локальным центром сертификации (ЦС), для шифрования трафика между кластером etcd и службами Shardman и ограничения доступа etcd. Для этого выполните действия, описанные в следующих разделах.

2.7.1. Создание SSL сертификатов

Чтобы создать SSL-сертификаты, выполните следующие шаги:

Если ЦС не существует, создайте самоподписанный корневой сертификат. Создавайте все сертификаты на одном доверенном узле. В примере ниже генерируются сертификаты, срок действия которых истекает через 10000 дней (можно выбрать более подходящий интервал):

# openssl genrsa -out rootCA.key 4096
# openssl req -x509 -new -key rootCA.key -days 10000 -out rootCA.crt

Подготовьте следующий файл конфигурации openssl для каждого узла etcd:

[ req ]
default_bits       = 4096
distinguished_name = req_distinguished_name
req_extensions     = req_ext
[ req_distinguished_name ]
countryName                 = Country Name (2 letter code)
stateOrProvinceName         = State or Province Name (full name)
localityName               = Locality Name (eg, city)
organizationName           = Organization Name (eg, company)
commonName                 = Common Name (e.g. server FQDN or YOUR name)
[ req_ext ]
subjectAltName = @alt_names
[alt_names]
DNS.1   = n1
IP.1   = 192.168.1.1
IP.2   = 127.0.0.1

В разделе [alt_names] укажите альтернативные имена субъектов для узла etcd. Эти имена должны включать имя узла сервера etcd, IP-адрес и локальный IP-адрес. Указывать локальный IP-адрес необязательно, но может оказаться полезным.

Сохраните файл. Например, имена файлов конфигурации для узлов n1 — n3 могут быть n1.san.conf — n3.san.conf.

Используя подготовленные файлы конфигурации, создайте закрытые ключи и запросы сертификатов для узлов etcd:

# openssl genrsa -out n1.etcd.key 4096
# openssl req -config n1.san.conf -new -key n1.etcd.key -out n1.etcd.csr -subj "/C=RU/ST=Moscow Region/L=Moscow/O=Test/CN=n1"

Здесь «/C=RU/ST=Moscow Region/L=Moscow/O=Test/CN=n1» означает, что запрос сертификата создаётся с названием страны RU, регионом Moscow Region, населённым пунктом Moscow, организацией Test и общим именем n1. Общее имя должно совпадать с DNS-именем вашего сервера etcd.

Подпишите запрос сертификации:

# openssl x509 -extfile n1.san.conf -extensions req_ext -req -in n1.etcd.csr  -CA rootCA.crt -CAkey rootCA.key -CAcreateserial -out n1.etcd.crt -days 10000

Проверьте сертификаты, чтобы убедиться, что они содержат правильные значения полей X509v3 Subject Alternative Name. Поля должны содержать список DNS-имён и IP-адресов, добавленных в файл конфигурации openssl:

# openssl x509 -in n1.etcd.crt -noout -text

Создайте клиентские сертификаты для служб Shardman и клиентских программ. Эти сертификаты не обязательно должны содержать заголовок subjectAltName, и значение переменной CN не имеет значения в приведённом ниже примере. В данном примере создаётся одна общая пара сертификат-ключ для служб и одна — для инструментов:

# openssl x509 genrsa -out shardman_services.key 4096
# openssl req -new -key shardman_services.key -out shardman_services.csr -subj "/C=RU/ST=Moscow Region/L=Moscow/O=Test/CN=shardman_services"
# openssl x509 -req -in shardman_services.csr  -CA rootCA.crt -CAkey rootCA.key -CAcreateserial -out shardman_services.crt -days 10000
# openssl x509 genrsa -out shardman_tools.key 4096
# openssl req -new -key shardman_tools.key -out shardman_tools.csr -subj "/C=RU/ST=Moscow Region/L=Moscow/O=Test/CN=shardman_tools"
# openssl x509 -req -in shardman_tools.csr  -CA rootCA.crt -CAkey rootCA.key -CAcreateserial -out shardman_tools.crt -days 10000

2.7.2. Настройка служб etcd и shardmand

Теперь настройте службы ( etcd и shardmand ) для использования сгенерированных сертификатов. Выполните следующие шаги:

На каждом узле etcd поместите файлы rootCA.crt, nX.etcd.crt и nX.etcd.key в каталог, доступный для демона etcd (например, создайте каталог /etc/etcd и поместите эти файлы в него). Убедитесь, что файл nX.etc.key доступен только пользователю демона etcd.

Укажите следующую конфигурацию для демонов etcd в /etc/default/etc:

# unqualified first name
ETCD_NAME=n1
# where we actually listen for peers
ETCD_LISTEN_PEER_URLS=https://0.0.0.0:2380
# where we actually listen for clients
ETCD_LISTEN_CLIENT_URLS=https://0.0.0.0:2379
# advertise where this machine is listening for clients
ETCD_ADVERTISE_CLIENT_URLS=https://n1:2379

# --initial flags are used during bootstrapping and ignored afterwards, so it is
# ok to specify them always
# advertise where this machine is listening for peer
ETCD_INITIAL_ADVERTISE_PEER_URLS=https://n1:2380
ETCD_INITIAL_CLUSTER_TOKEN=etcd-cluster
# ansible_nodename is fqdn
ETCD_INITIAL_CLUSTER=n1=https://n1:2380,n2=https://n2:2380,n3=https://n3:2380
ETCD_INITIAL_CLUSTER_STATE=new

ETCD_DATA_DIR=/var/lib/etcd/default/member
ETCD_AUTO_COMPACTION_RETENTION=1

ETCD_KEY_FILE=/etc/etcd/n1.etcd.key
ETCD_CERT_FILE=/etc/etcd/n1.etcd.crt
ETCD_TRUSTED_CA_FILE=/etc/etcd/rootCA.crt
ETCD_CLIENT_CERT_AUTH=true

ETCD_PEER_CERT_FILE=/etc/etcd/n1.etcd.crt
ETCD_PEER_KEY_FILE=/etc/etcd/n1.etcd.key
ETCD_PEER_TRUSTED_CA_FILE=/etc/etcd/rootCA.crt
ETCD_PEER_CLIENT_CERT_AUTH=true

Замените n1 на имя соответствующего узла.

Перезапустите службы etcd на всех узлах кластера etcd:

# systemctl restart etcd

Для проверки новой конфигурации используйте следующую команду:

# etcdctl  --endpoints=https://n1:2379,https://n2:2379,https://n3:2379 --cacert /etc/etcd/rootCA.crt --cert /etc/etcd/n1.etcd.crt --key /etc/etcd/n1.etcd.key member list -w table

+------------------+---------+------+-----------------+-----------------+------------+
|        ID        | STATUS  | NAME |    PEER ADDRS   |   CLIENT ADDRS  | IS LEARNER |
+------------------+---------+------+-----------------+-----------------+------------+
| 66ebe06d7302c3f0 | started |   n2 | https://n2:2380 | https://n2:2379 |      false |
| b1080bf5ff059980 | started |   n1 | https://n1:2380 | https://n1:2379 |      false |
| d98323257249fefb | started |   n3 | https://n3:2380 | https://n3:2379 |      false |
+------------------+---------+------+-----------------+-----------------+------------+

На каждом узле кластера Shardman поместите файлы rootCA.crt, shardman_services.crt и shardman_services.key в каталог, доступный для пользователя postgres (например, создайте каталог /etc/shardman и поместите эти файлы в него). Убедитесь, что файл shardman_services.key доступен только пользователю postgres.

Отредактируйте файл конфигурации shardmand /etc/shardman/shardmand-cluster0.env следующим образом:

SDM_STORE_ENDPOINTS=https://n1:2379,https://n2:2379,https://n3:2379
SDM_STORE_CA_FILE=/etc/shardman/rootCA.crt
SDM_STORE_CERT_FILE=/etc/shardman/shardman_services.crt
SDM_STORE_KEY=/etc/shardman/shardman_services.key

Перезапустите службы shardmand@cluster0 на всех узлах Shardman:

# systemctl restart shardmand@cluster0

2.7.3. Использование инструментов Shardman

Перед использованием инструментов Shardman скопируйте rootCA.crt, shardman_tools.crt и shardman_tools.key в какое-либо место на узле управления Shardman, где они доступны пользователю управления. Здесь под узлом управления понимается любой узел с установленными утилитами Shardman, который используется для управления кластером Shardman. Это также может быть один из узлов кластера Shardman (или все они). Под управляющим пользователем подразумевается пользователь, запускающий инструмент shardmanctl . Предполагается, что сертификаты и ключ находятся в каталоге /etc/shardman.

При использовании инструментов Shardman обязательно добавьте --store-ca-file, --store-cert-file и --store-key для команды shardmanctl. Например, следующая команда получает статус кластера:

# shardmanctl --store-ca-file /etc/shardman/rootCA.crt --store-cert-file /etc/shardman/shardman_tools.crt --store-key /etc/ shardman/shardman_tools.key --store-endpoints https://n1:2379,https://n2:2379,https://n3:2379 status

2.8. Обновление кластера

В этом разделе описан процесс обновления базы данных Shardman до более новой версии. Перед обновлением рекомендуется посмотреть Замечания к выпуску и найти те изменения, которые могут вызвать проблемы с вашим приложением. Если нет потенциальных проблем, можно перейти к обновлению.

Процесс обновления Shardman состоит из нескольких шагов, которые необходимо выполнять последовательно:

Обновить пакеты Shardman.

Перезапустить все службы Shardman и экземпляры базы данных.

Обновить расширение базы данных shardman.

2.8.1. Обновление пакетов

2.8.1.1. Системы с пакетным менеджером APT

Для обновления пакетов обычно достаточно выполнить следующую команду:

$ apt update && apt --only-upgrade install shardman-tools shardman-services postgrespro-sdm-14-contrib postgrespro-sdm-14-server

или обновить все пакеты в системе:

$ apt update && apt upgrade

Проверьте, что на каждом узле обновлены все пакеты:

$ dpkg -l | grep -E '(postgres pro|shardman)'

2.8.1.2. RPM-системы

Для обновления пакетов обычно достаточно выполнить следующую команду:

$ yum update shardman-tools shardman-services postgrespro-sdm-14-contrib postgrespro-sdm-14-server

или обновить все пакеты в системе:

$ yum update

Проверьте, что на каждом узле обновлены все пакеты:

$ yum list --installed | grep -E  '(postgrespro|shardman)'

2.8.2. Перезапуск служб Shardman и экземпляров баз данных

После обновления пакетов необходимо перезапустить все службы кластера. Это можно сделать одной командой shardmanctl restart:

$ shardmanctl --cluster-name cluster0 --store-endpoints http://etcd1:2379,http://etcd2:2379,http://etcd3:2379 restart

Можно пропустить параметры --cluster-name и --store-endpoints, установив переменные среды SDM_CLUSTER_NAME и SDM_STORE_ENDPOINTS, как в примере ниже:

                    export SDM_STORE_ENDPOINTS=http://etcd1:2379,http://etcd2:2379,http://etcd3:2379
                    export SDM_CLUSTER_NAME=cluster0

2.8.3. Обновление расширения

После перезапуска служб кластера следует обновить расширения сервера, выполнив следующую команду:

$ shardmanctl --cluster-name cluster0 --store-endpoints http://etcd1 :2379,http://etcd2:2379,http://etcd3:2379 upgrade

Если версия расширения shardman и версия библиотеки на сервере различаются, распределённые запросы и Shardman DDL не будут работать.

Расширения Shardman стараются предотвратить взаимодействие с несовместимым программным обеспечением. Несовместимости могут возникать по нескольким причинам: версия общей библиотеки shardman не соответствует версии расширения или версия удалённого сервера не соответствует версии локального сервера. В случае несовпадения версий расширения и библиотеки, Shardman не сможет изменить свои метаданные и не будет выполнять операции над глобальными объектами, пока расширение не будет обновлено. Если версия удалённого сервера не совпадает с версией локального сервера или они принадлежат разным кластерам, Shardman не будет взаимодействовать с сервером.

2.9. Отказоустойчивость и высокая доступность

Shardman обеспечивает отказоустойчивость сразу после установки. Демон shardmand контролирует конфигурацию кластера Shardman и управляет кластерами stolon, которые используются для обеспечения доступности сегментов и отказоустойчивости. Общая конфигурация Shardman (shardmand, stolon) хранится в кластере etcd.

Чтобы обеспечить отказоустойчивость каждого кластера stolon, необходимо установить Repfactor > 0 в режиме перекрёстной репликации (PlacementPolicy=cross) или добавить хотя бы одну реплику в режиме ручной топологии (PlacementPolicy=manual).

Процессы stolon sentinel отвечают за наблюдение за процессами keeper и выбор одного из таких процессов в качестве ведущего. Процессы sentinel проводят выборы при запуске кластера и каждый раз, когда текущий ведущий процесс sentinel выходит из строя.

Один из процессов keeper выбирается ведущим. Все операции записи выполняются в ведущем процессе, а остальные экземпляры используются в качестве резервных.

В случае автоматической отработки отказа stolon позаботится об автоматической замене резервного на ведущего, а вышедшего из строя ведущего — на резервного. Для выполнения отработки отказа дополнительно требуется наличие etcd, в котором сохраняется мгновенный статус ведущего/резервного от stolon.

При необходимости можно переключить ведущего вручную, выполнив команду shardmanctl shard switch.

Автоматическая отработка отказа основана на использовании тайм-аутов, которые можно переопределить в sdmspec.json, как в данном примере:

                {
                "ShardSpec":{
                    "failInterval": "20s",
                    "sleepInterval": "5s",
                    "convergenceTimeout": "30s",
                    "deadKeeperRemovalInterval": "48h",
                    "requestTimeout": "10s",
                    ...
                },
                ...
                },
                ...

Можно указать некоторые параметры отказоустойчивости, чтобы задать поведение кластера в состоянии сбоя: masterDemotionEnabled, masterDemotionTimeout, minSyncMonitorEnabled и minSyncMonitorUnhealthyTimeout.

2.9.1. Тайм-ауты

convergenceTimeout

Интервал ожидания достижения базой данных требуемого состояния, когда не ожидается длительных операций.

По умолчанию: 30s.

deadKeeperRemovalInterval

Интервал, по истечении которого «мёртвый» процесс keeper будет удалён из данных кластера.

По умолчанию: 48h.

failInterval

Интервал после первой ошибки по истечении которого процесс объявляется keeper или базы данных неработоспособной.

По умолчанию: 20s.

requestTimeout

Интервал, по истечении которого любой запрос (проверок процессов keeper процессами sentinel и т. д.) завершится ошибкой.

По умолчанию: 10s.

sleepInterval

Интервал ожидания перед следующей проверкой.

По умолчанию: 5s.

2.10. Ведение журнала

Shardman — критически важная точка в пользовательской инфраструктуре, так как в ней хранятся все пользовательские данные. Это делает ведение журнала обязательным. Поэтому пользователь должен понимать, как работает ведение журнала в Shardman. Из-за сложности устройства Shardman поддерживаются журналы из нескольких источников: журналы демона shardmand, который управляет конфигурацией кластера, и журналы из экземпляров базы данных PostgreSQL.

2.10.1. Журналы PostgreSQL

Shardman использует стандартные параметры ведения журнала PostgreSQL, описанные здесь. Параметры ведения журнала должны быть внесены в файл sdmspec.json в раздел pgParameters, как показано в следующем примере:

{
    "ShardSpec": {
    "pgParameters": {
        "logging_collector": "on",
        ...
    },
    ...
    },
    ...
}

По умолчанию в конфигурации для новых инсталляций Shardman указаны следующие значения параметров ведения журнала:

"logging_collector": "on",
"log_directory": "{{dataDir}}",
"log_filename": "postgres-{{cluster}}-{{shard}}-{{host}}-{{keeperID}}.log",
"log_line_prefix": = "%m [%r][%p]"

Согласно этим параметрам, журналы записываются в следующий файл: /var/lib/pgpro/sdm-VERSION/data/postgres-CLUSTERNAME-shard-N-HOSTNAME-keeper_M.log. Здесь VERSION — основная версия Shardman, CLUSTERNAME — имя текущего кластера, shard-N — имя текущего сегмента, HOSTNAME — имя текущего узла, keeper_M — идентификатор интегрированного процесса keeper.

2.10.2. Журналы shardmand

shardmand — это модуль systemd, его журналы записываются в journald. Ознакомиться с его работой можно, используя команду journalctl. Например, чтобы получить все журналы с 2023-05-09 10:00 для службы shardmand кластера cluster0, можно использовать следующую команду:

                 $ journalctl -u shardmand@cluster0.service

Для фильтра журналов по времени можно использовать параметры --since и --until, ограничивающие отображаемые записи после или до заданного времени соответственно. Значения времени могут быть представлены в различных форматах. Для абсолютных значений времени следует использовать YYYY-MM-DD HH:MM:SS. Например можно увидеть все записи с 10:15 10 января 2023 года, выполнив:

                     $ journalctl -u shardmand@cluster0.service --since "2023-01-10 17:15:00"

Если компоненты вышеуказанного формата опущены, будут применены некоторые значения по умолчанию. Например, если дата не указана, предполагается текущая дата. Если компонент времени отсутствует, указывается «00:00:00» (полночь). Секунды также можно не указывать, чтобы по умолчанию подставлялось значение «00»:

                     $ journalctl -u shardmand@cluster0.service --since "2023-01-10" --until "2023-01-11 03:00"

Чтобы задать уровень детализации журнала для всех служб Shardman, укажите SDM_LOG_LEVEL в файле конфигурации shardmand.

2.10.3. Сбор информации о сбоях обслуживающих процессов

Некоторые сбои вызваны отказами оборудования или проблемами самой СУБД. Чтобы понять причину сбоя, используйте crash_info. Для этого задайте параметр, следуя этим указаниям:

Создайте каталог на каждом узле кластера, доступный для пользователя Shardman операционной системы (обычно postgres). Записи об ошибках запишутся в этот каталог.

install -d -o postgres -g postgres -m 700  /var/lib/postgresql/crashinfo

Задайте значение параметра crash_info_location.

Примечание

Это приведёт к перезапуску СУБД.

shardmanctl --store-endpoints http://etcdserver:2379 set -y  crash_info_location=/var/lib/postgresql/crashinfo

Чтобы убедиться, что изменения вступили в силу, отправьте сигнал процессу СУБД, что приведёт к его отказу с созданием дампа памяти и перезапуску экземпляра.

Примечание

Делайте это исключительно в среде тестирования.

Подключитесь к СУБД и узнайте PID обслуживающего процесса текущего сеанса:

postgres=# select pg_backend_pid();
pg_backend_pid
----------------
    23770

Отправьте сигнал SIGSEGV процессу с данным PID:

kill -11 23770

Это приведёт к сбою этого процесса, а в каталог /var/lib/postgresql/crashinfo запишется файл, содержащий время, обратную трассировку и причину ошибки:

 # Signal
Program received signal: 11 (SIGSEGV)
Signal    UTC date time: 25.10.2024 08:37:02

# Program
                        pid: 23770
                        ppid: 17506
    program_invocation_name: postgres: postgres postgres 10.42.42.10(34202) idle
program_invocation_short_name: tgres 10.42.42.10(34202) idle
                    exe_path: /opt/pgpro/sdm-14/bin/postgres
                        exe: postgres

# Backtrace
1   postgres + 0x5b55c0              0x55c5ba8459b7  0x00007ffcbef19070  bt_crash_handler + 0x3f7
2   libc.so.6 + 0x4251f              0x7f01c2caa520  0x00007ffcbef19140  __sigaction + 0x50
unknown  ./signal/../sysdeps/unix/sysv/linux/x86_64/libc_sigaction.c:0
3   libc.so.6 + 0x125f80             0x7f01c2d8df9a  0x00007ffcbef195b8  epoll_wait + 0x1a
epoll_wait  ../sysdeps/unix/sysv/linux/epoll_wait.c:30
4   postgres + 0x433870              0x55c5ba6c39bb  0x00007ffcbef195c0  WaitEventSetWait + 0x14b
5   postgres + 0x320de0              0x55c5ba5b0e74  0x00007ffcbef19650  secure_read + 0x94
6   postgres + 0x327d20              0x55c5ba5b7dae  0x00007ffcbef196a0  pq_recvbuf + 0x8e
7   postgres + 0x328980              0x55c5ba5b8995  0x00007ffcbef196c0  pq_getbyte + 0x15
8   postgres + 0x457da0              0x55c5ba6e909c  0x00007ffcbef196d0  PostgresMain + 0x12fc
9   postgres + 0x3ce210              0x55c5ba65ef86  0x00007ffcbef19a60  ServerLoop + 0xd76
10  postgres + 0x3cf240              0x55c5ba65fe18  0x00007ffcbef1a040  PostmasterMain + 0xbd8
11  postgres + 0x14ecc0              0x55c5ba3df182  0x00007ffcbef1a0c0  main + 0x4c2
12  libc.so.6 + 0x29d10              0x7f01c2c91d90  0x00007ffcbef1a0f0  __libc_init_first + 0x90
__libc_start_call_main  ../sysdeps/nptl/libc_start_call_main.h:58
13  libc.so.6 + 0x29dc0              0x7f01c2c91e40  0x00007ffcbef1a190  __libc_start_main + 0x80
call_init  ../csu/libc-start.c:128
__libc_start_main_impl  ../csu/libc-start.c:379
14  postgres + 0x14f200              0x55c5ba3df225  0x00007ffcbef1a1e0  _start + 0x25

Глава 3. Разработка

В кластере Shardman используются два основных способа хранения данных: в виде сегментированных таблиц — основной и предназначен для больших данных; в виде глобальных таблиц — дополнительный, предназначен для небольших словарей. Сегментированная таблица содержит разные части данных в каждом сегменте, тогда как глобальная таблица содержит одни и те же данные во всех сегментах. Эффективное выполнение запроса в кластере Shardman требует правильного распределения данных по сегментам кластера и, прежде всего, правильного выбора ключа сегментирования.

При переходе от обычной схемы базы данных к распределённой имеет смысл начать проектирование с того, как данные будут распределяться в кластере Shardman. Shardman распределяет строки таблиц по сегментам в соответствии с хеш-значением столбца, который будет использоваться для секционирования таблицы. Другими словами, желаемое распределение должно быть равномерным и направленным на равномерное распределение как частей данных по узлам кластера, так и рабочей нагрузки.

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

Для большинства запросов, особенно для использующих соединения, ключ сегментирования должен быть включён в текст запроса. В противном случае Shardman не будет отправлять запросы на выполнение узлам кластера, что приведёт к существенному снижению производительности по сравнению с использованием одного экземпляра.

Кроме того, при выборе ключа сегментирования важно, чтобы он не менялся, поскольку операция повторного сегментирования, то есть смены ключа сегментирования, довольно трудоёмкая и ресурсоёмкая. В настоящее время в Shardman нет способов автоматизации этой процедуры. Если требуется повторное сегментирование, данные во всех сегментированных таблицах следует либо переместить в локальные таблицы, либо в сегментированные таблицы с другим ключом сегментирования. То есть придётся создавать новые сегментированные таблицы с новым ключом сегментирования и переместить данные обратно. Эта операция очень дорогая и ресурсоёмкая и часто её невозможно выполнить без отключения системы во время миграции.

Ещё одна особенность заключается в том, что распределённые транзакции, то есть изменяющие данные в нескольких сегментах кластера в один и тот же момент времени, не могут выполняться без издержек. Таким образом, чем лучше расположены данные и чем лучше выполняются вычисления внутри одного сегмента, тем быстрее выполняются запросы. В общем случае соотношение распределённых и нераспределённых транзакций в системе должно быть сильно смещено в пользу последних. Распределённые транзакции следует применять только при хорошо обоснованной необходимости.

И, наконец, Shardman — это распределённая система, имеющая как преимущества, так и недостатки, присущие таким системам. Shardman в первую очередь предназначена для OLTP-нагрузки. Простые OLAP-запросы к Shardman также возможны (подробнее см. limitations). Если нужно использовать OLAP-функциональность в OLTP-системе, имейте в виду, что список аналитических и агрегатных SQL-функций для отправки и исполнения в других сегментах, сильно ограничен.

Также, следует внимательно относится к приведению типов данных в запросах, так как наличие функции преобразования типов может привести к тому, что условие будет невозможно протолкнуть на удалённый сервер.

Учитывая вышеизложенные особенности и ограничения РСУБД, приведём два простых примера перехода от обычной к распределённой схеме базы данных.

3.1. Миграция схемы базы данных

В качестве примера для разработки воспользуемся демонстрационной базой данных «Авиакомпании». Подробное описание схемы базы данных доступно по ссылке https://postgrespro.ru/education/demodb. Эта демонстрационная схема используется в образовательных программах Postgres Professional, например в курсе «QPT. Оптимизация запросов».

Авторы схемы охарактеризовали её так: «Схема демонстрационной базы данных достаточно проста, чтобы быть понятной каждому, и в то же время достаточно сложна, чтобы строить нетривиальные запросы.»

Схема базы данных содержит несколько таблиц с осмысленным содержимым. Для примера возьмём версию демонстрационной БД от 13.10.2016. Ссылки для загрузки дампов базы данных и схемы (на русском языке) находятся на странице https://postgrespro.ru/education/courses/QPT. Примеры запросов, помимо приведённых ниже, можно взять из вышеупомянутого курса и книги «Postgres. Первое знакомство».

В этом разделе показаны два примера модификации схемы и адаптации запроса:

Наивный подход прост, требует минимальных преобразований схемы и призван внести ясность в работу запросов в распределённой схеме.

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

3.1.1. Исходная схема базы данных

Рисунок 3.1. Исходная схема базы данных

Авторы описывают базу данных «Airlines» следующим образом:

Основной сущностью является бронирование (bookings).

В одно бронирование можно включить несколько пассажиров, каждому из которых выписывается отдельный билет (tickets). Билет имеет уникальный номер и содержит информацию о пассажире. Как таковой пассажир не является отдельной сущностью. Как имя, так и номер документа пассажира могут меняться с течением времени, так что невозможно однозначно найти все билеты одного человека; для простоты можно считать, что все пассажиры уникальны.

Билет включает один или несколько перелетов (ticket_flights). Несколько перелетов могут включаться в билет в случаях, когда нет прямого рейса, соединяющего пункты отправления и назначения (полет с пересадками), либо когда билет взят «туда и обратно». В схеме данных нет жёсткого ограничения, но предполагается, что все билеты в одном бронировании имеют одинаковый набор перелетов.

Каждый рейс (flights) следует из одного аэропорта (airports) в другой. Рейсы с одним номером имеют одинаковые пункты вылета и назначения, но будут отличаться датой отправления.

При регистрации на рейс пассажиру выдаётся посадочный талон (boarding_passes), в котором указано место в самолете. Пассажир может зарегистрироваться только на тот рейс, который есть у него в билете. Комбинация рейса и места в самолете должна быть уникальной, чтобы не допустить выдачу двух посадочных талонов на одно место.

Количество мест (seats) в самолете и их распределение по классам обслуживания зависит от модели самолета (aircrafts), выполняющего рейс. Предполагается, что каждая модель самолета имеет только одну компоновку салона. Схема данных не контролирует, что места в посадочных талонах соответствуют имеющимся в самолете (такая проверка может быть сделана с использованием табличных триггеров или в приложении).

Давайте посмотрим на общие сущности и размеры таблиц в приведённой выше схеме. Можно заметить, что таблицы ticket_flights, boarding_passes и tickets связаны полем ticket_no. Кроме того, объём данных в этих таблицах составляет 95% от общего объёма БД.

Посмотрите на таблицу bookings. Хотя кажется, что у неё довольно компактная структура, со временем эта таблица может значительно вырасти.

Примеры миграции приведены для кластера Shardman, содержащего четыре сегмента. Сегментированные таблицы разделены на четыре части, так что одна часть сегментированной таблицы находится только в одном сегменте. Это сделано специально, чтобы планы запросов отображались более наглядно. В реальной жизни количество секций должно выбираться исходя из максимального количества узлов кластера.

При миграции реальной схемы БД следует заранее подумать о количестве секций, на которые могут быть разделены данные в распределённых таблицах. Также следует помнить, что лучший подход к миграции — использование таких SQL-преобразований, которые накладывают минимальные ограничения на объекты базы данных.

3.1.2. Конфигурация кластера Shardman

Кластер Shardman состоит из четырёх узлов — node1, node2, node3 и node4. Каждый узел кластера представляет собой отдельный сегмент.

В примерах предполагается, что таблицы разделены на четыре секции по ключу сегментирования (num_parts = 4) и распределены по узлам кластера. Каждая часть таблицы с данными расположена в соответствующем сегменте:

shard-1 находится на узле кластера node1

shard-2 находится на узле кластера node2

shard-3 находится на узле кластера node3

shard-4 находится на узле кластера node4

Кластер намеренно представлен в упрощённой конфигурации. У узлов кластера нет реплик, а конфигурация не является отказоустойчивой.

3.1.3. Выбор ключа сегментирования

3.1.3.1. Наивный [1] подход — ключ сегментирования ticket_no

При таком подходе выбор ключа сегментирования довольно очевиден. Это номер билета ticket_no. Номер билета является первичным ключом таблицы tickets и внешним ключом таблиц ticket_flights и boarding_passes.

Первичный ключ таблиц ticket_flights и boarding_passes является составным. Это уникальный индекс, состоящий из ticket_no и flight_id.

Следовательно, если выбрать в качестве ключа сегментирования ticket_no, то данные трёх таблиц распределятся по сегментам кластера, причём секции, содержащие связанные между собой данные, будут расположены в одних и тех же сегментах.

Остальные таблицы — airports, flights, aircrafts и seats достаточно малы и редко изменяются. Эти свойства позволяют сделать их глобальными таблицами, или таблицами-справочниками.

Рисунок 3.2. Схема наивного подхода

Основное преимущество данного подхода, с точки зрения создания схемы и запросов к БД — практически полное отсутствие каких-либо изменений, кроме тех, которые присущи при работе с распределённой системой, то есть явных указаний при создании таблиц, последовательностей и т. д. сделать их распределёнными.

После выбора ключа сегментирования, можно перейти к созданию распределённой схемы.

[1]

3.1.3.1.1. Создание схемы, распределённой по ticket_no

Сначала включите трансляцию DDL-операторов во все сегменты кластера:

SET shardman.broadcast_ddl TO on;

Создайте схему bookings для всех сегментов:

CREATE SCHEMA bookings;

Поскольку таблицы в схеме связаны друг с другом внешним ключом, важен порядок создания таблиц и вспомогательных объектов в схеме.

база данных содержит «снимки» данных — аналогично резервной копии реальной системы, сделанной в определённый момент времени. Например, статус рейса Departed означает, что воздушное судно уже вылетело и находилось в воздухе на момент создания резервной копии. Время «снимка» сохраняется в функции bookings.now(). Этой функцией можно пользоваться в демонстрационных запросах там, где в обычной жизни использовалась бы функция now(). Кроме того, значение, возвращаемое этой функцией, определяет версию демонстрационной базы данных. Последняя доступная версия — от 13.10.2016:

SELECT bookings.now() as now;
          now
-----------------------
2016-10-13 17:00:00+03

Относительно именно этого момента времени все рейсы делятся на прошедшие и будущие.

Давайте создадим вспомогательную функцию bookings.now():

    CREATE FUNCTION bookings.now() RETURNS timestamp with time zone
    LANGUAGE sql IMMUTABLE COST 0.00999999978
    AS
    $sql$
    SELECT $qq$2016-10-13 17:00:00$qq$::TIMESTAMP AT TIME ZONE
$zz$Europe/Moscow$zz$;
    $sql$;

Кроме самих таблиц нам потребуется глобальная последовательность для генерирования идентификаторов (ID) при вставке данных в таблицу flights. В данном примере последовательность создаётся явно и далее связывается со столбцом этой таблицы, задавая значения, генерируемые последовательностью по умолчанию.

Создайте последовательность, используя следующий DDL-оператор:

CREATE SEQUENCE bookings.flights_flight_id_seq
    INCREMENT BY 1
    NO MINVALUE
    NO MAXVALUE
    CACHE 1 with(global);

Выражение with(global) создаёт единую распределённую последовательность, доступную на всех узлах кластера, которая выдаёт значения из определённого диапазона в каждом сегменте кластера, при этом диапазоны разных сегментов не пересекаются. За более подробным описанием работы глобальных последовательностей обратитесь к Разделу 7.6 и Разделу 6.5.

На практике глобальные последовательности в каждом сегменте являются регулярные последовательности, которым выделяются последовательные блоки (по умолчанию — 65536 номеров). Когда все номера в блоке будут выделены, следующий блок выделяется локальной последовательности в сегменте. То есть числа из глобальных последовательностей уникальны, но строгой монотонности нет, и в значениях, заданных генератором последовательностей, могут быть «дыры» [2].

Последовательности могут иметь тип bigserial, smallserial или serial и применяться как для сегментированных, так и для глобальных таблиц.

Не следует создавать локальные последовательности в каждом сегменте, поскольку их значения могут дублироваться.

[2]

Далее следует создать глобальные таблицы. Как уже говорилось выше, эти таблицы небольшого размера, данные в них изменяются редко, логично воспринимать их как таблицы-справочники, которые должны содержать одинаковые данные во всех сегментах кластера. Обязательное требование при создании глобальных таблиц — наличие первичного ключа.

Создайте глобальные таблицы, используя следующие DDL-операторы:

CREATE TABLE bookings.aircrafts (
    aircraft_code character(3) NOT NULL primary key,
    model text NOT NULL,
    range integer NOT NULL,
    CONSTRAINT aircrafts_range_check CHECK ((range > 0))
) with (global);

CREATE TABLE bookings.seats (
    aircraft_code character(3) references bookings.aircrafts(aircraft_code),
    seat_no character varying(4) NOT NULL,
    fare_conditions character varying(10) NOT NULL,
    CONSTRAINT seats_fare_conditions_check CHECK (((fare_conditions)::text = ANY (ARRAY[('Economy'::character varying)::text, ('Comfort'::character varying)::text, ('Business'::character varying)::text]))),
    PRIMARY KEY (aircraft_code, seat_no)
) with (global);

CREATE TABLE bookings.airports (
    airport_code character(3) NOT NULL primary key,
    airport_name text NOT NULL,
    city text NOT NULL,
    longitude double precision NOT NULL,
    latitude double precision NOT NULL,
    timezone text NOT NULL
)  with (global);

CREATE TABLE bookings.bookings (
    book_ref character(6) NOT NULL,
    book_date timestamp with time zone NOT NULL,
    total_amount numeric(10,2) NOT NULL,
    PRIMARY KEY (book_ref)
) with (global);

CREATE TABLE bookings.flights (
    flight_id bigint NOT NULL PRIMARY KEY,-- <= a sequence will be assigned
    flight_no character(6) NOT NULL,
    scheduled_departure timestamp with time zone NOT NULL,
    scheduled_arrival timestamp with time zone NOT NULL,
    departure_airport character(3) REFERENCES bookings.airports(airport_code),
    arrival_airport character(3) REFERENCES bookings.airports(airport_code),
    status character varying(20) NOT NULL,
    aircraft_code character(3) references bookings.aircrafts(aircraft_code),
    actual_departure timestamp with time zone,
    actual_arrival timestamp with time zone,
    CONSTRAINT flights_check CHECK ((scheduled_arrival > scheduled_departure)),
    CONSTRAINT flights_check1 CHECK (((actual_arrival IS NULL) OR ((actual_departure IS NOT NULL) AND (actual_arrival IS NOT NULL) AND (actual_arrival > actual_departure)))),
    CONSTRAINT flights_status_check CHECK (((status)::text = ANY (ARRAY[('On Time'::character varying)::text, ('Delayed'::character varying)::text, ('Departed'::character varying)::text, ('Arrived'::character varying)::text, ('Scheduled'::character varying)::text, ('Cancelled'::character varying)::text])))
) with (global);

-- свяжите последовательность со столбцом таблицы
ALTER SEQUENCE bookings.flights_flight_id_seq OWNED BY bookings.flights.flight_id;

-- задайте значение для столбца по умолчанию
ALTER TABLE bookings.flights ALTER COLUMN flight_id SET DEFAULT nextval('bookings.flights_flight_id_seq');

ALTER TABLE bookings.flights ADD CONSTRAINT flights_flight_no_scheduled_departure_key UNIQUE (flight_no, scheduled_departure);

Далее создайте сегментированные таблицы tickets, ticket_flights и boarding_passes в схеме bookings:

CREATE TABLE bookings.tickets (
    ticket_no character(13) PRIMARY KEY,
    book_ref character(6) REFERENCES bookings.bookings(book_ref),
    passenger_id character varying(20) NOT NULL,
    passenger_name text NOT NULL,
    contact_data jsonb
) with (distributed_by='ticket_no', num_parts=4);

CREATE TABLE bookings.ticket_flights (
    ticket_no character(13) NOT NULL,
    flight_id bigint references bookings.flights(flight_id),
    fare_conditions character varying(10) NOT NULL,
    amount numeric(10,2) NOT NULL,
    CONSTRAINT ticket_flights_amount_check CHECK ((amount >= (0)::numeric)),
    CONSTRAINT ticket_flights_fare_conditions_check CHECK (((fare_conditions)::text = ANY (ARRAY[('Economy'::character varying)::text, ('Comfort'::character varying)::text, ('Business'::character varying)::text]))),
    PRIMARY KEY (ticket_no, flight_id)
) with (distributed_by='ticket_no', colocate_with='bookings.tickets');

CREATE TABLE bookings.boarding_passes (
    ticket_no character(13) NOT NULL,
    flight_id bigint NOT NULL,
    boarding_no integer NOT NULL,
    seat_no character varying(4) NOT NULL,
    FOREIGN KEY (ticket_no, flight_id) REFERENCES bookings.ticket_flights(ticket_no, flight_id),
    PRIMARY KEY (ticket_no, flight_id)
) with (distributed_by='ticket_no', colocate_with='bookings.tickets');

-- ограничения обязательно должны содержать ключ сегментирования
ALTER TABLE bookings.boarding_passes ADD CONSTRAINT boarding_passes_flight_id_boarding_no_key UNIQUE (ticket_no, flight_id, boarding_no);

ALTER TABLE bookings.boarding_passes ADD CONSTRAINT boarding_passes_flight_id_seat_no_key UNIQUE (ticket_no, flight_id, seat_no);

При создании распределённых таблиц можно дополнительно указать параметр num_parts, который отвечает за количество секций, на которые будут разделены распределённые таблицы. В данном примере он равен 4, в целях сокращения вывода планов запросов. Значение данного параметра по умолчанию — 20. Этот параметр может быть важен, если в будущем планируется добавлять сегменты в кластер и выполнять горизонтальное масштабирование.

На основании будущих нагрузки и объёма данных, значение параметра num_parts должно быть достаточным для выполнения перебалансировки данных при добавлении новых сегментов (num_parts должно быть больше или равно количеству узлов в кластере). С другой стороны, слишком большое количество секций приводит существенному увеличению времени планирования запроса. Поэтому нужно стремиться к разумному балансу между количеством секций и количеством узлов кластера.

Последнее, что осталось сделать – создать представление, которое понадобится при выполнении некоторых запросов:

CREATE VIEW bookings.flights_v AS
 SELECT f.flight_id,
    f.flight_no,
    f.scheduled_departure,
    timezone(dep.timezone, f.scheduled_departure) AS scheduled_departure_local,
    f.scheduled_arrival,
    timezone(arr.timezone, f.scheduled_arrival) AS scheduled_arrival_local,
    (f.scheduled_arrival - f.scheduled_departure) AS scheduled_duration,
    f.departure_airport,
    dep.airport_name AS departure_airport_name,
    dep.city AS departure_city,
    f.arrival_airport,
    arr.airport_name AS arrival_airport_name,
    arr.city AS arrival_city,
    f.status,
    f.aircraft_code,
    f.actual_departure,
    timezone(dep.timezone, f.actual_departure) AS actual_departure_local,
    f.actual_arrival,
    timezone(arr.timezone, f.actual_arrival) AS actual_arrival_local,
    (f.actual_arrival - f.actual_departure) AS actual_duration
   FROM bookings.flights f,
    bookings.airports dep,
    bookings.airports arr
  WHERE ((f.departure_airport = dep.airport_code) AND (f.arrival_airport = arr.airport_code));

Теперь создание распределённой схемы завершено. Отключите трансляцию DDL-операторов:

SET shardman.broadcast_ddl TO off;

3.1.3.2. Комплексный подход — ключ сегментирования book_ref

Более комплексный подход к выбору ключа сегментирования данных состоит из модификации исходной схемы данных, внедрения дополнительных параметров в запросы и прочих достаточно важных изменений.

Допустим, авиакомпания работает на рынке более 10 лет, и таблица bookings в этом случае вырастет в объёме до такого размера, что сделать её глобальной не представляется возможным. Но и распределить данные этой таблицы нельзя, так как она не содержит общих полей с другими таблицами, по которым её можно распределить (как в варианте 1).

При изменении исходной схемы в качестве ключа сегментирования можно использовать другое поле.

Если посмотреть на таблицу bookings, можно заметить, что поле book_ref — уникальное и является первичным ключом для данной таблицы, а также служит внешним ключом к таблице tickets. Поэтому это поле кажется подходящим для выбора в качестве ключа сегментирования. Однако поле book_ref отсутствует в таблицах ticket_flights и boarding_passes.

Если добавить поле book_ref в таблицы ticket_flights и boarding_passes, то станет возможным распределение всех таблиц: bookings, tickets, ticket_flights и boarding_passes по ключу сегментирования book_ref.

Операцию по добавлению ключа book_ref в таблицы ticket_flights и boarding_passes следует производить в исходной схеме, при этом, поле book_ref должно быть заполнено данными из таблицы bookings.

Рисунок 3.3. Изменение исходной схемы

3.1.3.2.1. Изменение исходной схемы

Для корректной передачи данных из исходной схемы в распределённую, исходную схему необходимо изменить следующим образом:

Добавьте поле book_ref в таблицы ticket_flights и boarding_passes:

ALTER TABLE ticket_flights
   ADD COLUMN book_ref char(6);

ALTER TABLE boarding_passes
   ADD COLUMN book_ref char(6);

В этих таблицах заполните добавленное поле book_ref данными:

WITH batch AS (SELECT book_ref,
                       ticket_no
                 FROM tickets)
UPDATE ticket_flights
   SET book_ref = batch.book_ref
  FROM batch
 WHERE ticket_flights.ticket_no = batch.ticket_no
   AND ticket_flights.book_ref IS NULL;

WITH batch AS (SELECT book_ref,
                      ticket_no
                 FROM tickets)
UPDATE boarding_passes
   SET book_ref = batch.book_ref
  FROM batch
 WHERE boarding_passes.ticket_no = batch.ticket_no
   AND boarding_passes.book_ref IS NULL;

Данный пример не стоит применять в нагруженной производственной системе, так как этот подход блокирует таблицы целиком, то есть все их строки. Для производственного применения данные следует переносить постепенно, по частям.

Теперь схема БД готова к переносу.

3.1.3.2.2. Создание схемы, распределённой по ключу book_ref

Здесь используется функция Shardman shardman.broadcast_all_sql() для трансляции DDL-операторов на все узлы кластера. Создайте схему bookings для всех сегментов:

SELECT shardman.broadcast_all_sql('CREATE SCHEMA bookings');

Поскольку таблицы в схеме связаны друг с другом внешним ключом, важен порядок создания таблиц.

Сначала создайте вспомогательную функцию bookings.now():

SELECT shardman.broadcast_all_sql(
    $sql$
    CREATE FUNCTION bookings.now() RETURNS timestamp with time zone
    LANGUAGE sql IMMUTABLE COST 0.00999999978
    AS
    $q$
    SELECT $qq$2016-10-13 17:00:00$qq$::TIMESTAMP
                    AT TIME ZONE $zz$Europe/Moscow$zz$;
    $q$;
    $sql$
);

Таблицы, пользователи и последовательности создаются с помощью обычных SQL-функций. Эта функция для этого не нужна.

В данном примере глобальная последовательность не создаётся явно, так как Shardman при указании типа поля bigserial создаёт глобальную последовательность автоматически.

Теперь создайте глобальные таблицы, используя следующие DDL-операторы:

CREATE TABLE bookings.aircrafts (
    aircraft_code character(3) NOT NULL PRIMARY KEY,
    model text NOT NULL,
    range integer NOT NULL,
    CONSTRAINT aircrafts_range_check CHECK ((range > 0))
) WITH (global);

CREATE TABLE bookings.seats (
    aircraft_code character(3) REFERENCES bookings.aircrafts(aircraft_code),
    seat_no character varying(4) NOT NULL,
    fare_conditions character varying(10) NOT NULL,
    CONSTRAINT seats_fare_conditions_check CHECK ((
          (fare_conditions)::text = ANY (ARRAY[
             ('Economy'::character varying)::text,
             ('Comfort'::character varying)::text,
             ('Business'::character varying)::text])
           )),
    PRIMARY KEY (aircraft_code, seat_no)
) WITH (global);

CREATE TABLE bookings.airports (
    airport_code character(3) NOT NULL PRIMARY KEY,
    airport_name text NOT NULL,
    city text NOT NULL,
    longitude double precision NOT NULL,
    latitude double precision NOT NULL,
    timezone text NOT NULL
)  WITH (global);

CREATE TABLE bookings.flights (
-- the global sequence will be created automatically
-- the default value will be assigned
    flight_id bigserial NOT NULL PRIMARY KEY,
    flight_no character(6) NOT NULL,
    scheduled_departure timestamp with time zone NOT NULL,
    scheduled_arrival timestamp with time zone NOT NULL,
    departure_airport character(3) REFERENCES bookings.airports(airport_code),
    arrival_airport character(3) REFERENCES bookings.airports(airport_code),
    status character varying(20) NOT NULL,
    aircraft_code character(3) REFERENCES bookings.aircrafts(aircraft_code),
    actual_departure timestamp with time zone,
    actual_arrival timestamp with time zone,
    CONSTRAINT flights_check CHECK ((scheduled_arrival > scheduled_departure)),
    CONSTRAINT flights_check1 CHECK ((
                  (actual_arrival IS NULL)
               OR ((actual_departure IS NOT NULL)
              AND (actual_arrival IS NOT NULL)
              AND (actual_arrival > actual_departure)))),
    CONSTRAINT flights_status_check CHECK (
           ((status)::text = ANY (
      ARRAY[('On Time'::character varying)::text,
            ('Delayed'::character varying)::text,
            ('Departed'::character varying)::text,
            ('Arrived'::character varying)::text,
            ('Scheduled'::character varying)::text,
            ('Cancelled'::character varying)::text])))
) WITH (global);

ALTER TABLE bookings.flights
   ADD CONSTRAINT flights_flight_no_scheduled_departure_key
   UNIQUE (flight_no, scheduled_departure);

Теперь создайте сегментированные таблицы bookings, tickets, ticket_flights и boarding_passes в схеме bookings, как в предыдущем примере:

-- в данных таблицах не предполагается изменений, кроме их распределения
CREATE TABLE bookings.bookings (
   book_ref character(6) NOT NULL PRIMARY KEY,
   book_date timestamp with time zone NOT NULL,
   total_amount numeric(10,2) NOT NULL
) WITH (distributed_by='book_ref', num_parts=4);

CREATE TABLE bookings.tickets (
   ticket_no character(13) NOT NULL,
   book_ref character(6) REFERENCES bookings.bookings(book_ref),
   passenger_id character varying(20) NOT NULL,
   passenger_name text NOT NULL,
   contact_data jsonb,
   PRIMARY KEY (book_ref, ticket_no)
) WITH (distributed_by='book_ref', colocate_with='bookings.bookings');

-- в данных таблицах добавляется дополнительный внешний ключ book_ref
CREATE TABLE bookings.ticket_flights (
   ticket_no character(13) NOT NULL,
   flight_id bigint NOT NULL,
   fare_conditions character varying(10) NOT NULL,
   amount numeric(10,2) NOT NULL,
   book_ref character(6) NOT NULL, -- <= added book_ref
   CONSTRAINT ticket_flights_amount_check
        CHECK ((amount >= (0)::numeric)),
   CONSTRAINT ticket_flights_fare_conditions_check
        CHECK (((fare_conditions)::text = ANY (
        ARRAY[('Economy'::character varying)::text,
              ('Comfort'::character varying)::text,
              ('Business'::character varying)::text]))),
   FOREIGN KEY (book_ref, ticket_no)
        REFERENCES bookings.tickets(book_ref, ticket_no),
   PRIMARY KEY (book_ref, ticket_no, flight_id) -- <= changed the primary key
) with (distributed_by='book_ref', colocate_with='bookings.bookings');

CREATE TABLE bookings.boarding_passes (
    ticket_no character(13) NOT NULL,
    flight_id bigint NOT NULL,
    boarding_no integer NOT NULL,
    seat_no character varying(4) NOT NULL,
    FOREIGN KEY (book_ref, ticket_no, flight_id)
         REFERENCES bookings.ticket_flights(book_ref, ticket_no, flight_id),
    PRIMARY KEY (book_ref, ticket_no, flight_id)
) WITH (distributed_by='book_ref', colocate_with='bookings.bookings');

CREATE TABLE bookings.boarding_passes (
  ticket_no character(13) NOT NULL,
  flight_id bigint NOT NULL,
  boarding_no integer NOT NULL,
  seat_no character varying(4) NOT NULL,
  book_ref character(6) NOT NULL, – <= added book_ref
FOREIGN KEY (book_ref, ticket_no, flight_id)
REFERENCES bookings.ticket_flights(book_ref, ticket_no, flight_id),
PRIMARY KEY (book_ref, ticket_no, flight_id)
) WITH (distributed_by='book_ref', colocate_with='bookings.bookings');

-- ограничения должны обязательно содержать ключ сегментирования
ALTER TABLE bookings.boarding_passes
  ADD CONSTRAINT boarding_passes_flight_id_boarding_no_key
  UNIQUE (book_ref, ticket_no, flight_id, boarding_no);

ALTER TABLE bookings.boarding_passes
  ADD CONSTRAINT boarding_passes_flight_id_seat_no_key
  UNIQUE (book_ref, ticket_no, flight_id, seat_no);

Создайте представление bookings.flights:

SELECT shardman.broadcast_all_sql($$
CREATE VIEW bookings.flights_v AS
SELECT f.flight_id,
      f.flight_no,
      f.scheduled_departure,
      timezone(dep.timezone, f.scheduled_departure) AS scheduled_departure_local,
      f.scheduled_arrival,
      timezone(arr.timezone, f.scheduled_arrival)   AS scheduled_arrival_local,
      (f.scheduled_arrival - f.scheduled_departure) AS scheduled_duration,
      f.departure_airport,
      dep.airport_name                              AS departure_airport_name,
      dep.city                                      AS departure_city,
      f.arrival_airport,
      arr.airport_name                              AS arrival_airport_name,
      arr.city                                      AS arrival_city,
      f.status,
      f.aircraft_code,
      f.actual_departure,
      timezone(dep.timezone, f.actual_departure)    AS actual_departure_local,
      f.actual_arrival,
      timezone(arr.timezone, f.actual_arrival)      AS actual_arrival_local,
      (f.actual_arrival - f.actual_departure)       AS actual_duration
FROM bookings.flights f,
    bookings.airports dep,
    bookings.airports arr
WHERE ((f.departure_airport = dep.airport_code) AND (f.arrival_airport = arr.airport_code));
$$);

Теперь создание схемы завершено. Следующая тема — миграция данных.

[1] В контексте компьютерных наук выражение «naïve approach» (дословно – наивный метод, наивный подход) очень похоже на «метод решения в лоб» и означает первую базовую идею, приходящую в голову при столкновении с проблемой, которая часто не учитывает сложности, крайние случаи или полный объём требований. С одной стороны, это грубый и прямой метод, направленный на получение работоспособного решения, с другой — такие решения легко понять и реализовать, но при этом системные ресурсы могут использоваться неэффективно.

[2] Возможно выделение значений из разных диапазонов, то есть значение может скакать. Например, в первом сегменте можно получить значение 5, во втором — 140003, в третьем — 70003 и т. д.

3.2. Миграция данных

При миграции данных важен порядок полей в исходной и целевой схеме. Порядок полей и их тип в таблицах нераспределённой и распределённой БД должен быть одинаковым.

Утилита миграции делает ровно то, что необходимо пользователю, никакими действиями не вторгаясь в процессы миграции данных, кроме, возможно, распределения данных при миграции сразу в тот сегмент, где они должны храниться.

Shardman предоставляет удобные инструменты для миграции данных. При уже созданной схеме и выбранном ключе сегментирования остаётся определить правила миграции данных. Источником данных могут быть, как файлы экспорта данных в формате CSV, так и одиночный сервер СУБД.

Далеко не всегда удобно использовать CSV-файлы, так как они могут значительно увеличиваться в объёме и требовать дополнительных ресурсов для хранения и передачи.

Гораздо удобнее использовать прямую миграцию данных из БД в БД без этапа промежуточного хранения.

При миграции данных следует учитывать порядок загрузки данных. Таблицы могут быть связаны друг с другом внешним ключом, поэтому сначала нужно загружать данные таблиц, на которые будут ссылаться другие таблицы. Для этого в файле миграции следует задать приоритет, определяющий порядок загрузки данных из таблиц. Чем больше значение параметра priority, тем выше приоритет. Например, если заданы приоритеты 1, 2 и 3, то сначала будут загружены данные из таблиц с приоритетом 3, потом с приоритетом 2, последними — с приоритетом 1.

Команда shardmanctl load позволяет определить порядок миграции таблиц, который можно указать в конфигурационном файле в формате YML.

3.2.1. Наивный подход

Ниже представлен пример содержимого файла migrate.yml:

version: "1.0"
migrate:
 connstr: "dbname=demo host=single-pg-instance port=5432 user=postgres password=******"
 jobs: 8
 batch: 2000
 options:
 schemas:
   - name: bookings
     # параметр all со значением false отключает автоматическое создание таблиц
     # таблицы уже созданы ранее, на этапе миграции схемы
     all: false
     tables:
       - name: airports
         # определяем глобальную таблицу
         type: global
         # так как таблицы связаны, нужно задать порядок миграции данных,
          # выставляем наивысший приоритет таблицам, данные которых
         # должны быть скопированы в первую очередь
         priority: 3
       - name: aircrafts
         type: global
         priority: 3
       - name: seats
         type: global
         priority: 3
       - name: bookings
         type: global
         priority: 3
       - name: flights
         type: global
         priority: 3
       - name: tickets
         type: sharded
         # определяем сегментированную таблицу
         # указываем ключ распределения
         distributedby: ticket_no
         partitions: 4
         priority: 2
       - name: ticket_flights
         type: sharded
         distributedby: ticket_no
         # определяем сегментированную и совместно размещённую таблицу
         # указываем имя таблицы с которой будет совместно размещена таблица tickets_flights
         colocatewith: tickets
         partitions: 4
         priority: 2
       - name: boarding_passes
         type: sharded
         distributedby: ticket_no
         colocatewith: tickets
         partitions: 4
         priority: 1

В данном файле определён источник данных — узел с именем single-pg-instance, его порт для подключения, имя пользователя и пароль, а также имя БД источника данных. Определены также и некоторые параметры работы утилиты (их может быть довольно много, как показано Подразделе «Загрузка данных из схемы PostgreSQL»). В файле также задано количество потоков — 8, то есть размер порции обрабатываемых данных в строках при миграции, а также приоритеты для последовательной обработки таблиц. Сначала мигрируют данные в глобальные таблицы, следом данные в распределённые таблицы tickets и ticket_flights, затем данные в таблицу boarding_passes. Значение priority задаёт приоритет загрузки данных, чем больше значение ключа, тем раньше будут загружены данные соответствующих таблиц. Миграция выполняется с помощью следующей команды:

shardmanctl load --schema migrate.yml

Если в конце работы утилиты выводится сообщение: «data loading completed successfully» (загрузка данных успешно завершена), то миграция данных прошла успешно.

3.2.2. Комплексный подход

При данном подходе, запуск и работа утилиты shardmanctl в режиме load не будет отличаться от работы при наивном подходе. Однако, немного изменится файл, определяющий порядок загрузки таблиц, так как изменился ключ сегментирования:

 ---
version: "1.0"
migrate:
 connstr: "dbname=demo host=single-pg-instance port=5432 user=postgres password=postgres"
 jobs: 8
 batch: 2000
 options:
 schemas:
   - name: bookings
     all: false
     tables:
       - name: airports
         type: global
         priority: 5
       - name: aircrafts
         type: global
         priority: 5
       - name: seats
         type: global
         priority: 5
       - name: flights
         type: global
         priority: 5
       - name: bookings
         type: sharded
         priority: 4
         partitions: 4
         distributedby: book_ref
       - name: tickets
         type: sharded
         distributedby: book_ref
         colocatewith: bookings
         partitions: 4
         priority: 3
       - name: ticket_flights
         type: sharded
         distributedby: book_ref
         colocatewith: bookings
         partitions: 4
         priority: 2
       - name: boarding_passes
         type: sharded
         distributedby: book_ref
         colocatewith: bookings
         partitions: 4
         priority: 1

3.3. Запросы

Когда все операции миграции были выполнены успешно, можно проверить, как выполняются запросы в распределённой схеме.

3.3.1. Запрос q1

Запрос q1 довольно прост, он возвращает бронирование с указанным номером:

SELECT *
  FROM bookings.bookings b
WHERE b.book_ref = '0824C5';

Для обычной СУБД PostgreSQL и ключа сегментирования ticket_no этот запрос выполняется сравнительно быстро. Скорость запроса для ключа сегментирования book_ref зависит от сегмента, в котором он выполняется. Если он выполняется в сегменте, где физически нет данных, Shardman отправляет запрос в другой сегмент, что вызывает задержку по времени из-за сетевого взаимодействия.

3.3.2. Запрос q2

В результате запроса q2 возвращаются все билеты из указанного бронирования:

SELECT t.*
FROM bookings.bookings b
JOIN bookings.tickets t
  ON t.book_ref = b.book_ref
WHERE b.book_ref = '0824C5';

С помощью ключа сегментирования book_ref запрос передаётся в сегменты, и глобальная таблица объединяется с секциями сегментированной таблицы:

Foreign Scan (actual rows=2 loops=1)
  Relations: (bookings_2_fdw b) INNER JOIN (tickets_2_fdw t)
  Network: FDW bytes sent=433 received=237

Посмотрите на план запроса для ключа сегментирования ticket_no:

Append (actual rows=2 loops=1)
  Network: FDW bytes sent=1263 received=205
  ->  Nested Loop (actual rows=1 loops=1)
        ->  Seq Scan on tickets_0 t_1 (actual rows=1 loops=1)
              Filter: (book_ref = '0824C5'::bpchar)
              Rows Removed by Filter: 207092
        ->  Index Only Scan using bookings_pkey on bookings b (actual rows=1 loops=1)
              Index Cond: (book_ref = '0824C5'::bpchar)
              Heap Fetches: 0
  ->  Async Foreign Scan (actual rows=1 loops=1)
        Relations: (tickets_1_fdw t_2) INNER JOIN (bookings b)
        Network: FDW bytes sent=421 received=205
  ->  Async Foreign Scan (actual rows=0 loops=1)
        Relations: (tickets_2_fdw t_3) INNER JOIN (bookings b)
        Network: FDW bytes sent=421
  ->  Async Foreign Scan (actual rows=0 loops=1)
        Relations: (tickets_3_fdw t_4) INNER JOIN (bookings b)
        Network: FDW bytes sent=421

План содержит узлы Async Foreign Scan, что означает сетевой обмен данными между узлом-источником запроса и сегментами, то есть данные получаются из сегментов и окончательная обработка выполняется на узле-источнике запроса.

Посмотрите на строку Network. Хорошим критерием оптимальности выполнения запросов в сегментах может быть значение received. Чем меньше это значение, тем лучше сегменты справляются с выполнением распределённых запросов. Большая часть обработки выполняется удалённо, и на узел-источник запроса возвращается уже готовый для дальнейшей обработки результат.

Вариант с ключом сегментирования book_ref выглядит значительно лучше, так как этот ключ уже присутствует в таблице с номерами билетов.

План запроса, выполняемого на произвольном узле, будет таким:

Foreign Scan (actual rows=2 loops=1)
  Relations: (bookings_2_fdw b) INNER JOIN (tickets_2_fdw t)
  Network: FDW bytes sent=433 received=237

Происходит сетевой обмен только с одним сегментом, в котором выполняется запрос. Это сегмент shard-3 и секция tickets_2 таблицы tickets на четвёртом узле.

Если этот запрос выполняется в сегменте, где физически присутствуют данные, то скорость выполнения будет ещё выше.

Посмотрите на план:

Nested Loop (actual rows=2 loops=1)
    ->  Index Only Scan using bookings_2_pkey on bookings_2
    ->  Bitmap Heap Scan on tickets_2
          ->  Bitmap Index Scan on tickets_2_book_ref_idx

В данном случае нет необходимости в сетевом обмене данными, так как запрашиваемый данные находятся в том же сегменте, в котором выполняется запрос.

В некоторых случаях, выбор сегмента для запуска запроса имеет смысл. Зная как работает функция распределения, можно реализовать данную логику на уровне приложения и на основании ключа сегментирования отправлять некоторые запросы сразу в сегмент, где содержатся требуемые данные.

3.3.3. Запрос q3

В результате запроса q3 находятся все рейсы для одного из билетов в выбранном ранее бронировании:

SELECT tf.*, t.*
FROM bookings.tickets t
JOIN bookings.ticket_flights tf
  ON tf.ticket_no = t.ticket_no
WHERE t.ticket_no = '0005435126781';

Чтобы выбрать конкретный фрагмент для выполнения запроса, как описано в Подраздел 3.3.2 обратите внимание, что при использовании ключа сегментирования ticket_no выполнение запроса будет более оптимальным в сегменте, содержащем секцию с данными. Планировщик знает, что сегмент содержит все данные, необходимые для объединения таблиц, поэтому никакого сетевого взаимодействия между сегментами не происходит.

Для ключа сегментирования book_ref обратите внимание, что по номеру бронирования можно вычислить номер билета и запросить его сразу с «правильного» сегмента.

В таком случае запрос выглядит следующим образом:

SELECT tf.*, t.*
FROM bookings.tickets t
JOIN bookings.ticket_flights tf
  ON tf.ticket_no = t.ticket_no
  AND t.book_ref = tf.book_ref
WHERE t.ticket_no = '0005435126781'
AND tf.book_ref = '0824C5';

Запрос выполняется медленнее в сегменте, не содержащем секцию с искомыми данными:

Foreign Scan (actual rows=6 loops=1)
  Relations: (tickets_1_fdw t) INNER JOIN (ticket_flights_1_fdw tf)
  Network: FDW bytes sent=434 received=369

Сетевая связь между сегментами присутствует в плане, так как он содержит узел Foreign Scan.

Важность указания в запросе ключа сегментирования, в случае с book_ref, можно проиллюстрировать таким запросом:

SELECT tf.*, t.*
FROM bookings.tickets t
JOIN bookings.ticket_flights tf
  ON tf.ticket_no = t.ticket_no
WHERE t.ticket_no = '0005435126781'
AND tf.book_ref = '0824C5';

Здесь ключ сегментирования намеренно не указан в join. Взглянем на план:

Nested Loop (actual rows=6 loops=1)
  Network: FDW bytes sent=1419 received=600
  ->  Foreign Scan on ticket_flights_2_fdw tf (actual rows=6 loops=1)
        Network: FDW bytes sent=381 received=395
  ->  Append (actual rows=1 loops=6)
        Network: FDW bytes sent=1038 received=205
        ->  Seq Scan on tickets_0 t_1 (actual rows=0 loops=6)
              Filter: (ticket_no = '0005435126781'::bpchar)
              Rows Removed by Filter: 207273
        ->  Async Foreign Scan on tickets_1_fdw t_2 (actual rows=0 loops=6)
              Network: FDW bytes sent=346 received=205
        ->  Async Foreign Scan on tickets_2_fdw t_3 (actual rows=1 loops=6)
              Network: FDW bytes sent=346
        ->  Async Foreign Scan on tickets_3_fdw t_4 (actual rows=0 loops=6)
              Network: FDW bytes sent=346

В отличие от предыдущих примеров заметны отклонения. Здесь запрос выполнялся на всех узлах, причём индекс при этом не использовался, поэтому для того, чтобы вернуть всего 6 строк, Shardman был вынужден просканировать последовательно секции таблицы tickets целиком, вернуть результат источнику запроса, после чего выполнить соединение (join) с таблицей ticket_flights. Наличие узлов Async Foreign Scan говорит о том, что в сегментах выполняется последовательное сканирование таблицы tickets.

3.3.4. Запрос q4

В результате данного запроса возвращаются все перелёты по всем билетам указанным в бронировании. Есть несколько вариантов, как его выполнить: включить в условии WHERE подзапрос с указанием номера бронирования, перечислить явно в конструкции IN номера билетов или использовать конструкцию WHERE... OR. Ниже показано, как будут работать все перечисленные варианты.

SELECT tf.*, t.*
FROM bookings.tickets t
JOIN bookings.ticket_flights tf
  ON tf.ticket_no = t.ticket_no
WHERE t.ticket_no IN (
   SELECT t.ticket_no
     FROM bookings.bookings b
     JOIN bookings.tickets  t
       ON t.book_ref = b.book_ref
    WHERE b.book_ref = '0824C5'
);

Данный пример — попытка выполнить запрос из нераспределённой БД. Но он выполняется одинаково плохо для обоих вариантов ключей сегментирования.

План запроса будет примерно таким:

Hash Join (actual rows=12 loops=1)
  Hash Cond: (tf.ticket_no = t.ticket_no)
  ->  Append (actual rows=2360335 loops=1)
        ->  Async Foreign Scan on ticket_flights_0_fdw tf_1 (actual rows=589983 loops=1)
        ->  Async Foreign Scan on ticket_flights_1_fdw tf_2 (actual rows=590175 loops=1)
        ->  Seq Scan on ticket_flights_2 tf_3 (actual rows=590174 loops=1)
        ->  Async Foreign Scan on ticket_flights_3_fdw tf_4 (actual rows=590003 loops=1)
  ->  Hash (actual rows=2 loops=1)
        Buckets: 1024  Batches: 1  Memory Usage: 9kB
        ->  Hash Semi Join (actual rows=2 loops=1)
              Hash Cond: (t.ticket_no = t_5.ticket_no)
              ->  Append (actual rows=829071 loops=1)
                    ->  Async Foreign Scan on tickets_0_fdw t_1 (actual rows=207273 loops=1)
                    ->  Async Foreign Scan on tickets_1_fdw t_2 (actual rows=207058 loops=1)
                    ->  Seq Scan on tickets_2 t_3 (actual rows=207431 loops=1)
                    ->  Async Foreign Scan on tickets_3_fdw t_4 (actual rows=207309 loops=1)
              ->  Hash (actual rows=2 loops=1)
                    Buckets: 1024  Batches: 1  Memory Usage: 9kB
                    ->  Nested Loop (actual rows=2 loops=1)
                          ->  Index Only Scan using tickets_2_pkey on tickets_2 t_5
                          ->  Materialize (actual rows=1 loops=2)
                                ->  Index Only Scan using bookings_2_pkey on bookings_2 b

Такой план говорит о том, что Shardman справился с подзапросом в WHERE, и был вынужден запросить все строки таблиц tickets и ticket_flights, после чего выполнить их обработку на узле источнике запроса, что крайне неэффективно. Попробуем другие варианты:

Для запроса с ключом сегментирования ticket_no:

    SELECT tf.*, t.*
    FROM bookings.tickets t
    JOIN bookings.ticket_flights tf
      ON tf.ticket_no = t.ticket_no
    WHERE t.ticket_no IN ('0005435126781','0005435126782');

план будет таким:

    Append (actual rows=12 loops=1)
      Network: FDW bytes sent=1098 received=1656
      ->  Async Foreign Scan (actual rows=6 loops=1)
            Relations: (tickets_0_fdw t_1) INNER JOIN (ticket_flights_0_fdw tf_1)
            Network: FDW bytes sent=549 received=1656
      ->  Async Foreign Scan (actual rows=6 loops=1)
            Relations: (tickets_1_fdw t_2) INNER JOIN (ticket_flights_1_fdw tf_2)
            Network: FDW bytes sent=549

Этот план эффективнее, запрос выполняется на двух сегментах из четырёх, и требуется лишь выполнить Append для полученных результатов.

Вновь обратим внимание, что book_ref присутствует в обеих таблицах — tickets и ticket_flights. Запрос для ключа сегментирования book_ref:

SELECT tf.*, t.*
FROM bookings.tickets t
JOIN bookings.ticket_flights tf
ON tf.ticket_no = t.ticket_no
AND tf.book_ref = t.book_ref
WHERE t.book_ref = '0824C5';

при этом план запроса:

Foreign Scan (actual rows=12 loops=1)
  Relations: (tickets_2_fdw t) INNER JOIN (ticket_flights_2_fdw tf)
  Network: FDW bytes sent=547 received=1717

Это отличный результат: запрос был модифицирован для эффективного выполнения в распределённой схеме.

3.3.5. Запрос q5

Это небольшой аналитический запрос, который возвращает имена и номера билетов тех пассажиров, которые прошли регистрацию первыми.

SELECT t.passenger_name, t.ticket_no
FROM bookings.tickets t
JOIN bookings.boarding_passes bp
  ON bp.ticket_no = t.ticket_no
GROUP BY t.passenger_name, t.ticket_no
HAVING max(bp.boarding_no) = 1
AND count(*) > 1;

Данный запрос выполняется одинаково медленно для обоих вариантов ключей сегментирования. План запроса с ключом сегментирования book_ref выглядит так:

HashAggregate (actual rows=424 loops=1)
  Group Key: t.ticket_no
  Filter: ((max(bp.boarding_no) = 1) AND (count(*) > 1))
  Batches: 85  Memory Usage: 4265kB  Disk Usage: 112008kB
  Rows Removed by Filter: 700748
  Network: FDW bytes sent=1215 received=77111136
  ->  Append (actual rows=1894295 loops=1)
        Network: FDW bytes sent=1215 received=77111136
        ->  Async Foreign Scan (actual rows=473327 loops=1)
              Relations: (tickets_0_fdw t_1) INNER JOIN (boarding_passes_0_fdw bp_1)
              Network: FDW bytes sent=404 received=813128
        ->  Async Foreign Scan (actual rows=472632 loops=1)
              Relations: (tickets_1_fdw t_2) INNER JOIN (boarding_passes_1_fdw bp_2)
              Network: FDW bytes sent=404
        ->  Async Foreign Scan (actual rows=475755 loops=1)
              Relations: (tickets_2_fdw t_3) INNER JOIN (boarding_passes_2_fdw bp_3)
              Network: FDW bytes sent=407
        ->  Hash Join (actual rows=472581 loops=1)
              Hash Cond: (bp_4.ticket_no = t_4.ticket_no)
              Network: FDW bytes received=28841344
              ->  Seq Scan on boarding_passes_3 bp_4 (actual rows=472581 loops=1)
              ->  Hash (actual rows=207118 loops=1)
                    Buckets: 65536  Batches: 4  Memory Usage: 3654kB
                    Network: FDW bytes received=9176680
                    ->  Seq Scan on tickets_3 t_4 (actual rows=207118 loops=1)
                          Network: FDW bytes received=9176680

Обратите внимание на довольно большой объём передачи данных по сети между сегментами. Попробуйте улучшить запрос, добавив book_ref как дополнительное условие для соединения таблиц:

SELECT t.passenger_name, t.ticket_no
FROM bookings.tickets t
JOIN bookings.boarding_passes bp
  ON bp.ticket_no = t.ticket_no
  AND bp.book_ref=t.book_ref -- <= added book_ref
GROUP BY t.passenger_name, t.ticket_no
HAVING max(bp.boarding_no) = 1
AND count(*) > 1;

Посмотрите на план запроса:

GroupAggregate (actual rows=424 loops=1)
  Group Key: t.passenger_name, t.ticket_no
  Filter: ((max(bp.boarding_no) = 1) AND (count(*) > 1))
  Rows Removed by Filter: 700748
  Network: FDW bytes sent=1424 received=77092816
  ->  Merge Append (actual rows=1894295 loops=1)
        Sort Key: t.passenger_name, t.ticket_no
        Network: FDW bytes sent=1424 received=77092816
        ->  Foreign Scan (actual rows=472757 loops=1)
              Relations: (tickets_0_fdw t_1) INNER JOIN (boarding_passes_0_fdw bp_1)
              Network: FDW bytes sent=472 received=2884064
        ->  Sort (actual rows=472843 loops=1)
              Sort Key: t_2.passenger_name, t_2.ticket_no
              Sort Method: external merge  Disk: 21152kB
              Network: FDW bytes received=22753536
              ->  Hash Join (actual rows=472843 loops=1)
                    Hash Cond: ((bp_2.ticket_no = t_2.ticket_no) AND (bp_2.book_ref = t_2.book_ref))
                    Network: FDW bytes received=22753536
                    ->  Seq Scan on boarding_passes_1 bp_2 (actual rows=472843 loops=1)
                    ->  Hash (actual rows=207058 loops=1)
                          Buckets: 65536  Batches: 8  Memory Usage: 2264kB
                          Network: FDW bytes received=22753536
                          ->  Seq Scan on tickets_1 t_2 (actual rows=207058 loops=1)
                                Network: FDW bytes received=22753536
        ->  Foreign Scan (actual rows=474715 loops=1)
              Relations: (tickets_2_fdw t_3) INNER JOIN (boarding_passes_2_fdw bp_3)
              Network: FDW bytes sent=476 received=2884120
        ->  Foreign Scan (actual rows=473980 loops=1)
              Relations: (tickets_3_fdw t_4) INNER JOIN (boarding_passes_3_fdw bp_4)
              Network: FDW bytes sent=476 received=25745384

Ситуация заметно улучшилась, результат был получен на узле-источнике запроса был получен, и затем произведена окончательная фильтрация, группировка и объединение данных.

Для ключа сегментирования ticket_no план исходного запроса выглядит так:

HashAggregate (actual rows=424 loops=1)
  Group Key: t.ticket_no
  Filter: ((max(bp.boarding_no) = 1) AND (count(*) > 1))
  Batches: 85  Memory Usage: 4265kB  Disk Usage: 111824kB
  Rows Removed by Filter: 700748
  Network: FDW bytes sent=1188 received=77103620
  ->  Append (actual rows=1894295 loops=1)
        Network: FDW bytes sent=1188 received=77103620
        ->  Async Foreign Scan (actual rows=473327 loops=1)
              Relations: (tickets_0_fdw t_1) INNER JOIN (boarding_passes_0_fdw bp_1)
              Network: FDW bytes sent=394
        ->  Hash Join (actual rows=472632 loops=1)
              Hash Cond: (bp_2.ticket_no = t_2.ticket_no)
              Network: FDW bytes received=77103620
              ->  Seq Scan on boarding_passes_1 bp_2 (actual rows=472632 loops=1)
              ->  Hash (actual rows=206712 loops=1)
                    Buckets: 65536  Batches: 4  Memory Usage: 3654kB
                    Network: FDW bytes received=23859576
                    ->  Seq Scan on tickets_1 t_2 (actual rows=206712 loops=1)
                          Network: FDW bytes received=23859576
        ->  Async Foreign Scan (actual rows=475755 loops=1)
              Relations: (tickets_2_fdw t_3) INNER JOIN (boarding_passes_2_fdw bp_3)
              Network: FDW bytes sent=397
        ->  Async Foreign Scan (actual rows=472581 loops=1)
              Relations: (tickets_3_fdw t_4) INNER JOIN (boarding_passes_3_fdw bp_4)
              Network: FDW bytes sent=397

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

3.3.6. Запрос q6

В результате данного запроса для каждого билета, забронированного неделю назад от текущего момента, выводятся входящие в него перелёты вместе с запасом времени на пересадку на следующий рейс.

SELECT tf.ticket_no,f.departure_airport,
      f.arrival_airport,f.scheduled_arrival,
      lead(f.scheduled_departure) OVER w AS next_departure,
      lead(f.scheduled_departure) OVER w - f.scheduled_arrival AS gap
FROM bookings.bookings b
JOIN bookings.tickets t
 ON t.book_ref = b.book_ref
JOIN bookings.ticket_flights tf
 ON tf.ticket_no = t.ticket_no
JOIN bookings.flights f
 ON tf.flight_id = f.flight_id
WHERE b.book_date = bookings.now()::date - INTERVAL '7 day'

WINDOW w AS (
PARTITION BY tf.ticket_no
ORDER BY f.scheduled_departure);

Для этого запроса тип столбца book_date из timestamptz должен быть приведён к типу date. При приведении типа PostgreSQL приводит тип данных столбца к типу данных, указанному в условии фильтрации, но не наоборот. Поэтому Shardman сначала должен получить все данные из других сегментов, привести тип, и только после этого применить правило фильтрации. План запроса будет выглядеть примерно так:

WindowAgg (actual rows=26 loops=1)
  Network: FDW bytes sent=1750 received=113339240
  ->  Sort (actual rows=26 loops=1)
        Sort Key: tf.ticket_no, f.scheduled_departure
        Sort Method: quicksort  Memory: 27kB
        Network: FDW bytes sent=1750 received=113339240
        ->  Append (actual rows=26 loops=1)
              Network: FDW bytes sent=1750 received=113339240
              ->  Hash Join (actual rows=10 loops=1)
                    Hash Cond: (t_1.book_ref = b.book_ref)
                    Network: FDW bytes sent=582 received=37717376
              ->  Hash Join (actual rows=6 loops=1)
                    Hash Cond: (t_2.book_ref = b.book_ref)
                    Network: FDW bytes sent=582 received=37700608
              ->  Hash Join (actual rows=2 loops=1)
                    Hash Cond: (t_3.book_ref = b.book_ref)
                    Network: FDW bytes sent=586 received=37921256
              ->  Nested Loop (actual rows=8 loops=1)
                    ->  Nested Loop (actual rows=8 loops=1)
                          ->  Hash Join (actual rows=2 loops=1)
                                Hash Cond: (t_4.book_ref = b.book_ref)
                                ->  Seq Scan on tickets_3 t_4 (actual rows=207118 loops=1)
                    ->  Index Scan using flights_pkey on flights f (actual rows=1 loops=8)
                          Index Cond: (flight_id = tf_4.flight_id)

Обратите внимание на количество байт, полученных от других сегментов кластера и на последовательное сканирование таблицы tickets. Попробуем переписать запрос так, чтобы можно было избежать приведения.

Интервал будет вычисляться не на уровне базы данных, а на уровне приложения, запросу сразу будут передаваться данные типа timestamptz. Кроме того, может помочь создание дополнительного индекса:

CREATE INDEX if not exists bookings_date_idx ON bookings.bookings(book_date);

Запрос с ключом сегментирования book_ref будет выглядеть так:

SELECT tf.ticket_no,f.departure_airport,
      f.arrival_airport,f.scheduled_arrival,
      lead(f.scheduled_departure) OVER w AS next_departure,
      lead(f.scheduled_departure) OVER w - f.scheduled_arrival AS gap
FROM bookings.bookings b
JOIN bookings.tickets t
 ON t.book_ref = b.book_ref
JOIN bookings.ticket_flights tf
 ON tf.ticket_no = t.ticket_no
AND tf.book_ref = t.book_ref -- <= added book_ref
JOIN bookings.flights f
 ON tf.flight_id = f.flight_id
WHERE b.book_date = '2016-10-06 14:00:00+00'
WINDOW w AS (
PARTITION BY tf.ticket_no
ORDER BY f.scheduled_departure);

У данного запроса будет уже другой план:

WindowAgg (actual rows=18 loops=1)
  Network: FDW bytes sent=2268 received=892
  ->  Sort (actual rows=18 loops=1)
        Sort Key: tf.ticket_no, f.scheduled_departure
        Sort Method: quicksort  Memory: 26kB
        Network: FDW bytes sent=2268 received=892
        ->  Append (actual rows=18 loops=1)
              Network: FDW bytes sent=2268 received=892
              ->  Nested Loop (actual rows=4 loops=1)
                    ->  Nested Loop (actual rows=4 loops=1)
                          ->  Nested Loop (actual rows=1 loops=1)
                                ->  Bitmap Heap Scan on bookings_0 b_1
                                      Heap Blocks: exact=1
                                      ->  Bitmap Index Scan on bookings_0_book_date_idx
                                ->  Index Only Scan using tickets_0_pkey on tickets_0 t_1
                                      Index Cond: (book_ref = b_1.book_ref)
                                      Heap Fetches: 0
                          ->  Index Only Scan using ticket_flights_0_pkey on ticket_flights_0 tf_1
                                Heap Fetches: 0
                    ->  Index Scan using flights_pkey on flights f (actual rows=1 loops=4)
                          Index Cond: (flight_id = tf_1.flight_id)
              ->  Async Foreign Scan (actual rows=14 loops=1)
                    Network: FDW bytes sent=754 received=892
              ->  Async Foreign Scan (actual rows=0 loops=1)
                    Network: FDW bytes sent=757 -- received=0!
              ->  Async Foreign Scan (actual rows=0 loops=1)
                    Network: FDW bytes sent=757 -- received=0!

Он гораздо эффективнее. Во-первых, таблица не сканируется целиком, используется Index Only Scan. Во-вторых, видно, насколько снизился объём переданных по сети данных между узлами.

3.3.7. Запрос q7

Допустим, нужна статистика по количеству пассажиров на одно бронирование. Для её получения сначала посчитаем количество пассажиров в каждом бронировании, а затем — количество бронирований с каждым вариантом количества пассажиров.

SELECT tt.cnt, count(*)
FROM (
   SELECT count(*) cnt
   FROM bookings.tickets t
   GROUP BY t.book_ref
   ) tt
GROUP BY tt.cnt
ORDER BY tt.cnt;

В результате данного запроса будут обработаны все данные таблиц tickets и bookings, поэтому не получится избежать интенсивного обмена данными по сети между сегментами кластера. Также обратите внимание, что значение параметра work_mem должно быть достаточно большим во избежание использования диска при соединении таблиц. Измените значение параметра work_mem в кластере:

shardmanctl set work_mem='256MB';

План запроса с ключом сегментирования ticket_no:

GroupAggregate (actual rows=5 loops=1)
  Group Key: tt.cnt
  Network: FDW bytes sent=798 received=18338112
  ->  Sort (actual rows=593433 loops=1)
        Sort Key: tt.cnt
        Sort Method: quicksort  Memory: 57030kB
        Network: FDW bytes sent=798 received=18338112
        ->  Subquery Scan on tt (actual rows=593433 loops=1)
              Network: FDW bytes sent=798 received=18338112
              ->  Finalize HashAggregate (actual rows=593433 loops=1)
                    Group Key: t.book_ref
                    Batches: 1  Memory Usage: 81953kB
                    Network: FDW bytes sent=798 received=18338112
                    ->  Append (actual rows=763806 loops=1)
                          Network: FDW bytes sent=798 received=18338112
                          ->  Async Foreign Scan (actual rows=190886 loops=1)
                                Relations: Aggregate on (tickets_0_fdw t)
                                Network: FDW bytes sent=266 received=1558336
                          ->  Async Foreign Scan (actual rows=190501 loops=1)
                                Relations: Aggregate on (tickets_1_fdw t_1)
                                Network: FDW bytes sent=266
                          ->  Async Foreign Scan (actual rows=191589 loops=1)
                                Relations: Aggregate on (tickets_2_fdw t_2)
                                Network: FDW bytes sent=266
                          ->  Partial HashAggregate (actual rows=190830 loops=1)
                                Group Key: t_3.book_ref
                                Batches: 1  Memory Usage: 36881kB
                                Network: FDW bytes received=4981496
                                ->  Seq Scan on tickets_3 t_3 (actual rows=207118 loops=1)
                                      Network: FDW bytes received=4981496

План запроса с ключом сегментирования book_ref:

Sort (actual rows=5 loops=1)
  Sort Key: (count(*))
  Sort Method: quicksort  Memory: 25kB
  Network: FDW bytes sent=798 received=14239951
  ->  HashAggregate (actual rows=5 loops=1)
        Group Key: (count(*))
        Batches: 1  Memory Usage: 40kB
        Network: FDW bytes sent=798 received=14239951
        ->  Append (actual rows=593433 loops=1)
              Network: FDW bytes sent=798 received=14239951
              ->  GroupAggregate (actual rows=148504 loops=1)
                    Group Key: t.book_ref
                    ->  Index Only Scan using tickets_0_book_ref_idx on tickets_0 t (rows=207273)
                          Heap Fetches: 0
              ->  Async Foreign Scan (actual rows=148256 loops=1)
                    Relations: Aggregate on (tickets_1_fdw t_1)
                    Network: FDW bytes sent=266 received=1917350
              ->  Async Foreign Scan (actual rows=148270 loops=1)
                    Relations: Aggregate on (tickets_2_fdw t_2)
                    Network: FDW bytes sent=266
              ->  Async Foreign Scan (actual rows=148403 loops=1)
                    Relations: Aggregate on (tickets_3_fdw t_3)
                    Network: FDW bytes sent=266

Видно, что планы запросов различаются прежде всего порядком соединения таблиц и вычислением агрегатов.

Для ключа сегментирования ticket_no принимаются все частично агрегированные данные объединяемых таблиц (17 Мб), а вся остальная обработка выполняется на узле-источнике запроса.

Для ключа сегментирования book_ref, поскольку он включён в запрос, большая часть вычислений агрегатов выполняется на узлах, и на узел-источник запроса возвращается только результат (13 МБ), который затем финально обрабатывается.

3.3.8. Запрос q8

Этот запрос отвечает на следующие вопросы: какие сочетания имён и фамилий встречаются чаще всего и как понять какую долю от числа всех пассажиров составляют такие сочетания? Для получения результата в запросе используется оконная функция:

SELECT passenger_name,
      round( 100.0 * cnt / sum(cnt) OVER (), 2)
   AS percent
FROM (
 SELECT passenger_name,
        count(*) cnt
 FROM bookings.tickets
 GROUP BY passenger_name
) t
ORDER BY percent DESC;

В обоих случаях план запроса будет выглядеть примерно так:

Sort (actual rows=27909 loops=1)
  Sort Key: (round(((100.0 * ((count(*)))::numeric) / sum((count(*))) OVER (?)), 2)) DESC
  Sort Method: quicksort  Memory: 3076kB
  Network: FDW bytes sent=816 received=2376448
  ->  WindowAgg (actual rows=27909 loops=1)
        Network: FDW bytes sent=816 received=2376448
        ->  Finalize HashAggregate (actual rows=27909 loops=1)
              Group Key: tickets.passenger_name
              Batches: 1  Memory Usage: 5649kB
              Network: FDW bytes sent=816 received=2376448
              ->  Append (actual rows=74104 loops=1)
                    Network: FDW bytes sent=816 received=2376448
                    ->  Partial HashAggregate (actual rows=18589 loops=1)
                          Group Key: tickets.passenger_name
                          Batches: 1  Memory Usage: 2833kB
                          ->  Seq Scan on tickets_0 tickets (actual rows=207273 loops=1)
                    ->  Async Foreign Scan (actual rows=18435 loops=1)
                          Relations: Aggregate on (tickets_1_fdw tickets_1)
                          Network: FDW bytes sent=272 received=2376448
                    ->  Async Foreign Scan (actual rows=18567 loops=1)
                          Relations: Aggregate on (tickets_2_fdw tickets_2)
                          Network: FDW bytes sent=272
                    ->  Async Foreign Scan (actual rows=18513 loops=1)
                          Relations: Aggregate on (tickets_3_fdw tickets_3)
                          Network: FDW bytes sent=272

В плане запроса видно, что предварительная обработка данных, соединение таблиц и частичное агрегирование выполняется в сегментах, а финальная обработка — на узле-источнике запроса.

3.3.9. Запрос q9

Данный запрос отвечает на следующие вопросы: кто летел позавчера рейсом Москва (SVO) — Новосибирск (OVB) на месте 1A, и когда он забронировал себе билет? «Позавчера» считается от функции booking.now, а не от текущей даты. Исходный запрос в нераспределённой схеме выглядит так:

SELECT
   t.passenger_name,
   b.book_date v
FROM bookings b
JOIN tickets t ON
   t.book_ref = b.book_ref
JOIN boarding_passes bp
   ON bp.ticket_no = t.ticket_no
JOIN flights f ON
   f.flight_id = bp.flight_id
WHERE f.departure_airport = 'SVO'
AND f.arrival_airport = 'OVB'
AND f.scheduled_departure::date = bookings.now()::date - INTERVAL '2 day'
AND bp.seat_no = '1A';

Как уже объяснялось в описании Запроса q6, использование INTERVAL вызовет приведение типов. Поэтому следует сразу от него избавиться и переписать запрос для ключа сегментирования book_ref следующим образом:

SELECT
   t.passenger_name,
   b.book_date v
FROM bookings b
JOIN tickets t ON
   t.book_ref = b.book_ref
JOIN boarding_passes bp
   ON bp.ticket_no = t.ticket_no
   AND bp.book_ref = b.book_ref -- <= added book_ref
JOIN flights f ON
   f.flight_id = bp.flight_id
WHERE f.departure_airport = 'SVO'
AND f.arrival_airport = 'OVB'
AND f.scheduled_departure
  BETWEEN '2016-10-11 14:00:00+00' AND '2016-10-13 14:00:00+00'
AND bp.seat_no = '1A';

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

CREATE INDEX idx_boarding_passes_seats
     ON boarding_passes((seat_no::text));
CREATE INDEX idx_flights_sched_dep
     ON flights(departure_airport,arrival_airport,scheduled_departure);

В результате должен получиться достаточно эффективный план запроса:

Append (actual rows=1 loops=1)
  Network: FDW bytes sent=2484 received=102
  ->  Nested Loop (actual rows=1 loops=1)
        Join Filter: (bp_1.ticket_no = t_1.ticket_no)
        Rows Removed by Join Filter: 1
        ->  Nested Loop (actual rows=1 loops=1)
              ->  Hash Join (actual rows=1 loops=1)
                    Hash Cond: (bp_1.flight_id = f.flight_id)
                    ->  Bitmap Heap Scan on boarding_passes_0 bp_1 (actual rows=4919 loops=1)
                          Recheck Cond: ((seat_no)::text = '1A'::text)
                          Heap Blocks: exact=2632
                          ->  Bitmap Index Scan on boarding_passes_0_seat_no_idx (actual rows=4919)
                                Index Cond: ((seat_no)::text = '1A'::text)
                    ->  Hash (actual rows=2 loops=1)
                          Buckets: 1024  Batches: 1  Memory Usage: 9kB
                          ->  Bitmap Heap Scan on flights f (actual rows=2 loops=1)
                                Recheck Cond:
                     ((departure_airport = 'SVO'::bpchar) AND (arrival_airport = 'OVB'::bpchar) AND
                     (scheduled_departure >= '2016-10-11 14:00:00+00'::timestamp with time zone) AND
                     (scheduled_departure < '2016-10-13 14:00:00+00'::timestamp with time zone))
                                Heap Blocks: exact=2
                                ->  Bitmap Index Scan on idx_flights_sched_dep (actual rows=2 loops=1)
                                      Index Cond:
                                   ((departure_airport = 'SVO'::bpchar) AND
                                   (arrival_airport = 'OVB'::bpchar) AND
                       (scheduled_departure >= '2016-10-11 14:00:00+00'::timestamp with time zone) AND
                       (scheduled_departure <= '2016-10-13 14:00:00+00'::timestamp with time zone))
              ->  Index Scan using bookings_0_pkey on bookings_0 b_1 (actual rows=1 loops=1)
                    Index Cond: (book_ref = bp_1.book_ref)
        ->  Index Scan using tickets_0_book_ref_idx on tickets_0 t_1 (actual rows=2 loops=1)
              Index Cond: (book_ref = b_1.book_ref)
  ->  Async Foreign Scan (actual rows=0 loops=1)
        Relations: (((boarding_passes_1_fdw bp_2) INNER JOIN (flights f)) INNER JOIN (tickets_1_fdw t_2)) INNER JOIN (bookings_1_fdw b_2)
        Network: FDW bytes sent=826 received=68
  ->  Async Foreign Scan (actual rows=0 loops=1)
        Relations: (((boarding_passes_2_fdw bp_3) INNER JOIN (flights f)) INNER JOIN (tickets_2_fdw t_3)) INNER JOIN (bookings_2_fdw b_3)
        Network: FDW bytes sent=829 received=34
  ->  Async Foreign Scan (actual rows=0 loops=1)
        Relations: (((boarding_passes_3_fdw bp_4) INNER JOIN (flights f)) INNER JOIN (tickets_3_fdw t_4)) INNER JOIN (bookings_3_fdw b_4)
        Network: FDW bytes sent=829

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

Если бы данный запрос выполнялся в другом сегменте, план был бы таким же, но данные для итоговой обработки результата были бы получены от сегмента, содержащего данные.

3.4. Подключение и работа с кластером Shardman

Как уже упоминалось в Подразделе 3.1.2, кластер состоит из четырёх сегментов. Распределение секций с данными главной сегментированной таблицы по сегментам кластера будет выглядеть как показано ниже.

Для ключа сегментирования ticket_no:

tickets_0 — сегмент-1 (узел кластера node1)

tickets_1 — сегмент-2 (узел кластера node2)

tickets_2 — сегмент-3 (узел кластера node3)

tickets_3 — сегмент-4 (узел кластера node4)

Для ключа сегментирования book_ref:

bookings_0 — сегмент-1 (узел кластера node1)

bookings_1 — сегмент-2 (узел кластера node2)

bookings_2 — сегмент-3 (узел кластера node3)

bookings_3 — сегмент-4 (узел кластера node4)

Ниже приведены примеры для ключа сегментирования book_ref, но указанный в подразделах код будет справедлив и для ключа сегментирования ticket_no.

Не стоит рассматривать данный код как оптимальный или пригодный для производственной среды. Он дан только как пример реализации создания пула соединений для работы с кластером Shardman.

Общее для всех приведённых примеров — строка подключения к кластеру, которая должна содержать имена узлов, номера TCP-портов, имя и пароль пользователя, имя базы данных для подключения и набор параметров сеанса.

Такую строку можно получить с помощью утилиты shardmanctl. В простейшем случае строка будет выглядеть так:

$ shardmanctl getconnstr

dbname=postgres host=node1,node2,node3,node4 port=5432,5432,5432,5432

Её можно использовать для подключения к узлам кластера или для создания пула соединений в приложениях.

3.4.1. SQL

В Shardman реализовано несколько удобных функций и представлений для наблюдения за кластером:

Вывод списка глобальных таблиц

Вывод списка сегментированная таблиц

Вывод списка глобальных последовательностей

Вычисление номера сегмента по ключу сегментирования

Выполнение ANALYZE для всех глобальных и сегментированных таблиц в кластере

3.4.1.1. Отображение списка глобальных таблиц

Для вывода всех глобальных таблиц в кластере используйте представление shardman.global_tables:

postgres=# select
    relname as table_name,
    nspname as schema
from shardman.global_tables;

 table_name |  schema
------------+----------
 aircrafts  | bookings
 seats      | bookings
 airports   | bookings
 flights    | bookings
(4 rows)

3.4.1.2. Отображение списка сегментированная таблиц

Для получения сведений обо всех сегментированных таблицах в кластере выполните запрос к представлению shardman.sharded_tables как показано ниже:

postgres=# select
    relname as table_name,
    nparts  as partitions,
    colocated_with::oid::regclass::text as colocated_with,
    nspname as schema
from shardman.sharded_tables;

   table_name    | partitions | colocated_with |  schema
-----------------+------------+----------------+----------
 bookings        |          4 |                | bookings
 ticket_flights  |          4 | bookings       | bookings
 tickets         |          4 | bookings       | bookings
 boarding_passes |          4 | bookings       | bookings
(4 rows)

3.4.1.3. Отображение списка глобальных последовательностей

Для вывода всех глобальных последовательностей в кластере используйте представление shardman.sequence:

postgres=# select
    seqns   as schema,
    seqname as sequence_name,
    seqmin  as min_value,
    seqmax  as max_value,
    seqblk  as bulk_size
from shardman.sequence;

  schema  |      sequence_name      | min_value |      max_value      | bulk_size
----------+-------------------------+-----------+---------------------+-----------
 bookings | flights_flight_id_seq   |    262145 | 9223372036854775807 |     65536
(1 rows)

3.4.1.4. Вычисление номера сегмента по ключу сегментирования

Для вывода имени секции, содержащей данные и имя группы репликации вызовите функцию shardman.get_partition_for_value(). Например, пусть book_ref = 0369E5:

postgres=# select * from shardman.get_partition_for_value(
            'bookings'::regclass,
            '0369E5'::character(6));

 rgid | local_nspname | local_relname | remote_nspname | remote_relname
------+---------------+---------------+----------------+----------------
    1 | bookings      | bookings_0    | bookings       | bookings_0

Этот вывод показывает, что данные в секции bookings_0 таблицы bookings расположены в том же узле, в котором выполнялся запрос.

Выполните запрос, показывающий имя сервера, где находится секция с данными. Если подключиться к серверу, содержащему искомую секцию, то в выводе имени сервера будет написано «current server» (текущий сервер). Если данные расположены в другом сегменте, показывается имя узла мастера сегмента:

SELECT p.rgid,
      local_relname AS partition_name,
      CASE
          WHEN r.srvid IS NULL THEN 'current server'
          ELSE (SELECT (SELECT split_part(kv, '=', 2)
                        FROM (SELECT unnest(fs.srvoptions) as kv) x
                        WHERE split_part(kv, '=', 1) = 'host')
                FROM shardman.repgroups rg
                         JOIN pg_catalog.pg_foreign_server AS fs ON fs.oid = rg.srvid
                WHERE rg.id = p.rgid)
          END       AS server_name
FROM shardman.get_partition_for_value('bookings'::regclass, '0369E5'::character(6)) p
        JOIN shardman.repgroups AS r ON
   r.id = p.rgid;

 rgid | partition_name |  server_name
------+----------------+----------------
    1 | bookings_0     | current server
(1 row)

При выполнении запроса с другим ключом сегментирования — 0369E6 — результат будет таким:

 rgid | partition_name | server_name
------+----------------+-------------
    4 | bookings_3_fdw | node4
(1 row)

Видно, что секция находится на узле node4.

Также обратите внимание, что параметр shardman.rgid позволяет вам найти номер узла с сеансом подключения. Для этого выполните следующий запрос:

SELECT pg_catalog.current_setting('shardman.rgid');

Это значение можно использовать для определения расположения секций в подобных запросах.

Функция shardman.get_partition_for_value() в основном предназначена для административных целей и лучшего понимания топологии данных.

Как правило, административные функции не следует использовать при написании SQL-кода для доступа к данным.

3.4.1.5. Расположение секций сегментированных таблиц по сегментам

Список всех сегментированных таблиц в схеме bookings, количество их секций и распределение по серверам (сегментам) можно получить из метаданных Shardman на любом узле кластера.

Рассмотрим следующий запрос:

SELECT p.rel::regclass::text AS table_name,
      p.pnum,
      p.rgid,
      r.srvid,
      fs.srvname
FROM shardman.parts p
JOIN shardman.repgroups r
  ON p.rgid = r.id
LEFT OUTER JOIN pg_foreign_server fs
             ON r.srvid = fs.oid;

Чтобы выяснить как распределены данные, объедините этот запрос с подзапросом из Раздел 3.4.1.4:

SELECT p.rel::regclass AS table_name,
      st.nparts AS total_parts,
      p.pnum AS num_part,
      CASE
         WHEN r.srvid IS NULL THEN 'connected server'
      ELSE
       (SELECT split_part(kv, '=', 2)
       FROM (SELECT unnest(fs.srvoptions) AS kv) x
       WHERE split_part(kv, '=', 1) = 'host')
       END AS server_name
FROM shardman.parts p
       JOIN shardman.repgroups r
         ON p.rgid = r.id
       LEFT JOIN shardman.sharded_tables st
              ON p.rel = st.rel
       LEFT JOIN pg_foreign_server fs
              ON r.srvid = fs.oid
WHERE st.nspname = 'bookings'
ORDER BY table_name, num_part, server_name;

Формат вывода результата: имя таблицы, количество секций в таблице, номер секции и имя сервера:

        table_name        | total_parts | num_part |   server_name
--------------------------+-------------+----------+------------------
 bookings.bookings        |           4 |        0 | connected server
 bookings.bookings        |           4 |        1 | node2
 bookings.bookings        |           4 |        2 | node3
 bookings.bookings        |           4 |        3 | node4
 bookings.ticket_flights  |           4 |        0 | connected server
 bookings.ticket_flights  |           4 |        1 | node2
 bookings.ticket_flights  |           4 |        2 | node3
 bookings.ticket_flights  |           4 |        3 | node4
 bookings.tickets         |           4 |        0 | connected server
 bookings.tickets         |           4 |        1 | node2
 bookings.tickets         |           4 |        2 | node3
 bookings.tickets         |           4 |        3 | node4
 bookings.boarding_passes |           4 |        0 | connected server
 bookings.boarding_passes |           4 |        1 | node2
 bookings.boarding_passes |           4 |        2 | node3
 bookings.boarding_passes |           4 |        3 | node4

3.4.1.6. Сбор статистики

Для сбора статистики по сегментированным и глобальным таблицам вызовите функцию shardman.global_analyze(). Сначала эта функция выполняет сбор статистики для всех локальных секций распределённых таблиц на каждом узле, а затем транслирует эту статистику на другие узлы. Для глобальной таблицы будет выполнен сбор статистики на одном выбранном узле, после чего собранная статистика транслируется на все остальные узлы кластера.

3.4.2. psql/libpq

Для подключения к кластеру Shardman и полноценной работы с ним, достаточно подключиться к любому узлу кластера. Для этого необходимо сначала получить строку подключения.

В документации PostgreSQL описана строка подключения к кластеру. Строка может быть представлена в двух вариантах: ключ-значение и URI. Для подключения к кластеру Shardman можно использовать любой из этих вариантов.

Кроме того, должны быть указаны некоторые параметры. Список этих параметров также доступен в документации PostgreSQL.

Для параметра target_session_attrs должно быть указано значение read-write, то есть приемлемы только подключения, допускающие транзакции чтения/записи. При успешном подключении к узлу кластера будет отправлен запрос «SHOW transaction_read_only;». Если в результате получено значение on, соединение будет закрыто. Если в строке подключения указаны несколько серверов, будут перебираться остальные серверы, как и при неудачной попытке подключения. Использование параметра target_session_attrs даёт возможность указывать в строке подключение как ведущие серверы, так и реплики кластера Shardman.

Ниже представлены примеры подключения:

psql -d  "dbname=postgres host=node3,node4,node2,node1 port=5432,5432,5432,5432 user=username password=password target_session_attrs=read-write"

psql postgres://username:password@node1:5432,node2:5432,node3:5432,node4:5432/postgres?target_session_attrs=read-write

3.4.3. Python

Подключение к кластеру Shardman с использованием библиотеки psycopg2 будет выглядеть следующим образом:

import psycopg2
from psycopg2 import pool

pool = psycopg2.pool.SimpleConnectionPool(
                             min_size=1,
                             max_size=5,
                             user="pguser",
                             password="*****",
                             host="node1,node2,node3,node4",
                             port="5432,5432,5432,5432",
                             database="postgres",
                             target_session_attrs="read-write")

connection = pool.getconn()

Создаётся пул соединений со следующими параметрами: минимальное количество подключений min_size=1, а максимальное — max_size=5. Далее выбирается подключение для соединения с кластером, указывается логин и пароль пользователя, список узлов, TCP-портов, база данных и параметры подключения (за дополнительной информацией обратитесь к Подразделу 3.4.2)

3.4.4. Java

Подключение к кластеру Shardman с использованием JDBC будет выглядеть следующим образом:

String url = "jdbc:postgresql://node1:5432,node2:5432,node3:5432,node4:5432/postgres?loadBalanceHosts=true&targetServerType=primary";
Properties props = new Properties();

props.setProperty("user","postgres");
props.setProperty("password","********");

Connection conn = DriverManager.getConnection(url, props);

Здесь в переменной url содержится строка подключения, где перечислены все доступные в кластере ведущие серверы сегментов. Если не указывать дополнительные параметры подключения драйвера JDBC, то подключение к кластеру будет происходить через первый доступный для соединения узел. Данный вариант не всегда может оказаться удобным. Поэтому, в строке подключения добавлены параметры, позволяющие использовать разные сегменты кластера для разных подключений.

Параметр loadBalanceHosts=true позволяет перебирать узлы, подключаясь к какому-то одному из них, а параметр targetServerType=primary указывает, что необходимо выбирать только ведущие сервера, тогда в строку подключения можно добавлять реплики.

3.4.5. Go

Подключение к кластеру Shardman для Go не слишком отличается от способов подключения, принятых в Java или Python. Необходимо использовать перечисление узлов, их TCP-портов, параметры подключения и выбрать подходящий драйвер.

Одним из таких драйверов для Go является pgx версии 4 или 5.

Ниже представлен пример строки подключения и создания пула для подключения к кластеру:

dbURL := "postgres://username:password@node1:5432,node2:5432,node3:5432,node4:5432/postgres?target_session_attrs=read-write")
dbPool, err := pgxpool.New(context.Background(), dbURL)

Рекомендуем также ознакомиться с описанием параметра target_session_attrs.

Глава 4. Дополнительные возможности

Shardman включает некоторые дополнительные возможности и модули, импортированные из Postgres Pro Enterprise, а именно: AQO (адаптивная оптимизация запросов), CFS (сжатая файловая система), а также модули pgpro_stats, pgpro_pwr и pg_query_state.

4.1. AQO (адаптивная оптимизация запросов)

AQO — это расширение Shardman, которое использует статистику выполнения запросов для улучшения оценки количества строк, что может способствовать выбору лучшего плана и, как следствие, ускорению запросов.

Для включения AQO выполните следующие шаги:

Добавьте aqo в параметр shared_preload_libraries в sdmspec.json.

Создайте расширение aqo на всех узлах.

SET shardman.broadcast_ddl TO ON;
CREATE EXTENSION aqo;
RESET shardman.broadcast_ddl;

Установите для aqo.mode значение learn и выполняйте запросы, которые вы хотите оптимизировать, с помощью EXPLAIN ANALYZE, пока план не перестанет меняться.

BEGIN;
SET aqo.mode = 'learn';
EXPLAIN ANALYZE <query>
RESET aqo.mode;
COMMIT;

Обратите внимание, что статистика aqo собирается отдельно для каждого узла в кластере Shardman. Поэтому вам придётся повторить этот процесс на каждом узле в кластере. В качестве альтернативы можно установить для aqo.mode значение learn и дать приложению поработать в этом режиме некоторое время, а затем вернуть его в режим по умолчанию (controlled).

Примечание

AQO не будет работать для запросов, содержащих меньшее количество соединений, чем указано в aqo.join_threshold (по умолчанию 3).

Полную документацию по AQO можно найти здесь.

4.2. CFS (сжатая файловая система)

CFS добавляет в Shardman сжатие на уровне страницы. Сжатие можно включить только для отдельных табличных пространств. Для сжатия табличного пространства нужно включить параметр сжатия при создании этого табличного пространства. Например:

CREATE TABLESPACE data LOCATION '/mnt/data-{rgid}' WITH (global, compression='zlib');

Теперь в этом табличном пространстве можно создавать таблицы и индексы или перемещать в него существующие таблицы или индексы.

CREATE TABLE pgbench_branches (
       bid integer NOT NULL PRIMARY KEY USING INDEX TABLESPACE data,
       bbalance integer,
       filler character(88)
)
WITH (distributed_by = 'bid') TABLESPACE data;

Примечание

Функция cfs_compression_ratio() возвращает фактическое значение степени сжатия для всех сегментов сжатого отношения. Однако для секционированных и сторонних таблиц она возвращает значение типа NaN, поэтому работает только для локальных секций сегментированной таблицы.

Полную документацию CFS можно найти здесь.

4.3. pgpro_stats (статистика планирования и выполнения)

Расширение pgpro_stats предоставляет возможности для сбора статистики планирования и выполнения всех обрабатываемых сервером SQL-операторов. В дополнение к отслеживанию локальных операторов расширение pgpro_stats собирает агрегированную статистику для распределённых запросов, затрагивающих несколько узлов в кластере. Это позволяет пользователям лучше понимать, как системные ресурсы используются для распределённых запросов.

Архитектура дополнений Shardman к расширению pgpro_stats описана в Разделе 7.8.

Полную документацию pgpro_stats можно найти здесь.

4.4. pgpro_pwr (отчёты о нагрузке)

Модуль pgpro_pwr предназначен для выявления наиболее ресурсоёмких операций в базе данных. Данный модуль основывается на представлениях Сборщика статистики Postgres Pro и расширении pgpro_stats или pg_stat_statements.

Чтобы создавать отчёты о нагрузке в кластере Shardman с помощью модуля pgpro_pwr, выполните следующие действия:

Установите модуль dblink и расширение pgpro_stats на каждом узле кластера Shardman.

Установите совместимый с Shardman модуль pgpro_pwr на каждом узле кластера Shardman:

sudo apt install pgpro-pwr-sdm-14

Полную документацию pgpro_pwr можно найти здесь.

4.5. pg_query_state

Модуль pg_query_state даёт возможность узнавать текущее состояние выполнения запросов в работающем обслуживающем процессе, а также в рабочих процессах silkworm мультиплексора.

Полную документацию pg_query_state можно найти здесь.

Глава 5. Настройка производительности

Настройка производительности должна выполняться во время разработки приложения и включать в себя точный выбор аппаратного обеспечения (например, оценку количества ЦП и памяти для каждого узла кластера Shardman или настройку хранилища), настройку ОС (например, настройку параметра swappiness или поведения, связанного с сетью) и настройку СУБД (выбор эффективной конфигурации). Но в первую очередь приложение должно быть протестировано и настроено для работы с распределённой СУБД. В такую настройку входит разработка распределённой схемы (или преобразование существующей схемы в распределённую), настройка запросов, использование пулов соединений, кеширование и даже проверка проблем с производительностью, связанных с возможными ошибками сериализации или выходом из строя узла Shardman. Проектирование схемы должно включать точный выбор ключа сегментирования и выбор таблиц, которые должны стать глобальными. Обычно ключ сегментирования выбирается таким образом, чтобы:

Большинство запросов отфильтровывало большинство секций сегментированной таблицы.

Сегментированные таблицы размещались совместно, и все соединения сегментированных таблиц являлись эквивалентными соединениями по ключу сегментирования.

Эти правила позволяют Shardman эффективно исключать из запросов неиспользуемые сегменты и передавать соединения для выполнения на сегменты, в которых находятся требуемые данные.

Каждый узел Shardman работает как обычный сервер СУБД, поэтому все стандартные рекомендации по настройке PostgreSQL для производственной нагрузки остаются в силе. Следует выбрать значения shared_buffers, work_mem, efficient_cache_size в зависимости от ресурсов, доступных для СУБД. Имейте в виду, что если для топологии кластера задано значение cross, несколько экземпляров (указанное в Repfactor количество) будут запущены на одном узле w. Когда все узлы кластера подключены к сети, реплики не должны использовать много ЦП. Однако при отказе узла ведущие серверы Repfactor групп репликации могут оказаться работающими на одном сервере, что может создать для него значительную нагрузку. При настройке параметра max_connections обратите внимание, что каждая транзакция может инициировать n-1 подключений, где n — количество групп репликации в кластере. При включённом транспорте Silk, указанное выше верно и для транзакций, содержащих операции DML, а когда транспорт Silk отключён — также для транзакций только для чтения.

Другие параметры, которые, возможно, стоит настроить, — это параметры стороннего сервера. Их можно установить в разделе FDWOptions файла конфигурации Shardman. Параметры, которые существенно влияют на производительность Shardman: fetch_size, batch_size и async_capable. Когда транспорт Silk отключён, fetch_size определяет количество записей, которые одновременно извлекаются с удалённого сервера. Когда включён транспорт Silk, fetch_size на данный момент не оказывает существенного влияния на выполнение запроса. Параметр batch_size указывает, сколько строк можно объединить в одной удалённой операции INSERT для сегментированной таблицы. Параметр async_capable разрешает асинхронное выполнение и всегда должен быть включён (значение по умолчанию).

Параметр конфигурации shardman.gt_batch_size позволяет оптимизировать размер промежуточного буфера для операций INSERT и DELETE в глобальных таблицах.

5.1. Изучение планов

Настраивать выполнение запросов лучше на подмножестве производственных данных, представляющем фактическое распределение данных. Посмотрите на некоторые примеры планов.

EXPLAIN VERBOSE
SELECT bid,avg(abalance) FROM pgbench_accounts
WHERE bid IN (10,20,30,40)
GROUP BY bid;
                                                                QUERY PLAN
-------------------------------------------------------------------------------------------------------------------------------------------
 Append  (cost=0.29..21.98 rows=4 width=36)
   ->  GroupAggregate  (cost=0.29..18.98 rows=1 width=36)
         Output: pgbench_accounts.bid, avg(pgbench_accounts.abalance)
         Group Key: pgbench_accounts.bid
         ->  Index Scan using pgbench_accounts_15_pkey on public.pgbench_accounts_15 pgbench_accounts  (cost=0.29..18.96 rows=1 width=8)
               Output: pgbench_accounts.bid, pgbench_accounts.abalance
               Index Cond: (pgbench_accounts.bid = ANY ('{10,20,30,40}'::integer[]))
   ->  Async Foreign Scan  (cost=0.99..0.99 rows=1 width=36)
         Output: pgbench_accounts_1.bid, (avg(pgbench_accounts_1.abalance))
         Relations: Aggregate on (public.pgbench_accounts_16_fdw pgbench_accounts_1)
         Remote SQL: SELECT bid, avg(abalance) FROM public.pgbench_accounts_16 WHERE ((bid = ANY ('{10,20,30,40}'::integer[]))) GROUP BY 1
         Transport: Silk
   ->  Async Foreign Scan  (cost=0.99..0.99 rows=1 width=36)
         Output: pgbench_accounts_2.bid, (avg(pgbench_accounts_2.abalance))
         Relations: Aggregate on (public.pgbench_accounts_17_fdw pgbench_accounts_2)
         Remote SQL: SELECT bid, avg(abalance) FROM public.pgbench_accounts_17 WHERE ((bid = ANY ('{10,20,30,40}'::integer[]))) GROUP BY 1
         Transport: Silk
   ->  Async Foreign Scan  (cost=1.00..1.00 rows=1 width=36)
         Output: pgbench_accounts_3.bid, (avg(pgbench_accounts_3.abalance))
         Relations: Aggregate on (public.pgbench_accounts_19_fdw pgbench_accounts_3)
         Remote SQL: SELECT bid, avg(abalance) FROM public.pgbench_accounts_19 WHERE ((bid = ANY ('{10,20,30,40}'::integer[]))) GROUP BY 1
         Transport: Silk
 Query Identifier: -1714706980364121548

Здесь видно, что запросы, сканирующие три секции, будут отправляться на другие узлы, данные координатора также будут сканироваться с использованием Index Scan. Неизвестно, какой план будет использоваться на удалённой стороне, но видно, какие запросы будут отправлены (отмечены как Remote SQL). Обратите внимание, что секция Transport: Silk присутствует в описании стороннего сканирования. Это означает, что для передачи результатов будет использоваться транспорт Silk. Видно, что будет использоваться стороннее сканирование Async, это нормально. Чтобы узнать, какие серверы используются в запросе, нужно посмотреть определения сторонних таблиц. Например, можно узнать, что public.pgbench_accounts_19_fdw находится на сервере shardman_rg_2 и прослушивает 127.0.0.2:65432:

SELECT srvname,srvoptions FROM pg_foreign_server s JOIN pg_foreign_table ON ftserver = s.oid
WHERE ftrelid = 'public.pgbench_accounts_19_fdw'::regclass;
-[ RECORD 1 ]-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
srvname    | shardman_rg_2
srvoptions | {async_capable=on,batch_size=100,binary_format=on,connect_timeout=5,dbname=postgres,extended_features=on,fdw_tuple_cost=0.2,fetch_size=50000,host=127.0.0.2,port=65432,silk_port=8000,tcp_user_timeout=10000}

Теперь можно подключиться к серверу shardman_rg_2 и узнать, какой план используется для локального запроса, показанного выше в EXPLAIN:

EXPLAIN SELECT bid, avg(abalance)
FROM public.pgbench_accounts_19
WHERE ((bid = ANY ('{10,20,30,40}'::integer[]))) GROUP BY 1;

                                   QUERY PLAN
---------------------------------------------------------------------------------
 HashAggregate  (cost=3641.00..3641.01 rows=1 width=36)
   Group Key: bid
   ->  Seq Scan on pgbench_accounts_19  (cost=0.00..3141.00 rows=100000 width=8)
         Filter: (bid = ANY ('{10,20,30,40}'::integer[]))

При рассмотрении планов распределённых запросов видно, что иногда агрегатные функции не проталкиваются:

EXPLAIN VERBOSE
SELECT avg(abalance) FROM pgbench_accounts;
                                                                                    QUERY PLAN
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 Finalize Aggregate  (cost=156209.38..156209.39 rows=1 width=32) (actual time=590.359..590.371 rows=1 loops=1)
   Output: avg(pgbench_accounts.abalance)
   ->  Append  (cost=2891.00..156209.33 rows=20 width=32) (actual time=56.815..590.341 rows=20 loops=1)
         ->  Partial Aggregate  (cost=2891.00..2891.01 rows=1 width=32) (actual time=56.812..56.813 rows=1 loops=1)
               Output: PARTIAL avg(pgbench_accounts.abalance)
               ->  Seq Scan on public.pgbench_accounts_0 pgbench_accounts  (cost=0.00..2641.00 rows=100000 width=4) (actual time=0.018..38.478 rows=100000 loops=1)
                     Output: pgbench_accounts.abalance
         ->  Partial Aggregate  (cost=23991.00..23991.01 rows=1 width=32) (actual time=75.133..75.134 rows=1 loops=1)
               Output: PARTIAL avg(pgbench_accounts_1.abalance)
               ->  Foreign Scan on public.pgbench_accounts_1_fdw pgbench_accounts_1  (cost=100.00..23741.00 rows=100000 width=4) (actual time=41.281..67.293 rows=100000 loops=1)
                     Output: pgbench_accounts_1.abalance
                     Remote SQL: SELECT abalance FROM public.pgbench_accounts_1
                     Transport: Silk
.....

Здесь avg() вычисляется на стороне координатора. Это может привести к значительному росту объёма данных, передаваемых между узлами. Фактическую передачу данных можно отслеживать, используя параметр NETWORK EXPLAIN ANALYZE (посмотрите на поле Network Received самого верхнего узла плана):

EXPLAIN (ANALYZE, VERBOSE, NETWORK)
SELECT avg(abalance) FROM pgbench_accounts
                                                                                     QUERY PLAN
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 Finalize Aggregate  (cost=156209.38..156209.39 rows=1 width=32) (actual time=589.014..589.027 rows=1 loops=1)
   Output: avg(pgbench_accounts.abalance)
   Network: FDW bytes sent=3218 received=14402396
   ->  Append  (cost=2891.00..156209.33 rows=20 width=32) (actual time=52.111..588.999 rows=20 loops=1)
         Network: FDW bytes sent=3218 received=14402396
         ->  Partial Aggregate  (cost=2891.00..2891.01 rows=1 width=32) (actual time=52.109..52.109 rows=1 loops=1)
               Output: PARTIAL avg(pgbench_accounts.abalance)
               ->  Seq Scan on public.pgbench_accounts_0 pgbench_accounts  (cost=0.00..2641.00 rows=100000 width=4) (actual time=0.020..34.472 rows=100000 loops=1)
                     Output: pgbench_accounts.abalance
         ->  Partial Aggregate  (cost=23991.00..23991.01 rows=1 width=32) (actual time=78.616..78.617 rows=1 loops=1)
               Output: PARTIAL avg(pgbench_accounts_1.abalance)
               Network: FDW bytes sent=247 received=2400360
               ->  Foreign Scan on public.pgbench_accounts_1_fdw pgbench_accounts_1  (cost=100.00..23741.00 rows=100000 width=4) (actual time=42.359..69.984 rows=100000 loops=1)
                     Output: pgbench_accounts_1.abalance
                     Remote SQL: SELECT abalance FROM public.pgbench_accounts_1
                     Transport: Silk
                     Network: FDW bytes sent=247 received=2400360
.....

В таких случаях иногда можно переписать запрос:

EXPLAIN  (ANALYZE, NETWORK, VERBOSE)
SELECT sum(abalance)::float/count(abalance) FROM pgbench_accounts where abalance is not null;

                                                                             QUERY PLAN
--------------------------------------------------------------------------------------------------------------------------------------------------------------------
 Finalize Aggregate  (cost=12577.20..12577.22 rows=1 width=8) (actual time=151.632..151.639 rows=1 loops=1)
   Output: ((sum(pgbench_accounts.abalance))::double precision / (count(pgbench_accounts.abalance))::double precision)
   Network: FDW bytes sent=3907 received=872
   ->  Append  (cost=3141.00..12577.10 rows=20 width=16) (actual time=55.589..151.621 rows=20 loops=1)
         Network: FDW bytes sent=3907 received=872
         ->  Partial Aggregate  (cost=3141.00..3141.01 rows=1 width=16) (actual time=55.423..55.424 rows=1 loops=1)
               Output: PARTIAL sum(pgbench_accounts.abalance), PARTIAL count(pgbench_accounts.abalance)
               ->  Seq Scan on public.pgbench_accounts_0 pgbench_accounts  (cost=0.00..2641.00 rows=100000 width=4) (actual time=0.023..37.212 rows=100000 loops=1)
                     Output: pgbench_accounts.abalance
                     Filter: (pgbench_accounts.abalance IS NOT NULL)
         ->  Async Foreign Scan  (cost=1.00..1.00 rows=1 width=16) (actual time=0.055..0.089 rows=1 loops=1)
               Output: (PARTIAL sum(pgbench_accounts_1.abalance)), (PARTIAL count(pgbench_accounts_1.abalance))
               Relations: Aggregate on (public.pgbench_accounts_1_fdw pgbench_accounts_1)
               Remote SQL: SELECT sum(abalance), count(abalance) FROM public.pgbench_accounts_1 WHERE ((abalance IS NOT NULL))
               Transport: Silk
               Network: FDW bytes sent=300 received=800
....

Переписав запрос здесь, удалось уменьшить входящий сетевой трафик, генерируемый запросом, с 13 МБ до 872 байт.

Теперь посмотрите на два почти идентичных соединения.

EXPLAIN ANALYZE SELECT count(*) FROM pgbench_branches b
JOIN pgbench_history h ON b.bid = h.bid
WHERE mtime > '2023-03-14 10:00:00'::timestamptz AND b.bbalance > 0;

                                                                         QUERY PLAN
------------------------------------------------------------------------------------------------------------------------------------------------------------
 Finalize Aggregate  (cost=8125.68..8125.69 rows=1 width=8) (actual time=27.464..27.543 rows=1 loops=1)
   ->  Append  (cost=3.85..8125.63 rows=20 width=8) (actual time=0.036..27.475 rows=20 loops=1)
         ->  Partial Aggregate  (cost=3.85..3.86 rows=1 width=8) (actual time=0.033..0.036 rows=1 loops=1)
               ->  Nested Loop  (cost=0.00..3.69 rows=67 width=0) (actual time=0.025..0.027 rows=0 loops=1)
                     Join Filter: (b.bid = h.bid)
                     ->  Seq Scan on pgbench_branches_0 b  (cost=0.00..1.01 rows=1 width=4) (actual time=0.023..0.024 rows=0 loops=1)
                           Filter: (bbalance > 0)
                           Rows Removed by Filter: 1
                     ->  Seq Scan on pgbench_history_0 h  (cost=0.00..1.84 rows=67 width=4) (never executed)
                           Filter: (mtime > '2023-03-14 10:00:00+03'::timestamp with time zone)
         ->  Partial Aggregate  (cost=222.65..222.66 rows=1 width=8) (actual time=3.969..3.973 rows=1 loops=1)
               ->  Nested Loop  (cost=200.00..222.43 rows=86 width=0) (actual time=3.736..3.920 rows=86 loops=1)
                     Join Filter: (b_1.bid = h_1.bid)
                     ->  Foreign Scan on pgbench_branches_1_fdw b_1  (cost=100.00..101.22 rows=1 width=4) (actual time=1.929..1.932 rows=1 loops=1)
                     ->  Foreign Scan on pgbench_history_1_fdw h_1  (cost=100.00..120.14 rows=86 width=4) (actual time=1.795..1.916 rows=86 loops=1)
                           Filter: (mtime > '2023-03-14 10:00:00+03'::timestamp with time zone)
         ->  Partial Aggregate  (cost=864.54..864.55 rows=1 width=8) (actual time=1.780..1.786 rows=1 loops=1)
               ->  Hash Join  (cost=200.01..864.53 rows=5 width=0) (actual time=1.769..1.773 rows=0 loops=1)
                     Hash Cond: (h_2.bid = b_2.bid)
                     ->  Foreign Scan on pgbench_history_2_fdw h_2  (cost=100.00..760.81 rows=975 width=4) (never executed)
                           Filter: (mtime > '2023-03-14 10:00:00+03'::timestamp with time zone)
                     ->  Hash  (cost=100.00..100.00 rows=1 width=4) (actual time=1.740..1.742 rows=0 loops=1)
                           Buckets: 1024  Batches: 1  Memory Usage: 8kB
                           ->  Foreign Scan on pgbench_branches_2_fdw b_2  (cost=100.00..100.00 rows=1 width=4) (actual time=1.738..1.738 rows=0 loops=1)
....
 Planning Time: 6.066 ms
 Execution Time: 33.851 ms

Интересно, что объединение секций pgbench_branches и pgbench_history происходит локально. Это универсальный план — его можно узнать по соединениям, расположенным над сторонними сканированиями. Не всегда очевидно, почему не происходит проталкивания соединения. Но если посмотреть на определение pgbench_history, видно, что mtime имеет тип timestamp without time zone.

\d pgbench_history
              Partitioned table "public.pgbench_history"
 Column |            Type             | Collation | Nullable | Default
--------+-----------------------------+-----------+----------+---------
 tid    | integer                     |           |          |
 bid    | integer                     |           |          |
 aid    | integer                     |           |          |
 delta  | integer                     |           |          |
 mtime  | timestamp without time zone |           |          |
 filler | character(22)               |           |          |
Partition key: HASH (bid)
Number of partitions: 20 (Use \d+ to list them.)

В приведённом выше запросе строка, описывающая время, преобразуется в timestamp with timezone. Для этого требуется сравнение столбца mtime (типа timestamp) и значения timestamptz. Сравнение выполняется неявно с использованием стабильной функции timestamp_gt_timestamptz. Фильтр, содержащий функцию переменной природы, не может быть передан на сторонний сервер, поэтому соединение выполняется локально. Если переписать запрос, преобразовав строку в отметку времени, станет заметно не только то, что соединения проталкиваются, но и то, что удалённые запросы могут выполняться асинхронно, поскольку сторонние сканирования в дереве плана расположены сразу после Append:

EXPLAIN ANALYZE SELECT count(*) FROM pgbench_branches b
JOIN pgbench_history h ON b.bid = h.bid
WHERE mtime > '2023-03-14 10:00:00'::timestamp AND b.bbalance > 0;
                                                                   QUERY PLAN
------------------------------------------------------------------------------------------------------------------------------------------------
 Finalize Aggregate  (cost=84.30..84.31 rows=1 width=8) (actual time=22.962..22.990 rows=1 loops=1)
   ->  Append  (cost=3.85..84.25 rows=20 width=8) (actual time=0.196..22.927 rows=20 loops=1)
         ->  Partial Aggregate  (cost=3.85..3.86 rows=1 width=8) (actual time=0.032..0.034 rows=1 loops=1)
               ->  Nested Loop  (cost=0.00..3.69 rows=67 width=0) (actual time=0.024..0.026 rows=0 loops=1)
                     Join Filter: (b.bid = h.bid)
                     ->  Seq Scan on pgbench_branches_0 b  (cost=0.00..1.01 rows=1 width=4) (actual time=0.023..0.023 rows=0 loops=1)
                           Filter: (bbalance > 0)
                           Rows Removed by Filter: 1
                     ->  Seq Scan on pgbench_history_0 h  (cost=0.00..1.84 rows=67 width=4) (never executed)
                           Filter: (mtime > '2023-03-14 10:00:00'::timestamp without time zone)
         ->  Async Foreign Scan  (cost=0.99..0.99 rows=1 width=8) (actual time=10.870..10.871 rows=1 loops=1)
               Relations: Aggregate on ((pgbench_branches_1_fdw b_1) INNER JOIN (pgbench_history_1_fdw h_1))
         ->  Async Foreign Scan  (cost=0.99..0.99 rows=1 width=8) (actual time=0.016..0.017 rows=1 loops=1)
               Relations: Aggregate on ((pgbench_branches_2_fdw b_2) INNER JOIN (pgbench_history_2_fdw h_2))
...
 Planning Time: 7.729 ms
 Execution Time: 14.603 ms

Обратите внимание, что сторонние сканирования здесь включают список соединённых отношений. Ожидаемая стоимость стороннего соединения ниже 1,0. Это связано с оптимистичной методикой оценки стоимости стороннего соединения, включённой настройкой postgres_fdw.enforce_foreign_join. Сравните общее время выполнения (время планирования + время выполнения) исходного и изменённого запроса — его удалось уменьшить примерно с 40 до 22 мс.

В целом, изучая планы запросов, следует обращать внимание на то, какие запросы на самом деле проталкиваются. Некоторые распространённые причины, по которым соединения не могут быть протолкнуты, — это отсутствие эквивалентных соединений по ключу сегментирования и фильтры, содержащие непостоянные функции (возможно, неявно). Если данные извлекаются из нескольких групп репликации, проверьте, что выполнение в основном асинхронно.

5.1.1. Параметры EXPLAIN

В этом разделе описываются параметры EXPLAIN, специфичные для Shardman.

NETWORK (boolean)

Включать в вывод команды EXPLAIN ANALYZE фактическую передачу данных между узлами. Если параметр не указан, предполагается значение off. Если параметр указан без значения, предполагается значение on.

REMOTE (boolean)

Включать планы запросов, выполненных на внешних серверах. Если параметр не указан или его значение не задано, предполагается значение on.

5.2. Оптимизация DML

При оценке производительности операторов DML важно понимать, как они обрабатываются в Shardman.

Прежде всего, выполнение оператора INSERT существенно отличается от выполнения UPDATE и DELETE. Поведение INSERT для сегментированных таблиц контролируется параметром стороннего сервера batch_size, который можно установить в разделе FDWOptions файла конфигурации Shardman. Если batch_size больше 0, INSERT в одном операторе для нескольких значений, которые попадают в одну и ту же стороннюю секцию, приводит к тому, что значения группируются вместе в порции указанного размера. Удалённые операторы INSERT подготавливаются с необходимым количеством параметров и затем выполняются с заданными значениями. Если количество значений не совпадает с количеством подготовленных аргументов, снова подготавливается изменённый оператор с необходимым количеством параметров. Оптимизация массовой вставки может завершиться ошибкой, если транзакция вставляет записи одну за другой или записи, направляемые в разные сторонние таблицы, смешиваются в одном операторе INSERT. Порция формируется для одной операции стороннего изменения. Она отправляется на удалённый сервер при заполнении порции или при завершении операции изменения. Операция изменения завершается, когда кортежи начинают перенаправляться в другую секцию сегментированной таблицы. Таким образом, для массовой загрузки рекомендуется вставка нескольких значений в одной команде INSERT или использование команды COPY (поскольку она оптимизируется аналогичным образом). Большие значения batch_size позволяют выдавать меньше операторов INSERT на удалённой стороне и, таким образом, значительно снижают стоимость связи. Однако при формировании параметров для подготовленных операторов INSERT все вставленные значения должны быть скопированы в память, выделенную libpq. Это может привести к неограниченному использованию памяти на стороне координатора запросов при загрузке нескольких больших объектов text или bytea.

Операторы UPDATE и DELETE могут выполняться в прямом или непрямом режиме. Прямой режим используется, когда оператор может быть напрямую отправлен на сторонний сервер. В этом режиме для изменения таблицы на удалённом сервере создаётся новый оператор на основе исходного узла плана ModifyTable. Использование прямого изменения не всегда возможно. В частности, оно невозможно когда некоторые условия должны оцениваться локально. В этом случае используется гораздо менее эффективное непрямое изменение. Непрямое изменение включает в себя несколько операторов. Первый — SELECT FOR UPDATE для блокировки строк на удалённой части. Второй — фактический UPDATE или DELETE, который готовится один раз, а затем выполняется с разными параметрами для каждой строки результата оператора SELECT FOR UPDATE после применения к результаты локальных фильтров. Очевидно, что прямые модификации намного эффективнее.

Можно легко определить, в прямом или непрямом режиме будет выполняться оператор DML, посмотрев на план запроса. Типичный пример непрямого изменения:

EXPLAIN VERBOSE DELETE FROM pgbench_history
WHERE bid = 20 AND mtime > '2023-03-14 10:00:00'::timestamptz;
                                                  QUERY PLAN
--------------------------------------------------------------------------------------------------------------
 Delete on public.pgbench_history  (cost=100.00..142.66 rows=0 width=0)
   Foreign Delete on public.pgbench_history_17_fdw pgbench_history_1
     Remote SQL: DELETE FROM public.pgbench_history_17 WHERE ctid = $1
   ->  Foreign Scan on public.pgbench_history_17_fdw pgbench_history_1  (cost=100.00..142.66 rows=4 width=10)
         Output: pgbench_history_1.tableoid, pgbench_history_1.ctid
         Filter: (pgbench_history_1.mtime > '2023-03-14 10:00:00+03'::timestamp with time zone)
         Remote SQL: SELECT mtime, ctid FROM public.pgbench_history_17 WHERE ((bid = 20)) FOR UPDATE

При выборе другого типа строковой константы это было бы прямым изменением.

EXPLAIN VERBOSE DELETE FROM pgbench_history
WHERE bid = 20 AND mtime > '2023-03-14 10:00:00'::timestamp;
explain verbose delete from pgbench_history where bid = 20 and mtime > '2023-03-14 10:00:00'::timestamp;
                                                                   QUERY PLAN
-------------------------------------------------------------------------------------------------------------------------------------------------
 Delete on public.pgbench_history  (cost=100.00..146.97 rows=0 width=0)
   Foreign Delete on public.pgbench_history_17_fdw pgbench_history_1
   ->  Foreign Delete on public.pgbench_history_17_fdw pgbench_history_1  (cost=100.00..146.97 rows=4 width=10)
         Remote SQL: DELETE FROM public.pgbench_history_17 WHERE ((mtime > '2023-03-14 10:00:00'::timestamp without time zone)) AND ((bid = 20))

Видно, что в режиме прямого изменения на удалённом сервере выполняется только один оператор.

5.2.1. Оптимизация DML для глобальных таблиц

Настраиваемый параметр конфигурации shardman.gt_batch_size задаёт размер промежуточного буфера до отправки данных на удалённый сервер.

Операция INSERT использует бинарный протокол и формирует порции данных размером shardman.gt_batch_size. Высокие значения размера буфера позволяют выдавать меньше запросов по сети на удалённой стороне и, таким образом, значительно снижают стоимость связи. Однако это может привести к неограниченному использованию памяти на стороне координатора запросов. Поэтому важно найти золотую середину между стоимостью связи и размером используемой памяти.

Для операции UPDATE на координаторе формируется запрос для каждого столбца и каждой строки и отправляется на удалённые узлы.

Для операции DELETE на координаторе формируется запрос для порции данных с размером shardman.gt_batch_size и рассылается на удалённые узлы.

5.3. Синхронизация по времени

Алгоритм, обеспечивающий согласованность данных на всех узлах кластера, использует время системных часов, установленных на машине. Таким образом, зависит от расхождения времени на разных машинах, поскольку координатор запросов всегда дожидается машины с наибольшим отставанием. Поэтому принципиально важно, чтобы время на всех связанных узлах кластера Shardman было синхронизировано, поскольку отсутствие этой синхронизации может негативно повлиять на производительность Shardman из-за увеличенной задержки фиксации транзакции.

Во-первых, для обеспечения синхронизации времени на всех узлах кластера установите и разверните демон chrony.

  sudo apt update
  sudo apt install -y chrony
  sudo systemctl enable --now chrony

Проверьте, что chrony работает правильно.

chronyc tracking

Ожидаемый вывод:

      Reference ID    : C0248F82 (Time100.Stupi.SE)
      Stratum         : 2
      Ref time (UTC)  : Tue Apr 18 11:50:44 2023
      System time     : 0.000019457 seconds slow of NTP time
      Last offset     : -0.000005579 seconds
      RMS offset      : 0.000089375 seconds
      Frequency       : 30.777 ppm fast
      Residual freq   : -0.000 ppm
      Skew            : 0.003 ppm
      Root delay      : 0.018349268 seconds
      Root dispersion : 0.000334640 seconds
      Update interval : 1039.1 seconds
      Leap status     : Normal

Обратите внимание, что контроль величины расхождения часов должен выполняться инструментарием операционной системы. Средства диагностики Shardman не могут являться единственным достоверным средством измерения.

Чтобы проверить, существует ли на данный момент существенная рассинхронизация, используйте представление shardman.pg_stat_csn, которое выводит статистику задержек, возникающих во время импорта снимков CSN. Расчёт значений производится непосредственно в момент соответствующего действия или при вызове функций shardman.trim_csnxid_map() или shardman.pg_oldest_csn_snapshot(). Вызов этих функций осуществляется из служебного процесса csn trimmer routine (процесс усечения CSN), поэтому его отключение приведёт к остановке сбора этой статистики.

Поле csn_max_shift представления shardman.pg_stat_csn отображает максимальную задержку снимка CSN, вызвавшего задержку. Это значение определяет расхождение часов между узлами кластера. Последовательный рост этого значения является индикатором того, что в кластере есть по крайней мере одни часы, не синхронизованные с другими. Если данное значение превышает 1000 микросекунд, рекомендуется проверить параметры синхронизации по времени.

Другим индикатором расхождения может быть повышение значения csn_total_import_delay при неизменном значении csn_max_shift. Однако разовое повышение может быть вызвано единичным сбоем, а не проблемами с синхронизацией по времени.

Кроме того, если разница между CSNXidMap_head_csn и shardman.oldest_csn превышает значение параметра csn_snapshot_defer_time и долгое время не меняется, это значит, что заполнилась карта CSNSnapshotXidMap. Это может привести к сбою глобальной транзакции.

У этой проблемы две возможные причины.

В системе существует длительная активная транзакция, которая живет больше csn_snapshot_defer_time секунд и этим удерживает горизонт во всем кластере, препятствуя нормальной работе VACUUM. В этом случае следует использовать значение поля xid представления shardman.oldest_csn для определения идентификатора этой транзакции и значение поля rgid для определения узла кластера, на котором эта транзакция запущена.

Карта CSNSnapshotXidMap имеет недостаточный размер. При штатной работе системы могут быть транзакции, которые выполняются дольше csn_snapshot_defer_time секунд. Следует увеличить значение csn_snapshot_defer_time до такого размера, чтобы длительность таких транзакций не превышала этого значения.

При выполнении команды EXPLAIN для распределённых запросов, при включённом параметре конфигурации shardman.silk_tracepoints выводится информация о трассировке времени прохождения запроса и результата его выполнения по компонентам системы. Эта информация состоит из строк со значениями метрик, которые показывают время прохождения через каждый компонент. Метрики net (qry), net (1st tup) и net (last tup) вычисляются как разница отметок времени на разных серверах. Эта величина включает в себя время передачи сообщения и величину (положительную или отрицательную) сдвига часов между серверами. Таким образом, по величине этих метрик возможно косвенно оценить расхождение часов между серверами.

5.4. Диагностика распределённых запросов

Shardman расширяет возможности команды EXPLAIN, предоставляя дополнительную информацию по запросу, если он распределённый. Работа с распределёнными таблицами построена на узлах плана с типом ForeignScan. Запрос к каждой удалённой секции определяется одним узлом плана такого типа. При этом Shardman предоставляет дополнительную информацию в блоки EXPLAIN, описывающие эти узлы.

При выполнении распределённого запроса часть плана (поддерево), которая касается конкретной удалённой секции, сериализуется в SQL-выражение (происходит deparsing). После этого такое выражение отправляется на удалённый сервер. Результат выполнения этого запроса виден в выводе для узла ForeignScan. Он участвует в сборке окончательного результата выполнения распределённого запроса.

Когда задано значение on для параметра VERBOSE команды EXPLAIN, в блоке узла ForeignScan в поле Remote SQL будет показано выражение, отправляемое на удалённый сервер. При этом в поле Server будет указано имя сервера в том же виде, в каком оно задано при конфигурировании кластера и как оно отображается в каталоге pg_foreign_server, а также вид транспорта, применяющегося для отправки этого выражения. Поле transport может принимать два значения: silk для использования оптимизированного транспортного механизма Shardman или libpq для отправки через стандартный протокол PostgreSQL.

5.4.1. Показ планов с удалённого сервера

Чтобы увидеть под блоком EXPLAIN узла ForeignScan, какой план выполнения будет реализован на удалённом сервере, используется параметр конфигурации postgres_fdw.foreign_explain. Возможные значения: none не включает вывод EXPLAIN с удалённых серверов, full включает вывод EXPLAIN с удалённых серверов для всех узлов ForeignScan, collapsed включает вывод EXPLAIN только для первого узла ForeignScan под узлами Append/MergeAppend.

В производственной системе рекомендуется выключать этот параметр (задать значение none) или оставлять его со значением collapsed, так как получение любого фрагмента EXPLAIN является дополнительным неявным запросом к серверу. Кроме того, этот запрос выполняется в синхронном режиме, то есть общий вывод EXPLAIN будет построен после последовательного опроса всех серверов. Для таблиц с большим количеством секций это может быть затратной операцией.

Необходимо учитывать, что внутренний запрос на получение блоков EXPLAIN для удалённого плана осуществляется с принудительным отключением некоторых параметров (вне зависимости от того, какие параметры указал пользователь при запросе EXPLAIN от координатора): ANALYZE OFF, TIMING OFF, SUMMARY OFF, SETTINGS OFF, NETWORK OFF. Соответствующие метрики в блоках EXPLAIN удалённого плана будут отсутствовать. Остальные параметры EXPLAIN (FORMAT, VERBOSE, COSTS, BUFFERS, WAL) наследуются с координатора.

Если в результате сериализация подплана выполнения в SQL формируется выражение, включающее в себя параметры (аргументы, представленные в выражении при помощи символов $1, $2), такое выражение в целом нельзя отправить на удалённый сервер для получения результата EXPLAIN. Поэтому для SQL-выражений с параметрами построение блоков ForeignExplain не осуществляется.

5.4.2. Сетевые метрики и время ожидания

При включённом параметре NETWORK команды EXPLAIN как для отдельных узлов плана ForeignScan, так и для общих узлов Append или MergeAppend отображаются метрики сетевых операций.

Для каждого узла плана отображаются параметры FDW bytes, sent и received для исходящего и входящего трафика, потраченного при выполнении этого узла (вне зависимости от вида транспорта). Необходимо учитывать, что эти метрики выводятся, только если задано значение on параметра ANALYZE команды EXPLAIN.

При включённом параметре конфигурации track_fdw_wait_timing дополнительно выводится метрика wait_time. Она обобщает все этапы выполнения данного узла плана, начиная от отправки запроса на удалённый сервер, включая время, потраченное собственно на выполнение запроса, а также время до получения полного объёма результатов для этого узла плана.

Необходимо учитывать, что узел ForeignScan может выполняться как в синхронном, так и в асинхронном режиме. В случае асинхронного выполнения функция выполнения узла отправляет запрос на удалённый сервер и завершает выполнение, не дожидаясь получения результата, который будет учтён и обработан позже, по факту получения. В этом случае метрика wait_time может не отражать реальное время выполнения.

5.4.3. Трассировка прохождения запроса для транспорта Silk

Для транспорта Silk существует возможность вывести расширенную отладочную информацию по трассировке прохождения запроса от координатора на удалённый сервер, включающую получение результатов с удалённого сервера. Эта информация отображается, если задано значение on для параметра ANALYZE команды EXPLAIN и включён параметр конфигурации shardman.silk_tracepoints.

При включении этого режима каждое сообщение, передаваемое через транспорт Silk (отправка SQL-запроса, доставка его адресату, выполнение там этого запроса и передача результата выполнения обратно), сопровождается массивом отметок времени, измеренного в некоторых точках конвейера. После выполнения такого запроса эта информация будет показана в блоке EXPLAIN в виде строк, начинающихся со слова Trace. Каждая такая метрика является разницей между отметками времени в разных точках и выводится в миллисекундах:

Таблица 5.1. Метрики трассировки прохождения запроса для транспорта Silk

Интервал | Описание
bk shm->mp1 (qry) | Время передачи SQL-запроса от координатора к его мультиплексору через общую память.
mp1 shm->net (qry) | Время между приёмом запроса внутри мультиплексора из общей памяти и передачей по сети.
net (qry) | Время прохождения SQL-запроса по сети между мультиплексорами.
mp2 recv->shm (qry) | Время между приёмом SQL-запроса из сети и передачей в очередь в общей памяти на удалённом мультиплексоре.
wk exec (1st tup) | Время выполнения запроса на Silkworm до получения первой строки результата.
wk exec (all tups) | Время выполнения запроса на Silkworm до получения полного результата.
wk->shm (1st tup) | Время передачи в очередь Silkworm первой строки результата.
wk->shm (last tup) | Время передачи в очередь Silkworm последней строки результата.
mp2 shm->net (1st tup) | Время между чтением из очереди удалённым мультиплексором первой строки результата и передачей её в сеть.
net (1st tup) | Время передачи по сети первой строки результата между мультиплексорами.
mp1 recv->shm (1st tup) | Время между приемом из сети и передачей в очередь первой строки результата локальным мультиплексором.
mp1 shm->bk (1st tup) | Время получения координатором из очереди первой строки результата.
mp2 shm->net (last tup) | Время между чтением из очереди удалённым мультиплексором последней строки результата и передачей её в сеть.
net (last tup) | Время передачи по сети между мультиплексорами последней строки результата.
mp1 recv->shm (last tup) | Время между приёмом из сети и передачей в очередь последней строки результата локальным мультиплексором.
mp1 shm->bk (last tup) | Время получения координатором из очереди последней строки результата.
END-TO-END | Общее время от отправки запроса до получения последней строки результата. Примерно совпадает с wait_time.

Для метрик net (qry), net (1st tup) и net (last tup) значение интервала считается как разница отметок времени, измеренных на разных серверах. Поэтому в этих строках допускается появление отрицательных значений. Величина такого интервала по сути представляет собой сумму времени передачи сообщения по сети и величины (положительной или отрицательной) сдвига часов между серверами. Поэтому даже при незначительном сдвиге, если его абсолютное значение превышает длительность передачи по сети, будут встречаться отрицательные значения. Несмотря на то, что это не является сбоем, при достаточно больших значениях необходимо удостовериться в правильной синхронизации времени в кластере. Более подробно информация описана в Разделе 5.3.

Глава 6. Справочное руководство по Shardman

Статьи этого справочного руководства составлены так, чтобы дать авторитетную, полную и формальную сводку в разумном объёме по соответствующим темам. Дополнительные сведения об использовании Shardman в повествовательной, ознакомительной или показательной форме можно найти в других частях этой книги. Ссылки на них содержатся на страницах этого руководства.

6.1. Функции

shardman.broadcast_all_sql(statement text )

Выполняет оператор в каждой группе репликации.

Предупреждение

Функция shardman.broadcast_all_sql не может выполняться рекурсивно. Попытка это сделать приводит к ошибке «Command execution must be initiated by coordinator» (Выполнение команды должно инициироваться координатором).

shardman.broadcast_query(statement text)

Действует аналогично shardman.broadcast_all_sql, а также возвращает результаты исполняемого выражения SQL.

Можно задать необязательный параметр include_rgid, тогда в результирующих кортежах будет номер узла, из которого получен кортеж.

Пример с отключённым параметром include_rgid:

SELECT shardman.broadcast_query('SELECT relname FROM pg_class WHERE relkind=''f''');
broadcast_query
-----------------
(t_1_fdw)
(t_2_fdw)
(t_0_fdw)
(t_2_fdw)
(t_0_fdw)
(t_1_fdw)
(6 rows)

Пример с включённым параметром include_rgid:

SELECT shardman.broadcast_query('SELECT relname FROM pg_class WHERE relkind=''f''', include_rgid => true);
broadcast_query
-----------------
(1,t_1_fdw)
(1,t_2_fdw)
(2,t_0_fdw)
(2,t_2_fdw)
(3,t_0_fdw)
(3,t_1_fdw)
(6 rows)

shardman.broadcast_sql(statement text)

Выполняет оператор в каждой группе репликации, кроме текущей.

Предупреждение

Функция shardman.broadcast_sql не может выполняться рекурсивно. Попытка это сделать приводит к ошибке «Command execution must be initiated by coordinator» (Выполнение команды должно быть инициироваться координатором).

shardman.get_partition_for_value(relid oid, val variadic "any") → shardman.get_partition_for_value_type ( rgid int, local_nspname text, local_relname text, remote_nspname text, remote_relname text)

Выясняет, к какой секции сегментированной таблицы с oid relid принадлежит val. Возвращает NULL, если сегментированная таблица с oid relid не существует. Возвращает имя локальной схемы и имена отношений. Если значение принадлежит секции, хранящейся в другой группе репликации, также возвращает удалённую схему и имя отношения. Возвращает только rgid, если используется секционирование второго уровня.

Пример:

select * from  shardman.get_partition_for_value('pgbench_branches'::regclass, 20);
 rgid | local_nspname |      local_relname      | remote_nspname |   remote_relname
------+---------------+-------------------------+----------------+---------------------
    3 | public        | pgbench_branches_17_fdw | public         | pgbench_branches_17

shardman.global_analyze()

Выполняет кластерный анализ сегментированных и глобальных таблиц. Сначала эта функция выполняет ANALYZE для всех локальных секций сегментированных таблиц на каждом узле, а затем отправляет эту статистику на другие узлы. Затем она выбирает один узел для каждой глобальной таблицы и запускает ANALYZE этой таблицы на выбранном узле. Собранная статистика транслируется на все остальные узлы кластера.

Пример:

select shardman.global_analyze();

shardman.attach_subpart(relid regclass, snum int, partition_bound text[])

Присоединяет ранее отсоединённую подсекцию с номером snum к локально секционированной таблице relid в качестве секции для указанных значений в диапазоне partition_bound. Все таблицы подсекции и сторонние таблицы уже должны существовать. Параметр partition_bound — это пара нижней и верхней границ секции. Если и нижняя, и верхняя границы равны NULL, подсекция присоединятся как стандартная.

Операция выполняется на уровне кластера.

Пример:

select shardman.attach_subpart('pgbench_history'::regclass, 1,$${'2021-01-01 00:00', '2022-01-01 00:00'}$$);

shardman.create_subpart(relid regclass, snum int, partition_bound text[])

Создаёт подсекцию с номером snum для локально секционированной таблицы relid в качестве секции для значений в диапазоне partition_bound. Параметр partition_bound — это пара нижней и верхней границ секции. Если и нижняя, и верхняя границы равны NULL, подсекция создаётся как стандартная. Если номер подсекции не указан, он будет выбран в качестве следующего доступного номера секции.

Операция выполняется на уровне кластера.

Примеры:

select shardman.create_subpart('pgbench_history'::regclass, 1, $${'2021-01-01 00:00', '2022-01-01 00:00'}$$);
select shardman.create_subpart('pgbench_history'::regclass, partition_bound:=$${'2022-01-01 00:00', '2023-01-01 00:00'}$$);

shardman.detach_subpart(relid regclass, snum int)

Отсоединяет подсекцию с номером snum от локально секционированной таблицы relid. Номер секции можно определить из представления shardman.subparts.

Операция выполняется на уровне кластера.

Пример:

select shardman.detach_subpart('pgbench_history'::regclass, 1);

shardman.drop_subpart(relid regclass, snum int)

Удаляет подсекцию с номером snum из локально секционированной таблицы relid. Номер секции можно определить из представления shardman.subparts.

Операция выполняется на уровне кластера.

Пример:

select shardman.drop_subpart('pgbench_history'::regclass, 1);

shardman.am_coordinator()

Проверяет, является ли текущий сеанс координатором запроса. Данная проверка позволят избежать случаев повторного срабатывание триггеров глобальных и сегментированных таблиц, когда триггер срабатывает сначала в координаторе запроса, а потом на удалённых узлах при изменении данных.

SELECT shardman.am_coordinator();
am_coordinator
----------------
t
(1 row)

Пример проверки триггерной функцией координатора запросов:

CREATE OR REPLACE FUNCTION trg_func() RETURNS TRIGGER
AS $$
BEGIN
IF NOT shardman.am_coordinator() THEN
        -- exit on non coordinator
        RETURN NEW;
END IF;
-- execute only by coordinator
RAISE WARNING 'Trigger fired!';
END
$$ LANGUAGE plpgsql;

shardman.silk_statinfo_reset()

Сбрасывает значение метрик с префиксом transferred_ и временных метрик (с префиксами read_efd_, write_efd_ и sort_time_) в представлении shardman.silk_statinfo.

shardman.silk_routing

Выводит результаты функций мультиплексора silk_connects, silk_backends и silk_routes.

shardman.silk_rbc_snap

Выводит согласованный снимок всех соединений, процессов и маршрутов, которые могут использоваться функциями silk_connects, silk_backends и silk_routes.

6.2. Функции pgpro_stats

pgpro_stats_sdm_stats_updated

возвращает количество записей статистики, полученных от каждого узла сегмента, и метку времени последней полученной статистики.

pgpro_stats_sdm_stats_updated_reset

сбрасывает указанную выше информацию.

6.3. Функции рекомендательных блокировок

Рекомендательные блокировки — это необязательные блокировки, распространяющиеся на весь кластер. Ниже приведён список функций для работы с такими блокировками.

Таблица 6.1. Функции рекомендательных блокировок

Функция | Результат
shardman.advisory_xact_lock(key64 BIGINT); | void
shardman.advisory_xact_lock_shared(key64 BIGINT); | void
shardman.try_advisory_xact_lock(key64 BIGINT); | bool
shardman.try_advisory_xact_lock_shared(key64 BIGINT); | bool
shardman.advisory_xact_lock(key1 INT, key2 INT); | void
shardman.advisory_xact_lock_shared(key1 INT, key2 INT); | void
shardman.try_advisory_xact_lock(key1 INT, key2 INT); | bool
shardman.try_advisory_xact_lock_shared(key1 INT, key2 INT); | bool

6.4. Представления

6.4.1. Представления, специфичные для Shardman

6.4.1.1. shardman.pg_stat_csn

В представлении shardman.pg_stat_csn содержится одна строка, показывающая статистику задержек, возникающих во время импорта снимков CSN. Эти задержки возникают из-за того, что системные часы на узлах кластера Shardman могут быть не синхронизированы. Задержки негативно влияют на производительность, увеличивая задержку запросов. Представление shardman.pg_stat_csn позволяет отслеживать эти задержки. Представление основано на данных Сборщика статистики. Столбцы представления показаны в Таблице 6.2.

Таблица 6.2. Столбцы shardman.pg_stat_csn

Name | Тип | Описание
csn_snapshots_imported | bigint | Общее количество импортированных снимков CSN
csn_total_import_delay | interval | Суммарная продолжительность всех задержек при импорте снимков CSN, в микросекундах
csn_max_shift | bigint | Максимальное зарегистрированное смещение CSN снимка, вызвавшее задержку
local_oldest_csn | bigint | CSN старейшей транзакции на текущем узле
local_oldest_xid | xid | XID старейшей транзакции на текущем узле
indoubt_threshold_incidents | bigint | Общее количество транзакций, превысивших 10-секундный порог нахождения в состоянии inDoubt.
CSNXidMap_head_csn | bigint | Последний CSN в CSNSnapshotXidMap
CSNXidMap_head_xid | xid | XID, соответствующий последнему CSN в CSNSnapshotXidMap
CSNXidMap_tail_csn | bigint | Старейший CSN в CSNSnapshotXidMap
CSNXidMap_tail_xid | xid | XID, соответствующий старейшему CSN в CSNSnapshotXidMap
stats_reset | timestamp with time zone | Последнее время сброса этих статистических данных
CSNXidMap_last_trim | timestamp with time zone | Показывает время последнего вызова функции shardman.trim_csnxid_map().

Чтобы сбросить статистику, связанную с CSN, вызовите функцию pg_stat_reset_shared с единственным текстовым аргументом, равным csn.

Примечание

Функциональность Shardman, связанная со снимками CSN, находится в стадии разработки. Поэтому в будущих выпусках ожидаются изменения в соответствующих представлениях.

6.4.1.2. shardman.pg_indoubt_xacts

Представление shardman.pg_indoubt_xacts отображает информацию о транзакциях, находящихся в состоянии InDoubt. Элемент удаляется, когда состояние транзакции меняется.

Таблица 6.3. Столбцы shardman.pg_indoubt_xacts

Name | Тип | Описание
xid | xid | Идентификатор транзакции, находящейся в состоянии InDoubt
duration_msec | bigint | Время, которое транзакция находилась в состоянии inDoubt, в миллисекундах

Когда запрашивается представление pg_prepared_xacts, внутренние структуры данных менеджера транзакций на мгновение блокируются и создаётся их копия для вывода через это представление. Это гарантирует, что представление выдаёт согласованный набор результатов, при этом не задерживая обычные операции на более продолжительное время, чем необходимо. Тем не менее это может отрицательно сказаться на производительности базы данных при частых обращениях к представлению.

6.4.1.3. shardman.pg_stat_xact_time

В представлении shardman.pg_stat_xact_time отображается статистика о затраченном на транзакцию времени. Столбцы представления приведены в разделе Таблица 6.4.

Таблица 6.4. Столбцы shardman.pg_stat_xact_time

Name | Тип | Описание
overall_committed_xact_time | bigint | Общее время, затраченное на зафиксированные транзакции
overall_aborted_xact_time | bigint | Общее время, затраченное на прерванные транзакции
overall_commit_time | bigint | Общее время, затраченное на фиксирование транзакций
local_commit_time | bigint | Общее время, затраченное на запись в WAL для всех зафиксированных транзакций
global_commit_time | bigint | Общее время, затраченное на отправку распределёнными запросами сообщений о статусах транзакций для всех зафиксированных транзакций
overall_abort_time | bigint | Общее время, затраченное на прерывание транзакций
local_abort_time | bigint | Общее время, затраченное на запись в WAL для всех прерванных транзакций
global_abort_time | bigint | Общее время, затраченное распределёнными запросами на отправку сообщений о статусах транзакций для всех прерванных транзакций
stats_reset | timestamp with time zone | Последнее время сброса этих статистических данных

6.4.1.4. shardman.oldest_csn

В представлении shardman.oldest_csn содержится одна строка, показывающая csn кортежа, xid и rgid с CSN и XID самой старой транзакции в кластере, а также номер группы репликации транзакции.

6.4.1.5. shardman.pg_stat_monitor

В представлении shardman.pg_stat_monitor содержится одна строка с метриками Shardman monitor. Данные этого представления основаны на Сборщике статистики. Столбцы представления описаны в Таблице 6.5.

Таблица 6.5. Столбцы shardman.pg_stat_monitor

Name | Тип | Описание
resolved_deadlocks | bigint | Число снятых распределённых взаимоблокировок
aborted_xacts | bigint | Число прерванных устаревших подготовленных транзакций
committed_xacts | bigint | Число зафиксированных устаревших подготовленных транзакций
errors | bigint | Число ошибок Shardman monitor
stats_reset | timestamp with time zone | Последнее время сброса этих статистических данных

6.4.1.6. shardman.pg_stat_netusage

В представлении shardman.pg_stat_netusage содержится одна строка, показывающая общий объём данных, передаваемых по сети между узлами кластера Shardman. Данные этого представления основаны на Сборщике статистики. Столбцы представления описаны в Таблице 6.6.

Таблица 6.6. Столбцы shardman.pg_stat_netusage

Name | Тип | Описание
netusage_recv_bytes | numeric | Общее количество байтов, полученных по сети от других узлов каждым узлом кластера Shardman
netusage_sent_bytes | numeric | Общее количество байтов, отправленных по сети другим узлам каждым узлом кластера Shardman
stats_reset | timestamp with time zone | Последнее время сброса этих статистических данных

6.4.1.7. shardman.pg_stat_foreign_stat_bytes

В представлении shardman.pg_stat_foreign_stat_bytes показывается объём статистики для сторонних отношений, передаваемый по сети между узлами кластера Shardman. Данные этого представления основаны на Сборщике статистики. Столбцы представления описаны в Таблице 6.7.

Таблица 6.7. Столбцы shardman.pg_stat_foreign_stat_bytes

Name | Тип | Описание
foreign_stat_recv_bytes | bigint | Общее количество байтов статистики для сторонних отношений, полученных этим узлом по сети от других узлов
stats_reset | timestamp with time zone | Последнее время сброса этих статистических данных

6.4.1.8. Глобальные представления, специфичные для Shardman

6.4.1.8.1. shardman.gv_sharded_tables

В представлении показываются все сегментированные таблицы кластера.

6.4.1.8.2. shardman.gv_global_tables

В представлении показываются все глобальные таблицы кластера.

6.4.2. Диагностические представления для мультиплексора

Представления в данном разделе отображают информацию о процессе мультиплексирования Silk. Более подробная информация о процессе мультиплексирования silkroad представлена в разделе Раздел 7.4.

6.4.2.1. shardman.silk_routes

В представлении shardman.silk_routes отображается снимок актуального состояния таблицы маршрутов мультиплексора. Столбцы этого представления приведены в разделе Таблица 6.8.

Таблица 6.8. Столбцы shardman.silk_routes

Name
Тип
Описание

hashvalue
integer
Внутренний уникальный идентификатор маршрута. Он может использоваться для соединения с другими диагностическими представлениями Silk.

origin_ip
inet
IP-адрес узла-источника, сгенерировавшего данный маршрут

origin_port
int2
Внешний порт соединения по протоколу TCP узла-источника, сгенерировавшего данный маршрут

channel_id
integer
Порядковый номер маршрута в пределах узла, который сгенерировал данный маршрут. channel_id уникален для пары origin_ip + origin_port. Данная пара является уникальным идентификатором узла в кластере Shardman, и, таким образом, кортеж, состоящий из origin_ip + origin_port + channel_id, является уникальным идентификатором маршрута в кластере Shardman.

from_cn
integer
Для входящих маршрутов (то есть маршрутов, не сгенерированных данным узлом) содержит индекс соединения в представлении shardman.silk_connects, а для сгенерированных данным узлом маршрутов — -1.

backend_id
integer
Идентификатор локального процесса, который в данный момент использует этот маршрут: либо идентификатор обслуживающего процесса, сгенерировавшего этот маршрут, либо идентификатор рабочего процесса silkworm, которому назначен маршрут. Для входящих маршрутов в очереди заданий, которые ещё не назначены рабочим процессам, — -1.

pending_queue_bytes
bigint
Размер очереди отложенных сообщений (ожидающих свободный рабочий процесс) для данного маршрута, в байтах. Это значение применимо только для входящих маршрутов каждого узла, которым ещё не назначен рабочий процесс.

pending_queue_messages
bigint
Число сообщений в очереди отложенных сообщений в ожидании рабочего процесса для данного маршрута. Это значение применимо только для входящих маршрутов каждого узла, которым ещё не назначен рабочий процесс.

connects
integer[]
Список индексов соединений, которые сейчас используют данный маршрут.

6.4.2.2. shardman.silk_connects

В представлении shardman.silk_connects отображается список текущих соединений мультиплексора. Столбцы представления приведены в разделе Таблица 6.9.

Таблица 6.9. Столбцы shardman.silk_connects

Name | Тип | Описание
cn_index | integer | Уникальный индекс соединения
reg_ip | inet | «Регистрационный» IP-адрес узла, с которым установлено соединение. Более подробное описание представлено в разделе Примечания.
reg_port | int2 | «Регистрационный» TCP-порт узла, с которым установлено соединение. Более подробное описание представлено в разделе Примечания.
read_ev_active | boolean | true, если мультиплексор готов к получению данных во входящую очередь. Более подробное описание представлено в разделе Примечания.
write_ev_active | boolean | true, если мультиплексор заполнил очередь неотправленными сообщениями и ожидает её освобождения. Более подробная информация представлена в разделе Примечания.
is_outgoing | boolean | true для исходящих соединений (созданных командой connect), false для входящих соединений (созданных командой accept). Используется только в процессе начального согласования.
state | text | Текущее состояние соединения: connected — соединение установлено, in progress — клиент уже подключился, но начальное согласование ещё не произошло, и free — клиент отключился, но соединение ещё не было разорвано.
pending_queue_bytes | bigint | Размер очереди неотправленных сообщений для данного соединения, в байтах
pending_queue_messages | bigint | Число сообщений в очереди из неотправленных сообщений для данного соединения
blocked_by_backend | integer | Идентификатор обслуживающего процесса, блокирующего данное соединение
blocks_backends | integer[] | Список идентификаторов обслуживающих процессов, заблокированных данным соединением
routes | integer[] | Список уникальных идентификаторов маршрутов, использующих данное соединение
elapsed_time_write | bigint | Время с последней записи подключения
elapsed_time_read | bigint | Время с последнего чтения подключения

6.4.2.3. shardman.silk_backends

В представлении shardman.silk_backends отображается список текущих процессов двух типов: обслуживающие процессы для клиентских соединений и рабочие процессы silkworm мультиплексора, которые с ним взаимодействуют. Столбцы данного представления описаны в разделе Таблица 6.10.

Таблица 6.10. Столбцы shardman.silk_backends

Name | Тип | Описание
backend_id | integer | Уникальный идентификатор обслуживающего/рабочего процесса
pid | integer | Идентификатор процесса ОС
attached | boolean | Приобретает значение true, если процесс привязан к мультиплексору, в противном случае false
read_ev_active | boolean | true, если обслуживающий/рабочий процесс готов к получению данных во входящую очередь. Более подробное описание представлено в разделе Примечания.
write_ev_active | boolean | true, если обслуживающий/рабочий процесс заполнил очередь неотправленных сообщений и ожидает её освобождения. Более подробное описание представлено в разделе Примечания.
is_worker | boolean | true, если данный процесс — это рабочий процесс silkworm мультиплексора; false, если любой другой
pending_queue_bytes | bigint | Размер очереди сообщений, отправляемых этому обслуживающему/рабочему процессу, в байтах
pending_queue_messages | bigint | Число сообщений в очереди сообщений, отправляемых этому обслуживающему/рабочему процессу
blocked_by_connect | integer | Индекс соединения, блокирующего данный обслуживающий/рабочий процесс
blocks_connects | integer[] | Список индексов соединений, заблокированных данным обслуживающим/рабочим процессом
routes | integer[] | Список уникальных идентификаторов маршрутов, используемых данным обслуживающим/рабочим процессом
in_queue_used | bigint | Объём данных входящей очереди в байтах в общей памяти между обслуживающим процессом и мультиплексором
out_queue_used | bigint | Объём данных (в байтах) исходящей очереди в общей памяти между обслуживающим процессом и мультиплексором
elapsed_time_write | bigint | Время с последней записи рабочего процесса
elapsed_time_read | bigint | Время с последнего чтения с рабочего процесса

6.4.2.4. shardman.silk_routing

В представлении shardman.silk_routing отображается результат работы функции shardman.silk_routing. Столбцы этого представления приведены в Таблице 6.11.

Таблица 6.11. Столбцы shardman.silk_routing

Name
Тип
Описание

hashvalue
integer
Внутренний уникальный идентификатор маршрута

origin_ip
inet
IP-адрес узла, сгенерировавшего данный маршрут

origin_port
int2
Внешний порт соединения по протоколу TCP узла-источника, сгенерировавшего данный маршрут

channel_id
integer
Порядковый номер маршрута в пределах узла, сгенерировавшего данный маршрут

is_outgoing
boolean
true, если маршрут был создан исходящим сетевым соединением, false, если он был создан входящим сетевым соединением.

pending_queue_bytes
bigint
Размер очереди заданий в байтах

pending_queue_messages
bigint
Количество сообщений в очереди заданий

backend_id
integer
Идентификатор локального процесса, который в данный момент использует этот маршрут: либо идентификатор обслуживающего процесса, сгенерировавшего этот маршрут, либо идентификатор рабочего процесса silkworm, которому назначен маршрут. Для входящих маршрутов в очереди заданий, которые ещё не назначены рабочим процессам, — -1.

backend_pid
integer
Идентификатор серверного процесса, обслуживающего текущий сеанс

attached
boolean
Приобретает значение true, если процесс привязан к мультиплексору, в противном случае false

backend_rd_active
boolean
true, если обслуживающий/рабочий процесс готов к получению данных во входящую очередь. Более подробное описание представлено в разделе Примечания.

backend_wr_active
boolean
true, если обслуживающий/рабочий процесс заполнил очередь неотправленных сообщений и ожидает её освобождения. Более подробное описание представлено в разделе Примечания.

is_worker
boolean
true, если данный процесс — это рабочий процесс silkworm мультиплексора; false, если любой другой

backend_blocked_by_cn
integer
Индекс соединения, блокирующего данный обслуживающий/рабочий процесс

blocks_connects
integer[]
Список индексов соединений, заблокированных данным обслуживающим/рабочим процессом

in_queue_used
bigint
Объём данных входящей очереди в байтах в общей памяти между обслуживающим процессом и мультиплексором

out_queue_used
bigint
Объём данных (в байтах) исходящей очереди в общей памяти между обслуживающим процессом и мультиплексором

connect_id
integer
Уникальный индекс соединения

reg_ip
inet
«Регистрационный» IP-адрес узла, с которым установлено соединение

reg_port
int2
«Регистрационный» TCP-порт узла, с которым установлено соединение

connect_rd_active
boolean
true, если мультиплексор готов к получению данных во входящую очередь

connect_wr_active
boolean
true, если мультиплексор заполнил очередь неотправленными сообщениями и ожидает её освобождения

connect_is_outgoing
boolean
true для исходящих соединений (созданных командой connect), false для входящих соединений (созданных командой accept). Используется только в процессе начального согласования.

connect_state
text
Текущее состояние соединения: connected — соединение установлено, in progress — клиент уже подключился, но начальное согласование ещё не произошло, и free — клиент отключился, но соединение ещё не было разорвано

connect_outgoing_queue_bytes
bigint
Размер очереди неотправленных сообщений для данного соединения, в байтах

connect_outgoing_queue_messages
bigint
Число сообщений в очереди из неотправленных сообщений для данного соединения

connect_blocked_by_bk
integer
Идентификатор обслуживающего процесса, блокирующего данное соединение

blocks_backends
integer[]
Список идентификаторов обслуживающих процессов, заблокированных данным соединением

connect_elapsed_time_write
bigint
Время с последней записи подключения

connect_elapsed_time_read
bigint
Время с последнего чтения подключения

backend_elapsed_time_write
bigint
Время с последней записи рабочего процесса

backend_elapsed_time_read
bigint
Время с последнего чтения с рабочего процесса

6.4.2.5. shardman.silk_pending_jobs

В представлении shardman.silk_pending_jobs отображается список текущих маршрутов в очереди заданий мультиплексора, которые ещё не назначены рабочим процессам. Столбцы представления приведены в разделе Таблица 6.12.

Таблица 6.12. Столбцы shardman.silk_pending_jobs

Name | Тип | Описание
hashvalue | integer | Внутренний уникальный идентификатор маршрута
origin_ip | inet | IP-адрес узла, сгенерировавшего данный маршрут
origin_port | int2 | Порт соединения по протоколу TCP узла, сгенерировавшего данный маршрут
channel_id | integer | Порядковый номер маршрута в пределах узла, сгенерировавшего данный маршрут
query | text | Первое сообщение в очереди заданий
pending_queue_bytes | bigint | Размер очереди заданий в байтах
pending_queue_messages | bigint | Количество сообщений в очереди заданий

6.4.2.6. shardman.silk_statinfo

В представлении shardman.silk_statinfo отображается информация о текущем состоянии мультиплексора. Столбцы представления приведены в разделе Таблица 6.13.

Таблица 6.13. Столбцы shardman.silk_statinfo

Name | Тип | Описание
pid | integer | Идентификатор процесса silkroad
started_at | timestamp with time zone | Время запуска процесса silkroad
transferred_bytes | json | Объект JSON из пар ключ/значение, в которой ключ — тип сообщения, а значение — общее число байтов, отправленных для такого типа сообщений при условии, что было послано хотя бы одно сообщение такого типа
transferred_pkts | json | Объект JSON из пар ключ/значение, в которой ключ — тип сообщения, а значение — общее число отправленных сообщений такого типа при условии, что было послано хотя бы одно сообщение такого типа
transferred_max | json | Объект JSON из пар ключ/значение, в которой ключ — тип сообщения, а значение — максимальный размер сообщения такого типа при условии, что было послано хотя бы одно сообщение такого типа
memcxt_dpg_allocated | bigint | Значение mem_allocated процесса DPGMemoryContext
memcxt_top_allocated | bigint | Значение mem_allocated процесса TopMemoryContext
read_efd_max | bigint | Максимальное время чтения eventfd с момента перезапуска
write_efd_max | bigint | Максимальное время записи eventfd с момента перезапуска
read_efd_total | bigint | Общее время чтения eventfd с момента перезапуска
write_efd_total | bigint | Общее время записи eventfd с момента перезапуска
read_efd_count | bigint | Общее количество событий чтения eventfd с момента перезапуска
write_efd_count | bigint | Общее количество событий записи eventfd с момента перезапуска
sort_time_max | bigint | Максимальное время операций сортировки с включением silk_flow_control (при значении, отличном от none)
sort_time_total | bigint | Общее время операций сортировки с включением silk_flow_control (при значении, отличном от none)
sort_time_count | bigint | Общее количество операций сортировки с включением silk_flow_control (при значении, отличном от none)

Обратите внимание, что значения для read_efd_max, write_efd_max, read_efd_total, write_efd_total, read_efd_count, write_efd_count, sort_time_max, sort_time_total и sort_time_count рассчитываются, только если включён параметр конфигурации shardman.silk_track_time.

6.4.2.7. shardman.silk_state

В представлении shardman.silk_state отображается снимок текущего состояния процесса silkroad. Столбцы этого представления приведены в разделе Таблица 6.14.

Таблица 6.14. Столбцы shardman.silk_state

Name | Тип | Описание
state | text | Состояние процесса silkroad

6.4.2.8. Примечания

reg_ip и reg_port являются не фактическими сетевыми адресами, а адресами, через которые мультиплексор подключается к узлу. Они определяются в ходе начального согласования между мультиплексором и узлами и равны параметрам соответствующих серверов из таблицы pg_foreign_server.

Если мультиплексор находится в состоянии idle, для параметра read_ev_active устанавливаются значения true и для параметра write_ev_active устанавливаются значения false.

6.4.3. Глобальные представления

В Shardman есть ряд глобальных представлений, основанных на локальных представлениях PostgreSQL. Определение столбцов глобального представления совпадает с их определением в соответствующем локальном представлении. Глобальное представление показывает объединение результатов выборки из соответствующих локальных представлений. Строки возвращаются из каждого узла кластера. В глобальных представлениях в столбце rgid выводятся идентификаторы группы репликации узла, из которого взяты строки.

6.4.3.1. Глобальные представления для работы со статистикой

Ниже представлен список представлений, относящихся к статистике, со ссылками на соответствующие локальные представления:

Таблица 6.15. Глобальные и локальные представления для работы со статистикой

Глобальное представление
Локальное представление
Описание

shardman.gv_stats
pg_stats
По одной строке со статистикой планировщика.

shardman.gv_stats_ext
pg_stats_ext
Открывает доступ к информации о каждом объекте расширенной статистики в базе данных.

shardman.gv_stats_ext_exprs
pg_stats_ext_exprs
Открывает доступ к информации обо всех выражениях, включённых в объекты расширенной статистики.

shardman.gv_stat_activity
pg_stat_activity
По одной строке для каждого серверного процесса с информацией, относящейся к текущей деятельности этого процесса.

shardman.gv_stat_replication
pg_stat_replication
По одной строке для каждого процесса-передатчика WAL со статистикой по репликации на резервном сервере, к которому подключён этот процесс.

shardman.gv_stat_replication_slots
pg_stat_replication_slots
По одной строке со статистикой по использованию слота репликации для каждого такого слота.

shardman.gv_stat_subscription
pg_stat_subscription
По одной строке для подписки для основного рабочего процесса (с NULL в PID, если процесс не работает) и дополнительные строки для рабочих процессов, осуществляющих копирование начальных данных для таблиц в подписке.

shardman.gv_stat_ssl
pg_stat_ssl
По одной строке для каждого обслуживающего процесса и процесса, передающего WAL, которые показывают статистику использования SSL для подключений.

shardman.gv_stat_gssapi
pg_stat_gssapi
По одной строке для каждого обслуживающего процесса с информацией об использовании GSSAPI для конкретного подключения.

shardman.gv_stat_archiver
pg_stat_archiver
Только одна строка со статистикой работы процесса архивации WAL.

shardman.gv_stat_bgwriter
pg_stat_bgwriter
Только одна строка со статистикой работы фонового процесса записи.

shardman.gv_stat_progress_analyze
pg_stat_progress_analyze
По одной строке с текущим состоянием для каждого обслуживающего процесса (включая рабочие процессы автоочистки), в котором работает ANALYZE.

shardman.gv_stat_progress_basebackup
pg_stat_progress_basebackup
По одной строке с текущим состоянием для каждого передающего WAL процесса, транслирующего базовую копию.

shardman.gv_stat_progress_cluster
pg_stat_progress_cluster
По одной строке с текущим состоянием для каждого обслуживающего процесса, в котором выполняется CLUSTER или VACUUM FULL.

shardman.gv_stat_checkpointer
pg_stat_checkpointer
Только одна строка, содержащая данные о текущем состоянии процесса контрольных точек в кластере.

shardman.gv_statistic_ext
pg_statistic_ext
Расширенная статистика планировщика (определение)

shardman.gv_stat_progress_create_index
pg_stat_progress_create_index
По одной строке для каждого обслуживающего процесса, выполняющего CREATE INDEX или REINDEX, показывающей состояние создания индекса.

shardman.gv_stat_progress_vacuum
pg_stat_progress_vacuum
По одной строке для каждого обслуживающего процесса (включая рабочие процессы автоочистки), производящего очистку в данный момент, показывающей состояние её выполнения.

shardman.gv_stat_progress_copy
pg_stat_progress_copy
По одной строке с текущим состоянием для каждого обслуживающего процесса, в котором выполняется COPY, показывающей текущее состояние выполнения команды.

shardman.gv_stat_wal
pg_stat_wal
Только одна строка со статистикой работы WAL.

shardman.gv_stat_database
pg_stat_database
По одной строке на каждую базу данных со статистикой по отменам запросов, выполненным вследствие конфликта с процессами восстановления на резервных серверах.

shardman.gv_stat_database_conflicts
pg_stat_database_conflicts
По одной строке на каждую базу данных со статистикой по отменам запросов, выполненным вследствие конфликтов с процессами восстановления на резервных серверах. Данное представление содержит информацию только о резервных серверах, поскольку на ведущих серверах конфликты не происходят.

shardman.gv_stat_all_tables
pg_stat_all_tables
По одной строке на каждую таблицу в текущей базе данных со статистикой по обращениям к этой таблице.

shardman.gv_stat_sys_tables
pg_stat_sys_tables
Аналогично pg_stat_all_tables, за исключением того, что отображаются только системные таблицы.

shardman.gv_stat_user_tables
pg_stat_user_tables
Аналогично pg_stat_all_tables, за исключением того, что отображаются только пользовательские таблицы.

shardman.gv_stat_all_indexes
pg_stat_all_indexes
По одной строке для каждого индекса в текущей базе данных со статистикой по обращениям к этому индексу.

shardman.gv_stat_user_indexes
pg_stat_user_indexes
Аналогично pg_stat_all_indexes, за исключением того, что показываются только индексы по пользовательским таблицам.

shardman.gv_stat_sys_indexes
pg_stat_sys_indexes
Аналогично pg_stat_all_indexes, за исключением того, что показываются только индексы по системным таблицам.

shardman.gv_stat_user_indexes
pg_stat_user_indexes
Аналогично pg_stat_all_indexes, за исключением того, что показываются только индексы по пользовательским таблицам.

shardman.gv_statio_user_indexes
pg_statio_user_indexes
Аналогично pg_statio_all_indexes, за исключением того, что показываются только индексы по пользовательским таблицам.

shardman.gv_statio_all_tables
pg_statio_all_tables
По одной строке для каждой таблицы в текущей базе данных со статистикой по операциям ввода/вывода с этой таблицей.

shardman.gv_statio_all_indexes
pg_statio_all_indexes
По одной строке для каждого индекса в текущей базе данных со статистикой по операциям ввода/вывода для этого индекса.

shardman.gv_statio_sys_indexes
pg_statio_sys_indexes
Аналогично pg_statio_all_indexes, за исключением того, что показываются только индексы по системным таблицам.

shardman.gv_statio_all_sequences
pg_statio_all_sequences
По одной строке для каждой последовательности в текущей базе данных со статистикой по операциям ввода/вывода с этой последовательностью.

shardman.gv_statio_user_sequences
pg_statio_user_sequences
Аналогично pg_statio_all_sequences, за исключением того, что показываются только пользовательские последовательности.

shardman.gv_statio_sys_sequences
pg_statio_sys_sequences
Аналогично pg_statio_all_sequences, за исключением того, что показываются только системные последовательности.

shardman.gv_statio_sys_tables
pg_statio_sys_tables
Аналогично pg_statio_all_tables, за исключением того, что показываются только системные таблицы.

shardman.gv_statio_user_tables
pg_statio_user_tables
Аналогично pg_statio_all_tables, за исключением того, что показываются только пользовательские таблицы.

shardman.gv_stat_user_functions
pg_stat_user_functions
По одной строке для каждой отслеживаемой функции со статистикой по выполнениям этой функции.

shardman.gv_stat_slru
pg_stat_slru
По одной строке со статистикой работы для каждого SLRU-кеша.

shardman.gv_stat_csn
shardman.pg_stat_csn
Одна строка, показывающая статистику задержек, возникающих во время импорта снимков CSN.

shardman.gv_stat_monitor
shardman.pg_stat_monitor
Одна строка, показывающая метрики Shardman monitor.

shardman.gv_stat_netusage
shardman.pg_stat_net_usage
Одна строка, показывающая совокупный сетевой трафик между узлами кластера Shardman.

shardman.gv_stat_xact_time
shardman.pg_stat_xact_time
Одна строка со статистикой о затраченном на транзакцию времени.

shardman.gv_silk_routes
shardman.silk_routes
По одной строке, отображающей снимок актуального состояния таблицы маршрутов мультиплексора.

shardman.gv_silk_connects
shardman.silk_connects
По одной строке, отображающей список текущих соединений мультиплексора.

shardman.gv_silk_backends
shardman.silk_backends
По одной строке, отображающей список текущих процессов двух типов: обслуживающие процессы для клиентских соединений и рабочие процессы silkworm мультиплексора, которые с ним взаимодействуют.

shardman.gv_silk_pending_jobs
shardman.silk_pending_jobs
По одной строке, отображающей список текущих маршрутов в очереди заданий мультиплексора, которые ещё не назначены рабочим процессам.

shardman.gv_silk_routing
shardman.silk_routing
По одной строке, отображающей результат работы функции shardman.silk_routing.

shardman.gv_stats_sdm_statements
pgpro_stats_sdm_statements
Данное представление даёт доступ к агрегированной статистике распределённых запросов. Его можно создать только в базе данных, где Shardman установлен раньше, чем pgpro_stats. Чтобы это глобальное представление работало, необходимо, чтобы pgpro_stats был создан на всех узлах кластера.

shardman.gv_lock_graph
shardman.lock_graph
По одной строке, отображающей граф блокировок между процессами на узлах кластера Shardman, включая внешние блокировки. Оно основано на системных представлениях pg_locks и pg_prepared_xacts, а также на представлении pg_stat_activity сборщика статистики.

shardman.gv_stat_foreign_bytes
shardman.pg_stat_foreign_stat_bytes
По одной строке, отображающей объём статистики для сторонних отношений, передаваемый по сети между узлами кластера Shardman.

shardman.gv_stat_wal_receiver
pg_stat_wal_receiver
Только одна строка со статистикой приёмника WAL, полученной с сервера, на котором работает приёмник.

shardman.gv_stat_xact_all_tables
pg_stat_xact_all_tables
Подобно pg_stat_all_tables, но подсчитывает действия, выполненные в текущей транзакции к настоящему моменту (которые ещё не вошли в pg_stat_all_tables и связанные представления). Столбцы для числа живых и мёртвых строк, а также количества операций очистки и сбора статистики, в этом представлении отсутствуют.

shardman.gv_stat_xact_sys_tables
pg_stat_xact_sys_tables
Аналогично pg_stat_xact_all_tables, за исключением того, что отображаются только системные таблицы.

shardman.gv_stat_xact_user_functions
pg_stat_xact_user_functions
Аналогично pg_stat_user_functions, однако подсчитываются только вызовы функций, выполненные в текущей транзакции (которые ещё не были включены в pg_stat_user_functions).

shardman.gv_stat_xact_user_tables
pg_stat_xact_user_tables
Аналогично pg_stat_xact_all_tables, за исключением того, что отображаются только пользовательские таблицы.

6.4.3.2. Глобальные представления для работы с системным каталогом

Ниже представлен список глобальных представлений для работы с системным каталогом со ссылками на соответствующие локальные представления:

Таблица 6.16. Глобальные и локальные представления для работы с системным каталогом

Глобальное представление | Локальное представление | Описание
shardman.gv_aggregate | pg_aggregate | Хранит информацию об агрегатных функциях
shardman.gv_am | pg_am | Методы доступа отношений
shardman.gv_amop | pg_amop | Операторы методов доступа
shardman.gv_amproc | pg_amproc | Опорные функции методов доступа
shardman.gv_attrdef | pg_attrdef | Значения столбцов по умолчанию
shardman.gv_attribute | pg_attribute | Столбцы таблиц («атрибуты»)
shardman.gv_auth_members | pg_auth_members | Отношения членства для объектов авторизации
shardman.gv_available_extension_versions | pg_available_extension_versions | Определённые версии расширений, доступные для установки
shardman.gv_available_extensions | pg_available_extensions | Расширения, доступные для установки
shardman.gv_cast | pg_cast | Приведения (преобразования типов данных)
shardman.gv_class | pg_class | Таблицы, индексы, последовательности, представления («отношения»)
shardman.gv_collation | pg_collation | Правила сортировки (параметры локали)
shardman.gv_config | pg_config | Конфигурационные параметры времени компиляции для текущей установленной версии Postgres Pro
shardman.gv_constraint | pg_constraint | Ограничения-проверки, ограничения уникальности, ограничения первичного ключа и внешних ключей
shardman.gv_conversion | pg_conversion | Информация о перекодировках
shardman.gv_database | pg_database | Базы данных в этом кластере
shardman.gv_db_role_setting | pg_db_role_setting | Параметры, задаваемые на уровне ролей и баз данных
shardman.gv_default_acl | pg_default_acl | Права по умолчанию для различных типов объектов
shardman.gv_depend | pg_depend | Зависимости между объектами базы данных
shardman.gv_description | pg_description | Описания или комментарии к объектам базы данных
shardman.gv_enum | pg_enum | Определения меток и значений перечислений
shardman.gv_event_trigger | pg_event_trigger | Событийные триггеры
shardman.gv_extension | pg_extension | Установленные расширения
shardman.gv_file_settings | pg_file_settings | Установленные расширения
shardman.gv_foreign_data_wrapper | pg_foreign_data_wrapper | Определения обёрток сторонних данных
shardman.gv_foreign_server | pg_foreign_server | Определения сторонних серверов
shardman.gv_foreign_table | pg_foreign_table | Дополнительная информация о сторонних таблицах
shardman.gv_group | pg_group | Существует для обратной совместимости: оно эмулирует каталог, существовавший в Postgres Pro до версии 8.1
shardman.gv_hba_file_rules | pg_hba_file_rules | Сводное содержимое файла конфигурации аутентификации клиентов
shardman.gv_index | pg_index | Дополнительные свойства индексов
shardman.gv_indexes | pg_indexes | Даёт доступ к полезной информации обо всех индексах в базе данных
shardman.gv_inherits | pg_inherits | Иерархия наследования таблиц
shardman.gv_init_privs | pg_init_privs | Начальные права для объектов
shardman.gv_language | pg_language | Языки для написания функций
shardman.gv_largeobject | pg_largeobject | Страницы данных для больших объектов
shardman.gv_largeobject_metadata | pg_largeobject_metadata | Метаданные, связанные с большими объектами
shardman.gv_matviews | pg_matviews | Даёт доступ к полезной информации обо всех материализованных представлениях в базе данных
shardman.gv_namespace | pg_namespace | Схемы
shardman.gv_opclass | pg_opclass | Классы операторов методов доступа
shardman.gv_operator | pg_operator | Операторы
shardman.gv_opfamily | pg_opfamily | Семейства операторов методов доступа
shardman.gv_partitioned_table | pg_partitioned_table | Информация о ключах секционирования таблиц
shardman.gv_proc | pg_proc | Функции и процедуры
shardman.gv_profile | pg_profile | Профили, представляющие собой наборы ограничений аутентификации
shardman.gv_publication | pg_publication | Публикации для логической репликации
shardman.gv_publication_rel | pg_publication_rel | Сопоставление отношений с публикациями
shardman.gv_publication_tables | pg_publication_tables | Информация о сопоставлении публикаций с информацией о содержащихся в них таблицах
shardman.gv_range | pg_range | Информация о типах диапазонов
shardman.gv_replication_origin | pg_replication_origin | Зарегистрированные источники репликации
shardman.gv_replication_origin_status | pg_replication_origin_status | Информацию о позиции воспроизведения записей репликации, достигнутой для определённого источника
shardman.gv_replication_slots | pg_replication_slots | Список всех слотов репликации, существующих в данный момент в кластере баз данных, а также их текущее состояние
shardman.gv_rewrite | pg_rewrite | Правила перезаписи запросов
shardman.gv_rules | pg_rules | Открывает доступ к полезной информации о правилах перезаписи запросов
shardman.gv_seclabel | pg_seclabel | Метки безопасности для объектов базы данных
shardman.gv_seclabels | pg_seclabels | Содержит информацию о метках безопасности
shardman.gv_sequence | pg_sequence | Информация о последовательностях
shardman.gv_sequences | pg_sequences | Даёт доступ к полезной информации обо всех последовательностях в базе данных
shardman.gv_settings | pg_settings | Даёт доступ к параметрам времени выполнения сервера
shardman.gv_shdepend | pg_shdepend | Зависимости общих объектов
shardman.gv_shdescription | pg_shdescription | Комментарии к общим объектам
shardman.gv_shseclabel | pg_shseclabel | Метки безопасности для общих объектов баз данных
shardman.gv_subscription | pg_subscription | Подписки логической репликации
shardman.gv_subscription_rel | pg_subscription_rel | Состояние отношений для подписок
shardman.gv_tablespace | pg_tablespace | Табличные пространства в этом кластере баз данных
shardman.gv_tables | pg_tables | Даёт доступ к полезной информации обо всех таблицах в базе данных
shardman.gv_prepared_xacts | pg_prepared_xacts | Содержит информацию о транзакциях, которые в настоящее время подготовлены для двухфазной фиксации
shardman.gv_timezone_names | pg_timezone_names | Список имён часовых поясов, распознаваемых командой SET TIMEZONE, вместе с соответствующими аббревиатурами, смещением UTC и статусом летнего времени
shardman.gv_timezone_abbrevs | pg_timezone_abbrevs | Список аббревиатур часовых поясов, которые в настоящее время распознаются процедурами ввода даты/времени
shardman.gv_transform | pg_transform | Трансформации (тип данных для преобразований процедурных языков)
shardman.gv_trigger | pg_trigger | Триггеры
shardman.gv_ts_config | pg_ts_config | Конфигурации текстового поиска
shardman.gv_ts_config_map | pg_ts_config_map | Сопоставления фрагментов в конфигурациях текстового поиска
shardman.gv_ts_dict | pg_ts_dict | Словари текстового поиска
shardman.gv_ts_parser | pg_ts_parser | Анализаторы текстового поиска
shardman.gv_ts_template | pg_ts_template | Шаблоны текстового поиска
shardman.gv_type | pg_type | Типы данных
shardman.gv_user_mapping | pg_user_mapping | Сопоставления пользователей для сторонних серверов
shardman.gv_user_mappings | pg_user_mappings | Даёт доступ к информации о сопоставлениях пользователей
shardman.gv_views | pg_views | Даёт доступ к полезной информации обо всех представлениях в базе данных
shardman.gv_locks | pg_locks | Даёт доступ к информации о блокировках, удерживаемых активными процессами на сервере баз данных.
shardman.gv_shmem_allocations | pg_shmem_allocations | Показывает блоки памяти, выделенные в основном сегменте общей памяти сервера.

6.5. Команды SQL

Shardman расширяет некоторые SQL-команды DDL, поддерживаемые PostgreSQL, чтобы включить распределённую обработку DDL. В этом справочнике описывается только синтаксис команд, специфичный для Shardman. Стандартные команды DDL SQL описаны в документации PostgreSQL.

ALTER SEQUENCE

ALTER SEQUENCE — изменить определение генератора последовательности

Синтаксис

ALTER SEQUENCE [ IF EXISTS ] имя
    [ AS тип_данных ]
    [ INCREMENT [ BY ] шаг ]
    [ MINVALUE мин_значение | NO MINVALUE ] [ MAXVALUE макс_значение | NO MAXVALUE ]
    [ RESTART [ [ WITH ] перезапуск ] ]
    [ CACHE кеш ] [ [ NO ] CYCLE ]
    [ OWNED BY { имя_таблицы.имя_столбца | NONE } ]
ALTER SEQUENCE [ IF EXISTS ] имя OWNER TO { новый_владелец | CURRENT_ROLE | CURRENT_USER | SESSION_USER }
ALTER SEQUENCE [ IF EXISTS ] имя RENAME TO новое_имя
ALTER SEQUENCE [ IF EXISTS ] имя SET SCHEMA новая_схема

Описание

Команда ALTER SEQUENCE изменяет параметры существующего генератора последовательности. Расширенные формы ALTER SEQUENCE в основном такие же, как и в PostgreSQL (см. ALTER SEQUENCE), за исключением следующих отличий:

Параметр, задающий минимальное значения последовательности в Shardman работает скорее как нижняя граница глобального диапазона доступных значений, поэтому его можно увеличить только для того, чтобы исключить создание повторяющихся чисел.

Предложение RESTART WITH позволяет перезапустить последовательность с любой произвольной нижней границы, но в этом случае нет гарантии, что созданные ранее числа не будут повторяться.

Во избежание путаницы использование RESTART WITH и MINVALUE в одном операторе не допускается.

Примеры

Изменить параметр размера блока последовательности с именем serial:

ALTER SEQUENCE serial SET (block_size = 8192);

См. также

CREATE SEQUENCE, Раздел 7.6

ALTER TABLE

ALTER TABLE — изменить определение таблицы

Синтаксис

ALTER TABLE [ IF EXISTS ] [ ONLY ] имя [ * ]
    действие [, ... ]
ALTER TABLE [ IF EXISTS ] [ ONLY ] имя [ * ]
    RENAME [ COLUMN ] имя_столбца TO новое_имя_столбца
ALTER TABLE [ IF EXISTS ] [ ONLY ] имя [ * ]
    RENAME CONSTRAINT имя_ограничения TO имя_нового_ограничения
ALTER TABLE [ IF EXISTS ] имя
    RENAME TO новое_имя
ALTER TABLE [ IF EXISTS ] имя
    SET SCHEMA новая_схема
ALTER TABLE ALL IN TABLESPACE имя [ OWNED BY имя_роли [, ... ] ]
    SET TABLESPACE новое_табл_пространство [ NOWAIT ]
ALTER TABLE [ IF EXISTS ] имя
    ATTACH PARTITION имя_секции { FOR VALUES указание_границ_секции | DEFAULT }
ALTER TABLE [ IF EXISTS ] имя
    DETACH PARTITION имя_секции [ CONCURRENTLY | FINALIZE ]

Где действие может быть следующим:

    ADD [ COLUMN ] [ IF NOT EXISTS ] имя_столбца тип_данных [ COLLATE правило_сортировки ] [ ограничение_столбца [ ... ] ]
    DROP [ COLUMN ] [ IF EXISTS ] имя_столбца [ RESTRICT | CASCADE ]
    ALTER [ COLUMN ] имя_столбца [ SET DATA ] TYPE тип_данных [ COLLATE правило_сортировки ] [ USING выражение ]
    ALTER [ COLUMN ] имя_столбца SET DEFAULT выражение
    ALTER [ COLUMN ] имя_столбца DROP DEFAULT
    ALTER [ COLUMN ] имя_столбца { SET | DROP } NOT NULL
    ALTER [ COLUMN ] имя_столбца DROP EXPRESSION [ IF EXISTS ]
    ALTER [ COLUMN ] имя_столбца ADD GENERATED { ALWAYS | BY DEFAULT } AS IDENTITY [ ( параметры_последовательности ) ]
    ALTER [ COLUMN ] имя_столбца { SET GENERATED { ALWAYS | BY DEFAULT } | SET параметр_последовательности | RESTART [ [ WITH ] перезапуск ] } [...]
    ALTER [ COLUMN ] имя_столбца DROP IDENTITY [ IF EXISTS ]
    ALTER [ COLUMN ] имя_столбца SET STATISTICS integer
    ALTER [ COLUMN ] имя_столбца SET ( атрибут = значение [, ... ] )
    ALTER [ COLUMN ] имя_столбца RESET ( атрибут [, ... ] )
    ALTER [ COLUMN ] имя_столбца SET STORAGE { PLAIN | EXTERNAL | EXTENDED | MAIN }
    ALTER [ COLUMN ] имя_столбца SET COMPRESSION метод_сжатия
    ADD ограничение_таблицы [ NOT VALID ]
    ADD ограничение_таблицы_по_индексу
    ALTER CONSTRAINT имя_ограничения [ DEFERRABLE | NOT DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ]
    VALIDATE CONSTRAINT имя_ограничения
    DROP CONSTRAINT [ IF EXISTS ]  имя_ограничения [ RESTRICT | CASCADE ]
    DISABLE TRIGGER [ имя_триггера | ALL | USER ]
    ENABLE TRIGGER [ имя_триггера | ALL | USER ]
    ENABLE REPLICA TRIGGER имя_триггера
    ENABLE ALWAYS TRIGGER имя_триггера
    DISABLE RULE имя_правила_перезаписи
    ENABLE RULE имя_правила_перезаписи
    ENABLE REPLICA RULE имя_правила_перезаписи
    ENABLE ALWAYS RULE имя_правила_перезаписи
    DISABLE ROW LEVEL SECURITY
    ENABLE ROW LEVEL SECURITY
    FORCE ROW LEVEL SECURITY
    NO FORCE ROW LEVEL SECURITY
    CLUSTER ON имя_индекса
    SET WITHOUT CLUSTER
    SET WITHOUT OIDS
    SET TABLESPACE новое_табл_пространство
    SET { LOGGED | UNLOGGED }
    SET ( параметр_хранения [= значение] [, ... ] )
    RESET ( параметр_хранения [, ... ] )
    INHERIT таблица_родитель
    NO INHERIT таблица_родитель
    OF имя_типа
    NOT OF
    OWNER TO { новый_владелец | CURRENT_ROLE | CURRENT_USER | SESSION_USER }
    REPLICA IDENTITY { DEFAULT | USING INDEX имя_индекса | FULL | NOTHING }

и указание_границ_секции:

IN ( выражение_границ_секции [, ...] ) |
FROM ( { выражение_границ_секции | MINVALUE | MAXVALUE } [, ...] )
  TO ( { выражение_границ_секции | MINVALUE | MAXVALUE } [, ...] ) |
WITH ( MODULUS числовая_константа, REMAINDER числовая_константа )

и ограничение_столбца:

[ CONSTRAINT имя_ограничения ]
{ NOT NULL |
  NULL |
  CHECK ( выражение ) [ NO INHERIT ] |
  DEFAULT выражение_по_умолчанию |
  GENERATED ALWAYS AS ( генерирующее_выражение ) STORED |
  GENERATED { ALWAYS | BY DEFAULT } AS IDENTITY [ ( параметры_последовательности ) ] |
  UNIQUE параметры_индекса |
  PRIMARY KEY параметры_индекса |
  REFERENCES целевая_таблица [ ( целевой_столбец ) ] [ MATCH FULL | MATCH PARTIAL | MATCH SIMPLE ]
    [ ON DELETE ссылочное_действие ] [ ON UPDATE ссылочное_действие ] }
[ DEFERRABLE | NOT DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ]

и ограничение_таблицы:

[ CONSTRAINT имя_ограничения ]
{ CHECK ( выражение ) [ NO INHERIT ] |
  UNIQUE ( имя_столбца [, ... ] ) параметры_индекса |
  PRIMARY KEY ( имя_столбца [, ... ] ) параметры_индекса |
  EXCLUDE [ USING индексный_метод ] ( элемент_исключения WITH оператор [, ... ] ) параметры_индекса [ WHERE ( предикат ) ] |
  FOREIGN KEY ( имя_столбца [, ... ] ) REFERENCES целевая_таблица [ ( целевой_столбец [, ... ] ) ]
    [ MATCH FULL | MATCH PARTIAL | MATCH SIMPLE ] [ ON DELETE ссылочное_действие ] [ ON UPDATE ссылочное_действие ] }
[ DEFERRABLE | NOT DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ]

и ограничение_таблицы_по_индексу:

    [ CONSTRAINT имя_ограничения ]
    { UNIQUE | PRIMARY KEY } USING INDEX имя_индекса
    [ DEFERRABLE | NOT DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ]

параметры_индекса в ограничениях UNIQUE, PRIMARY KEY и EXCLUDE:

[ INCLUDE ( имя_столбца [, ... ] ) ]
[ WITH ( параметр_хранения [= значение] [, ... ] ) ]
[ USING INDEX TABLESPACE табл_пространство ]

элемент_исключения в ограничении EXCLUDE:

{ имя_столбца | ( выражение ) } [ класс_операторов ] [ ASC | DESC ] [ NULLS { FIRST | LAST } ]

Описание

Расширение Shardman синтаксиса команды ALTER TABLE позволяет последовательно изменять определения сегментированных и глобальных таблиц.

Набор операций ALTER, поддерживаемых для глобальных и сегментированных таблиц, ограничен. Подробнее см. Ограничения ALTER TABLE.

Параметры

Параметры хранения

Shardman добавляет к параметрам хранения таблиц собственные метапараметры хранения. Они не сохраняются в соответствующей записи каталога, а используются для указания расширению Shardman выполнить некоторые дополнительные действия.

global

Данный параметр можно указать только для глобальных таблиц. Если установлено значение 0, глобальная таблица будет преобразована в обычную в группе репликации, где выполняется команда. После завершения этого оператора глобальная таблица не будет существовать на других узлах. Никакой другой параметр хранения не может быть установлен, если указан параметр global.

Примеры

Создайте глобальную таблицу pgbench_tellers, а затем преобразуйте её в локальную.

CREATE TABLE pgbench_tellers (
       tid       integer PRIMARY KEY,
       bid       integer,
       tbalance  integer,
       filler    character(84)
)
WITH (global);
ALTER TABLE pgbench_tellers SET (global=0);

См. также

ALTER TABLE Ограничения, PostgreSQL ALTER TABLE

CREATE SEQUENCE

CREATE SEQUENCE — создать генератор последовательности

Синтаксис

CREATE SEQUENCE [ IF NOT EXISTS ] имя
    [ AS тип_данных ]
    [ INCREMENT [ BY ] шаг ]
    [ MINVALUE мин_значение | NO MINVALUE ] [ MAXVALUE макс_значение | NO MAXVALUE ]
    [ START [ WITH ] start ] [ CACHE кеш ] [ [ NO ] CYCLE ]
    [ OWNED BY { имя_таблицы.имя_столбца | NONE } ]
    WITH ( [ global ],
           [ block_size = block_size ]
         )

Описание

Расширения Shardman для команды CREATE SEQUENCE позволяют создавать числовые генераторы глобальных последовательностей. Эта команда создаёт обычную последовательность PostgreSQL на всех узлах кластера и записывает параметры последовательности в словарь состояния глобальной последовательности. (Подробности описаны в Раздел 7.6.)

После создания глобальной последовательности функцию nextval можно использовать для создания значений последовательности, которые гарантированно будут уникальными во всём кластере. Стандартные функции управления последовательностями (например, setval) нельзя использовать для глобальных последовательностей, так как это может привести к неожиданным результатам.

Параметры

В дополнение к параметрам, распознаваемым PostgreSQL, следующие параметры также поддерживаются Shardman.

global

Если указан, объект последовательности создаётся как глобальная последовательность, управляемая Shardman.

block_size

Количество элементов, выделенных для локальной последовательности. Значение по умолчанию — 65536.

Примечания

Предполагается, что глобальные последовательности ведут себя аналогично обычным последовательностям PostgreSQL (см. CREATE SEQUENCE) с некоторыми ограничениями, наиболее важным из которых является то, что глобальная последовательность всегда увеличивается. Нет поддержки отрицательного приращения значений или зацикливания (как в CYCLE), что также означает, что практически нет разницы между минимальным значением последовательности и его начальным значением, поэтому оба параметра не могут быть заданы одновременно во избежание путаницы.

Как и в случае с обычными объектами последовательности, команда DROP SEQUENCE удаляет глобальную последовательность, а команда ALTER SEQUENCE позволяет изменить некоторые параметры глобальной последовательности.

Примеры

Создать глобальную последовательность с именем serial.

CREATE SEQUENCE serial MINVALUE 100 WITH (global);

Получить следующее число из этой последовательности:

SELECT nextval('serial');
 nextval
---------
     100
(1 row)

См. также

ALTER SEQUENCE, Раздел 7.6

CREATE TABLE

CREATE TABLE — создать таблицу

Синтаксис

CREATE [ UNLOGGED ] TABLE [ IF NOT EXISTS ] имя_таблицы ( [
  { имя_столбца тип_данных [ COLLATE правило_сортировки ] [ ограничение_столбца [ ... ] ]
    | ограничение_таблицы
    | LIKE исходная_таблица [ вариант_копирования ... ]}
    [, ... ]
] )
[ USING метод ]
[ WITH ( параметр_хранения [= значение] [, ... ] ) ]
[ TABLESPACE табл_пространство ]

CREATE TABLE имя_таблицы ( [
  { имя_столбца тип_данных }
    [, ... ]
] )
WITH ( { distributed_by = 'имя_столбца [, ... ]'
         [, num_parts = число_секций ]
         [, colocate_with = 'имя_табл_совм_размещения' ]
         [, partition_by = 'имя_столбца',
            partition_bounds = 'массив_выражений_границ_секций' ] |
            global = true }
)

Здесь ограничение_столбца:

[ CONSTRAINT имя_ограничения ]
{ NOT NULL |
  NULL |
  CHECK ( выражение ) [ NO INHERIT ] |
  DEFAULT выражение_по_умолчанию |
  UNIQUE параметры_индекса |
  PRIMARY KEY параметры_индекса }
[ DEFERRABLE | NOT DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ]

и ограничение_таблицы:

[ CONSTRAINT имя_ограничения ]
{ CHECK ( выражение ) [ NO INHERIT ] |
  UNIQUE ( имя_столбца [, ... ] ) параметры_индекса |
  PRIMARY KEY ( имя_столбца [, ... ] ) параметры_индекса |
  EXCLUDE [ USING индексный_метод ] ( элемент_исключения WITH оператор [, ... ] ) параметры_индекса [ WHERE ( предикат ) ] }
[ DEFERRABLE | NOT DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ]

Описание

Расширение Shardman синтаксиса CREATE TABLE позволяет создавать сегментированные таблицы, распределённые по всем группам репликации, используя один оператор DDL.

Расширенный синтаксис CREATE TABLE накладывает ограничения на общий синтаксис команды. Например, в настоящее время нет поддержки для:

Генерируемых столбцов.

Ограничений REFERENCES и FOREIGN KEY между несовмещёнными сегментированными таблицами.

Предложений PARTITION BY и PARTITION OF.

При создании совмещённой таблицы следует помнить о соответствующих ограничениях. В частности, из этих ограничений следует, что внешний ключ в глобальной или сегментированной таблице может поддерживаться, только если он ссылается на кортежи, которые хранятся в той же группе репликации. Это приводит к следующим ограничениям: внешний ключ в глобальной таблице может ссылаться только на другую глобальную таблицу, внешний ключ в сегментированной таблице может ссылаться на совмещённую сегментированную таблицу или глобальную таблицу. Обратите внимание, что когда внешний ключ в сегментированной или глобальной таблице ссылается на глобальную таблицу, поддерживаются только ссылочные действия NO ACTION или RESTRICT для действия ON UPDATE, а для ON DELETE — только действия NO ACTION, RESTRICT или CASCADE.

Столбцы типа SERIAL8 реализованы с использованием автоматически созданной глобальной последовательности, поэтому здесь также применяются все свойства глобальной последовательности. (Подробности описаны в Раздел 7.6.)

Параметры

IF NOT EXISTS

Не считать ошибкой, если отношение с таким именем уже существует. В этом случае будет выдано замечание. С IF NOT EXISTS ошибка не выдаётся, если уже существующая одноимённая таблица является глобальной или сегментированной или она находится на узле, где выполняется запрос. В ином случае такой запрос завершится ошибкой.

Параметры хранения

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

distributed_by (text)

Задаёт список столбцов, используемых для секционирования таблицы. В настоящее время поддерживается только разбиение по хешу, так что оно эквивалентно PARTITION BY HASH, но все конечные секции будут созданы немедленно во всех группах репликации, а таблица будет зарегистрирована в метаданных Shardman.

num_parts (integer)

Устанавливает количество секций, которые будут созданы для этой таблицы. Этот параметр является необязательным. Если он не указан, по умолчанию будет использоваться значение глобального параметра shardman.num_parts.

colocate_with (text)

Указывает имя таблицы, с которой будет выполнено совмещение. Если установлено, Shardman попытается разместить секции созданной таблицы с тем же ключом секции на тех же узлах, что и имя_табл_совм_размещения. Этот параметр является необязательным.

partition_by (text)

Указывает имя столбца, используемого для секционирования таблицы второго уровня. В настоящее время поддерживается только секционирование по диапазонам. При использовании этого параметра каждая секция таблицы создаётся как секционированная таблица. Подсекции могут быть созданы сразу, если установлен параметр границы_секции. Этот параметр является необязательным.

partition_bounds (text)

Устанавливает границы секций таблицы второго уровня. Границы должны быть строковым представлением двумерного массива. Каждый элемент массива представляет собой пару нижней и верхней границ секций. Если и нижняя, и верхняя границы равны NULL, создаётся стандартная секция. Количество секций определяется первым измерением массива. Этот параметр является необязательным.

global (boolean)

Определяет, что таблица является глобальной. Если этот параметр задан, таблица будет распределена по всем группам репликации и будет синхронизироваться триггерами. Этот параметр является необязательным.

Примеры

В данном примере создаётся таблица pgbench_branches, а также совмещённые таблицы pgbench_accounts и pgbench_history. Каждая секция таблицы pgbench_history дополнительно разбивается на секции по диапазону.

CREATE TABLE pgbench_branches (
       bid integer NOT NULL PRIMARY KEY,
       bbalance integer,
       filler character(88)
)
WITH (distributed_by = 'bid',
      num_parts = 8);
CREATE TABLE pgbench_accounts (
       aid integer NOT NULL,
       bid integer,
       abalance integer,
       filler character(84),
       PRIMARY KEY (bid, aid)
)
WITH (distributed_by = 'bid',
      num_parts = 8,
      colocate_with = 'pgbench_branches');
CREATE TABLE public.pgbench_history (
            tid integer,
            bid integer,
            aid integer,
            delta integer,
            mtime timestamp without time zone,
            filler character(22)
        )
WITH (distributed_by = 'bid',
      colocate_with = 'pgbench_branches',
      partition_by = 'mtime',
      partition_bounds =
          $${{minvalue, '2021-01-01 00:00'},{'2021-01-01 00:00', '2022-01-01 00:00'},{'2022-01-01 00:00', maxvalue}}$$
);

В следующих примерах команды CREATE TABLE показаны ограничения, связанные с созданием совмещённых таблиц:

Эта команда создаёт таблицу для совместного размещения:

CREATE TABLE teams_players (
       team_id integer NOT NULL,
       player_id integer,
       scores int,
       PRIMARY KEY (team_id, player_id)
) WITH (distributed_by='team_id, player_id');

Следующая команда корректно создаёт совмещённую таблицу:

CREATE TABLE players_scores (
       player_id integer NOT NULL,
       team_id integer,
       interval tstzrange,
       scores integer,
       foreign key (team_id, player_id) references teams_players(team_id, player_id)
) WITH (distributed_by='team_id, player_id', colocate_with='teams_players');

А следующая команда содержит ошибку в определении внешнего ключа:

CREATE TABLE players_scores (
       player_id integer NOT NULL,
       team_id integer,
       interval tstzrange,
       scores integer,
       foreign key (team_id, player_id) references teams_players(team_id, player_id)
) WITH (distributed_by='player_id, team_id', colocate_with='teams_players');
ERROR:  foreign key should start with distributed_by columns

Рассмотрим другой пример:

CREATE TABLE teams (team_id integer primary key, team_name text) with (distributed_by='team_id');
CREATE TABLE players_teams (
       player_id integer,
       team_id integer references teams(team_id),
       scores integer
) WITH (distributed_by='player_id', colocate_with='teams');
ERROR:  foreign key should start with distributed_by columns

См. также

Ограничения CREATE TABLE, PostgreSQL CREATE TABLE

CREATE TABLESPACE

CREATE TABLESPACE — создать табличное пространство

Синтаксис

CREATE TABLESPACE табл_пространство
    [ OWNER { новый_владелец | CURRENT_ROLE | CURRENT_USER | SESSION_USER } ]
    LOCATION 'шаблон'
    [ WITH ( параметр_табличного_пространства = значение [, ... ] ) ]

Описание

Расширение синтаксиса команды CREATE TABLESPACE в Shardman позволяет создавать новое табличное пространство на уровне кластера. Все табличные пространства в кластере Shardman должны создаваться на уровне кластера. Табличное пространство на уровне кластера создаётся на каждом узле с расположением, полученным из параметра шаблон.

Параметры

табл_пространство

Имя создаваемого табличного пространства. Это имя не может начинаться с pg_, так как такие имена зарезервированы для системных табличных пространств. Имя также не может содержать символы начала новой строки.

шаблон

Шаблон имени каталога, который будет использоваться для табличного пространства. Шаблон должен включать подстроку «{rgid}», которая преобразовывается в фактический идентификатор группы репликации в каждом экземпляре, где выполняется оператор. Шаблон имени каталога должен разрешать преобразование в абсолютный путь. Путь не может содержать символы начала новой строки. CREATE TABLESPACE создаёт соответствующий каталог, если он отсутствует. Если каталог существует, он должен быть пуст и принадлежать системному пользователю PostgreSQL.

параметр_табличного_пространства

Параметр табличного пространства, который нужно установить или сбросить. Список параметров должен включать логический параметр global. Создание неглобальных табличных пространств по умолчанию запрещено.

Примеры

Чтобы создать табличное пространство dbspace, расположенное в файловой системе в каталоге /data/dbs, сначала создайте этот каталог средствами операционной системы на всех узлах и установите для него подходящего владельца (или проверьте, что у пользователя postgres есть право его создать):

mkdir /data/dbs
chown postgres:postgres /data/dbs

Затем выполните в PostgreSQL команду, собственно создающую табличное пространство:

CREATE TABLESPACE dbspace LOCATION '/data/dbs/ts-{rgid}' WITH (global);

См. также

PostgreSQL CREATE TABLESPACE

6.6. Ограничения SQL

В целях обеспечения согласованности сегментированной базы данных, Shardman ограничивает возможности некоторых выполняемых SQL-команд.

6.6.1. Ограничения команды ALTER SYSTEM

Команда ALTER SYSTEM запрещена (изменение конфигурации должно выполняться через shardmanctl config update).

6.6.2. Ограничения команды ALTER TABLE

Команда ALTER TABLE запрещена для секций сегментированных таблиц.

Все формы команды ALTER TABLE запрещены для сегментированных или глобальных таблиц, за исключением следующих:

Команда ALTER TABLE OWNER разрешена. Для сегментированной таблицы эта команда также меняет владельца секций таблицы. Только глобальный пользователь может быть владельцем сегментированной или глобальной таблицы.

Для команды ALTER TABLE COLUMN TYPE существуют следующие ограничения. Нельзя изменить тип столбца сегментированной таблицы, участвующего в сегментировании или ключе секционирования. Нельзя изменить тип столбца сегментированной таблицы с помощью предложения USING (но это разрешено для глобальных таблиц). Кроме того, на данный момент пользователь должен самостоятельно создавать и поддерживать точное равенство новых типов на каждом узле кластера.

Разрешена команда ALTER TABLE COLUMN RENAME.

Допускается добавление или удаление уникальных ограничений и проверок для всей таблицы. Для глобальных таблиц запрещено удаление ограничения первичного ключа или удаление столбцов, являющихся частью первичного ключа.

Добавление внешних ключей между сегментированными таблицами возможно только в том случае, если они размещены совместно и внешний ключ ссылается на кортежи, которые хранятся в той же группе репликации. Внешний ключ между сегментированными таблицами должен начинаться со столбцов, используемых для секционирования в обеих таблицах. Внешний ключ в глобальной таблице может ссылаться только на другую глобальную таблицу. Внешний ключ в сегментированной таблице может ссылаться на совмещённую сегментированную таблицу или глобальную таблицу.

Разрешены действия SET/DROP NOT NULL.

Задание параметров хранения разрешено для глобальных таблиц.

Глобальные таблицы не могут наследовать другие таблицы.

Команда ALTER COLUMN SET STATISTICS разрешена для глобальных и сегментированных таблиц.

6.6.3. Ограничения команды CREATE TABLE

Для команды CREATE TABLE применяются все ограничения команды ALTER TABLE.

Использование невстроенных типов (типов со значениями OID >= 10000) или небазовых типов или массивов в столбцах «distributed_by» запрещено.

Только глобальный пользователь может создавать сегментированные или глобальные таблицы.

В совмещённой таблице количество и типы столбцов, используемых для секционирования таблицы, должны быть такими же, как и в таблице для совместного размещения.

Нельзя создать временную сегментированную или глобальную таблицу.

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

Следующие ограничения применяются к таблицам, созданным с помощью LIKE исходная_таблица, где исходная_таблица является локальной:

Копирование без предложения вариант_копирования или с INCLUDING INDEXES поддерживается.

С помощью INCLUDING INDEXES копируются только уникальные индексы и индексы с поддержкой первичного ключа отношения.

Копирование индексов для столбцов не поддерживается.

Использование ограничений EXCLUDE не поддерживается.

У локальных таблиц в команде CREATE TABLE LIKE должны быть только столбцы базовых типов.

Частичные индексы не поддерживаются.

Поддерживаются только стандартные правила сортировки.

Ограничение по NULLS NOT DISTINCT не поддерживается.

6.6.4. Ограничения команды DROP TABLE

Сегментированные глобальные или локальные таблицы нельзя удалить командой DROP TABLE в одном и том же операторе.

Нельзя удалять секции сегментированной таблицы.

6.6.5. Ограничения команды CREATE INDEX CONCURRENTLY

CREATE INDEX CONCURRENTLY — это нетранзакционная команда. Если при построении индекса для сегментированной или глобальной таблицы возникает проблема, такая как сбой сети, взаимоблокировка или нарушение уникальности в уникальном индексе, CREATE INDEX CONCURRENTLY выполнится частично неверно, но может оставить после себя рабочие или нерабочие индексы в узлах кластера Shardman. Также в некоторых узлах может полностью отсутствовать индекс. В последнем случае команда DROP INDEX не будет работать. Рекомендуемый способ удаления такого индекса для всего кластера — использовать команду DROP INDEX IF EXISTS. Обратите внимание, что DROP INDEX CONCURRENTLY не поддерживается для сегментированных таблиц, поэтому эту операцию лучше выполнять в период обслуживания.

6.6.6. Ограничения команды UPDATE

Команда UPDATE для сегментированной таблицы выполняется как серия обычных команд UPDATE, если она не перемещает данные между секциями или подсекциями. В противном случае она выполняется внутри как удаление (DELETE) из одной секции и вставка (INSERT) в другую (так называемую целевую секцию). Если секция, в которую UPDATE добавляет данные (INSERT), изменяется в том же операторе, возникнет ошибка. На практике это означает, что если UPDATE перемещает данные между секциями, нужно явно исключить целевую секцию из изменения в предложении WHERE оператора.

6.6.7. Ограничения команды INSERT ON CONFLICT DO UPDATE

Команда INSERT ON CONFLICT DO UPDATEимя_таблицы... ON CONFLICT [conflict_target] conflict_action [WHERE condition] не поддерживается для сторонних таблиц, когда conflict_target это DO UPDATE. Поддерживается для сегментированных таблиц, если выражения в предложениях SET и WHERE могут быть безопасно разобраны (в настоящее время разбор sqlvalue-функций, параметров и подзапросов внутри этих предложений не поддерживается) и если нечастичный уникальный индекс, содержащий только столбцы таблицы (но не выражения на основе столбцов), соответствует выражению conflict_target. Обычно этим критериям соответствует первичный ключ таблицы.

6.6.8. Ограничения управления глобальными ролями

Глобальных пользователей может создавать только пользователь с разрешением CREATEROLE на всех узлах кластера.

Глобальные роли не могут быть переименованы.

Глобальные и локальные роли нельзя удалить одновременно в одном операторе.

GRANT для локальной и глобальной роли в одном операторе запрещён.

REVOKE от локальной и глобальной роли в одном операторе запрещён.

6.6.9. Ограничения сопоставлений пользователей

Команды CREATE USER MAPPING, ALTER USER MAPPING, and DROP USER MAPPING запрещены, если сопоставление происходит для сторонних серверов и кластера Shardman. Вместо этого используйте механизмы Shardman, описанные в разделе Управление пользователями и ролями.

6.6.10. Ограничения команды ALTER SCHEMA

Схемы, содержащие глобальные или сегментированные таблицы, нельзя переименовывать с помощью команды ALTER SCHEMA. Служебные схемы Shardman (shardman) нельзя переименовывать или удалять.

6.6.11. Ограничения команды DROP SERVER

Серверы кластера Shardman не могут быть удалены командой DROP SERVER. Используйте инструменты Shardman для удаления серверов из кластера.

6.6.12. Ограничения использования пользовательских баз данных

Работа с пользовательскими базами данных не поддерживается. В ходе работы shardmanctl все локальные пользовательские базы данных могут быть повреждены или потеряны.

6.6.13. Ограничения команды CREATE COLLATION

Если используются пользовательские правила сортировки с помощью команды CREATE COLLATION, на всех серверах должна быть установлена одна и та же версия icu. В противном случае результаты запросов к сегментированным таблицам могут быть некорректными.

6.6.14. Ограничения логической репликации

Попытка публикации таблицы, содержащей сторонние секции, с указанием параметра publish_via_partition_root завершится ошибкой. Без этого параметра в публикацию будут включены только локальные секции.

При использовании FOR TABLES IN SCHEMA или FOR ALL TABLES будут публиковаться только локальные секции.

Из публикации с FOR TABLES IN SCHEMA WITH или FOR ALL TABLES вместе с параметром publish_via_partition_root исключаются любые таблицы со сторонними секциями. Добавление сторонних секций в таблицы, включённые в публикации с publish_via_partition_root, также приведёт к ошибке.

При выполнении ALTER SUBSCRIPTION ... REFRESH PUBLICATION таблицы могут добавляться или удаляться из публикации в зависимости от изменений секций.

При использовании FOR ALL TABLES из публикации исключаются таблицы схемы shardman. При этом можно создать публикацию для всех таблиц этой схемы или для отдельных таблиц.

6.6.15. Прочие ограничения

Команда DROP TYPE CASCADE запрещена, если она влияет на типы, используемые в глобальных или сегментированных таблицах.

Управление правами доступа на глобальные таблицы на уровне столбцов не поддерживается.

6.7. Справочное руководство по Shardman CLI

shardmanctl

shardmanctl — вспомогательный клиент командной строки и средство развёртывания Shardman

Синтаксис

shardmanctl [общие_параметры] backup --datadir каталог [ --maxtasks число_заданий] --use-ssh

shardmanctl [общие_параметры] daemon check -n | --nodes имена_узлов:порт

shardmanctl [общие_параметры] cleanup [ -p | --processrepgroups ] --after-node-operation --after-rebalance

shardmanctl [общие_параметры] config generate [ -f | --file имя_файла]

shardmanctl [общие_параметры] config verify [ -f | --file имя_файла]

shardmanctl [общие_параметры] config get [ -f | --file ] [ -c | --choose-revision ] [ -r | --revision ]

shardmanctl [общие_параметры] config revisions rm [ -r | --revision ] [ -y | --yes ]

shardmanctl [общие_параметры] config update [[ -f | --file файл_конфигурации_stolon|файл_конфигурации_shardman] | текст_конфигурации [ --force ] [ -p | --patch ] [ -w | --wait длительность]]

shardmanctl [общие_параметры] config rollback [ -r | --revision ] [ -w | --wait длительность] [ --force ]

shardmanctl [общие_параметры] config update credentials [ -u | --user ] [ -p | --password ] [ -k | --ssl-key ] [ -c | --ssl-cert ] [ -w | --wait длительность] [ -f | --force ] [ -y | --yes ]

shardmanctl [общие_параметры] config revisions [ -f | --format json|text ]

shardmanctl [общие_параметры] config revisions set --keep-config-revisions

shardmanctl [общие_параметры] config update ip [ -u | ip_1=ip_2,hostname_1=hostname_2 ] [ -y | --yes ]

shardmanctl [общие_параметры] config update fdw [ -y | --yes ]

shardmanctl [общие_параметры] cluster repfactor set --value значение

shardmanctl [общие_параметры] cluster start

shardmanctl [общие_параметры] cluster stop [ -y | --yes ]

shardmanctl [общие_параметры] cluster topology [ -f | --format table|json|text ]

shardmanctl [общие_параметры] forall --sql query [ --twophase]

shardmanctl [общие_параметры] getconnstr --all

shardmanctl [общие_параметры] init [ -y | --yes ] [ -f | --spec-file имя_файла_конфигурации] | текст_конфигурации

shardmanctl [общие_параметры] intcheck [ -s | --system ] [ -c | --catalog ] [ -u | --user ] [ -o | --output ] [ -n | --node узел]

shardmanctl [общие_параметры] load [ -b | --batch-size предел_числа_строк] [ --destination-fields список_полей] [ --distributed-keys список_типов_ключей] [ -D | --delimiter символ] [ --null_marker строка] [ -e | --escape символ] [ -f | --file входной_файл] [ -F | --format text | csv ] [ -j | --jobs число_заданий] [ -q | --quote символ] [ --reject-file имя_файла] [ --schema имя_файла] [ --source file | postgres ] [ --source-connstr строка_подключения] [ --source-fields список_полей] [ --source-table таблица|представление|функция] [ -t | --table целевая_таблица] [ -h | --help ]

shardmanctl [общие_параметры] nodes add -n | --nodes имена_узлов [ --no-rebalance]

shardmanctl [общие_параметры] nodes start -n | --nodes имена_узлов [ --no-wait]

shardmanctl [общие_параметры] nodes restart -n | --nodes имена_узлов [ --no-wait]

shardmanctl [общие_параметры] nodes stop -n | --nodes имена_узлов [ --no-wait]

shardmanctl [общие_параметры] nodes replace --old старый_узел --new новый_узел

shardmanctl [общие_параметры] nodes rm -n | --nodes имена_узлов

shardmanctl [общие_параметры] probackup [ init | archive-command | backup | checkdb | delete | merge | restore | set-config | show | validate | show-config ] [ параметры_подкоманды]

shardmanctl [общие_параметры] rebalance [ -f | --force ]

shardmanctl [общие_параметры] recover [ --info файл] [ --dumpfile файл] [ --shard сегмент] [ --metadata-only] [ --schema-only] [ --timeout секунды]

shardmanctl [общие_параметры] restart [ -y | --yes ] [ --no-wait ]

shardmanctl [общие_параметры] set pgParam1=value1 [pgParam2=value2 [...]] [ -y | --yes ] [ -w | --wait длительность] [ -f | --force ]

shardmanctl [общие_параметры] shard -s | --shard имя_сегмента add -n | --node имена_узлов

shardmanctl [общие_параметры] shard -s | --shard имя_сегмента master set [ -y | --yes ] -n | --node имена_узлов

shardmanctl [общие_параметры] shard -s | --shard имя_сегмента master reset [ -y | --yes ]

shardmanctl [общие_параметры] shard -s | --shard имя_сегмента reset [ -y | --yes ] [ --new-primary | -p ]

shardmanctl [общие_параметры] shard -s | --shard имя_сегмента rm -n | --node имена_узлов [ -f | --force ]

shardmanctl [общие_параметры] shard -s | --shard имя_сегмента switch [ --new-primary имена_узлов]

shardmanctl [общие_параметры] shard -s | --shard имя_сегмента start [ --no-wait ] [ -n | --node имя_узла]

shardmanctl [общие_параметры] shard -s | --shard имя_сегмента stop [ -n | --node имя_узла]

shardmanctl [общие_параметры] shard -s | --shard имя_сегмента replicas reinit [ --no-wait ] [ -y | --yes ] [ -n | --node имена_узлов]

shardmanctl [общие_параметры] status [ --filter all | dictionary | primary | metadata | rg | shardmand | store | топология | restart_required_params ] [ -f | --format текст | json ] [ -s | --sort узел | группа_репликации | статус ]

shardmanctl [общие_параметры] status transactions [ -r | --repgroup имя_группы_репликации]

shardmanctl [общие_параметры] store dump [ -f | --file имя_файла]

shardmanctl [общие_параметры] store restore [ --delete-old-keys ] [ -f | --file имя_файла] [ -y | --yes ]

shardmanctl [общие_параметры] store get [ -a | --alias кластер | ковш | группы_репликации | конфигурация_stolon | конфигурация ] [ -k | --key имя_ключа] [ -f | --file имя_файла]

shardmanctl [общие_параметры] store keys

shardmanctl [общие_параметры] store set [ -a | --alias кластер | ковш | группы_репликации | конфигурация_stolon | конфигурация ] [ -k | --key имя_ключа] [ -f | --file имя_файла]

shardmanctl [общие_параметры] store lock [ -f | --format текст | json ]

shardmanctl [общие_параметры] tables sharded info [ -t | --table таблица ]

shardmanctl [общие_параметры] tables sharded list

shardmanctl [общие_параметры] tables sharded norebalance

shardmanctl [общие_параметры] tables sharded partmove [ -t | --table таблица ] [ -s | --shard имя_сегмента ] [ -p | --partnum номер_секции ]

shardmanctl [общие_параметры] tables sharded rebalance [ -t | --table таблица ] [ --skip-run-rebalance ]

shardmanctl [общие_параметры] upgrade

shardmanctl [общие_параметры] bench init [ --schema-type single|simple|shardman|custom ] [ -S | --schema-file имя_файла] [ -s | --scale значение_масштабирования] [ --partitions значение_секций] [ -n | --no-vacuum ] [ -F | --fillfactor значение_коэффициента_заполнения]

shardmanctl [общие_параметры] bench run [ --schema-type single|simple|shardman|custom ] [ -f | --file имя_файла] [ -c | --client число_клиентов] [ -C | --connect ] [ --full-output ] [ -j | --jobs число_процессов] [ -s | --scale коэффициент_масштаба] [ -T | --time секунды] [ -t | --transactions число_транзакций] [ -P | --progress секунды] [ -R | --rate скорость_передачи] [ -M | --protocol режим_запросов]

shardmanctl [общие_параметры] bench cleanup

shardmanctl [общие_параметры] bench generate [ -c | --config файл_конфигурации] [ -o | --output-file имя_файла]

shardmanctl [общие_параметры] script [ -s | --shard имя_сегмента] [[ -f | --file имя_файла | --sql query]]

shardmanctl [общие_параметры] psql -s | --shard имя_сегмента

shardmanctl [общие_параметры] daemon set [ --session-log-level | debug | info | warn | error ] [ --session-log-format | text | json ] [ --session-log-nodes ]

shardmanctl [общие_параметры] history [ -r | --reverse ] [ -f | --format текст | json ] [ -l | --limit число_команд ]

Здесь общие_параметры могут принимать следующие значения:

[ --cluster-name имя_кластера ] [ --log-level error | warn | info | debug ] [ --monitor-port порт] [ --retries число_повторов] [ --session-timeout секунды] [ --store-endpoints адреса_хранилища] [ --store-ca-file файл_сертификата_ca] [ --store-cert-file файл_сертификата_клиента] [ --store-key частный_ключ_клиента] [ --store-timeout длительность] [ --version] [ -h | --help ]

Описание

shardmanctl — это утилита для управления кластером Shardman.

Для любой команды, которая использует имя узла в качестве аргумента, имя узла кластера может быть указано либо по имени узла сети, либо по IP-адресу.

Команда backup используется для резервного копирования кластера Shardman. Резервная копия представляет собой каталог с базовыми копиями всех групп репликации и файлами WAL, необходимыми для восстановления. Метаданные etcd сохраняются в файле etcd_dump. Файл backup_info создаётся во время резервного копирования и содержит описание копии. Подробнее логика работы команды backup описана в разделе Резервное копирование кластера приложением pg_basebackup. Использование команды описано в Подразделе «Резервное копирование кластера Shardman».

Команда cleanup используется для очистки после сбоя команды nodes add или команды rebalance утилиты shardmanctl . Окончательные изменения в хранилище etcd вносятся в конце выполнения команды. Это упрощает процесс очистки. Во время очистки неполные определения звена и определения соответствующих групп репликации удаляются из метаданных etcd. Определения соответствующих сторонних серверов удаляются из метаданных СУБД остальных групп репликации. Поскольку процесс cleanup может удалять данные, по умолчанию инструмент работает исключительно в режиме отчёта: он показывает только те действия, которые необходимо выполнить во время фактической очистки. Для выполнения реальной очистки нужно добавить ключ -p. Использование команды подробно описано в Подразделе «Выполнение очистки».

Команда daemon check используется, чтобы проверить, что демон shardmand работает на узлах, указанных в параметре --nodes, и настроен для того же кластера, что и shardmanctl . Использование команды подробно описано в Подразделе «Проверка работы службы shardmand на узлах».

Команда init используется для регистрации нового кластера Shardman в хранилище etcd или переинициализации существующего (будет задана новая конфигурация кластера, удалены все данные и узлы). В режиме инициализации утилита shardmanctl считывает спецификацию кластера, обрабатывает её и сохраняет в хранилище etcd как части двух документов JSON: ClusterSpec — как часть shardman/cluster0/data/cluster и LadleSpec — как часть shardman/cluster0/data/ladle (cluster0 — это имя кластера по умолчанию, используемое утилитами Shardman). Общие параметры, связанные с хранилищем etcd, например --store-endpoints, также сохраняются в хранилище etcd и передаются всем службам Shardman, запущенным расширением shardmand. Формат файла инициализации Shardman подробно описан в разделе sdmspec.json, а использование команды init — в Подразделе «Регистрация кластера Shardman».

Команда config generate используется для создания шаблона sdmspec.json по умолчанию. Результат записывается в стандартный вывод. Чтобы записать результат в файл, используйте флаг -f имя_файла. Формат файла инициализации Shardman описан в sdmspec.json.

Команда config verify используется для проверки корректности входного файла инициализации Shardman. По умолчанию конфигурация считывается со стандартного ввода. Чтобы конфигурация читалась из файла, используйте флаг -f имя файла. За описанием формата файла инициализации Shardman обратитесь к sdmspec.json.

Команда config get используется для вывода текущей полной конфигурации кластера или конфигурации указанной версии. Текущая конфигурация кластера берётся из хранилища кластера. Формат файла инициализации Shardman описан в sdmspec.json.

Команда config update используется для обновления конфигурации stolon или конфигурации всего Shardman. Новая конфигурация применяется ко всем группам репликации и сохраняется в ключе etcd shardman/cluster0/data/cluster. Обратите внимание, что config update может привести к перезапуску СУБД.

Команда forall используется для выполнения оператора SQL во всех группах репликации в кластере Shardman.

Команда getconnstr используется для получения строки подключения libpq и подключения к кластеру в роли администратора.

Команда load используется для загрузки данных из текстового файла в распределённую таблицу или для загрузки схемы базы данных из базы данных PostgreSQL в Shardman. При загрузке данных из файла поддерживаются форматы text и csv (файлы могут быть сжаты при помощи gzip, тогда при чтении они декодируются автоматически); если нужно прочесть данные из stdin, то следует указать параметр --file=-. Процесс загрузки данных можно оптимизировать, указав число параллельных рабочих процессов (ключ -j).

Команда nodes add используется для добавления новых узлов в кластер Shardman. Со стандартной политикой размещения cross узлы добавляются в кластер в виде звеньев. На каждом узле в звене работает ведущий экземпляр СУБД и, возможно, несколько реплик других узлов этого звена. Число реплик определяется параметром конфигурации Repfactor. Таким образом, каждое звено состоит из Repfactor + 1 узлов и может выдержать потерю Repfactor узлов.

При ручной политике размещения каждый новый узел добавляется как группа репликации, состоящая из одного ведущего сервера. После добавления ведущих узлов можно добавить реплики в новую группу репликации, используя команду shard add.

Утилита shardmanctl выполняет операцию nodes add в несколько этапов:

Получает глобальную блокировку метаданных.

Для каждого указанного узла проверяет, работает ли на нём служба shardmand и видит ли он текущую конфигурацию кластера.

Вычисляет службы, которые должны присутствовать на каждом узле, и сохраняет эту информацию в etcd как часть Layout объекта shardman/cluster0/data/ladle.

Создаёт конфигурацию для новых кластеров stolon (также называемых группами репликации) и инициализирует их.

Регистрирует добавленные группы репликации в ключе etcd shardman/cluster0/data/ladle.

Ожидает, пока shardmand запустит все необходимые службы, и проверяет доступность новых групп репликации и правильность их конфигураций.

Создаёт вспомогательный сервер трансляций, который удерживает блокировки для каждой существующей группы репликации в кластере.

Для каждой новой группы репликации в кластере копирует все схемы и данные схем shardman из случайно выбранной существующей группы репликации в новую группу, а также проверяет, что расширение Shardman установлено в новой группе репликации, и пересчитывает OID, используемые в таблицах конфигурации расширения.

В каждой существующей группе репликации определяет сторонние серверы, ссылающиеся на новую группу репликации, и воссоздаёт определения сторонних серверов в новой группе репликации.

Пересоздаёт все секции сегментированных таблиц как сторонние таблицы, ссылающиеся на данные из старых групп репликации, и регистрирует изменения в хранилище etcd.

Для каждой новой группы репликации копирует данные глобальной таблицы из существующих групп репликации в новую.

Выполняет перебалансировку секции сегментированных таблиц. В процессе перебалансировки для каждой сегментированной таблицы итерационно определяется группа репликации с максимальным и минимальным количеством секций и создаётся задача на перемещение одной секции в группу репликации с минимальным количеством секций. Этот процесс повторяется, пока max - min > 1. Для перемещения секций используется логическая репликация. Секции совместно размещённых таблиц перемещаются совместно с секциями распределённых таблиц, на которые они ссылаются. Можно пропустить этот шаг, используя --no-rebalance.

Использование данной команды подробно описано в Подразделе «Добавление узлов в кластер Shardman».

Команда nodes rm используется для удаления узлов из кластера Shardman. В режиме manual удаляются только указанные узлы. Если узел является последним в репликационной группе, то удаляется и вся группа репликации. В режиме cross команда удаляет из кластера звенья, содержащие указанные узлы. Последнее звено в кластере не может быть удалено. Любые данные (например, секции сегментированных отношений) в удалённых группах репликации переносятся в оставшиеся группы посредством логической репликации, а все ссылки на удалённые группы репликации (включая определения сторонних серверов) удаляются из метаданных оставшихся групп репликации. Наконец, обновляются метаданные в etcd. Использование команды подробно описано в Подразделе «Удаление узлов из кластера Shardman».

Команда probackup выполняет резервное копирование и восстановление кластера Shardman, используя утилиту резервного копирования pg_probackup. Логика команды probackup описана в разделе Резервное копирование и восстановление резервных копий Shardman посредством pg_probackup. Более подробное использование команды probackup описано в Подразделе « probackup ».

Команда rebalance используется для равномерной перебалансировки сегментированных таблиц в кластере. Это может быть полезно, например, если перебалансировка не выполнялась при добавлении узлов в кластер. Если не указан параметр --force, таблицы с разделами, перемещёнными вручную, будут пропущены.

Команда cleanup с флагом --after-rebalance используется для выполнения очистки после сбоя команды rebalance. На каждом узле она удаляет подписки и публикации, оставшиеся после команды rebalance, а также таблицы, в которых хранятся данные частично переданных секций сегментированных таблиц.

Команда cluster repfactor set используется для установки значения коэффициента репликации для кластера Shardman. Эту команду можно использовать только в ручном (manual) режиме топологии кластера. Значение нового коэффициента репликации передаётся через флаг командной строки --value коэффициент_репликации.

Команда cluster start используется для запуска всех экземпляров PostgreSQL, остановленных командой cluster stop. Чтобы команда работала, должен быть запущен shardmand.

Команда cluster stop используется для остановки всех экземпляров PostgreSQL для кластера Shardman. При этом демоны shardmand продолжают работать.

Команда cluster topology используется для визуализации топологии кластера. По умолчанию топология возвращается в виде таблицы. Если необходимо получить представление в формате JSON, используйте флаг --format json|text.

Команда recover используется для восстановления кластера Shardman из резервной копии, созданной командой backup. Логика команды recover описана в разделе Восстановление кластера из резервной копии посредством pg_basebackup. Более подробное использование команды recover описано в разделе «Восстановление кластера Shardman».

Команда restart используется для перезапуска кластера Shardman, включая все экземпляры shardmand. Если экземпляры PostgreSQL были предварительно остановлены командой cluster stop, они будут запущены. Команда возвращает управление после перезапуска всех ведущих серверов в кластере.

Команда set используется для установки одного или нескольких параметров экземпляров СУБД кластера Shardman. Параметры передаются в командной строке в качестве аргументов, каждый из них имеет вид param=value. Эта команда является аналогом shardmanctl config update -p для изменения параметров базы данных.

Команда status используется для отображения состояния работоспособности подсистем кластера Shardman. Она может отображать состояние нескольких компонентов: хранилища, метаданных, shardmand, групп репликации, ведущих серверов, словаря и перезапуска необходимых параметров. Если нужна информация об определённых подсистемах, можно использовать параметр --filter. Также status поддерживает сортировку своих результатов по значениям status, node или replication group и выводит их в виде таблицы (table), текста (text) или в формате JSON (json) на stdout, значение по умолчанию — table. Использование команды описано в разделе «Получение статуса подсистем кластера».

Команда store dump получает все ключи и их значения из хранилища etcd и выводит их в --file, причём значение - используется для вывода в стандартный вывод (по умолчанию). Она предназначена для отладки, поэтому во время выполнения могут возникать некоторые некритичные ошибки, но при этом вся доступная информация будет сохранена. Будут выгружены только ключи для текущего кластера (с текущим префиксом кластера, например shardman/cluster0/). Использование команды описано в разделе «Выгрузка всех ключей из хранилища для отладки конфигурации ошибок».

Команда store get получает конкретное значение из хранилища по имени ключа. Ожидается, что это значение JSON, поэтому, если это не так (что не запрещено), могут возникать некоторые некритичные ошибки. Ключ для извлечения из хранилища можно указать в параметре --key; несколько ключей имеют псевдонимы — короткие имена для удобства использования. Чтобы получить ключ по его псевдониму, используйте параметр --alias с одним из доступных псевдонимов (используйте --help или примеры ниже для справки). Также псевдонимы stolonspec и spec можно использовать для явного управления начальным кластером и конфигурацией stolon, не извлекая их из полной конфигурации кластера. Рекомендуется использовать существующие псевдонимы вместо полных имён ключей, так как при обработке псевдонимов есть некоторые дополнительные проверки, которые помогают достичь более надёжных результатов. По умолчанию ключ выводится на стандартный вывод (явно — с параметром --file=-), но может быть выведен в любой желаемый файл. Использование команды описано в разделе «Получение текущей конфигурации stolon».

Команда store keys показывает все сохранённые ключи для текущего кластера (с префиксом кластера) и его псевдонимов. Псевдонимы stolonspec и spec не показаны, так как они являются частями других ключей. Использование команды описано в разделе «Получение имён ключей кластера и ковша для текущего кластера».

Команда store set создаёт или перезаписывает один конкретный ключ в хранилище. Это не обязательно должно быть значение JSON для случайного ключа, но если это один из ключей с известным сопоставлением псевдонимов (например, ladle или cluster), команда не примет некорректные структуры JSON. Как и store get команда store set принимает имя ключа в параметре --key или --alias и входной файл в параметре --file (stdin указывается со значением -). Использование команды описано в разделе «Установка новой конфигурации для кластера».

Команда store lock показывает информацию о текущей блокировке метаданных кластера. Если блокировки не существует, возвращает Lock not found. Отображает идентификатор кластера, команду, которая получила блокировки, имя узла и время блокировки. Вы можете указать в параметре --format формат вывода: json или text (по умолчанию). Использование команды описано в разделе «Вывод информации о текущей блокировке метаданных кластера».

Команда upgrade используется для обновления версии расширения PostgreSQL Shardman на всех узлах кластера. Перед обновлением расширений необходимо установить новые пакеты и выполнить команду restart. В результате выполнения upgrade утилиты обновят shardman и все остальные расширения на сервере.

Иногда после запуска команды upgrade или некоторых действий пользователя при выводе команды status могут обнаруживаться ошибки словаря. Они возникают в том числе потому, что значения полей srvoptions таблицы pg_foreign_server отличаются от ожиданий системы. Чтобы решить эту проблему, воспользуйтесь командой config update fdw, которая вернёт srvoptions в ожидаемое состояние.

Примечание

Для большинства описанных команд shardmanctl используется глобальная блокировка метаданных.

Справка по командной строке

В этом разделе описываются команды shardmanctl. Общие параметры команд Shardman описаны в разделе «Общие параметры».

backup

Синтаксис:

    shardmanctl [общие_параметры] backup --datadir каталог [--maxtasks число_заданий][--use-ssh]

Создаёт резервную копию кластера Shardman.

--datadir каталог

Обязательный параметр.

Указывает каталог для записи вывода. Если каталог существует, он должен быть пустым. Если он не существует, shardmanctl создаст его (но не родительские каталоги).

--maxtasks число_заданий

Задаёт максимальное количество одновременно выполняемых задач (команды pg_probackup).

По умолчанию соответствует числу логических CPU в системе.

--use-ssh

Если указано, команда shardmanctl recover будет использовать команду scp для восстановления данных. Это позволяет использовать хранилище резервных копий на локальном узле.

За подробностями обратитесь к Подразделу «Резервное копирование кластера Shardman»

cleanup

Синтаксис:

shardmanctl [общие_параметры] cleanup [-p|--processrepgroups] --after-node-operation|--after-rebalance

Выполняет очистку после команды nodes add или rebalance.

-p имена_узлов
--processrepgroups=имена_узлов

Выполняет фактическую очистку. По умолчанию утилита показывает только действия, которые необходимо выполнить во время фактической очистки. За дополнительными сведениями обратитесь к разделу Подразделу «Выполнение очистки».

--after-node-operation

Выполняет очистку после сбоя команды nodes add.

--after-rebalance

Выполняет очистку после сбоя команды rebalance.

config update credentials

Синтаксис:

shardmanctl [общие_параметры] config update credentials [-u | --user] [-p | --password] [-k | --ssl-key] [-c | --ssl-cert] [-w|--wait длительность] [--force] [-y | --yes]

Изменяет пароль или сертификат/ключ пользователя для подключения к кластеру Shardman. Изменяет только тип аутентификации, указанный пользователем (scram-sha-256, ssl), а не сам тип.

-u
--user

Пользователь, для которого требуется изменить параметры аутентификации.

-p
--password

Новый пароль.

-k
--ssl-key

Новый SSL-ключ.

-c
--ssl-cert

Новый SSL-сертификат.

-w
--wait

Указывает, что shardmanctl должен дождаться вступления в силу изменений конфигурации. Если новая конфигурация не может быть загружена всеми группами репликации, время ожидания shardmanctl будет бесконечным.

--force

Выполнять принудительное изменение, если выполняется операция на уровне кластера.

-y
--yes

Подтверждает операцию вместо того, чтобы запрашивать подтверждение от стандартного ввода.

cluster repfactor set

Синтаксис:

shardmanctl [общие_параметры] cluster repfactor set --value новый_коэффициент_репликации

Устанавливает коэффициент репликации для режима топологии manual.

--value=новый_коэффициент_репликации

Новое значение коэффициента репликации

cluster start

Синтаксис:

shardmanctl [common_options] cluster start

Запускает все экземпляры сервера PostgreSQL.

cluster stop

Синтаксис:

shardmanctl [общие_параметры] cluster stop [-y|--yes]

Останавливает все экземпляры сервера PostgreSQL.

-y
--yes

Подтверждает операцию вместо того, чтобы запрашивать подтверждение от стандартного ввода.

cluster topology

Синтаксис:

shardmanctl [общие_параметры] cluster topology -f|--format table|json|text

Выводит топологию кластера.

-f table|json|text
--format=table|json|text

Формат вывода. За подробностями обратитесь к Подразделу «Отображение топологии кластера».

daemon check

Синтаксис:

shardmanctl [общие_параметры] daemon check -n|--nodes имя_узла:порт

Проверяет shardmand на узлах.

-n имя_узла:порт
--nodes=имя_узла:порт

Список узлов, на которых будет проведена проверка shardmand. За подробностями обратитесь к Подразделу «Проверка работы службы shardmand на узлах».

forall

Синтаксис:

shardmanctl [общие_параметры] forall --sql запрос[ --sql запрос[ --sql запрос ...]] [--twophase]

Выполнение оператора SQL для всех групп репликации в кластере Shardman.

--sql query

Указывает оператор, который должен быть выполнен.

--twophase

Указывает использовать протокол двухфазной фиксации для выполнения оператора.

getconnstr

Синтаксис:

shardmanctl [общие_параметры] getconnstr --all

Получает строку подключения libpq для подключения к кластеру в роли администратора.

--all

Добавляет информацию о репликах в результат команды getconnstr.

init

Синтаксис:

    shardmanctl [общие_параметры] init [-y|--yes] [-f|--spec-file имя_файла_конфигурации]|текст_конфигурации

Регистрирует новый кластер Shardman в хранилище etcd или повторно инициализирует уже существующий кластер, задавая новую конфигурацию кластера и удаляя все его данные и узлы.

-f имя_файла_конфигурации
--specfile=имя_файла_конфигурации

Задаёт файл со строкой конфигурации кластера. Значение - означает стандартный ввод. По умолчанию строка передаётся в тексте_конфигурации. Использование данной команды подробно описано в разделе «Регистрация кластера Shardman».

-y
--yes

Подтверждает операцию вместо того, чтобы запрашивать подтверждение от стандартного ввода.

intcheck

Синтаксис:

    shardmanctl [общие_параметры] intcheck [-s|--system] [-u|--user] [-c|--catalog] [-o|--output]  [-n|--node узел]

Запускает pg_integrity_check на всех узлах кластера Shardman или на выбранном одном узле.

-s
--system

Проверить контрольные суммы неизменяемых файлов. В контрольных суммах неизменяемых файлов учитывается и содержимое, и атрибуты этих файлов.

-u
--user

Проверить контрольные суммы дополнительных файлов. В контрольных суммах дополнительных файлов учитывается и содержимое, и атрибуты этих файлов.

-c
--catalog

Проверить контрольные суммы для таблиц системных каталогов. Чтобы ключ -c работал корректно, также необходимо задать параметры подключения к базе данных. Сервер баз данных должен быть запущен и готов принимать подключения.

-o
--output

Пересчитать контрольные суммы и записать их в файл

-n имена_узлов
--node=имена_узлов

Выполнять команду pg_integrity_check только на выбранном узле

load

Синтаксис:

     shardmanctl [общие_параметры] load [ -b | --batch-size предел_числа_строк] [ --destination-fields список_полей]
     [ --distributed-keys список_типов_ключей] [ -D | --delimiter символ]
     [--null_marker строка] [ -e | --escape символ] [ -f | --file входной_файл]
     [ -F | --format текст|csv ] [ -j | --jobs общее_число_заданий] [ -q | --quote символ]
     [ --reject-file имя_файла] [ --schema имя_файла] [ --source файл|postgres]
     [ --source-connstr строка_подключения] [ --source-fields список_полей] [ --source-table исходная_таблица]
     [ -t | --table целевая_таблица]

Загрузка данных в кластер Shardman.

-b предел_числа_строк
--batch-size=предел_числа_строк

Показывает список резервных копий кластера Shardman.

По умолчанию: 1000.

--destination-fields=список_полей

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

--distributed-keys=список_типов_ключей

Список пар, разделённых запятыми. Каждая пара состоит из номера поля (начиная с ноля) и типа, разделённых двоеточием. Поддерживаются следующие типы: bool, char, float4, float8, int2, int4, int8, name, text, varchar и uuid.

-D символ
--delimiter=символ

Задаёт символ, разделяющий столбцы в строках файла. Задаваемый символ должен быть однобайтовым.

По умолчанию: табуляция для текстового формата, запятая для формата CSV.

--null_marker=строка

Указывает строку, представляющую нулевое значение.

По умолчанию: \N для текстового формата, пустая строка без кавычек для формата CSV.

-e символ
--escape=символ

Задаёт символ, который будет выводиться перед символом данных, совпавшим со значением QUOTE. По умолчанию это тот же символ, что и QUOTE (то есть при появлении в данных кавычек они дублируются). Задаваемый символ должен быть однобайтовым. Этот параметр допускается только для режима CSV.

-f имя_файла
--file=имя_файла

Имя файла входных данных (или - для стандартного ввода)

-F текст|csv
--format=текст|csv

Формат входных данных. Возможные значения: text и csv.

По умолчанию: text.

-j число
--jobs=число

Число параллельных процессов для загрузки данных.

По умолчанию равно числу групп репликации.

-q символ
--quote=символ

Указывает символ кавычек, используемый для заключения данных в кавычки. По умолчанию это символ двойных кавычек. Задаваемый символ должен быть однобайтовым. Этот параметр поддерживается только для формата CSV.

--reject-file=имя_файла

Все порции данных с ошибками при загрузке будут записаны в этот файл. Если значение не задано, то такие порции будут пропущены.

--schema=имя_файла

Схема, определяющая правила передачи данных из PostgreSQL в Shardman. Если установлен данный параметр, то все остальные параметры не используются.

--source=файл|postgres

Тип источника данных — file или postgres.

По умолчанию: file.

--source-connstr=строка

Строка подключения к базе источника данных

--source-fields=список_полей

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

--source-table=таблица

Исходная таблица, представление или функция (funcname(param1,...,paramN)).

-t таблица
--table=таблица

Целевая таблица.

nodes add

Синтаксис:

shardmanctl [общие_параметры] nodes add -n|--nodes имена_узлов [--no-rebalance]

Добавляет узлы в кластер Shardman.

-n имена_узлов
--nodes=имена_узлов

Обязательный параметр.

Задаёт список добавляемых узлов, разделённых запятыми.

--no-rebalance

Пропуск шага перебалансировки секций сегментированных таблиц. За подробностями обратитесь к Подразделу «Добавление узлов в кластер Shardman».

nodes rm

Синтаксис:

shardmanctl [общие_параметры] nodes rm -n|--nodes имена_узлов

Удаляет узлы из кластера Shardman.

-n имена_узлов
--nodes=имена_узлов

Задаёт список узлов, разделённых запятыми, которые необходимо удалить. За подробностями обратитесь к Подразделу «Удаление узлов из кластера Shardman».

probackup

Синтаксис:

shardmanctl [общие_параметры] probackup
       [init|archive-command|backup|checkdb|delete|merge|restore|set-config|show|validate|show-config]
       [--log-to-console][--help]
       [параметры_подкоманды]

Создаёт резервную копию кластера Shardman и восстанавливает кластер Shardman из резервной копии, используя pg_probackup.

Список подкоманд:

init

Инициализирует новый каталог репозитория для резервной копии кластера Shardman, а также создаёт конфигурационный файл для подключения к хранилищу резервных копий, если для параметра --storage-type установлено значение S3.

archive-command

Добавляет, включает или отключает archive_command для каждой группы репликации в кластере Shardman или только для одной группы, если указан параметр --shard.

backup

Создаёт резервную копию кластера Shardman.

checkdb

Проверяет кластер Shardman на наличие физических повреждений или логических нарушений.

delete

Удаляет резервную копию кластера Shardman с заданным идентификатором backup_id.

merge

Объединяет резервные копии, относящиеся к одной цепочке инкрементальных копий. При полном копировании резервные копии объединяются с их первой инкрементальной копией. При инкрементальном резервном копировании резервные копии объединяются с их родительской полной копией и всеми инкрементальными копиями между ними. После выполнения команды полная копия содержит все объединённые данные, а инкрементальные копии удаляются как ненужные. В текущей версии не поддерживается выполнение команды merge через интерфейс S3.

restore

Восстанавливает кластер Shardman из выбранной резервной копии.

show

Показывает список резервных копий кластера Shardman.

validate

Проверяет целостность выбранной резервной копии кластера Shardman.

show-config

Выводит все текущие параметры конфигурации pg_probackup, в том числе те, что содержатся в файле pg_probackup.conf, размещённом в каталоге каталог_копий/backups/имя_сегмента, а также те, что были заданы в командной строке.

set-config

Добавляет указанные параметры в файл pg_probackup.conf или изменяет значения, добавленные в него ранее.

Следующие параметры можно использовать во всех подкомандах probackup:

--log-to-console

Выводит полный журнал probackup в консоль. По умолчанию для каждой группы репликации файл журнала probackup появляется в каталоге резервного копирования (см. --backup-path ниже) в виде <backup-directory>/backup/log/pg_probackup-<repgroup-name>.log. Максимальный размер файла журнала составляет 20 МБ. По достижении этого лимита происходит ротация журнала при запуске команды shardmanctl probackup validate или shardmanctl probackup backup.

--help

Показывает справку по подкомандам.

init

Синтаксис:

shardmanctl [общие_параметры] probackup init
-B|--backup-path путь
-E|--etcd-path путь
[--remote-port порт]
[--remote-user имя_пользователя]
[--ssh-key путь]
[-t|--timeout секунды]
[-m|--maxtasks число_заданий]
[--storage-type mount|remote|S3]
[--s3-config-only]
[--s3-config-path путь]
[--s3-host узел_S3]
[--s3-port порт_S3]
[--s3-access-key ключ_доступа_S3]
[--s3-secret-key секретный_ключ_S3]
[--s3-bucket корзина_S3]
[--s3-region регион_S3]
[--s3-buffer-size размер_буфера_S3]
[--s3-retries число_повторов]
[--s3-timeout время]
[--s3-https]
[-y|--yes]

Инициализирует новый каталог репозитория для резервной копии кластера Shardman.

-B путь
--backup-path путь

Требуется при отсутствии параметра --s3-config-only. Указывает путь к каталогу, в котором должны храниться резервные копии кластера Shardman.

-E путь
--etcd-path путь

Требуется при отсутствии параметра --s3-config-only. Указывает путь к каталогу, в котором должны храниться копии etcd.

--remote-port порт

Указывает удалённый порт SSH для экземпляров группы репликации.

По умолчанию: 22.

--remote-user имя_пользователя

Указывает удалённого пользователя для подключения по SSH для экземпляров группы репликации.

По умолчанию: postgres.

--ssh-key путь

Указывает закрытый ключ SSH для удалённого выполнения команд по SSH.

По умолчанию: $HOME/.ssh/id_rsa.

--storage-type mount|remote|S3

Тип хранилища резервных копий. При значении remote протокол SSH используется для копирования файлов с данными в удалённый каталог резервных копий. Но это поведение можно изменить, если для хранения резервных копий используется каталог, смонтированный на всех узлах, или S3-совместимое объектное хранилище. Чтобы это сделать, установите для параметра --storage-type значение mount или S3 соответственно.

По умолчанию: remote.

--s3-config-path путь

Задаёт путь к каталогу, в котором создаётся файл конфигурации S3 на всех узлах Shardman.

По умолчанию: <shardman-data-dir>/s3.config.

--s3-config-only

Создаёт файлы конфигурации S3 на всех узлах, не инициализируя хранилище резервных копий. Этот флаг следует использовать, если параметр --storage-type имеет значение S3.

--s3-host узел

Задаёт узел сервера S3 для подключения к S3-совместимому хранилищу.

--s3-port порт

Задаёт порт сервера S3 для подключения к S3-совместимому хранилищу.

--s3-access-key ключ_доступа

Задаёт ключ доступа сервера S3 для подключения к S3-совместимому хранилищу.

--s3-secret-key ключ_доступа

Задаёт секретный ключ сервера S3 для подключения к S3-совместимому хранилищу.

--s3-bucket корзина

Задаёт имя корзины для хранения резервных копий в S3-совместимом объектном хранилище.

--s3-region корзина

Задаёт регион выбора сервера для S3-совместимого объектного хранилища.

--s3-buffer-size размер_буфера

Размер буфера чтения/записи приложения pg_probackup для организации связи S3-совместимым объектным хранилищем, в МиБ.

По умолчанию: 16.

--s3-retries число_повторов

Максимальное количество попыток выполнения запроса к S3 в случае сбоя.

По умолчанию: 5.

--s3-timeout время

Максимальное время передачи объёма данных, заданного параметром --s3-buffer-size, в S3-совместимое объектное хранилище или из него (в секундах).

По умолчанию: 300.

--s3-https

Задаёт протокол HTTPS для подключения к S3-совместимому объектному хранилищу.

-y|--yes

Подтверждает операцию независимо от наличия файла, указанного в параметре --s3-config-path.

archive-command

Синтаксис:

shardmanctl [общие_параметры] probackup archive-command [add|rm]
        -B|--backup-path путь
        [-j|--jobs число]
        [--compress]
        [--compress-algorithm алгоритм]
        [--compress-level уровень]
        [--batch-size размер_порции]
        [--storage-type mount|remote|S3]
        [--remote-port порт]
        [--remote-user имя_пользователя]
        [-s|--shard имя_сегмента]
        [--s3-config-path путь]
        [-y|--yes]

Добавляет/удаляет и включает/отключает команду архивирования для каждой группы репликации в кластере Shardman для размещения журналов WAL в инициализированном репозитории резервных копий.

add

Добавляет и включает команду archive для каждой группы репликации в кластере Shardman.

rm

Отключает команду archive в каждой группе репликации в кластере Shardman. Никаких дополнительных параметров не требуется.

-B путь
--backup-path путь

Требуется при добавлении archive_command. Указывает путь к каталогу, в котором должны храниться резервные копии кластера Shardman.

--batch-size batch_size

Для ускорения архивирования используется параметр --batch-size, определяющий размер порции из нескольких копируемых сегментов WAL. Вместе с параметром --batch-size также можно применить указание -j, чтобы порции копировались в несколько потоков.

--jobs число
-j число

Число параллельных потоков, которые используются pg_probackup при создании резервной копии. По умолчанию: 1.

--compress

Включает сжатие резервных копий. Если этот флаг не установлен, сжатие будет отключено. Если флаг установлен, используется принятый по умолчанию алгоритм zstd с уровнем сжатия 1, в то время как остальные параметры сжатия игнорируются, даже если они заданы.

--compress-algorithm алгоритм

Определяет алгоритм сжатия: zlib, lz4, zstd, pglz или none. Как только алгоритм задан, этот параметр проверяет, что значение уровня сжатия находится в пределах возможных значений для заданного алгоритма.

Список поддерживаемых алгоритмов сжатия зависит от версии Postgres Pro Enterprise, включающей используемое приложение pg_probackup. Подробная информация описана в статье Параметры сжатия.

По умолчанию: none.

--compress-level уровень

Определяет уровень сжатия: 0-9 для zlib, 1 для pglz, 0-22 для zstd и 0-12 для lz4.

По умолчанию: 1.

--storage-type mount|remote|S3

Тип хранилища резервных копий. При значении remote протокол SSH используется для копирования файлов с данными в удалённый каталог резервных копий. Но это поведение можно изменить, если для хранения резервных копий используется каталог, смонтированный на всех узлах, или S3-совместимое объектное хранилище. Чтобы это сделать, установите для параметра --storage-type значение mount или S3 соответственно.

По умолчанию: remote.

--remote-port порт

Указывает удалённый порт SSH для экземпляров группы репликации.

По умолчанию: 22.

--remote-user имя_пользователя

Указывает удалённого пользователя для подключения по SSH для экземпляров группы репликации.

По умолчанию: postgres.

-s|--shard имя_сегмента

Задаёт имя сегмента, в котором необходимо добавить, включить или выключить команду archive. Если параметр не указан, команда archive включается или выключается во всех сегментах.

--s3-config-path путь

Задаёт путь к файлу конфигурации S3.

По умолчанию: <shardman-data-dir>/s3.config.

-y
--yes

Подтвердить перезапуск вместо того, чтобы запрашивать подтверждение из стандартного ввода. Применяется только для команды add.

backup

Синтаксис:

shardmanctl [общие_параметры] probackup backup -B|--backup-path путь
        -E|--etcd-path путь
        -b|--backup-mode РЕЖИМ
        [-j|--jobs число]
        [--compress]
        [--compress-algorithm алгоритм]
        [--compress-level уровень]
        [--batch-size размер_порции]
        [--storage-type mount|remote|S3]
        [--remote-port порт]
        [--remote-user имя_пользователя]
        [--ssh-key путь]
        [-t|--timeout секунды]
        [-m|--maxtasks число_заданий]
        [--log-directory путь]
        [--s3-config-path путь]
        [--no-validate]
        [--skip-block-validation]
        [--log-to-console]
        [--retention-redundancy]
        [--retention-window]
        [--wal-depth]
        [--delete-wal]
        [--delete-expired]
        [--merge-expired]
        [-y | --yes]
            [--lock-lifetime]

Создаёт резервную копию кластера Shardman.

-B путь
--backup-path путь

Обязательный параметр. Указывает путь к каталогу, в котором должны храниться резервные копии кластера Shardman.

-E путь
--etcd-path путь

Обязательный параметр. Указывает путь к каталогу хранения копий etcd.

-b РЕЖИМ
--backup-mode РЕЖИМ

Обязательный параметр. Определяет режим резервного копирования: FULL, PAGE, DELTA, PTRACK.

--batch-size batch_size

Для ускорения архивирования используется параметр --batch-size, определяющий размер порции из нескольких копируемых сегментов WAL. Вместе с параметром --batch-size также можно применить указание -j, чтобы порции копировались в несколько потоков.

--jobs число
-j число

Число параллельных потоков, которые используются pg_probackup при создании резервной копии. По умолчанию: 1.

--compress

Включает сжатие резервных копий. Если этот флаг не установлен, сжатие будет отключено. Если флаг установлен, используется принятый по умолчанию алгоритм zstd с уровнем сжатия 1, в то время как остальные параметры сжатия игнорируются, даже если они заданы.

--compress-algorithm алгоритм

Определяет алгоритм сжатия: zlib, lz4, zstd, pglz, или none.

Список поддерживаемых алгоритмов сжатия зависит от версии Postgres Pro Enterprise, включающей используемое приложение pg_probackup. Подробная информация описана в статье Параметры сжатия.

По умолчанию: none.

--compress-level уровень

Определяет уровень сжатия: 0-9 для zlib, 1 для pglz, 0-22 для zstd и 0-12 для lz4.

По умолчанию: 1.

--remote-port порт

Указывает удалённый порт SSH для экземпляров группы репликации.

По умолчанию: 22.

--remote-user имя_пользователя

Указывает удалённого пользователя для подключения по SSH для экземпляров группы репликации.

По умолчанию: postgres.

--ssh-key путь

Указывает закрытый ключ SSH для удалённого выполнения команд по SSH.

По умолчанию: $HOME/.ssh/id_rsa.

-t секунды
--timeout секунды

Выход с ошибкой после указанной в секундах задержки при ожидании готовности кластера.

-m число_заданий
--maxtasks число_заданий

Задаёт максимальное количество одновременно выполняемых задач (команды pg_probackup).

По умолчанию соответствует числу логических CPU в системе.

--no-validate

Пропускает автоматическую проверку созданной резервной копии. Этот ключ может быть полезен, если вы регулярно проверяете резервные копии и хотите сократить время создания копии.

По умолчанию: false.

--skip-block-validation

Отключает проверку контрольных сумм на уровне блоков в процессе резервного копирования.

По умолчанию: false.

--storage-type mount|remote|S3

Тип хранилища резервных копий. При значении remote протокол SSH используется для копирования файлов с данными в удалённый каталог резервных копий. Но это поведение можно изменить, если для хранения резервных копий используется каталог, смонтированный на всех узлах, или S3-совместимое объектное хранилище. Чтобы это сделать, установите для параметра --storage-type значение mount или S3 соответственно.

По умолчанию: remote.

--log-to-console

Включает вывод журналов pg_probackup на консоль.

По умолчанию: false.

--log-directory путь

Задаёт путь к каталогу журналов для приложения pg_probackup. Обязательный параметр в случаях, если для параметра --storage-type установлено значение S3 и не задана переменная окружения SDM_LOG_DIRECTORY.

По умолчанию: <backup-directory>/backup/log.

--s3-config-path путь

Задаёт путь к файлу конфигурации S3.

По умолчанию: <shardman-data-dir>/s3.config.

--retention-redundancy=избыточность

Определяет количество полных резервных копий, которое должно сохраняться в каталоге данных. Должно быть неотрицательным целым числом. При нулевом значении отключает сохранение.

По умолчанию: текущее значение в файле pg_probackup.conf, если не задано, то 0.

--retention-window=окно

Количество дней, в течение которых возможно восстановление. Должно быть неотрицательным целым числом. При нулевом значении окно восстановления отсутствует.

По умолчанию: текущее значение в файле pg_probackup.conf, если не задано, то 0.

--wal-depth=глубина_wal

Количество резервных копий на каждой линии времени, которое должно сохраняться для обеспечения возможности восстановления PITR. Должно быть неотрицательным целым числом. При нулевом значении этот параметр отключается.

По умолчанию: текущее значение в файле pg_probackup.conf, если не задано, то 0.

--delete-wal

Удаляет файлы WAL, которые не требуются для восстановления никаких резервных копий.

По умолчанию: false.

--delete-expired

Удаляет резервные копии, не удовлетворяющие политике хранения.

По умолчанию: false.

--merge-expired

Объединяет самую старую инкрементальную копию, удовлетворяющую требованиям политики хранения, с её родительскими копиями, срок хранения которых истёк.

По умолчанию: false.

-y
--yes

Подтвердить перезапуск вместо того, чтобы запрашивать подтверждение из стандартного ввода.

--lock-lifetime

Позволяет задать максимальное время удержания блокировки утилитой probackup (в секундах).

По умолчанию: 1800.

checkdb

Синтаксис:

shardmanctl [общие_параметры] probackup checkdb
[--amcheck [--skip-block-validation] [--heapallindexed]] [--shard сегмент]
[-m|--maxtasks число_заданий]

Проверяет кластер Shardman на наличие физических повреждений или логических нарушений.

--amcheck

Выполняет логическую проверку индексов при отсутствии повреждений в ходе проверки файлов данных. Для проверки индексов в базе данных должны быть установлены расширения amcheck или amcheck_next. Для баз данных без расширения amcheck проверка индексов пропускается. Расширение amcheck входит в состав установочного пакета Shardman.

--heapallindexed

Проверяет, что все кортежи из кучи, требующие индексирования, действительно проиндексированы. Этот параметр используется только совместно с параметром --amcheck. Поддержка данного параметра зависит от версии установленного amcheck/amcheck_next. Расширение amcheck из установочного пакета Shardman поддерживает такую проверку.

--skip-block-validation

Пропускает проверку файлов данных. Этот флаг используется только совместно с флагом --amcheck, что позволяет выполнить только логическую проверку индексов.

--shard сегмент

Выполнять проверку только в указанном сегменте. По умолчанию проверка выполняется во всех сегментах.

-m число_заданий
--maxtasks число_заданий

Задаёт максимальное количество одновременно выполняемых задач (команды pg_probackup).

По умолчанию соответствует числу логических CPU в системе.

delete

Синтаксис:

shardmanctl [общие_параметры] probackup delete -B|--backup-path путь
        -i|--backup-id ид_резервной_копии
        [-j|--jobs число]
        [-m|--maxtasks число_заданий]
        [--storage-type mount|remote|S3]
        [--s3-config-path путь]
        [--delete-wal]
        [-y|--yes]
        [--retention-redundancy]
        [--retention-window]
        [--wal-depth]
        [--delete-expired]
        [--merge-expired]

Удаляет резервную копию кластера Shardman с заданным идентификатором backup_id или запускает процедуру удаления резервных копий или заархивированных файлов WAL, не удовлетворяющих текущей политике хранения.

Обратите внимание, что backup_id нельзя использовать одновременно с merge-expired или delete-expired.

-B путь
--backup-path путь

Обязательный параметр. Указывает путь к каталогу (или ключ в корзине S3-совместимого хранилища), в котором должны храниться резервные копии кластера Shardman.

-i ид_резервной_копии
--backup-id ид_резервной_копии

Задаёт уникальный идентификатор резервной копии.

--jobs число
-j число

Число параллельных потоков, которые используются pg_probackup при создании резервной копии. По умолчанию: 1.

-m число_заданий
--maxtasks число_заданий

Задаёт максимальное количество одновременно выполняемых задач (команды pg_probackup).

По умолчанию соответствует числу логических CPU в системе.

--storage-type mount|remote|S3

Тип хранилища резервных копий. При значении remote протокол SSH используется для копирования файлов с данными в удалённый каталог резервных копий. Но это поведение можно изменить, если для хранения резервных копий используется каталог, смонтированный на всех узлах, или S3-совместимое объектное хранилище. Чтобы это сделать, установите для параметра --storage-type значение mount или S3 соответственно.

По умолчанию: remote.

Для удаления резервной копии, у которой параметр --storage-type имеет значение S3, при запуске команды delete необходимо установить значение S3 для параметра --storage-type.

--s3-config-path путь

Задаёт путь к файлу конфигурации S3.

По умолчанию: <shardman-data-dir>/s3.config.

--delete-wal

Удаляет файлы WAL, которые не требуются для восстановления никаких резервных копий.

По умолчанию: false.

-y
--yes

Подтверждает операцию.

По умолчанию: false.

--retention-redundancy=избыточность

Определяет количество полных резервных копий, которое должно сохраняться в каталоге данных. Должно быть неотрицательным целым числом. При нулевом значении отключает сохранение.

По умолчанию: текущее значение в файле pg_probackup.conf, если не задано, то 0.

--retention-window=окно

Количество дней, в течение которых возможно восстановление. Должно быть неотрицательным целым числом. При нулевом значении окно восстановления отсутствует.

По умолчанию: текущее значение в файле pg_probackup.conf, если не задано, то 0.

--wal-depth=глубина_wal

Количество резервных копий на каждой линии времени, которое должно сохраняться для обеспечения возможности восстановления PITR. Должно быть неотрицательным целым числом. При нулевом значении этот параметр отключается.

По умолчанию: текущее значение в файле pg_probackup.conf, если не задано, то 0.

--delete-expired

Удаляет резервные копии, не удовлетворяющие политике хранения.

По умолчанию: false.

--merge-expired

Объединяет самую старую инкрементальную копию, удовлетворяющую требованиям политики хранения, с её родительскими копиями, срок хранения которых истёк.

По умолчанию: false.

merge

Синтаксис:

shardmanctl [общие_параметры] probackup merge -B|--backup-path путь
        -i|--backup-id ид_резервной_копии
        [-j|--jobs число]
        [-m|--maxtasks число_заданий]
        [--no-validate]
        [--no-sync]
        [-y|--yes]

Объединяет резервные копии, относящиеся к одной цепочке инкрементальных копий. При полном копировании резервные копии объединяются с их первой инкрементальной копией. При инкрементальном резервном копировании резервные копии объединяются с их родительской полной копией и всеми инкрементальными копиями между ними. После выполнения команды полная копия содержит все объединённые данные, а инкрементальные копии удаляются как ненужные.

-B путь
--backup-path путь

Обязательный параметр. Указывает путь к каталогу, в котором должны храниться резервные копии кластера Shardman.

-i ид_резервной_копии
--backup-id ид_резервной_копии

Обязательный параметр. Задаёт уникальный идентификатор резервной копии.

--jobs число
-j число

Число параллельных потоков, которые используются pg_probackup при создании резервной копии. По умолчанию: 1.

-m число_заданий
--maxtasks число_заданий

Задаёт максимальное количество одновременно выполняемых задач (команды pg_probackup).

По умолчанию соответствует числу логических CPU в системе.

--no-sync

Не сбрасывать объединяемые файлы на диск. Этот флаг позволяет несколько ускорить процесс объединения. Использование этого флага может привести к повреждению данных при сбое операционной системы или аппаратного сбоя.

По умолчанию: false.

--no-validate

Пропускает автоматическую проверку созданной резервной копии до и после объединения.

По умолчанию: false.

-y
--yes

Подтверждает операцию.

По умолчанию: false.

restore

Синтаксис:

shardmanctl [общие_параметры] probackup restore
        -B|--backup-path путь
        -i|--backup-id идентификатор
        -j|--jobs число
        [--recovery-target-time дата_время]
        [-I|--recovery-mode инкрементальный_режим]
        [-t|--timeout секунды]
        [-m|--maxtasks число_заданий]
        [--metadata-only] [--schema-only] [--shard сегмент]
        [--no-validate]
        [--skip-block-validation]
        [--s3-config-path путь]
        [--storage-type mount|remote|S3]
        [--wal-limit число_сегментов_wal]
        [--log-directory путь]
        [--data-validate]

Восстанавливает кластер Shardman из выбранной резервной копии.

-B путь
--backup-path путь

Обязательный параметр. Указывает путь к каталогу, в котором должны храниться резервные копии кластера Shardman.

-i идентификатор
--backup-id идентификатор

Обязательный параметр. Указывает идентификатор резервной копии для восстановления.

--jobs число
-j число

Число параллельных потоков, которые используются pg_probackup при восстановлении из резервной копии. По умолчанию: 1.

--recovery-target-time временная_метка

Параметр PITR (восстановление на момент времени). Указывает метку времени для восстановления. Пример: «2024-01-25 15:30:36» в часовом поясе UTC.

-I инкрементальный_режим
--recovery-mode инкрементальный_режим

Выбирает инкрементальный режим восстановления. Поддерживаются следующие режимы:

checksum — заменять только страницы с неподходящей контрольной суммой и LSN.

lsn — заменять только те страницы, LSN которых больше точки расхождения.

none — обычное восстановление, по умолчанию.

-t секунды
--timeout секунды

Выход с ошибкой после указанной в секундах задержки при ожидании готовности кластера или завершения восстановления.

--metadata-only

Выполняет восстановление только метаданных. По умолчанию выполняется полное восстановление.

--schema-only

Выполняет восстановление только схемы. По умолчанию выполняется полное восстановление.

--shard сегмент

Выполнять восстановление только в указанном сегменте. По умолчанию восстановление выполняется во всех сегментах.

--no-validate

Пропускать автоматическую проверку созданной резервной копии. Этот ключ может быть полезен, если вы регулярно проверяете резервные копии и хотите сократить время создания копии.

По умолчанию: false.

--skip-block-validation

Отключает проверку контрольных сумм на уровне блоков для ускорения проверки целостности. При автоматической проверке перед восстановлением будут проверяться только контрольные суммы на уровне файлов.

По умолчанию: false.

--s3-config-path путь

Задаёт путь к файлу конфигурации S3.

По умолчанию: <shardman-data-dir>/s3.config.

--storage-type mount|remote|S3

Тип хранения резервных копий. При значении remote протокол SSH используется для копирования файлов с данными в удалённый каталог резервных копий. Но это поведение можно изменить, если для хранения резервных копий используется каталог, смонтированный на всех узлах, или S3-совместимое объектное хранилище. Чтобы это сделать, установите для параметра --storage-type значение mount или S3 соответственно. Чтобы создать резервную копию с параметром --storage-type со значением S3, укажите их при запуске команды restore.

По умолчанию: remote.

--wal-limit число_сегментов_wal

Задаёт число сегментов WAL, по которым при восстановлении PITR будет производиться поиск ближайших точек синхронизации.

По умолчанию: 0 — без ограничений.

--log-directory путь

Задаёт путь к каталогу журналов для приложения pg_probackup. Обязательный параметр в случаях, если для параметра --storage-type установлено значение S3 и не задана переменная окружения SDM_LOG_DIRECTORY.

По умолчанию: <backup-directory>/backup/log.

--data-validate

Если включен, перед восстановлением проверяет данные с помощью команды probackup validate.

По умолчанию: отключено.

show

Синтаксис:

shardmanctl [общие_параметры] probackup show
        -B|--backup-path путь
        [-f|--format таблица|json]
        [--archive ]
        [-i|--backup-id ид_резервной_копии]
        [--instance экземпляр]
        [--storage-type mount|remote|S3]
        [--s3-config-path путь]

Показывает список резервных копий кластера Shardman.

-B путь
--backup-path путь

Обязательный параметр. Указывает путь к каталогу, в котором должны храниться резервные копии кластера Shardman.

-f table|json
--format table|json

Указывает выходной формат.

По умолчанию: table.

--archive

Показывает информацию об архиве WAL.

-i ид_резервной_копии
--backup-idид_резервной_копии

Показывает информацию о конкретных резервных копиях.

--instanceэкземпляр

Показывает информацию о конкретных экземплярах.

--s3-config-path путь

Задаёт путь к файлу конфигурации S3.

По умолчанию: <shardman-data-dir>/s3.config.

--storage-type mount|remote|S3

Тип хранения резервных копий. При значении remote протокол SSH используется для копирования файлов с данными в удалённый каталог резервных копий. Но это поведение можно изменить, если для хранения резервных копий используется каталог, смонтированный на всех узлах, или S3-совместимое объектное хранилище. Чтобы это сделать, установите для параметра --storage-type значение mount или S3 соответственно. Чтобы показать резервную копию с параметром --storage-type со значением S3, укажите их при запуске команды show.

По умолчанию: remote.

show-config

Синтаксис:

shardmanctl [общие_параметры] probackup show-config
        -B путь
        [-f|--format text|json]
         [--no-scale-units]
         -s|--shard имя_сегмента
        [--s3-config-path путь]
        [--storage-type mount|remote|S3]

Выводит все текущие параметры конфигурации pg_probackup, в том числе те, что содержатся в файле pg_probackup.conf, размещённом в каталоге каталог_копий/backups/имя_сегмента, а также те, что были заданы в командной строке.

-B строка
--backup-path=строка

Обязательный параметр. Задаёт абсолютный путь к каталогу резервных копий.

--format text|json

Указывает выходной формат.

По умолчанию: text.

--no-scale-units

Выводить значения конфигурационных параметров времени и объёма памяти в единицах измерения по умолчанию.

По умолчанию: false.

-s строка
--shard=строка

Имя сегмента, для которого необходимо выполнить команду show-config.

--s3-config-path путь

Задаёт путь к каталогу, в котором создаётся файл конфигурации S3 на всех узлах Shardman.

По умолчанию: <shardman-data-dir>/s3.config.

--storage-type mount|remote|S3

Тип хранилища резервных копий. При значении remote протокол SSH используется для копирования файлов с данными в удалённый каталог резервных копий. Но это поведение можно изменить, если для хранения резервных копий используется каталог, смонтированный на всех узлах, или S3-совместимое объектное хранилище. Чтобы это сделать, установите для параметра --storage-type значение mount или S3 соответственно.

По умолчанию: remote.

validate

Синтаксис:

shardmanctl [общие_параметры] probackup validate
        -B|--backup-path путь
        -i|--backup-id идентификатор
        [-t|--timeout секунды]
        [-m|--maxtasks число_заданий]
        [--log-to-console]
        [--storage-type mount|remote|S3]
        [--s3-config-path путь]
        [--log-directory путь]
        [--remote-port порт]
        [--remote-user имя_пользователя]

Проверяет целостность выбранной резервной копии кластера Shardman.

-B путь
--backup-path путь

Обязательный параметр. Указывает путь к каталогу, в котором должны храниться резервные копии кластера Shardman.

-i идентификатор
--backup-id идентификатор

Обязательный параметр. Указывает резервный идентификатор для проверки.

--log-to-console

Включает вывод журналов pg_probackup на консоль.

По умолчанию: false.

-t секунды
--timeout секунды

Выход с ошибкой после указанной в секундах задержки при ожидании готовности кластера.

-m число_заданий
--maxtasks число_заданий

Задаёт максимальное количество одновременно выполняемых задач (команды pg_probackup).

По умолчанию соответствует числу логических CPU в системе.

--s3-config-path путь

Задаёт путь к файлу конфигурации S3.

По умолчанию: <shardman-data-dir>/s3.config.

--storage-type mount|remote|S3

Тип хранения резервных копий. При значении remote протокол SSH используется для копирования файлов с данными в удалённый каталог резервных копий. Но это поведение можно изменить, если для хранения резервных копий используется каталог, смонтированный на всех узлах, или S3-совместимое объектное хранилище. Чтобы это сделать, установите для параметра --storage-type значение mount или S3 соответственно. Чтобы проверить резервную копию с параметром --storage-type со значением S3, укажите их при запуске команды validate.

По умолчанию: remote.

--log-directory путь

Задаёт путь к каталогу журналов для приложения pg_probackup. Обязательный параметр в случаях, если для параметра --storage-type установлено значение S3 и не задана переменная окружения SDM_LOG_DIRECTORY.

По умолчанию: <backup-directory>/backup/log.

--remote-port порт

Указывает удалённый порт SSH для экземпляров группы репликации.

По умолчанию: 22.

--remote-user имя_пользователя

Указывает удалённого пользователя для подключения по SSH для экземпляров группы репликации.

По умолчанию: postgres.

--ssh-key путь

Указывает закрытый ключ SSH для удалённого выполнения команд по SSH.

По умолчанию: $HOME/.ssh/id_rsa.

set-config

Синтаксис:

shardmanctl [общие_параметры] probackup set-config
        [--archive-timeout целое]
        [-B | --backup-path строка]
        [-m |--maxtasks целое]
        [--remote-port целое]
        [--remote-user строка]
        [--retention-redundancy целое]
        [--retention-window целое]
        [--wal-depth целое]
        [--s3-config-path строка]
        [-s |--shard строка]
        [--storage-type строка]

Добавляет указанные параметры в файл pg_probackup.conf или изменяет существующие.

--archive-timeout целое

Устанавливает время ожидания для архивирования или потоковой репликации сегментов WAL, в секундах.

По умолчанию: pg_probackup ждёт 300 секунд.

-B строка
--backup-path=строка

Задаёт абсолютный путь к каталогу резервных копий.

-m целое
--maxtasks=целое

Задаёт максимальное количество одновременно выполняемых задач (команды pg_probackup).

По умолчанию соответствует числу логических CPU в системе.

--remote-port целое

Порт для подключения к SSH серверу, где создаётся резервная копия.

По умолчанию: 22.

--remote-user строка

Пользователь, который подключается к удалённому SSH серверу для создания резервной копии.

--retention-redundancy целое

Определяет количество полных резервных копий, которое должно сохраняться в каталоге данных. Должно быть неотрицательным целым числом. При нулевом значении отключает сохранение.

По умолчанию: 0.

--retention-window целое

Количество дней, в течение которых возможно восстановление. Должно быть неотрицательным целым числом. При нулевом значении окно восстановления отсутствует.

По умолчанию: 0.

--wal-depth целое

Количество резервных копий на каждой линии времени, которое должно сохраняться для обеспечения возможности восстановления PITR. Должно быть неотрицательным целым числом. При нулевом значении этот параметр отключается.

--s3-config-path строка

Задаёт путь к файлу конфигурации S3.

По умолчанию: /var/lib/pgpro/sdm-14/data/s3.config.

-s строка
--shard=строка

Имя сегмента, для которого необходимо запустить команду set-config. Если сегмент не указан, команда запускается для всех сегментов.

По умолчанию: текущее значение в файле pg_probackup.conf.

--storage-type строка

Тип хранилища резервных копий, возможные значения: remote, mount, S3.

По умолчанию: remote.

rebalance

Синтаксис:

shardmanctl [общие_параметры] rebalance [-f|--force]

Выполняет перебалансировку сегментированных таблиц.

-f
--force

Выполнить принудительную перебалансировку сегментированных таблиц, секции которых были перемещены вручную.

recover

Синтаксис:

shardmanctl [общие_параметры] recover [--info файл] [--dumpfile файл] [--shard сегмент] [--metadata-only][--schema-only] [--timeout секунды]

Восстанавливает кластер Shardman из резервной копии, созданной командой backup.

--dumpfile файл

Требуется для восстановления только метаданных.

Указывает файл для загрузки ранее выгруженных метаданных etcd.

--info файл

Требуется для полного восстановления.

Указывает файл, из которого необходимо загрузить информацию о резервной копии.

--shard сегмент

Выполнять восстановление только в указанном сегменте. По умолчанию восстановление выполняется во всех сегментах.

--metadata-only

Выполняет восстановление только метаданных. По умолчанию выполняется полное восстановление.

--schema-only

Выполняет восстановление только схемы. По умолчанию выполняется полное восстановление.

--timeout секунды

Выход с ошибкой после указанной в секундах задержки при ожидании готовности кластера или завершения восстановления.

За подробностями обратитесь к Подразделу «Восстановление кластера Shardman»

restart

Синтаксис:

     shardmanctl [общие_параметры] restart [-y|--yes] [--no-wait]

Перезапускает кластер Shardman.

-y
--yes

Подтверждает операцию вместо того, чтобы запрашивать подтверждение от стандартного ввода.

--no-wait

Не ждать запуска реплик.

shard add

Синтаксис:

shardmanctl [общие_параметры] shard -s|--shard имя_сегмента add -n|--nodes имена_узлов [--no-wait]

Добавляет реплику в сегмент.

-s имя_сегмента
--shard=имя_сегмента

Имя сегмента.

-n имена_узлов
--nodes=имена_узлов

Задаёт список добавляемых узлов реплики через запятую.

--no-wait

Не ждать запуска сегмента.

shard master set

Синтаксис:

shardmanctl [общие_параметры] shard -s|--shard имя_сегмента master set [--yes | -y] [-n| node имена_узлов]

Задаёт приоритет для определённого главного сервера для заданного сегмента.

-s имя_сегмента
--shard=имя_сегмента

Имя сегмента.

master set

Приоритетный главный сервер.

-y
--yes

Подтверждает операцию вместо того, чтобы запрашивать подтверждение от стандартного ввода.

-n имена_узлов
--nodes=имена_узлов

Задаёт список узлов реплики через запятую.

shard master reset

Синтаксис:

shardmanctl [общие_параметры] shard -s|--shard имя_сегмента master reset [--yes | -y] -n| node имена_узлов

Сбрасывает параметры приоритетного главного сервера для сегмента.

-s имя_сегмента
--shard=имя_сегмента

Имя сегмента.

master reset

Сбрасывает параметры приоритетного главного сервера для сегмента.

-y
--yes

Подтверждает операцию вместо того, чтобы запрашивать подтверждение от стандартного ввода.

-n имена_узлов
--nodes=имена_узлов

Задаёт список узлов реплики через запятую.

shard add

Синтаксис:

shardmanctl [общие_параметры] shard -s|--shard shard_name reset [--yes | -y][--new-primary | -p]

Сбрасывает узлы группы репликации, если они зависли.

-s имя_сегмента
--shard=имя_сегмента

Имя сегмента.

-y
--yes

Подтверждает операцию вместо того, чтобы запрашивать подтверждение от стандартного ввода.

--new-primary
-p

Имя нового ведущего узла.

shard rm

Синтаксис:

     shardmanctl [общие_параметры] shard -s|--shard имя_сегмента rm -n|--nodes имя_узла [-f|--force]

Удаляет реплику из сегмента.

-s имя_сегмента
--shard=имя_сегмента

Имя сегмента

-n имена_узлов
--nodes=имена_узлов

Задаёт список удаляемых узлов реплики, разделённых запятыми.

-f
--force

Выполнить принудительное удаление узла, даже если он «мёртв».

shard switch

Синтаксис:

     shardmanctl [общие_параметры] shard -s|--shard имя_сегмента switch [--new-primary имена_узлов]

Переключает ведущий узел.

-s имя_сегмента
--shard=имя_сегмента

Имя сегмента.

--new-primary=имена_узлов

Имя нового ведущего узла.

shard start

Синтаксис:

     shardmanctl [общие_параметры] shard -s |--shard имя_сегмента start [--no-wait] [-n|--node имя_узла]

Запускает сегмент.

-s имя_сегмента
--shard=имя_сегмента

Имя сегмента.

--no-wait

Не ждать запуска сегмента.

-n имя_узла
--node=имя_узла

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

shard stop

Синтаксис:

     shardmanctl [общие_параметры] shard -s |--shard имя_сегмента stop [-n|--node имя_узла]

Останавливает сегмент.

-s имя_сегмента
--shard=имя_сегмента

Имя сегмента.

-n имя_узла
--node=имя_узла

Указывает узел, который необходимо остановить.

shard replicas reinit

Синтаксис:

     shardmanctl [общие_параметры] shard -s|--shard имя_сегмента replicas reinit [-n|--node имена_узлов] [-y|--yes] [--no-wait]

Сбрасывает реплики определённого сегмента.

-s имя_сегмента
--shard=имя_сегмента

Имя сегмента.

-n имена_узлов
--node=имена_узлов

Указывает узел, на котором необходимо сбросить реплики. Если не задан, проверяет реплики сегмента на всех узлах.

-y
--yes

Подтверждает операцию вместо того, чтобы запрашивать подтверждение от стандартного ввода.

--no-wait

Не ждать готовности реплик.

За подробностями обратитесь к Подразделу «Переинициализация реплик».

nodes start

Синтаксис:

     shardmanctl [общие_параметры] nodes start -n|--nodes имена_узлов [--no-wait]

Запускает узлы.

-n имена_узлов
--nodes=имена_узлов

Имена узлов.

--no-wait

Задаёт поведение shardmanctl, при котором не ожидается запуск узлов.

nodes restart

Синтаксис:

     shardmanctl [общие_параметры] nodes restart -n|--nodes имена_узлов [--no-wait]

Перезапускает узлы.

-n имена_узлов
--nodes=имена_узлов

Имена узлов.

--no-wait

Не ждать перезапуска узлов.

nodes stop

Синтаксис:

     shardmanctl [общие_параметры] nodes stop -n|--nodes имена_узлов [--no-wait]

Останавливает узлы.

-n имена_узлов
--nodes=имена_узлов

Имена узлов.

--no-wait

Не ждать остановки узлов.

status

Синтаксис:

     shardmanctl [общие_параметры] status [-f|--format table|json] [--filter store|metadata|shardmand|rg|master|dictionary|all|biharestart_required_params] [-s|--sort node|rg|status]

Отчёт о состоянии подсистем кластера Shardman.

-f table|json
--format=table|json

Указывает формат отчёта.

По умолчанию: table.

За подробностями обратитесь к Подразделу «Получение статуса подсистем кластера».

--filter store|metadata|shardmand|rg|master|dictionary|allrestart_required_params

Указывает подсистемы, информация о состоянии которых должна быть включена в вывод.

По умолчанию: all.

За подробностями обратитесь к Подразделу «Получение статуса подсистем кластера».

-s node|rg|status
--sort node|rg|status

Сортирует сообщения внутри одной группы (таблицы) указанным способом.

По умолчанию: node.

За подробностями обратитесь к Подразделу «Получение статуса подсистем кластера».

status transactions

Синтаксис:

     shardmanctl [общие_параметры] status transactions [-r|--repgroup имя_группы_репликации

Показывает распредёленные транзакции, которые не удалось разобрать встроенными инструментами мониторинга Shardman.

-r имя_группы_репликации
--repgroup=имя_группы_репликации

Указывает группу репликации, для которой необходимо выводить транзакции.

По умолчанию: все группы репликации.

За подробностями обратитесь к Подразделу «Вывод списка неразобранных распределённых транзакций».

store dump

Синтаксис:

     shardmanctl [общие_параметры] store dump [-f|--file имя_файла]

Выгружает текущие конфигурации кластеров из хранилища.

-f имя_файла
--file=имя_файла

Задаёт выходной файл (- для стандартного вывода).

По умолчанию: -.

За подробностями обратитесь к Подразделу «Выгрузка всех ключей из хранилища для отладки конфигурации ошибок».

store restore

Синтаксис:

     shardmanctl [общие_параметры] store restore [--delete-old-keys][-f|--file имя_файла][-y|--yes]

Позволяет безопасно восстановить кластер etcd из дампа. Для этого необходимо отключить shardmand на всех сегментах. Работает только при холодном резервном копировании.

--delete-old-keys

Удалить все ключи etcd перед восстановлением.

-f имя_файла
--file=имя_файла

Задаёт имя дампа ключей etcd.

-y
--yes

Выполнять автоматическое подтверждение.

store lock

Синтаксис:

     shardmanctl [общие_параметры] store lock [-f|--format text|json]

Показывает информацию о текущей блокировке метаданных кластера.

-f=text|json
--format=text|json

Указывает выходной формат.

По умолчанию: text.

За подробностями обратитесь к Подразделу «Вывод информации о текущей блокировке метаданных кластера».

store get

Синтаксис:

    shardmanctl [общие_параметры] store get [[-a|--alias имя_псевдонима]|[-k|--key имя_ключа] [-f|--file имя_файла]]

Получает указанный ключ из хранилища.

-a имя_псевдонима
--alias=ladle|cluster |spec|stolonspec

Указывает использование псевдонима вместо полного имени ключа. Нельзя использовать с параметром --key.

За подробностями обратитесь к Подразделу «Получение текущей конфигурации stolon».

-k имя_ключа
--key=имя_ключа

Указывает ключ для извлечения из хранилища. Нельзя использовать с параметром --alias.

За подробностями обратитесь к Подразделу «Получение текущей конфигурации stolon».

-f имя_файла
--file=имя_файла

Задаёт файл для вывода значения.

По умолчанию: - (стандартный вывод).

За подробностями обратитесь к Подразделу «Получение текущей конфигурации stolon».

store keys

Синтаксис:

    shardmanctl [общие_параметры] store keys

Получает из хранилища все ключи с текущим префиксом кластера.

За подробностями обратитесь к Подразделу «Получение имён ключей кластера и ковша для текущего кластера».

store set

Синтаксис:

    shardmanctl [общие_параметры] store set [[-a|--alias имя_псевдонима]|[-k|--key имя_ключа]] [-f|--file имя_файла]

Создаёт или перезаписывает ключ в хранилище.

-a ladle|cluster |spec|stolonspec
--alias=ladle|cluster |spec|stolonspec

Указывает использование псевдонима вместо полного имени ключа. Нельзя использовать с параметром --key.

-k имя_ключа
--key=имя_ключа

Указывает имя ключа для размещения в хранилище. Нельзя использовать с параметром --alias.

-f имя_файла
--file=имя_файла

Задаёт файл с входными данными (- для стандартного ввода).

За подробностями обратитесь к Подразделу «Установка новой конфигурации для кластера».

tables sharded info

Синтаксис:

    shardmanctl [общие_параметры] tables sharded info [-t|--table имя_таблицы]

Получает информацию о сегментированной таблице.

-t таблица
--table=таблица

Указывает имя таблицы в формате schema.table

tables sharded list

Синтаксис:

    shardmanctl [общие_параметры] tables sharded list

Получает список всех сегментированных таблиц.

tables sharded norebalance

Синтаксис:

    shardmanctl [общие_параметры] tables sharded norebalance

Получает список сегментированных таблиц с отключённой автоматической перебалансировкой.

tables sharded partmove

Синтаксис:

    shardmanctl [общие_параметры] tables sharded partmove [-t|--table имя_таблицы] [-s|--shard имя_сегмента] [-p|--partnum число]

Перемещает указанную секцию сегментированной таблицы в новый сегмент.

-t таблица
--table=таблица

Указывает имя таблицы в формате schema.table.

-p число
--partnum=число

Указывает номер секции для перемещения.

-s имя_сегмента
--shard=имя_сегмента

Указывает имя нового сегмента для секции.

tables sharded rebalance

Синтаксис:

    shardmanctl [общие_параметры] tables sharded rebalance [-t|--table имя_таблицы]

Включает и запускает автоматическую перебалансировку данных для выбранной сегментированной таблицы.

-t таблица
--table=таблица

Указывает имя таблицы в формате schema.table.

config get

Синтаксис:

shardmanctl [общие_параметры] config get [-c | --choose-revision] [-r | --revision ] [-f | --file]

Выгружает текущую полную конфигурацию кластера или конфигурацию указанной версии.

-c
--choose-revision

Включает интерактивный режим выбора конфигурации указанной версии.

-r
--revision

Идентификатор версии конфигурации.

-f имя_файла
--file=имя_файла

Имя файла для записи конфигурации. Если не указано, то значение — stdout.

config revisions rm

Синтаксис:

shardmanctl [общие_параметры] config revisions rm [-r | --revision ] [-y | --yes]

Удаляет указанную версию конфигурации из истории состояний.

-r
--revision

Идентификатор версии конфигурации. Если не указан, включает интерактивный режим выбора конфигурации указанной версии. Это временная метка операции, которая привела к изменению конфигурации Shardman.

-y
--yes

Выполнять автоматическое подтверждение.

config update

Синтаксис:

shardmanctl [общие_параметры] config update [[-f|--file файл_конфигурации_stolon|файл_конфигурации_shardman]|текст_конфигурации [-p|--patch][-w|--wait]]] [--force][-y | --yes]

Обновляет конфигурацию stolon или полную конфигурацию Shardman.

-f файл_конфигурации_stolon|файл_конфигурации_shardman
--specfile=файл_конфигурации_stolon|файл_конфигурации_shardman

Указывает файл конфигурации stolon или полной конфигурации Shardman. Тип файла конфигурации определяется автоматически. Значение - означает стандартный ввод. По умолчанию конфигурация передаётся в тексте_конфигурации.

-w
--wait

Указывает, что shardmanctl должен дождаться вступления в силу изменений конфигурации. Если новая конфигурация не может быть загружена всеми группами репликации, время ожидания shardmanctl будет бесконечным.

-p
--patch

Объединяет новой конфигурации с существующей. По умолчанию новая конфигурация заменяет существующую.

--force

Выполнять принудительное изменение, если выполняется операция на уровне кластера.

-y
--yes

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

config rollback

Синтаксис:

shardmanctl [общие_параметры] config rollback [-r | --revision] [-w|--wait длительность] [--force] [-y|--yes]

Выполняет откат конфигурации Shardman к одному из предыдущих состояний. При откате к версии конфигурации, имеющей параметры max_connections, max_prepared_transactions или max_worker_processes, реплики переинициализируются.

-r
--revision

Идентификатор версии, до которой нужно откатить состояние конфигурации. Это временная метка операции, которая привела к изменению конфигурации Shardman.

Если не указан, выводится список версий, из которого пользователь может выбрать нужную.

-w
--wait

Указывает, что shardmanctl должен дождаться вступления в силу изменений конфигурации. Если новая конфигурация не может быть загружена всеми группами репликации, время ожидания shardmanctl будет бесконечным.

По умолчанию: 1h.

-f
--force

Выполнить принудительную настройку параметра, если выполняется операция на уровне кластера.

-y
--yes

Выполнять автоматическое подтверждение.

config revisions

Синтаксис:

shardmanctl [общие_параметры] config revisions [-f|--format text|json]

Выводит историю версий конфигурации кластера Shardman. Для каждой версии содержит следующую информацию:

revision_id — временная метка операции, вызвавшей изменение конфигурации Shardman

host — имя узла, на котором запустили операцию

user — пользователь, запустивший операцию

command — сама операция

-f=text|json
--format=text|json

Указывает выходной формат.

По умолчанию: text.

config revisions set

Синтаксис:

shardmanctl [общие_параметры] config revisions set [--keep-config-revisions]

Позволяет задать длину истории версий конфигурации. Не может быть меньше 5; это значение устанавливается автоматически, если указать длину меньше. Для кластеров Shardman, у которых ещё не была сформирована история версий конфигурации, автоматически выставляется значение 20.

--keep-config-revisions

Лимит на количество версий одной конфигурации Shardman. Если лимит меньше текущей длины истории, наиболее старые версии за пределами этого лимита будут удалены. Если количество операций, приводящих к изменению конфигурации, превышает лимит, наиболее старая версия удаляется.

По умолчанию: 20.

config update ip

Синтаксис:

shardmanctl [общие_параметры] config update ip [-u|ip_1=ip_2,hostname_1=hostname_2][-y|--yes]

Обновляет указанные IP-адреса узлов кластера.

-u
ip_1=ip_2,hostname_1=hostname_2

Указывает IP-адреса узлов кластера, которые необходимо обновить.

-y
--yes

Выполнять автоматическое подтверждение.

set

Синтаксис:

shardmanctl [общие_параметры] set pgParam1=value1 [pgParam2=value2 [...]] [-y|--yes] [-w|--wait длительность] [-f|--force]

Устанавливает значения указанных параметров базы данных кластера Shardman.

-w
--wait

Указывает, что shardmanctl должен дождаться вступления в силу изменений конфигурации. Примеры значений: 2h45m, 1m30s, 5m, 10s.

По умолчанию: 1h.

-y
--yes

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

-f
--force

Выполнить принудительную настройку параметра, если выполняется операция на уровне кластера.

upgrade

Синтаксис:

shardmanctl [общие_параметры] upgrade

Обновляет расширение shardman базы данных и изменяет параметры pg_foreign_server.

bench init

Синтаксис:

shardmanctl [общие_параметры] bench init [--schema-type single|simple|shardman|custom]
[--schema-file имя_файла] [-s|--scale значение_масштабирования]  [-n|--no-vacuum]
[-F|--fillfactor значение_коэффициента_заполнения]

Инициализирует схему тестирования через pgbench. Схема может быть пользовательской или предопределённой. Создаёт таблицы схемы tpc-b и заполняет их.

--schema-type=single|simple|shardman|custom

Тип схемы, используемый при её инициализации. Возможные значения:

single — схема для одиночного теста производительности PostgreSQL

simple — простая сегментированная схема

shardman — сегментированная схема, оптимизированная для Shardman

custom — схема, инициализированная пользователем из файла --schema-file

По умолчанию: shardman.

--schema-file=имя_файла

Файл с DDL-запросом для пользовательского типа схемы, который будет использоваться для создания таблиц tpc-b для pgbench: pgbench_accounts, pgbench_branches, pgbench_tellers, pgbench_history.

-s значение_масштабирования
--scale=значение_масштабирования

Умножить количество сгенерированных строк на заданный коэффициент масштабирования.

-n
--no-vacuum

Не выполнять очистку во время инициализации.

-F значение_коэффициента_заполнения
--fillfactor=значение_коэффициента_заполнения

Заполнить таблицы pgbench заданным значением коэффициента заполнения.

bench run

Синтаксис:

shardmanctl [общие_параметры] bench run [--schema-type single|simple|shardman|custom]
[-f|--file имя_файла] [-c|--client число_клиентов]  [-C|--connect] [--full-output]
[-j|--jobs число_процессов][-T|--time секунды][-t|--transactions число_транзакций]
[-s|--scale коэффициент_масштаба] ] [ -P | --progress секунды] [ -R | --rate скорость_передачи] [ -M | --protocol режим_запросов]

Запускает инициализированный тест производительности через pgbench. Можно использовать скрипт pgbench по умолчанию или пользовательский скрипт из файла.

--schema-type=single|simple|shardman|custom

Тип схемы, используемый при её инициализации (bench init). Возможные значения:

single — схема для одиночного теста производительности PostgreSQL

simple — простая сегментированная схема

shardman — сегментированная схема, оптимизированная для Shardman

custom — схема, инициализированная пользователем из файла --schema-file.

По умолчанию: shardman.

-f имя_файла
--file=имя_файла

Добавить в список выполняемых скриптов скрипт транзакции из файла имя_файла.

Дополнительно можно задать целочисленный вес после @, меняющий вероятность выбора этого скрипта относительно других. По умолчанию вес считается равным 1. (Если вам нужно передать имя скрипта, содержащее символ @, добавьте к такому имени вес, чтобы исключить неоднозначность прочтения, например filen@me@1).

-c число_клиентов
--client=число_клиентов

Число имитируемых клиентов, то есть число одновременных сеансов базы данных.

-C
--connect

Устанавливать новое подключение для каждой транзакции вместо одного для каждого клиента.

--full-output

Вывести полный вывод pgbench.

-j число_процессов
--jobs=число_процессов

Количество рабочих потоков в pgbench.

-s коэффициент_масштаба
--scale=коэффициент_масштаба

Умножить число генерируемых строк на заданный коэффициент.

-T секунды
--time=секунды

Выполнять тест с ограничением по времени в указанное количество секунд. Значение по умолчанию — 0, что означает отсутствие ограничения по времени. Обратите внимание, что флаги -T и -t являются взаимоисключающими, и флаг -T имеет приоритет. Если задан флаг -T, флаг -t игнорируется.

-t число_транзакций
--transactions=число_транзакций

Выполнять тест с ограничением в указанное количество транзакций на каждом клиенте. Значение по умолчанию — 10. Обратите внимание, что флаги -T и -t являются взаимоисключающими, и флаг -T имеет приоритет. Если задан флаг -T, флаг -t игнорируется.

-P секунды
--progress=секунды

Выводить отчёт о прогрессе через заданное число секунд (сек). Выдаваемый отчёт включает время, прошедшее с момента запуска, скорость (в TPS) с момента предыдущего отчёта, а также среднее время ожидания транзакций, стандартное отклонение и количество неуспешных транзакций с момента последнего отчёта. В режиме ограничения скорости (-R) время ожидания вычисляется относительно назначенного времени запуска транзакции, а не фактического времени её начала, так что оно включает и среднее время отставания от графика. Когда параметр --max-tries включает повторение транзакций после ошибок сериализации/взаимоблокировок, в отчёт добавляется количество повторявшихся транзакций и общее число повторов.

-R скорость_передачи
--rate=скорость_передачи

Выполнять транзакции, ориентируясь на заданную скорость, а не максимально быстро (по умолчанию). Скорость задаётся в транзакциях в секунду. Если заданная скорость превышает максимально возможную, это ограничение скорости не повлияет на результаты.

-M режим_запросов
--protocol=режим_запросов

Протокол, выбираемый для передачи запросов на сервер:

simple: использовать простой протокол запросов.

extended: использовать расширенный протокол запросов.

prepared: использовать расширенный протокол запросов с подготовленными операторами.

В режиме prepared pgbench повторно использует результат разбора запроса, начиная со второй итерации, и поэтому работает быстрее, чем в других режимах.

По умолчанию: simple.

bench cleanup

Синтаксис:

shardmanctl [общие_параметры] bench cleanup

Очищает базу данных схемы после тестов производительности. Удаляет таблицы tpc-b.

bench generate

Синтаксис:

shardmanctl [общие_параметры] bench generate [-c|--config имя_файла] [-o|--output-file имя_файла]

Получает конфигурацию теста производительности из файла и генерирует bash-скрипт для создания схемы, оптимизированной для Shardman, и запуска теста производительности с использованием pgbench. Файл конфигурации должен быть в формате yaml.

-f имя_файла
--file=имя_файла

Путь к файлу конфигурации. Этот файл содержит последовательность конфигураций скрипта. Каждый скрипт должен иметь тип схемы (schema_type): single|simple|shardman|custom. Для пользовательской схемы необходимо указать schema_file с DDL-скриптом. Необязательные параметры: init_flags (набор по умолчанию: -s 1000), run_flags (набор по умолчанию: -n -P 10 -c 10 -j 4 -T 60), секции (значение по умолчанию: 50). Настоятельно рекомендуется использовать параметр -n (--no-vacuum) внутри run_flags. Пример файла конфигурации:

    benches:
    - schema_type: single
      init_flags: "-s 3"
      run_flags: "-n -P 10 -c 10 -j 4 -T 10"
    - schema_type: simple
      init_flags: "-s 4"
      run_flags: "-n -P 10 -c 20 -j 4 -T 10"
      partitions: 100
    - schema_type: shardman
      init_flags: "-s 5"
      run_flags: "-n -P 10 -c 20 -j 4 -T 10"
    - schema_type: custom
      init_flags: "-s 6"
      schema_file: "schema.psql"

-o имя_файла
--output-file=имя_файла

Файл вывода. По умолчанию: stdout.

script

Синтаксис:

shardmanctl [общие_параметры] script -s|--shard имя_сегмента][[-f|--file имя_файла][--sql запрос]]

Выполняет нетранзакционные команды из файла или командной строки на указанных сегментах.

-s имя_сегмента
--shard=имя_сегмента

Имя сегмента.

-f имя_файла
--file=имя_файла

Добавить в список выполняемых скриптов скрипт транзакции из файла имя_файла.

--sql query

Указывает оператора для выполнения. Нельзя использовать с параметром -f.

psql

Синтаксис:

shardmanctl [общие_параметры] psql -s |--shard имя_сегмента

Без заданных параметров подключается к первому доступному ведущему узлу.

-s имя_сегмента
--shard=имя_сегмента

Имя сегмента. Если оно указано, подключение происходит к текущему ведущему узлу сегмента.

daemon set

Синтаксис:

shardmanctl [общие_параметры] daemon set [--session-log-level debug | info | warn | error] [--session-log-format json|text] [--session-log-nodes]

Позволяет обновить параметры протоколирования «на лету».

--session-log-level debug | info | warn | error

Указывает уровень детализации сообщений: debug, info, warn или error.

--session-log-format json|text

Указывает выходной формат журнала: text или json.

--session-log-nodes

Указывает узел, которые необходимо обновить. Если не задан, параметры обновляются на всех узлах.

По умолчанию: все узлы.

history

Синтаксис:

shardmanctl [общие_параметры] ] history [--reverse | -r] [-f|--format json|text] [-l|--limit число_команд]

Выводит историю команд, которые привели к изменению кластера. По умолчанию отсортированы от самых недавних к самым старым.

-r
--reverse

Переключает на сортировку по возрастанию.

-f json|text
--format=json|text

Указывает выходной формат.

По умолчанию: text.

-l
--limit=число_команд

Лимит числа выводимых последних команд. Максимальное число — 200.

По умолчанию: 20.

Общие параметры

Общие параметры shardmanctl — это необязательные параметры, не являющиеся специфичными для данной утилиты. Они определяют параметры подключения etcd, имя кластера и некоторые другие параметры. По умолчанию shardmanctl пытается подключиться к хранилищу etcd 127.0.0.1:2379 и использовать имя кластера cluster0. Уровень журнала по умолчанию — info.

-h, --help

Показывает краткую справочную информацию.

--cluster-name имя_кластера

Указывает имя кластера, где будет работать. По умолчанию указывается имя кластера cluster0.

--log-level уровень

Задаёт уровень детализации журнала. Возможные значения уровня (от минимального до максимального): error, warn, info и debug. По умолчанию используется info.

--retries число

Указывает, сколько раз shardmanctl должен повторять прерванный запрос к etcd. Если запрос etcd прерывается, скорее всего, из-за проблем с подключением, shardmanctl повторяет его указанное количество раз, прежде чем сообщить об ошибке. Значение по умолчанию — 5.

--session-timeout секунды

Указывает таймаут блокировок в сеансе shardmanctl. Если нет связи между shardmanctl и хранилищем etcd в течение указанного количества секунд, блокировка снимается. Значение по умолчанию — 30.

--store-endpoints строка

Задаёт адрес/порт etcd в формате: http[s]://адрес[:порт](,http[s]://адрес[:порт])*. Значение по умолчанию — http://127.0.0.1:2379.

--store-ca-file строка

Проверяет сертификат сервера хранилища etcd с поддержкой HTTPS, используя этот пакет CA.

--store-cert-file строка

Указывает файл сертификата для идентификации клиента в хранилище etcd.

--store-key строка

Указывает файл закрытого ключа для идентификации клиента в хранилище etcd.

--store-timeout длительность

Задаёт тайм-аут для запроса etcd. Значение по умолчанию — 5 секунд.

--monitor-port число

Указывает порт HTTP-сервера shardmand для метрик и точек трассировки. По умолчанию — 15432.

--api-port число

Указывает порт для API HTTP-сервера shardmand. По умолчанию — 15432.

--version

Показывает информацию о версии shardman-utils.

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

SDM_BACKUP_MODE

Аналог параметра --backup-mode.

SDM_BACKUP_PATH

Аналог параметра --backup-path.

SDM_CLUSTER_NAME

Аналог параметра --cluster-name.

SDM_ETCD_PATH

Аналог параметра --etcd-path.

SDM_FILE

Аналог параметра --file в команде config update.

SDM_LOG_LEVEL

Аналог параметра --log-level.

SDM_NODES

Аналог параметра --nodes в командах nodes add и nodes rm.

SDM_RETRIES

Аналог параметра --retries.

SDM_SPEC_FILE

Аналог параметра --spec-file в команде init.

SDM_STORE_ENDPOINTS

Аналог параметра --store-endpoints.

SDM_STORE_CA_FILE

Аналог параметра --store-ca-file.

SDM_STORE_CERT_FILE

Аналог параметра --store-cert-file.

SDM_STORE_KEY

Аналог параметра --store-key.

SDM_STORE_TIMEOUT

Аналог параметра --store-timeout.

SDM_SESSION_TIMEOUT

Аналог параметра --session-timeout.

Использование

Добавление узлов в кластер Shardman

Чтобы добавить узлы в кластер Shardman, выполните следующую команду:

shardmanctl [общие_параметры] nodes add -n|--nodes имена_узлов

Необходимо указать -n (--nodes) для передачи списка добавляемых узлов, разделённых запятыми. Ко всем узлам можно обращаться по их именам хостов или IP-адресам. Имена должны быть правильно разрешены на всех узлах.

Если во время выполнения команды nodes add произошёл сбой, используйте команду cleanup --after-node-operation, чтобы исправить возможные проблемы с конфигурацией кластера.

Выполнение очистки

По умолчанию cleanup работает только в режиме отчёта, т. е. следующая команда покажет только действия, которые необходимо выполнить во время фактической очистки:

    shardmanctl [общие_параметры] cleanup --after-node-operation|--after-rebalance

Чтобы выполнить фактическую очистку, запустите следующую команду:

    shardmanctl [общие_параметры] cleanup -p|--processrepgroups --after-node-operation|--after-rebalance

Отображение топологии кластера

Команда cluster topology отображает текущую топологию кластера, по умолчанию в виде таблицы. Все узлы кластера будут сгруппированы по группам репликации, к которым они принадлежат. Для каждого узла будет отображаться его статус.

    shardmanctl [общие_параметры] cluster topology -f|--format table|json|text

Проверка работы службы shardmand на узлах

Команда daemon check не только проверяет, запущена ли служба shardmand на указанных узлах, но и гарантирует, что эти службы настроены для того же кластера, что и shardmanctl:

    shardmanctl [общие_параметры] daemon check -n|--nodes имена_узлов

Удаление узлов из кластера Shardman

Чтобы удалить узлы из кластера Shardman, выполните следующую команду:

shardmanctl [общие_параметры] nodes rm -n|--nodes имена_узлов

Укажите параметр -n (--nodes) для передачи списка удаляемых узлов, перечисленных через запятую. Команда восстанавливает все секции сегментированных таблиц.

Примечание

Не используйте команду cleanup для устранения возможных проблем с конфигурацией кластера после сбоя команды nodes rm. Вместо этого ещё раз выполните nodes rm.

Чтобы удалить все узлы в кластере без сохранения данных, повторно инициализируйте кластер. Если удалённая группа репликации содержит локальные (несегментированные и неглобальные) таблицы, данные теряются после удаления группы репликации.

Получение статуса подсистем кластера

Чтобы получить отчёт о состоянии кластера Shardman в формате таблицы для подсистем metadata и store, отсортированных по группам репликации, выполните следующую команду:

    shardmanctl [общие_параметры] status --filter=metadata,store --sort=rg

Чтобы получить отчёт в формате JSON, используйте параметр -f|--format=json (не включён выше, так как формат table используется по умолчанию). О каждой обнаруженной проблеме сообщается со статусом «Unknown», «Warning», «Error» или «Fatal error». Инструмент также может сообщить об операционной ошибке, что означает, что во время проверки работоспособности кластера возникла проблема. Когда команда обнаруживает критическую или операционную ошибку, дальнейшая диагностика прекращается. Например, несогласованность метаданных хранилища не позволяет выполнять правильные операции с кластером и должна быть устранена в первую очередь.

Вывод списка неразобранных распределённых транзакций

Чтобы просмотреть список распределённых транзакций, которые не удалось разобрать встроенными средствами мониторинга Shardman, выполните следующую команду:

    shardmanctl [общие_параметры] status transactions -r|--repgroup имя_группы_репликации

Информация о каждой транзакции состоит из tx_id (идентификатор транзакции), coordinator_id, creation_time и description (ошибка или статус транзакции). Чтобы отобразить список транзакций для определённой группы репликации, используйте параметр -r|--repgroup (по умолчанию для всех групп репликации). Если таких транзакций нет, команда возвращает значение null в формате JSON.

Выгрузка всех ключей из хранилища для отладки конфигурации ошибок

Столкнувшись с ошибкой при использовании кластера Shardman, для получения исчерпывающего отчёта полезно выгрузить все конфигурации, которые могут привести к такой ошибке, используя следующую команду:

    shardmanctl [общие_параметры] store dump -f|--file имя_файла

Могут отображаться некоторые некритичные ошибки, но они не будут прерывать выгрузку. Если имя файла не указано, данные выводятся в stdout и могут замусорить терминал.

Получение текущей конфигурации stolon

Чтобы получить текущую конфигурацию stolon, которая обычно является частью ключа кластера в хранилище, используйте следующую команду:

    shardmanctl [общие_параметры] store get -a|--alias stolonspec -f|--file имя_файла

Если сам ключ кластера повреждён, конфигурация stolon также не будет отображаться. Вместо использования псевдонима можно также узнать полное имя ключа данных кластера (выведя все ключи командой store keys) и использовать store get, чтобы получить его и найти в нём часть stolon. Учтите, что при использовании последнего варианта параметр shardman.config_uuid не будет удалён, что может привести к конфликту при последующем использовании этих данных. Для манипуляций с конфигурацией stolon рекомендуется использовать команду shardmanctl store get -a stolonspec.

Получение имён ключей кластера и ковша для текущего кластера

Чтобы получить сразу все имена ключей в хранилище, выполните следующую команду:

    shardmanctl [общие_параметры] store keys

Они могут отображаться только в формате JSON. Также будут выведены псевдонимы для тех ключей, у которых они есть (за исключением stolonspec и spec, так как они являются частями других ключей)

Вывод информации о текущей блокировке метаданных кластера

Можно просмотреть информацию о текущих блокировках метаданных кластера, полученных любой командой:

    shardmanctl [общие_параметры] store lock -f|--format json

Чтобы получить отчёт в формате JSON, используйте параметр -f|--format=json (не указан выше, поскольку формат text используется по умолчанию). Если блокировка не существует, возвращает Lock not found.

Установка новой конфигурации для кластера

Чтобы установить новую часть конфигурации кластера, выполните следующую команду:

    shardmanctl [общие_параметры] store set --alias=spec --file=spec.json

Поскольку spec является частью ключа данных кластера, его нельзя задать в параметре --key. Если выбранный файл не формата JSON, новая часть конфигурации не будет установлена.

Резервное копирование кластера Shardman

Требования к резервному копированию и восстановлению кластера Shardman командой basebackup перечислены в Подразделе 2.6.1.1.

Чтобы создать резервную копию кластера Shardman, вы можете запустить следующую команду:

    shardmanctl [общие_параметры] backup --datadir каталог [--use-ssh]

Следует указать каталог для записи выходных данных в параметре --datadir. Можно ограничить количество одновременно выполняющихся задач (команды pg_receivewal или pg_basebackup), указав ограничение в параметре --maxtasks.

Если указано --use-ssh, команда shardmanctl recover будет использовать команду scp для восстановления данных. Это позволяет использовать хранилище резервных копий на локальном узле.

Регистрация кластера Shardman

Чтобы зарегистрировать кластер Shardman в хранилище etcd, выполните следующую команду:

    shardmanctl [общие_параметры] init [-y|--yes] [-f|--spec-file имя_файла_конфигурации]|текст_конфигурации

В этой команде необходимо передать строку с конфигурацией кластера. Это можно сделать следующим образом:

В командной строке — не указывать параметр -f и передать строку в текст_конфигурации.

В стандартном вводе — указать параметр -f и передать - в имя_файла_конфигурации.

В файле — указать параметр -f и передать имя файла в имя_файла_конфигурации.

Восстановление кластера Shardman

Расширение shardmanctl может выполнять полное восстановление, восстановление только метаданных или восстановление только схемы кластера Shardman из резервной копии, созданной командой backup.

Чтобы выполнить полное восстановление, используйте следующую команду:

    shardmanctl [общие_параметры] recover --info файл

Передайте файл для загрузки информации о резервной копии в параметре --info. В большинстве случаев в этом параметре нужно указывать файл backup_info в каталоге резервного копирования или его изменённую копию.

Если возникли проблемы с экземпляром etcd, лучше выполнить восстановление только метаданных. Для этого можно запустить следующую команду:

   shardmanctl [общие_параметры] recover --dumpfile файл --metadata-only

Следует указать файл для загрузки ранее выгруженных метаданных etcd в параметре --dumpfile.

Если нужно восстановить только информацию о схеме, например: таблицы, роли и т. д., следует указать параметр --schema-only.

Для всех видов восстановления можно указать --timeout, чтобы утилита завершала работу ошибкой после указанной в секундах задержки при ожидании готовности кластера или завершения восстановления.

Можно указать параметр --shard для восстановления только в одном сегменте.

Перед выполнением команды recover укажите DataRestoreCommand и RestoreCommand в файле backup_info. DataRestoreCommand извлекает базовую резервную копию и восстанавливает её в каталог данных stolon. RestoreCommand извлекает файл WAL и сохраняет его в файл pg_wal в каталоге stolon. Эти команды могут использовать следующие замены:

%p

Путь назначения на сервере.

%s

SystemId восстанавливаемой базы данных (одинаковый в резервной копии и в восстанавливаемом кластере).

%f

Имя файла WAL для восстановления.

процесс stolon keeper запускает обе команды на каждом узле в кластере, поэтому:

Резервную копию нужно сделать доступной для этих узлов (например, сохранив её в общей файловой системе или используя протокол удалённого копирования, такой как SFTP).

Команды для извлечения резервной копии выполняются от имени пользователя операционной системы, под которым работают демоны stolon (обычно postgres), поэтому необходимо установить соответствующие разрешения для файлов резервных копий.

В данных примерах показано, как задать RestoreCommand и DataRestoreCommand:

Если резервная копия доступна через SCP без пароля, можно использовать:

 "DataRestoreCommand": "scp -r user@host:/var/backup/shardman/%s/backup/* %p",
 "RestoreCommand": "scp user@host:/var/backup/shardman/%s/wal/%f %p"

Если резервная копия хранится в NFS и доступна по пути /var/backup/shardman, используйте:

 "DataRestoreCommand": "cp -r /var/backup/shardman/%s/backup/* %p",
 "RestoreCommand": "cp /var/backup/shardman/%s/wal/%f %p"

Резервное копирование кластера Shardman командой probackup

Требования к резервному копированию и восстановлению кластера Shardman командой probackup перечислены в Подразделе 2.6.3.1.

Например, следуя этим требованиям, на узле резервного копирования:

  groupadd postgres
  useradd -m -N -g postgres -r -d /var/lib/postgresql -s /bin/bash

Затем добавьте ключи SSH, чтобы обеспечить SSH-соединение без пароля между узлом резервного копирования и узлами кластера Shardman. Затем на узле резервного копирования:

  apt-get install pg-probackup shardman-utils
  mkdir -p каталог
  chown postgres:postgres каталог -R
  shardmanctl [общие_параметры] probackup init --backup-path=каталог --etcd-path=каталог/etcd --remote-user=postgres --remote-port=22
  shardmanctl [общие_параметры] probackup archive-command --backup-path=каталог --remote-user=postgres --remote-port=22

Если вышеуказанные требования соблюдены, запустите подкоманду backup для резервного копирования кластера:

shardmanctl [общие_параметры] probackup backup --backup-path=каталог --etcd-path=каталог --backup-mode=РЕЖИМ

Следует указать каталоги в параметрах --backup-path и --etcd-path, а режим резервного копирования в --backup-mode. Доступны различные режимы копирования: FULL, DELTA, PTRACK и PAGE. Также можно указать параметры сжатия резервной копии в флагах --compress, --compress-algorithm и --compress-level и указать флаги --remote-port и --remote-user. Можно ограничить количество одновременно выполняемых задач при резервном копировании, задав ограничение во флаге --maxtasks.

По умолчанию для создания резервной копии используется копирование данных по протоколу SSH. Чтобы изменить это поведение и скопировать данные в смонтированную секцию, используется параметр --storage-type со значением mount. Это значение будет автоматически использоваться в процессе восстановления.

Можно скопировать данные в S3-совместимое хранилище. Для этого используйте параметр --storage-type со значением S3. Это значение требует указания каталога для хранения журналов pg_probackup в команде --log-directory или в переменной окружения SDM_LOG_DIRECTORY, например:

export SDM_LOG_DIRECTORY=/backup/logs

Чтобы выполнить резервное копирование или восстановление только для S3-совместимого хранилища, вместо указания параметра --storage-type в каждой команде probackup можно установить переменную окружения:

export SDM_STORAGE_TYPE=S3

Восстановление кластера Shardman командой probackup

Расширение shardmanctl в режиме probackup может выполнять полное восстановление, восстановление только метаданных или восстановление только схемы кластера Shardman из резервной копии, созданной командой probackup backup.

Чтобы выполнить полное или частичное восстановление, сначала необходимо выбрать желаемую резервную копию для восстановления. Чтобы отобразить список доступных резервных копий, выполните следующую команду:

shardmanctl [общие_параметры] probackup show --backup-path=путь --format=формат [--archive ] [-i|--backup-id ид_резервной_копии] [--instance экземпляр]

После этого должен отобразиться список резервных копий с их идентификаторами в формате таблицы или JSON. Затем выберите нужный идентификатор резервной копии и запустите команду восстановления probackup.

shardmanctl [общие_параметры] probackup restore --backup-path=путь --backup-id=идентификатор

Укажите путь к репозиторию в параметре --backup-path и идентификатор резервной копии во флаге --backup-id.

Если возникли проблемы с экземпляром etcd, лучше выполнить восстановление только метаданных. Для этого можно запустить следующую команду:

shardmanctl [общие_параметры] probackup restore --backup-path=путь --backup-id=идентификатор --metadata-only

Если нужно восстановить только информацию о схеме, например: таблицы, роли и т. д., следует указать параметр --schema-only.

Для обоих видов восстановления можно указать --timeout, чтобы утилита завершала работу ошибкой после указанной в секундах задержки при ожидании готовности кластера или завершения восстановления.

Можно указать параметр --shard для восстановления только в одном сегменте.

Также можно указать параметр --recovery-target-time для выполнения восстановления на момент времени. В этом случае Shardman находит ближайшую точку синхронизации к указанной временной метке и предлагает выполнить восстановление по найденному значению LSN. Чтобы ограничить количество обрабатываемых сегментов WAL, можно указать параметр --wal-limit.

Важно

Перед восстановлением кластера Shardman необходимо убедиться, что кластер запущен, выполнив команду shardmanctl status. Если в выводе присутствуют ошибки, восстановление кластера может сделать его недоступным. Сначала необходимо исправить ошибки, повторно инициализировав кластер, и восстановить метаданные etcd. Только после этого можно проводить восстановление кластера из резервной копии.

Переинициализация реплик

Если реплики находятся в неправильном состоянии, их можно сбросить с помощью команды shardmanctl:

shardmanctl [общие_параметры] shard --shard=имя_сегмента replicas reinit

Эта команда определяет узлы, на которых запущены реплики указанного сегмента, и отправляет запрос shardmand на этих узлах. После получения этого запроса shardmand очищает каталог данных postgres и перезапускает процесс keeper, отвечающий за управление репликой. После этого реплики перезапускаются и начинают получать данные от соответствующего ведущего сервера.

Примеры

Инициализация кластера

Для инициализации кластера Shardman с именем cluster0, который использует кластер etcd, состоящий из прослушивающих порт 2379 узлов n1, n2 и n3, проверьте правильность параметров в файле конфигурации sdmspec.json и выполните:

$ shardmanctl --store-endpoints http://n1:2379,http://n2:2379,http://n3:2379 init -f sdmspec.json

Получение строки подключения к кластеру

Чтобы получить строку подключения для кластера Shardman с именем cluster0, который использует кластер etcd, состоящий из узлов n1, n2 и n3, прослушивающих порт 2379, выполните:

  $ shardmanctl --store-endpoints http://n1:2379,http://n2:2379,http://n3:2379 getconnstr

  dbname=host postgres=n1,n4,n2,n1,n1,n2,n4,n3 password=yourpasswordhere port=5432,5433,5432,5433,5432,5433,5432,5433 user=postgres

Чтобы добавить информацию о репликах в результат команды getconnstr, используется параметр --all.

Получение статуса кластера

Ниже представлен пример вывода статуса из shardmanctl со статусами OK и Error:

        $ shardmanctl status --filter store,shardmand,rg --sort=node

┌──────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│                                            == STORE STATUS ==                                            │
├────────────┬─────────────────────────────────────────────┬───────────────────────┬───────────────────────┤
│   STATUS   │                   MESSAGE                   │   REPLICATION GROUP   │          NODE         │
├────────────┼─────────────────────────────────────────────┼───────────────────────┼───────────────────────┤
│     OK     │ etcd store is OK                            │                       │                       │
└────────────┴─────────────────────────────────────────────┴───────────────────────┴───────────────────────┘
┌──────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│                                          == SHARDMAND STATUS ==                                           │
├────────────┬─────────────────────────────────────────────┬───────────────────────┬───────────────────────┤
│   STATUS   │                   MESSAGE                   │   REPLICATION GROUP   │          NODE         │
├────────────┼─────────────────────────────────────────────┼───────────────────────┼───────────────────────┤
│     OK     │ shardmand on node 56d819b4e9e4 is OK        │                       │      56d819b4e9e4     │
├────────────┼─────────────────────────────────────────────┼───────────────────────┼───────────────────────┤
│     OK     │ shardmand on node 6d0aabd50acc is OK        │                       │      6d0aabd50acc     │
└────────────┴─────────────────────────────────────────────┴───────────────────────┴───────────────────────┘
┌───────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│                                       == REPLICATION GROUP STATUS ==                                      │
├────────────┬──────────────────────────────────────────────┬───────────────────────┬───────────────────────┤
│   STATUS   │                    MESSAGE                   │   REPLICATION GROUP   │          NODE         │
├────────────┼──────────────────────────────────────────────┼───────────────────────┼───────────────────────┤
│     OK     │ Replication group clover-1-56d819b4e9e4 is   │ clover-1-56d819b4e9e4 │                       │
│            │ OK                                           │                       │                       │
├────────────┼──────────────────────────────────────────────┼───────────────────────┼───────────────────────┤
│            │ Replication connection is down for slave     │                       │                       │
│    Error   │ 6d0aabd50acc:5442 in replication group       │ clover-1-6d0aabd50acc │   6d0aabd50acc:5442   │
│            │ clover-1-6d0aabd50acc                        │                       │                       │
└────────────┴──────────────────────────────────────────────┴───────────────────────┴───────────────────────┘
┌─────────────────────────────────────────────────────────────────────────────────────────┐

│                           == RESTART REQUIRED PARAMS STATUS ==                          │

├──────────┬──────────────────────────────────────┬───────────────────┬───────────────────┤

│  STATUS  │                MESSAGE               │ REPLICATION GROUP │        NODE       │

├──────────┼──────────────────────────────────────┼───────────────────┼───────────────────┤

│    OK    │     No pending restart parameters    │      shard-1      │       shrn1       │

├──────────┼──────────────────────────────────────┼───────────────────┼───────────────────┤

│    OK    │     No pending restart parameters    │      shard-2      │       shrn4       │

└──────────┴──────────────────────────────────────┴───────────────────┴───────────────────┘

Изменение конфигурации stolon

Сначала получите список доступных ключей в хранилище, используя следующую команду:

      $ shardmanctl store keys

{
 "Key": "shardman/cluster0/data/cluster",
 "Alias": "cluster"
}{
 "Key": "shardman/cluster0/data/shardmand/56d819b4e9e4"
}{
...
 "Key": "shardman/cluster0/stolon/remoteLogs/6d0aabd50acc/clover-1-6d0aabd50acc/keeper_1/error"
}

Получите конфигурацию stolon из хранилища и сохраните её в файле stolonspec.json, используя команду

       $ shardmanctl store get -a stolonspec -f stolonspec.json

Примените необходимые изменения и загрузите новую конфигурацию командой shardmanctl config update. Учтите, что параметр shardman.config_uuid удаляется в команде shardmanctl store get -a stolonspec, а не в shardmanctl store get -k full/path/to/clusterspec; использование конфигурации с существующим shardman.config_uuid приведёт к конфликту.

Важно

Не используйте команду store set для обновления конфигураций кластера, поскольку она не применяет новую конфигурацию ко всем узлам, а только записывает её в хранилище. Для текущего примера с конфигурацией stolon допустимо выполнение shardmanctl config update.

Для перепроверки можно получить ключ кластера с новой StolonSpec по полному имени ключа (которое было показано ранее командой store keys):

      $ shardmanctl store get -k shardman/cluster0/data/cluster

{
  "FormatVersion": 1,
  "Spec": {
    "PgSuAuthMethod": "md5",
    "PgSuPassword": "12345",
    "PgSuUsername": "postgres",
    "PgReplAuthMethod": "md5",
    "PgReplPassword": "12345",
    "PgReplUsername": "repluser",
    "ShardSpec": {
      ...
}

Добавление узлов в кластер

Чтобы добавить узлы n1,n2, n3 и n4 в кластер, выполните:

$ shardmanctl --store-endpoints http://n1:2379,http://n2:2379,http://n3:2379 nodes add -n n1,n2,n3,n4

Важно

Количество добавляемых узлов должно быть кратно Repfactor + 1, если используется политика размещения cross.

Удаление узлов из кластера

Чтобы удалить узлы n1 и n2 из кластера cluster0, выполните:

      $ shardmanctl --store-endpoints http://n1:2379,http://n2:2379,http://n3:2379 nodes rm -n n1,n2

Если используется политика размещения cross, вместе с узлами будут удалены звенья, содержащие эти узлы.

Выполнение запроса во всех группах репликации

Чтобы выполнить запрос select version() во всех группах репликации, используйте:

 $ shardmanctl --store-endpoints http://n1:2379,http://n2:2379,http://n3:2379 forall --sql 'select version()'

 Node 1 says:
 [PostgreSQL 13.1 on x86_64-pc-linux-gnu, compiled by gcc (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0, 64-bit]
 Node 4 says:
 [PostgreSQL 13.1 on x86_64-pc-linux-gnu, compiled by gcc (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0, 64-bit]
 Node 3 says:
 [PostgreSQL 13.1 on x86_64-pc-linux-gnu, compiled by gcc (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0, 64-bit]
 Node 2 says:
 [PostgreSQL 13.1 on x86_64-pc-linux-gnu, compiled by gcc (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0, 64-bit]

Выполнение перебалансировки

Чтобы выполнить перебалансировку сегментированных таблиц в кластере cluster0, выполните:

 $ shardmanctl --store-endpoints http://n1:2379,http://n2:2379,http://n3:2379 rebalance

Обновление параметров конфигурации PostgreSQL

Чтобы установить для параметра max_connections значение 200 в кластере, создайте файл конфигурации (например, ~/stolon.json) со следующим содержимым:

 {
   "pgParameters": {
     "max_connections": "200"
   }
 }

Затем выполните:

  $ shardmanctl --store-endpoints http://n1:2379,http://n2:2379,http://n3:2379 config update -p -f ~/stolon.json

Поскольку для изменения max_connections требуется перезапуск, эта команда перезапускает экземпляры СУБД.

Выполнение резервного копирования и восстановления

Чтобы создать резервную копию кластера cluster0, используя etcd на etcdserver, прослушивающем порт 2379, и сохранить его в локальном каталоге /var/backup/shardman, выполните:

$ shardmanctl --store-endpoints http://etcdserver:2379 backup --datadir=/var/backup/shardman --use-ssh

Предположим, что вы выполняете восстановление из резервной копии в кластер cluster0, используя etcd на etcdserver, прослушивающем порт 2379, и берёте описание резервной копии из файла /var/backup/shardman/backup_info. Отредактируйте файл /var/backup/shardman/backup_info, если необходимо, задайте параметры DataRestoreCommand, RestoreCommand и запустите:

$ shardmanctl --store-endpoints http://etcdserver:2379 recover --info /var/backup/shardman/backup_info

Чтобы восстановить только мета-данные:

$ shardmanctl --store-endpoints http://etcdserver:2379 recover --metadata-only --dumpfile /var/backup/shardman/etcd_dump

Чтобы восстановить только схемы:

$ shardmanctl --store-endpoints http://etcdserver:2379 recover --schema-only --dumpfile /var/backup/shardman/etcd_dump

Чтобы восстановить только один сегмент:

$ shardmanctl --store-endpoints http://etcdserver:2379 recover  --info /var/backup/shardman/backup_info --shard shard_1

Выполнение резервного копирования и восстановления с использованием команды probackup

Чтобы создать резервную копию кластера cluster0, используя etcd на etcdserver, прослушивающем порт 2379, и сохранить её в локальном каталоге /var/backup/shardman, сначала инициализируйте репозиторий резервных копий подкомандой init:

$ shardmanctl --store-endpoints http://etcdserver:2379 probackup init --backup-path=/var/backup/shardman --etcd-path=/var/backup/etcd_dump

Затем добавьте и включите команду archive_command с подкомандой archive-command:

$ shardmanctl --store-endpoints http://etcdserver:2379 probackup archive-command add --backup-path=/var/backup/shardman

Если репозиторий успешно инициализирован и успешно добавлена archive-command, создайте резервную копию в режиме FULL, используя подкоманду backup:

$ shardmanctl --store-endpoints http://etcdserver:2379 probackup backup --backup-path=/var/backup/shardman --etcd-path=/var/backup/etcd_dump --backup-mode=FULL --compress --compress-algorithm=zlib --compress-level=5

Чтобы создать резервную копию в режиме DELTA, PTRACK или PAGE, запустите подкоманду backup со значением DELTA, PTRACK или PAGE параметра --backup-mode:

$ shardmanctl --store-endpoints http://etcdserver:2379 probackup backup --backup-path=/var/backup/shardman --etcd-path=/var/backup/etcd_dump --backup-mode=DELTA --compress --compress-algorithm=zlib --compress-level=5

Чтобы узнать идентификатор созданной резервной копии, запустите подкоманду show:

$ shardmanctl --store-endpoints http://etcdserver:2379 probackup show --backup-path=/var/backup/shardman --format=table

┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│                                                                                                      == BACKUP ID 'S88FRO'                                                                                                     │
│                                                                                                               ==                                                                                                               │
├───────────────────────────────────┬───────────────────────────────────┬───────────────────────────────────┬────────────┬────────────┬────────────┬────────────┬────────────┬────────────┬────────────┬────────────┬────────────┤
│              INSTANCE             │                HOST               │           RECOVERY TIME           │    MODE    │  WAL MODE  │     TLI    │    DATA    │     WAL    │   Z-RATIO  │  START LSN │  STOP LSN  │   STATUS   │
├───────────────────────────────────┼───────────────────────────────────┼───────────────────────────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┤
│              shard-1              │               n1                  │       2024-02-02 14:19:05+00      │    FULL    │   ARCHIVE  │     1/0    │  42.37MiB  │    16MiB   │    1.00    │  0/C000028 │  0/D0018B0 │     OK     │
├───────────────────────────────────┼───────────────────────────────────┼───────────────────────────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┼────────────┤
│              shard-2              │               n2                  │       2024-02-02 14:19:05+00      │    FULL    │   ARCHIVE  │     1/0    │  42.38MiB  │    16MiB   │    1.00    │  0/C000028 │  0/D001E00 │     OK     │
└───────────────────────────────────┴───────────────────────────────────┴───────────────────────────────────┴────────────┴────────────┴────────────┴────────────┴────────────┴────────────┴────────────┴────────────┴────────────┘

В режиме PTRACK Shardman отслеживает изменения страниц на лету. Чтобы он работал, не требуется производить непрерывное архивирование. При каждом изменении страницы отношения она помечается в специальной битовой карте PTRACK. Это отслеживание немного увеличивает издержки в работе сервера, но значительно ускоряет инкрементальное резервное копирование.

Если будут использоваться резервные копии PTRACK, выполните следующие дополнительные шаги:

Предварительно загрузите общую библиотеку ptrack на каждом узле. Добавьте значение ptrack к параметру shared_preload_libraries.

Создайте расширение PTRACK на каждом узле кластера:

                            $ shardmanctl --store-endpoints http://etcdserver:2379 forall --sql "create extension ptrack"

Для включения отслеживания изменений страницы, задайте параметр ptrack.map_size следующим образом:

                            $ shardmanctl --store-endpoints http://etcdserver:2379 update '{"pgParameters":{"ptrack.map_size":"64"}}'

Для оптимальной производительности рекомендуется задавать ptrack.map_size равным N/1024, где N — максимальный размер узла кластера в мегабайтах. Если задать меньшее значение, увеличится вероятность наложения информации из разных блоков в карте PTRACK, что повлечёт ложные положительные результаты при определении изменённых блоков и, как следствие, увеличение размера инкрементальной копии, так как в копию будут попадать и фактически неизменённые блоки. Использовать значения ptrack.map_size, превышающие 1024, не рекомендуется, хотя PTRACK поддерживает большие карты.

Чтобы проверить созданную резервную копию, запустите подкоманду validate:

$ shardmanctl --store-endpoints http://etcdserver:2379 probackup validate --backup-path=/var/backup/shardman --backup-id=RFP1FI

Предположим, что выполняется восстановление из резервной копии в кластер cluster0, используя etcd на etcdserver, прослушивающем порт 2379, и берётся идентификатор резервной копии из команды show:

$ shardmanctl --store-endpoints http://etcdserver:2379 probackup restore --backup-path=/var/backup/shardman --backup-id=RFP1FI

Наконец, нужно снова включить archive_command.

$ shardmanctl --store-endpoints http://etcdserver:2379 probackup archive-command add --backup-path=/var/backup/shardman

Для восстановления только метаданных выполните:

$ shardmanctl --store-endpoints http://etcdserver:2379 probackup restore --schema-only --backup-path=/var/backup/shardman --backup-id=RFP1FI

Для восстановления одного сегмента выполните:

$ shardmanctl --store-endpoints http://etcdserver:2379 probackup restore --backup-path=/var/backup/shardman --backup-id=RFP1FI --shard shard_1

Для восстановления на определённый момент времени выполните:

$ shardmanctl --store-endpoints http://etcdserver:2379 probackup restore --metadata-only --backup-path=/var/backup/shardman --backup-id=RFP1FI --recovery-target-time='2006-01-02 15:04:05' -s

Загрузка данных из текстового файла

Чтобы загрузить данные в кластер Shardman, выполните следующую команду:

$ shardmanctl --store-endpoints http://etcdserver:2379 load --file=/var/load/data.tsv --table=mytable --source file --format text -j 8

В этом примере данные загружаются из файла данных /var/load/data.tsv (с разделением табуляцией) в таблицу mytable в 8 параллельных потоков. Можно использовать schema.table в качестве имени таблицы.

Загрузка данных из таблицы PostgreSQL

Чтобы загрузить данные в кластер Shardman из таблицы PostgreSQL, выполните следующую команду:

$ shardmanctl --store-endpoints http://etcdserver:2379 load -t desttable --source postgres --source-connstr "dbname=db host=srchost port=srcport user=login password=passwd" --source-table sourcetable -j 8

В этом примере данные загружаются из таблицы sourcetable в таблицу desttable в 8 параллельных потоков. Можно использовать schema.table в качестве имён таблиц.

Загрузка данных из схемы PostgreSQL

Чтобы загрузить данные из схемы PostgreSQL в кластер Shardman, выполните следующую команду:

$ shardmanctl --store-endpoints http://etcdserver:2379 load --schema load_schema.yaml

Файл load_schema.yaml имеет следующий формат:

version: "1.0"
migrate:
  connstr: "dbname=workdb host=workhost port=workport user=workuser password=workpassword"
  jobs: 8
  batch: 1000
  options:
    - create_schema
    - create_table
    - create_index
    - create_sequence
    - create_foreign_key
    - create_role
    - copy_ownership
    - copy_grants
    - truncate_table
    - skip_no_pkey_tables
    - skip_create_index_error
    - skip_create_extension_error
    - skip_load_errors
    - skip_create_foreign_key_error
    - skip_create_role_error
    - skip_copy_grants_error
    - skip_copy_ownership_error
  schemas:
    - name: public
      all: false
      tables:
        - name: tab1
          type: sharded
          partitions: 6
          distributedby: id
          priority: 3
        - name: tab2
          type: global
        - name: tab3
          type: sharded
          partitions: 6
          distributedby: field_id
          colocatewith: tab1
        - name: table4
            type: global
            source: schema.view
            source_pk: field_id
        - name: table5
            type: global
            source: schema.func(arg)
            source_pk: field_id
    - name: schema2
      all: false
      default_type: sharded
      default_partitions: 6
      tables:
        - name: table1
          distributedby: field_id
          priority: 2
        - name: table2
          type: global
        - name: table3
          source: schema.view
          distributedby: field_id
          priority: 3
        - name: table4
          distributedby: field_id
          source: schema.func(arg)
        - name: table5
          source: schema."complex.""table.name"
          distributedby: field_id
    - name: schema3
      all: true
      skip_tables: [table1, table2, table3]
  roles:
    - name: test_user1
      password: test_password
    - name: test_user2

Параметр migrate.jobs определяет количество параллельных процессов загрузки данных.

Параметр migrate.batch задаёт число строк в одной порции (рекомендуемое значение — 1000).

Параметр migrate.schema определяет массив желаемых схем исходной базы данных. Все остальные схемы будут пропущены.

Если для параметра all задано значение true, то будут перенесены все таблицы из текущей схемы (с типом global по умолчанию). Если таблица указана в массиве migrate.schemas.tables, то для неё необходимо явно указать тип целевой таблицы. В настоящее время поддерживаются два типа таблиц: global и sharded. Сначала загружаются глобальные (global) таблицы, затем сегментированные (sharded) таблицы и в конце сегментированные таблицы с параметром colocatedwith. Порядок загрузки таблиц одного типа можно изменить с помощью параметра priority.

Секция migrate.schemas.skip_tables определяет массив имён таблиц, которые будут пропущены при загрузке схемы, даже если для параметра all установлено значение true.

Для сегментированных таблиц должны быть установлены следующие атрибуты: distributedby (указывает имя столбца, используемого для секционирования таблицы) и partitions (количество секций, которые будут созданы для этой таблицы). Для сегментированных таблиц может быть дополнительно установлен атрибут colocatewith (имя таблицы, с которой выполняется совместное размещение). Shardman попытается разместить секции созданной таблицы с тем же ключом секции на тех же узлах, что и соответствующие секции таблицы, указанные в colocatewith.

Можно указать параметр таблицы default_type для схемы: global или sharded (по умолчанию: global). Для сегментированного типа также можно указать параметр default_partitions (по умолчанию: 20). Если установлен default_type sharded, необходимо указать параметр distributedby для каждой таблицы.

Параметр source для таблицы должен включать схему и исходную таблицу: schema.source. Исходной может быть таблица, представление или функция. Например: public.table, public.view, public.func(arg). Если устанавливается представление или функция source для глобальной таблицы, необходимо указать в параметре source_pk, какой первичный ключ установлен для этой таблицы. Если source не указан или содержит имя таблицы, также можно указать параметр source_pk, чтобы создать первичный ключ или переопределить существующий.

Параметр priority для таблицы определяет порядок загрузки таблиц одного типа. Таблицы с большим значением priority загружаются раньше. Значение priority по умолчанию — 0.

Раздел migrate.roles определяет массив имён таблиц и паролей, которые будут скопированы из исходной базы данных, если задан параметр create_role.

Схема поддерживает следующие параметры:

create_schema — создавать схемы баз данных, если они не существуют.

create_table — создавать таблицы, если они не существуют.

create_index — создавать индексы после создания таблиц.

create_sequence — создавать последовательности, если они не существуют.

create_index — создавать индексы после создания таблиц.

truncate_table — опустошать таблицы перед загрузкой данных.

create_role — создать глобальные роли, заданные в migrate.roles, и скопировать параметры ролей из исходной базы данных.

copy_grants — скопировать права доступа из исходной базы данных.

copy_ownership — сменить владельцев таблиц на владельца в исходной базе данных.

skip_no_pkey_tables — пропускать таблицы без первичных ключей.

skip_create_index_error — пропускать ошибки создания индекса.

skip_create_extension_error — пропускать ошибки создания расширений.

skip_load_errors — продолжать загрузку при возникновении ошибок.

skip_create_foreign_key_error — пропускать ошибки создания внешних ключей.

skip_create_role_error — пропускать ошибки создания ролей.

skip_copy_ownership_error — пропускать ошибки смены владельца таблицы.

skip_copy_grants_error — пропускать ошибки при копировании прав доступа из исходной базы данных.

Инициализация и тесты производительности

Чтобы инициализировать тест производительности через shardmanctl, используя pgbench со схемой shardman, масштабирование=1000, разделы=40, запустите:

$ shardmanctlbench init --schema-type=shardman --scale=1000 --partitions=40

Чтобы запустить инициализированный тест производительности для той же схемы shardman, при количестве заданий=4, количестве клиентов=10, продолжительности в секундах=60 и с полным выводом pgbench, используйте:

$ shardmanctl bench run --schema-type=shardman --jobs=4 --client=10 --time=60 --full-output

Чтобы инициализировать тест производительности с использованием custom схемы из файла schema.psql с масштабированием=1000, выполните:

$ shardmanctlbench init --schema-type=custom --schema-file=schema.psql --scale=1000

Чтобы запустить инициализированный тест производительности с использованием custom схемы и пользовательского скрипта транзакции из script.psql с количеством заданий =4, числом клиентов=10, продолжительность в секундах=60, используйте:

$ shardmanctl bench run --schema-type=custom --file=script.psql --jobs=4 --client=10 --time=60

Чтобы очистить базу данных PostgreSQL от таблиц tpc-b, используйте:

$ shardmanctl bench cleanup

Скрипты генерации тестов производительности

Чтобы сгенерировать последовательность тестов производительности через shardmanctl из файла конфигурации=cfg.yaml и вывести результат в file=script.sh, запустите:

$ shardmanctlbenchgenerate --config=cfg.yaml --output-file=script.sh

Пример файла конфигурации:

    benches:
    - schema_type: single
      init_flags: "-s 3"
      run_flags: "-n -P 10 -c 10 -j 4 -T 10"
    - schema_type: simple
      init_flags: "-s 4"
      run_flags: "-n -P 10 -c 20 -j 4 -T 10"
      partitions: 100
    - schema_type: shardman
      init_flags: "-s 5"
      run_flags: "-n -P 10 -c 20 -j 4 -T 10"
    - schema_type: custom
      init_flags: "-s 6"
      schema_file: "schema.psql"

См. также

sdmspec.json , shardmand

sdmspec.json

sdmspec.json — файл инициализации Shardman

Синтаксис

   sdmspec.json

Описание

Расширение shardmanctl использует файл конфигурации sdmspec.json во время инициализации кластера Shardman. Пакет shardman-utils содержит пример файла конфигурации.

Файл sdmspec.json содержит основные пути файловой системы, используемые Shardman, глобальные параметры кластера, параметры, связанные с базой данных, например логины администраторов и пользователей репликации и методы их аутентификации, параметры FDW и конфигурация сегментов (ShardSpec).

Обратите внимание, что существует ряд внутренних параметров Shardman, изменение которых пользователями может привести к разрушению кластера:

Параметр shardman.cluster_uuid используется для определения версии запущенного кластера, в который входит этот узел.

Параметр shardman.config_uuid определяет версию конфигурации. Игнорируется, если задан с помощью команды shardmanctl config update или shardmanctl init.

Параметр shardman.manual_execution используется для согласованной работы с глобальными объектами.

Параметр shardman.silk_never_restart запрещает перезапуск процессов мультиплексора в случае ошибок.

Параметр shardman.pre_promote_mode используется в механизме согласованного повышения резервного сервера до ведущего.

Список параметров

Repfactor

Целое число, определяющее, сколько реплик нужно настроить расширению shardmanctl для каждой СУБД. Этот параметр можно изменить только для кластера Shardman с режимом топологии manual.

PlacementPolicy

Строка, определяющая политику размещения экземпляров СУБД. В настоящее время поддерживаются только политики размещения cross и manual. Прежнее значение clover используется как псевдоним для политики cross.

С политикой cross узлы группируются в звенья, где на каждом узле работает главный сервер СУБД и реплики для всех остальных узлов в звене. Количество узлов в звене определяется параметром Repfactor и равно Repfactor + 1.

Политика размещения manual позволяет вручную добавлять или удалять необходимое количество реплик в указанных группах репликации. В этом случае Repfactor используется только в рекомендательных целях и не накладывает ограничений.

DataDir

Позволяет указать каталог для хранения данных, отличный от каталога по умолчанию (/var/lib/pgpro/sdm-14/data). Этот параметр нельзя изменить после инициализации кластера.

PGsInitialPort

Порты, начинающиеся с этого целого числа, назначаются экземплярам PostgreSQL. Этот параметр нельзя изменить после инициализации кластера.

SilkInitialPort

Порты, начинающиеся с этого целого числа, назначаются экземплярам Silk (Shardman InterLinK). Этот параметр нельзя изменить после инициализации кластера.

AuthMethod

Метод аутентификации, используемый администратором для подключения к СУБД. Может быть любым методом аутентификации, поддерживаемым PostgreSQL. В настоящее время рекомендуется использовать scram-sha-256. Метод md5 сейчас разрешён, но не рекомендован. Этот параметр нельзя изменить после инициализации кластера. Он должен быть расположен в отдельном блоке Users для каждого элемента массива.

По умолчанию: trust.

Groups

Массив, который может иметь два возможных значения: su для суперпользователя или repl для пользователя репликации.

HTTP

Задаёт параметры безопасного подключения по протоколу HTTP/HTTPS с помощью параметров Port, задающего порт API, и PortMetrics, задающего порт метрик. Если эти порты одинаковые, API и метрики слушают один и тот же порт.

По умолчанию: 15432.

Name

Имя пользователя. Создаётся при инициализации кластера. По умолчанию используется имя действительного пользователя, запустившего shardmanctl init. Этот параметр нельзя изменить после инициализации кластера. Он должен быть расположен в отдельном блоке Users для каждого элемента массива.

Password

Пароль пользователя. Можно изменить, используя shardmanctl config update credentials. Должен быть расположен в отдельном блоке Users для каждого элемента массива.

PgSuSSLCert

Клиентский сертификат для администратора СУБД.

PgSSLRootCert

Расположение файла корневого сертификата для подключения пользователя СУБД.

PgSuSSLKey

Закрытый ключ клиента для администратора СУБД.

PgSSLMode

Режим SSL для пользователя СУБД. Допустимые значения: verify-ca и verify-full.

PgReplSSLCert

Клиентский сертификат для пользователя репликации СУБД.

PgReplSSLKey

Закрытый ключ клиента для пользователя репликации СУБД.

ShardSpec

Спецификация кластера сегментов. За подробным описанием обратитесь к разделу Параметры ShardSpec. Спецификацию можно изменить, используя shardmanctl config update.

FDWOptions

Этот объект содержит параметры FDW.

Эти параметры можно изменить, используя shardmanctl config update (за исключением параметров, связанных с авторизацией, подключением к серверу, SSL и Kerberos, а также параметров service, target_session_attrs).

На сторонних серверах, соответствующих группам репликации Shardman, также будет автоматически включён параметр extended_features. Никогда не устанавливайте этот параметр для сторонних серверов postgres_fdw, которые определяются для пользовательских целей (например, для загрузки данных в кластер Shardman).

Параметры ShardSpec

Спецификация ShardSpec может включать все обычные параметры stolon, описанные в Спецификация кластера Stolon. Однако следующие параметры следует тщательно настроить для кластера Shardman.

pgHBA

Массив JSON строк pg_hba.conf. По умолчанию разрешает доступ пользователю из группы su из любого места с методом аутентификации AuthMethod. Если значение defaultSUReplAccessMode равно strict, строки pg_hba.conf должны явно разрешать доступ пользователей из групп su или repl со всех узлов кластера Shardman.

forceSuUserLocalPeerAuth

Если этот параметр включён, он устанавливает аутентификацию peer через сокет Unix для пользователя postgres, если для strictUserHBA не установлено значение true.

По умолчанию: false.

synchronousReplication

Определяет, должны ли реплики использовать синхронную репликацию. Должен иметь значение true в кластере Shardman.

По умолчанию: true.

maxSynchronousStandbys

Максимальное количество необходимых синхронных резервных серверов при включённой синхронной репликации. Должно быть >= Repfactor в кластере Shardman. По умолчанию: Repfactor.

strictUserHBA

Запрещает добавление автоматически сгенерированных строк в файл pg_hba.conf. По умолчанию: false.

automaticPgRestart

Определяет, должен ли экземпляр СУБД автоматически перезапускаться после изменения хеш-таблицы pgParameters, внесение которого требует перезапуска. Должен быть включён в кластере Shardman.

По умолчанию: true.

masterDemotionEnabled

Включить понижение роли ведущего сервера, если ведущий сервер группы реплик потерял связь с etcd. Ведущий сервер пытается подключиться к каждому из своих резервных узлов, чтобы определить, стал ли какой-либо из них ведущим. Если обнаруживается другой ведущий сервер, текущий выключает свой экземпляр СУБД до тех пор, пока не будет восстановлено соединение с etcd. Если ведущий сервер в течение длительного времени не может подключиться к одному из своих резервных узлов, происходит отключение экземпляра СУБД.

По умолчанию: false.

masterDemotionTimeout

Тайм-аут, в течение которого ведущий сервер пытается подключиться к своим резервным узлам в случаях, когда связь с etcd потеряна. Работает, только если для параметра masterDmotionEnabled установлено значение true.

По умолчанию: 30s.

minSyncMonitorEnabled

Включает отслеживание значения MinSynchronousStandbys для каждой группы реплики. Если узел теряет соединение с кластером (все процессы keeper неработоспособны: состояние keeper не обновляется дольше, чем minSyncMonitorUnhealthyTimeout), отслеживается уменьшение значения MinSynchronousStandbys для каждой группы реплик, связанной с отключённым узлом, до максимально доступного значения. Это позволяет предотвратить состояние только для чтения, вызванное поддельной репликой. Максимально доступное значение всегда меньше или равно значению, указанному в конфигурации кластера. Если все процессы keeper, связанные с отключённым узлом, становятся работоспособными, отслеживается изменение значения MinSynchronousStandbys группы реплик на значение, указанное в конфигурации кластера.

По умолчанию: false.

minSyncMonitorUnhealthyTimeout

Временной интервал, по истечении которого узел (и все процессы keeper, связанные с этим узлом) будет считаться неработоспособным. Работает, только если для параметра minSyncMonitorEnabled установлено значение true.

По умолчанию: 30s.

syncPointMonitorEnabled

Включить отслеживающий процесс, который каждую минуту создаёт точку синхронизации, гарантируя, что кластер Shardman можно восстановить в согласованном состоянии на данный LSN. В каждой точке синхронизации состояние кластера согласованно, то есть все транзакции завершены. Если для этого параметра установлено значение true, PITR будет гарантированно работать. Если задано значение true, история точки синхронизации сохраняется в etcd с ключом shardman/{cluster_name}/data/cluster/syncpoints.

По умолчанию: false.

dbWaitRewindTimeout

Перед полной повторной синхронизацией реплики программное обеспечение кластера сначала пытается задействовать pg_rewind, поскольку операция перемотки выполняется значительно быстрее других подходов, когда база данных большая и кластеры отличаются лишь небольшой частью блоков. Параметр dbWaitRewindTimeout указывает максимальное время работы для pg_rewind (примеры значений: 5m, 30s, 1m30s).

По умолчанию: 7m.

additionalReplicationSlots

Массив имён слотов физической репликации, созданных на ведущем сервере. Каждое имя слота должно начинаться с префикса stolon_.

createSlotsOnFollowers

Если задано значение true, слоты физической репликации также создаются на резервных узлах.

additionalSlotsLagLimit

Лимит объёма, на который слоты репликации, определённыe параметром конфигурации additionalReplicationSlots, могут отставать. Значение указывается числом с единицей измерения. Возможные единицы измерения: B (Б), kB (КБ), kiB (КиБ), MB (МБ), MiB (МиБ), GB (ГБ), GiB (ГиБ), TB (ТБ), TiB (ТиБ), PB (ПБ), PiB (ПиБ), EB (ЭБ), EiB (ЭиБ), ZB (ЗБ), ZiB (ЗиБ), YB (ЙБ) и YiB (ЙиБ). Например: 100MB.

pgParameters

Хеш-таблица, определяющая параметры PostgreSQL, включая параметры, специфичные для Shardman. Поддерживает следующие местозаполнители для параметров postgres: {{dataDir}} для директории данных, {{keeperDir}} для каталога данных keeper в директории dataDir, {{keeperName}} для имени keeper, {{keeperID}} для идентификатора keeper, {{host}}, {{cluster}} для имени кластера, {{shard}} для имени сегмента, {{host}} для узла с работающим экземпляром postgres.

Параметры PostgreSQL, специфичные для Shardman

Следующие параметры в pgParameters относятся к Shardman:

enable_csn_snapshot (boolean)

Включает или отключает для снимка отслеживание видимости транзакции на основе последовательного номера фиксации (CSN).

PostgreSQL использует метку времени в качестве CSN, поэтому включение снимков на основе CSN может быть полезно для реализации глобальных снимков и глобальной видимости транзакций.

Когда этот параметр включён, PostgreSQL создаёт каталог pg_csn в PGDATA для отслеживания сопоставлений CSN и XID.

По умолчанию: off.

enable_custom_cache_costs (boolean)

Включает логику оценки стоимости плана. Это позволяет планировщику чаще выбирать общие планы с учётом устранения секций во время выполнения запроса.

По умолчанию: off.

enable_sql_func_custom_plans (boolean)

Включение этого параметра позволяет создавать специализированные планы для выполнения функций на языке SQL. Эти планы зависят от значений параметров.

Планы запросов могут кешироваться в рамках одного выполнения запроса. Сначала план создаётся пять раз для разных значений параметров. После этого создаётся общий план, не зависящий от значений параметров. Если цена специализированного и общего плана отличается незначительно, общий план будет добавлен в кеш и использован в дальнейшем. Однако использование специализированного плана позволяет более эффективно отсекать запросы к секциям сегментированной таблицы, если выбор используемых секций зависит от параметров запроса.

По умолчанию: off.

enable_merge_append (boolean)

Включает использование планов MergeAppend планировщиком запросов.

По умолчанию: on.

enable_async_merge_append (boolean)

Включает или отключает использование планировщиком планов с асинхронным добавлением данных слиянием. По умолчанию имеет значение on (вкл.).

csn_snapshot_defer_time (integer)

Указывает минимальный возраст разрешённых для очистки записей в секундах.

Все глобальные транзакции должны начинаться на всех узлах-участниках в течение количества секунд, заданного в параметре csn_snapshot_defer_time, в противном случае они прерываются ошибкой «csn snapshot too old».

По умолчанию: 15.

csn_commit_delay (integer)

Задаёт максимально возможное значение рассогласования часов (в наносекундах) в кластере. Добавляет задержку перед каждой фиксацией в системе для обеспечения внешней согласованности. Если установлено значение 0, внешняя согласованность не гарантируется. Значения могут дополняться суффиксами ns, us, ms и s.

По умолчанию: 0.

csn_lsn_map_size (integer)

Размер карты CSNLSNMap.

Запись фиксации каждой завершённой транзакции в Shardman содержит назначенный CSN для этой транзакции. Это значение вместе с LSN этой записи образует пару значений (CSN, LSN). Каждый из узлов кластера хранит определённое количество таких пар в оперативной памяти в специальной структуре — карте CSNLSNMap. Эта карта используется для получения точки синхронизации. За дополнительной информацией обратитесь к разделу «Точки синхронизации и согласованное резервное копирование» в главе Внутреннее устройство.

По умолчанию: 1024.

csn_max_shift_error (boolean)

При проверке значения csn_max_shift и его превышении пишет ошибку.

По умолчанию: off.

csn_max_shift (integer)

Максимальный сдвиг CSN в секундах для распределённых запросов и импортированных снимков. При превышении значения csn_max_shift выводится ошибка или предупреждение. При нулевом значении проверка не запускается.

По умолчанию: 15 (секунд).

foreign_analyze_interval (integer)

Задаёт частоту сбора статистики по сторонним отношениям в процессе автоочистки, в секундах. Если значение параметра foreign_analyze_interval меньше значения autovacuum_naptime, статистика по сторонним отношениям собирается через заданные в autovacuum_naptime промежутки времени (в секундах).

По умолчанию: 60.

foreign_join_fast_path (boolean)

Включает быстрый путь для планирования стороннего соединения. Когда параметр включён, пути стороннего соединения для запросов SELECT ищутся перед всеми другими возможными путями, и поиск соединения останавливается, как только найден путь стороннего соединения.

По умолчанию: off.

optimize_correlated_subqueries (boolean)

Включает или отключает логику планировщика запросов для преобразования связанных подзапросов в полусоединения.

По умолчанию: on.

port (integer)

TCP-порт, через который сервер принимает подключения. Значение port для кластера Shardman назначается системой автоматически на основании параметра PGsInitialPort. Даже если значение параметра будет изменено вручную, оно перезапишется автоматически назначенным параметром конфигурации.

enable_partition_pruning_extra (boolean)

Включает механизм расширенного отсечения секций для подготовленных запросов. Включение этого параметра позволяет отсекать секции из планов, использующих соединение с учётом секционирования.

По умолчанию: off.

crash_info (boolean)

Если установлено значение по умолчанию on, Shardman записывает диагностическую информацию о сбое сервера в файл.

По умолчанию: on.

crash_info_dump (text)

Указывает разделённый запятыми список текстовых строк, содержащих источники данных для аварийных дампов. Возможны следующие значения строк:

queries — тексты запросов

memory_context — контекст памяти

system — информация об ОС

module — информация о модулях, загруженных в процесс postgres

cpuinfo — информация о процессоре

virtual_memory — информация о виртуальной памяти

Значение по умолчанию — system,module,queries,memory_context.

crash_info_location (string)

Указывает каталог, в котором должна храниться информация о сбое сервера. При значении stderr информация о сбое отправляется в каталог stderr. Если в этом параметре указана пустая строка '', используется каталог $PGDATA/crash_info. Если нужно сохранять файлы в другом месте, заранее создайте целевой каталог и выдайте соответствующие права.

По умолчанию: ''.

shardman.context_log (bool)

Протоколирует удалённые контексты. Если включён, в случае ошибки выводит поле Remote CONTEXT. Обратите внимание, что если уровень протоколирования для стандартного журнала log_verbosity=terse, то параметр shardman.context_log будет отключён автоматически.

По умолчанию: on.

postgres_fdw.enforce_foreign_join (boolean)

Включает альтернативные оценки стоимости стороннего соединения, что значительно повышает вероятность того, что соединение нескольких сторонних таблиц, ссылающихся на один и тот же сервер, будет протолкнуто. Стоимость исходного соединения оценивается как (1 - 1/(cost + 1)), где cost — это исходная предполагаемая стоимость этого удалённого соединения.

По умолчанию: off.

postgres_fdw.foreign_explain (enum)

Определяет, как включать вывод команды EXPLAIN с удалённых серверов, если план запроса содержит узлы ForeignScan. Возможные значения: none не включает вывод EXPLAIN с удалённых серверов, full включает вывод EXPLAIN с удалённых серверов, collapsed включает вывод EXPLAIN только для первого узла ForeignScan под узлами Append/MergeAppend.

По умолчанию: collapsed.

postgres_fdw.optimize_cursors (boolean)

Задаёт поведение postgres_fdw, при котором расширение будет пытаться извлечь первую часть данных курсора сразу после объявления и задерживать закрытие курсора.

Этот параметр postgres_fdw заставляет расширение избегать закрытия курсоров после окончания сканирования. Курсоры закрываются в конце транзакции.

По умолчанию: off.

postgres_fdw.subplan_pushdown (boolean)

Включает или отключает логику postgres_fdw для проталкивания подзапросов, ссылающихся только на таблицы стороннего сервера, на этот сторонний сервер.

По умолчанию: off.

postgres_fdw.use_twophase (enum)

Задаёт поведение postgres_fdw, при котором расширение использует протокол двухфазной фиксации (2PC) для распределённых транзакций.

Этот параметр postgres_fdw заставляет использовать двухфазную фиксацию, если транзакция затрагивает несколько узлов. Если установлено значение auto, двухфазная фиксация используется только в транзакциях с enable_csn_snapshot=true и уровнем изоляции REPEATABLE READ или выше.

Временные таблицы нельзя использовать в двухфазных транзакциях.

По умолчанию: auto.

postgres_fdw.estimate_as_hashjoin (boolean)

Когда этот параметр включён, планировщик оценивает стоимость стороннего соединения таким же образом, как и стоимость хеш-соединения, когда это возможно. Эта стоимость сравнивается со стоимостью по умолчанию (которая аналогична стоимости соединения вложенным циклом), и для пути выбирается меньшая стоимость.

По умолчанию: off.

postgres_fdw.estimate_indexscan (boolean)

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

При отключении данного параметра стоимость сканирования сторонней таблицы оценивается как при последовательном сканировании с добавлением стоимости передачи данных и локальной фильтрации, если некоторые фильтры применяются локально. При включении параметра любое удалённое сканирование оценивается как сканирование индексов, если есть подходящие индексы.

Если сторонняя таблица является частью сегментированной таблицы, то информация о её индексах берётся из случайной локальной секции сегментированной таблицы. Это происходит из предположения, что распределение данных между всеми секциями сегментированной таблицы происходит равномерно, а определения локальных и удалённых секций совпадают.

Выполнение удалённого сканирования как сканирования индексов делает стоимость стороннего сканирования сопоставимой со стоимостью локального сканирования, что может стать решающим при дальнейшем выборе пути. Обратите внимание, что такая оценка увеличивает стоимость планирования, а потому не рекомендуется к использованию для простых запросов.

По умолчанию: off.

postgres_fdw.additional_ordered_paths (boolean)

Когда этот параметр включён, сортировка на стороне удалённого сервера будет рассматриваться, если возможно её использование для выполнения операции MergeJoin или MergeAppend. Параметр по умолчанию включён в новых инсталляциях, но при обновлении кластера требуется явное включение.

shardman.broadcast_ddl (boolean)

Задаёт поведение, при котором расширение Shardman транслирует операторы DDL для всех групп репликации.

Если этот параметр включён, расширение Shardman транслирует поддерживаемые операторы DDL для всех групп репликации, если это имеет смысл для этих операторов. Это поведение можно включить/отключить в любой момент. Этот параметр не учитывается, если он установлен в файле конфигурации.

По умолчанию: off.

shardman.enable_limit_pushdown (boolean)

Включает проталкивание ограничительных предложений через нижележащие присоединения. Если этот параметр включён, оптимизатор Shardman попытается передать ограничительное предложение подпутям нижележащего узла плана Append/MergeAppend, если они ссылаются на сторонние таблицы postgres_fdw. Эта оптимизация работает только для планов SELECT, когда параметр ограничения представлен в виде константы или параметра. Она также ограничена для путей Append, соответствующих секционированной таблице. Оптимизация не работает для SELECT с предложениями блокировки (SELECT FOR UPDATE/NO KEY UPDATE/FOR SHARE/KEY SHARE).

По умолчанию: on.

shardman.num_parts (integer)

Указывает количество секций сегментированной таблицы по умолчанию.

Сегментированная таблица имеет указанное количество секций по умолчанию, если число_секций не указано в CREATE TABLE.

Чтобы разрешить масштабирование, значение shardman.num_parts должно быть больше ожидаемого максимального количества узлов в кластере Shardman.

Возможные значения: от 1 до 1000

По умолчанию: 20.

shardman.rgid (integer)

Указывает идентификатор группы репликации узла Shardman.

Этот параметр задаётся утилитами Shardman при добавлении узла в кластер и никогда не должен изменяться вручную.

По умолчанию: -1.

shardman.sync_schema (boolean)

Задаёт поведение Shardman, при котором все операторы DDL, касающиеся сегментированные и глобальные отношения, распространяются на все группы репликации.

Когда этот параметр включён, Shardman транслирует все поддерживаемые служебные операторы, касающиеся сегментированных и глобальных отношений, для всех групп репликации. Этот параметр не рекомендуется отключать. Он не учитывается, если он установлен в файле конфигурации.

По умолчанию: on.

shardman.sync_cluster_settings (boolean)

Включает синхронизацию всех выставленных пользователем в кластере параметров конфигурации. Параметры распространяются при каждом удалённом запросе.

По умолчанию: on.

shardman.sync_cluster_settings_blacklist (boolean)

Исключает параметры удалённого кластера, которые не нужно синхронизировать.

По умолчанию: конфигурационные параметры локальной системы, которые никогда не синхронизируются.

shardman.query_engine_mode (enum)

Переключение между режимами планирования/выполнения запроса. Возможные значения: none и text.

Значение none означает, что при планировании/выполнении запросов транспорт Silk не будет использоваться.

Значение text означает, что текстовое представление запроса передаётся через транспорт Silk для удалённого выполнения.

По умолчанию: none.

shardman.silk_use_ip (string)

Транспорт Silk использует IP-адрес, указанный в этом параметре, для идентификации узла. Если указано имя хоста, оно разбирается и используется первый IP-адрес, соответствующий этому имени.

По умолчанию: node hostname.

shardman.silk_listen_ip (string)

Демон маршрутизации Silk использует IP-адрес, указанный в этом параметре, для идентификации узла. Если указано имя хоста, оно разбирается и используется первый IP-адрес, соответствующий этому имени.

По умолчанию: node hostname.

shardman.silk_use_port (integer)

Демон маршрутизации Silk прослушивает входящие соединения на этом порту. Этот параметр должен быть одинаковым для всех узлов в кластере Shardman.

По умолчанию: 8888.

shardman.silk_tracepoints (bool)

Включает трассировку прохождения запросов через транспорт Silk. Результаты трассировки выводятся командой EXPLAIN со значением ON параметра ANALYZE.

По умолчанию: off.

shardman.silk_num_workers (integer)

Количество фоновых рабочих процессов, выделенных для распределённого выполнения. Значение этого параметра должно быть меньше, чем значение max_worker_processes (включая вспомогательные рабочие процессы postgres).

По умолчанию: 2.

shardman.silk_stream_work_mem (integer)

Задаёт базовый максимальный объём памяти, который будет использоваться потоком Silk (как размер буфера), прежде чем будут задействованы временные файлы на диске. Если это значение задаётся без единиц измерения, оно считается заданным в килобайтах.

Обратите внимание, что в большинстве запросов могут быть несколько одновременных операций выборки, обычно по одной на каждую удалённую секцию сегментированной таблицы, если таковые имеются. Как правило для операции выборку задействовано столько памяти, сколько задано в данном значении, по достижении которого запись начинается во временные файлы. Кроме того, несколько таких операций могут выполнятся одновременно в нескольких сеансах. Таким образом общий объём памяти, используемый для буфера Silk, может в несколько раз превышать значение shardman.silk_stream_work_mem и соотноситься со значением параметра shardman.num_parts. Поэтому об этом стоит помнить при выставлении значения.

По умолчанию: 16МБ.

shardman.silkworm_fetch_size (integer)

Количество строк в порции, которую рабочий процесс silkworm извлекает и отправляет мультиплексору в виде результата за одну итерацию чтения.

По умолчанию: 100.

shardman.silk_unassigned_job_queue_size (integer)

Размер очереди заданий, которые ещё не были назначены рабочим процессам silkworm мультиплексора, если все рабочие процессы заняты.

Значение по умолчанию: 1024.

shardman.silk_max_message (integer)

Максимальный размер сообщения (в байтах), которое можно передать через Silk. Обратите внимание, что данный параметр не ограничивает максимальный размер результата, возвращаемого запросом. Он относится только к сообщениям для рабочих процессов. Увеличение этого параметра приведёт к пропорциональному увеличению памяти, потребляемой Shardman. Не рекомендуется менять значение по умолчанию без острой необходимости.

По умолчанию: 524288.

shardman.silk_hello_timeout (integer)

Таймаут ожидания ответа (в секундах) при выполнении процедуры согласования между мультиплексорами разных узлов.

По умолчанию: 3.

shardman.silk_scheduler_mode (enum)

Включает дополнительные параметры планирования ЦП для процессов мультиплексора (silkroad и silkworm).

Если этот параметр равен fifo, Shardman назначает политику планирования SCHED_FIFO для процессов silkroad и каждого из silkworm. Оно назначает статический приоритет планирования (sched_priority) значениям shardman.silkroad_sched_priority и shardman.silkworm_sched_priority соответственно.

Этот параметр улучшает производительность транспорта silk при работе с высокой нагрузкой на процессор.

Обратите внимание, что для использования этого параметра двоичный файл postgres должен иметь мандат CAP_SYS_NICE. Если процессу не назначен соответствующий мандат, включение этого параметра не окажет никакого эффекта. Мандат должен быть назначен двоичному файлу postgres перед запуском postgres. Postgres (т. е. процессы silkroad и silkworm) применит параметры планирования один раз во время запуска службы. Чтобы изменить параметры планирования, необходимо перезапустить службу postgres.

По умолчанию: none.

Чтобы задать мандат, необходимо выполнить следующую команду один раз после установки postgres:

             $ sudo setcap cap_sys_nice+ep /opt/pgpro/sdm-14/bin/postgres

При необходимости замените /opt/pgpro/sdm-14/bin/postgres на правильный путь к двоичному файлу postgres. Также обратите внимание, что файловая система должна поддерживать расширенные атрибуты файлов. Необходимо установить такую поддержку для каждого узла в кластере, чтобы получить полный эффект.

В ядре Linux существует механизм «real-time throttling», который предназначен для предотвращения монополизации вычислительного ядра задачами с политиками планирования в реальном времени (например, SCHED_FIFO). Это гарантирует, что другие задачи с более низкими приоритетами, обычно планируемые в рамках политики SCHED_OTHER, всё равно получат часть вычислительного времени. Этот механизм управляется двумя параметрами, которые доступны через файловую систему proc или механизм sysctl:

Параметр /proc/sys/kernel/sched_rt_period_us устанавливает длительность периода планирования в микросекундах. В течение этого периода как задачи реального времени, так и прочие задачи делят вычислительное время между собой.

Параметр /proc/sys/kernel/sched_rt_runtime_us определяет, какая часть периода планирования выделяется для задач реального времени (с SCHED_FIFO). Оставшееся время отводится для прочих задач (SCHED_OTHER).

В типичной и допустимой конфигурации для Shardman установлены следующие значения этих параметров:

# cat /proc/sys/kernel/sched_rt_period_us
1000000
# cat /proc/sys/kernel/sched_rt_runtime_us
950000

Такая конфигурация позволяет задачам реального времени использовать до 950 миллисекунд каждой секунды, оставляя 50 миллисекунд для прочих задач.

Однако в некоторых дистрибутивах Linux значения по умолчанию для этих параметров могут быть настолько малы (или даже равны нулю), что задачи реального времени получают очень мало или вообще не получают вычислительного времени. Это может сделать планирование неэффективным или помешать применению конфигурации. Например, попытка вручную установить для задачи приоритет SCHED_FIFO с помощью chrt может привести к подобной ошибке:

$ sudo chrt -f -p 2 $(pgrep -f silkroad)
chrt: failed to set pid 1897706's policy: Operation not permitted

Эта ошибка указывает на то, что параметры ядра настроены неправильно. В таких случаях установите для параметров рекомендуемые значения:

echo 1000000 > /proc/sys/kernel/sched_rt_period_us
echo 950000 > /proc/sys/kernel/sched_rt_runtime_us

Или добавьте соответствующие значения в /etc/sysctl.conf и перезагрузите конфигурацию с помощью команды sysctl -p:

kernel.sched_rt_period_us = 1000000
kernel.sched_rt_runtime_us = 950000

shardman.silkroad_sched_priority (integer)

Значение статического приоритета планирования (sched_priority) для процесса silkroad. Этот параметр имеет смысл только в том случае, если shardman.silk_scheduler_mode равен «fifo».

По умолчанию: 2.

shardman.silkworm_sched_priority (integer)

Значение статического приоритета планирования (sched_priority) для процессов silkworm (одинаковое значение для обоих процессов). Этот параметр имеет смысл только в том случае, если shardman.silk_scheduler_mode равен «fifo».

По умолчанию: 1.

shardman.silk_set_affinity (bool)

Позволяет прикреплять процессы мультиплексора (silkroad и silkworm) к ядрам процессоров, чтобы устранить негативные последствия миграции потоков между процессорами.

Если этот параметр имеет значение true, процесс silkroad будет прикреплён к первому доступному ядру ЦП, а все процессы silkworm будут прикреплены ко всем доступным ядрам ЦП, кроме первого.

Этот параметр улучшает производительность транспорта silk при работе с высокой нагрузкой на процессор.

Обратите внимание, что для использования этого параметра двоичный файл postgres должен иметь мандат CAP_SYS_NICE. Если процессу не назначен соответствующий мандат, включение этого параметра не окажет никакого эффекта. Мандат должна быть назначен двоичному файлу postgres перед запуском postgres. Postgres (т. е. процессы silkroad и silkworm) применит параметры привязки один раз во время запуска службы. Чтобы изменить параметры привязки, необходимо перезапустить службу postgres.

Чтобы задать мандат, необходимо выполнить следующую команду один раз после установки postgres:

             $ sudo setcap cap_sys_nice+ep /opt/pgpro/sdm-14/bin/postgres

При необходимости замените /opt/pgpro/sdm-14/bin/postgres на правильный путь к двоичному файлу postgres. Также обратите внимание, что файловая система должна поддерживать расширенные атрибуты файлов. Необходимо установить такую поддержку для каждого узла в кластере, чтобы получить полный эффект.

По умолчанию: false.

shardman.silk_flow_control (boolean)

Управляет режимом работы с событиями чтения. Возможные значения: none, round_robin и shortest_job_first.

Режим none не предполагает управления и дополнительной нагрузки. Однако в этом режиме возможна монополизация канала одним распределённым запросом.

В режиме round_robin в каждом цикле событий те события, что были созданы раньше, обрабатываются первыми. При включении все процессы группируются таким образом, что клиентские процессы обрабатываются первыми.

В режиме shortest_job_first трафик контролируется полностью. При включении все процессы группируются, при этом клиентские процессы и процессы с наименьшим трафиком в текущем сеансе обрабатываются первыми.

По умолчанию: round_robin.

shardman.silk_track_time (boolean)

Включает или выключает сбор метрик с префиксом transferred_ и временных метрик (с префиксами read_efd_, write_efd_ и sort_time_). Если параметр выключен, всем метрикам задаётся значение 0.

По умолчанию: off.

shardman.silk_tracelog (bool)

Включает или отключает протоколирование Silk.

По умолчанию: off.

shardman.silk_tracelog_category (string)

Определяет уровень протоколирование для сообщений Silk.

По умолчанию: streams, routing, events.

shardman.database (string)

Имя базы данных, к которой подключаются все рабочие процессы Silk.

По умолчанию: postgres.

shardman.monitor_interval (integer)

shardman.monitor_interval устарел и действует как пустая команда.

Вместо этого используйте параметр shardman.monitor_dxact_interval.

shardman.monitor_dxact_interval (integer)

Интервал между проверками устаревших подготовленных транзакций.

Фоновый процесс Shardman monitor активируется каждые shardman.monitor_dxact_interval секунд и пытается проверить и разобрать все подготовленные транзакции, которые не завершились и по какой-то причине устарели. Чтобы разобрать эти транзакции, процесс Shardman monitor определяет координатора транзакции и запрашивает у него статус транзакции. В зависимости от статуса транзакции Shardman monitor либо откатывает, либо фиксирует транзакцию.

Чтобы отключить логику разбора подготовленных транзакций, установите для shardman.monitor_dxact_interval значение 0.

По умолчанию: 5 (секунд).

shardman.monitor_trim_csnxid_map_interval (integer)

Каждый узел кластера замораживает собственное значение xmin на csn_snapshot_defer_time секунд для поддержки глобальных транзакций. Большие значения csn_snapshot_defer_time могут негативно сказаться на производительности. У расширения Shardman monitor есть подпрограмма, которая каждые shardman.monitor_trim_csnxid_map_interval секунд обновляет xmin на всех узлах до минимально возможного значения (с учётом активных транзакций).

Фоновая процедура будет выполняться только на одном узле в кластере Shardman. Учтите, что это увеличит нагрузку на этот узел.

Чтобы отключить такие изменения, установите для shardman.monitor_trim_csnxid_map_interval значение 0.

По умолчанию: 5 (секунд).

shardman.monitor_dxact_timeout (integer)

Максимально допустимый возраст подготовленных транзакций до попытки разбора.

Во время разбора подготовленной транзакции Shardman monitor определяет, не устарела ли она. Транзакция становится устаревшей, если она была подготовлена более shardman.monitor_dxact_timeout секунд назад.

По умолчанию: 5 (секунд).

shardman.trim_csnxid_map_naptime (integer)

Указывает минимальную задержку между обновлениями xmin на всех узлах. За дополнительной информацией обратитесь к описанию shardman.monitor_trim_csnxid_map_interval.

Возможные значения: от 1 до 600.

По умолчанию: 5.

shardman.monitor_deadlock_interval (integer)

Интервал между проверками условий распределённой взаимоблокировки.

Фоновый процесс Shardman monitor активируется каждые shardman.monitor_deadlock_interval секунд и ищет распределённые взаимоблокировки в кластере. Он собирает информацию о взаимных блокировках со всех узлов и ищет циклические зависимости между транзакциями. Если он обнаруживает взаимоблокировку, то разрешает её, отменяя один из внутренних процессов, участвующих в блокировке.

Чтобы отключить логику разбора распределённых взаимоблокировок, задайте для shardman.monitor_deadlock_interval значение 0.

По умолчанию: 2 (секунды).

postgres_fdw.remote_plan_cache (boolean) — EXPERIMENTAL

Включает удалённое кеширование планов для запросов FDW, созданных локально кешированными планами.

По умолчанию: off.

shardman.plan_cache_mem (integer) — EXPERIMENTAL

Указывает, сколько памяти может быть выделено каждому рабочему процессу для кешей удалённых планов.

По умолчанию: 0 (кеши отключены).

shardman.gt_batch_size (integer) —

Определяет размер буфера для команд INSERT и DELETE в глобальных таблицах.

По умолчанию: 64K.

track_fdw_wait_timing (boolean)

Статистика сетевого ожидания операций между кластерами в миллисекундах. Выводится командой EXPLAIN с параметром network или через представление pgpro_stats_sdm_statements pgpro_stats.

По умолчанию: on.

track_xact_time (boolean)

Включает или отключает сбор статистики для времени, затраченного на транзакцию.

По умолчанию: off.

enable_non_equivalence_filters (boolean)

Позволяет оптимизатору генерировать дополнительные неэквивалентные условия с использованием классов эквивалентности.

По умолчанию: off.

optimize_row_in_expr (boolean)

Позволяет оптимизатору генерировать дополнительные условия из выражения IN ().

По умолчанию: off.

Примеры

Файл конфигурации для кластера с включённой аутентификацией scram-sha-256

Примечание

Исходный файл конфигурации должен быть создан с помощью следующей команды:

   shardmanctl config generate > sdmspec.json

Обратите внимание, что пример ниже представлен исключительно для сведения и мог устареть.

Ниже представлен пример содержимого файла конфигурации sdmspec.json:

{
   "ConfigVersion": "1",
   "Repfactor": 1,
   "PlacementPolicy": "manual",
   "PGsInitialPort": 5432,
   "SilkInitialPort": 8000,
   "HTTP": {
     "Port": 15432,
     "PortMetrics": 15432
   },
   "Users": [
  {
   "Name": "postgres",
   "Groups": [ "su"],
   "AuthMethod": "scram-sha-256",
   "Password": "changeMe"
  },
  {
   "Name": "repluser",
   "Groups": ["repl"],
   "AuthMethod": "scram-sha-256",
   "Password": "changeMe"
  }
 ],
   "ShardSpec": {
    "synchronousReplication": true,
    "usePgrewind": true,
    "pgParameters": {
     "csn_snapshot_defer_time": "300",
     "enable_csn_snapshot": "on",
     "enable_csn_wal": "true",
     "shardman.query_engine_mode": "text",
     "shardman.silk_num_workers": "8",
     "max_connections": "600",
     "max_files_per_process": "65535",
     "max_logical_replication_workers": "14",
     "max_prepared_transactions": "200",
     "max_worker_processes": "24",
     "shared_preload_libraries": "postgres_fdw, shardman"
    },
    "pgHBA": [
     "host replication postgres 0.0.0.0/0 scram-sha-256",
     "host replication postgres ::0/0 scram-sha-256"
    ],
    "automaticPgRestart": true,
    "masterDemotionEnabled": false
   },
   "FDWOptions": {
    "async_capable": "on",
    "batch_size": "100",
    "connect_timeout": "5",
    "fdw_tuple_cost": "0.2",
    "fetch_size": "50000",
    "tcp_user_timeout": "10000"
   }
}

Из этого файла конфигурации видно, что кластер Shardman, инициализированный этим файлом конфигурации, имеет значение Repfactor, равное 1 (одна реплика для каждого ведущего сервера). Файл конфигурации показывает, что в этом кластере созданы два специальных пользователя — суперпользователь postgres и пользователь репликации repluser с паролями ChangeMe. Они могут быть аутентифицированы, используя метод авторизации md5 или scram-sha-256. Одна операция выборки postgres_fdw позволяет получить до 50000 строк с удалённого сервера. Для стоимости выборки одной строки установлено достаточно большое значение, чтобы планировщик PostgreSQL рассматривал условия как привлекательные для проталкивания. Параметры pg_hba.conf разрешают пользователю postgres доступ из любого места с использованием протокола репликации; все остальные пользователи могут получить доступ к любой базе данных из любого места. Поскольку для defaultSUReplAccessMode не задано значение strict, утилиты автоматически добавляют записи, разрешающие пользователю PgSuUsername (postgres) доступ к любой базе данных из любого места и доступ к репликации пользователю PgReplUsername (repluser) из любого места.

Несколько важных параметров, специфичных для Shardman, задаются в хеш-таблице pgParameters, а именно:

wal_level

Для правильной работы Shardman должно быть установлено значение logical.

shared_preload_libraries

Должен включать расширения postgres_fdw и shardman в указанном порядке.

max_logical_replication_workers

Должно быть достаточно большим, поскольку процесс перебалансировки использует до max(max_replication_slots, max_logical_replication_workers, max_worker_processes, max_wal_senders)/3 параллельных потоков.

max_prepared_transactions

Должно быть достаточно большим, так как утилиты Shardman используют протокол 2PC. Если postgres_fdw.use_twophase имеет значение true, postgres_fdw также использует 2PC.

enable_csn_snapshot

Должна быть включена для достижения настоящего уровня изоляции REPEATABLE READ в распределённой системе.

csn_snapshot_defer_time

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

enable_partitionwise_aggregate
enable_partitionwise_join

Установите значение on, чтобы включить оптимизацию для секционированных таблиц.

Файл конфигурации для кластера с включённой аутентификацией по сертификату

Ниже представлен пример содержимого файла конфигурации sdmspec.json:

 {
   "ConfigVersion": "1",
   "HTTP": {
     "Port": 15432,
     "PortMetrics": 15432
     "SSLKey": "/pgpro/ssl/server.key",
     "SSLCert": "/pgpro/ssl/server.crt"
   },
   "Users": [
     {
       "Name": "postgres",
       "SSLKey": "/var/lib/postgresql/.ssh/client.key",
       "SSLCert": "/var/lib/postgresql/.ssh/client.crt",
       "Groups": ["su"],
       "AuthMethod":"scram-sha-256"
     },
     {
      "Name": "repluser",
       "SSLKey": "/var/lib/postgresql/.ssh/repluser.key",
       "SSLCert": "/var/lib/postgresql/.ssh/repluser.crt",
       "Groups": ["repl"],
       "AuthMethod":"scram-sha-256"
     }
   ],
    "ShardSpec": {
     "synchronousReplication": true,
     "usePgrewind": true,
     "pgParameters": {
      "ssl": "on",
      "ssl_cert_file": "/var/lib/postgresql/.ssh/server.crt",
      "ssl_key_file": "/var/lib/postgresql/.ssh/server.key",
      "ssl_ca_file": "/var/lib/postgresql/.ssh/ca.crt",
      "csn_snapshot_defer_time": "300",
      "enable_csn_snapshot": "on",
      "enable_csn_wal": "true",
      "log_line_prefix": "%m [%r][%p]",
      "log_min_messages": "INFO",
      "log_statement": "none",
      "maintenance_work_mem": "1GB",
      "max_connections": "600",
      "max_files_per_process": "65535",
      "max_logical_replication_workers": "9",
      "max_prepared_transactions": "200",
      "max_wal_size": "4GB",
      "max_worker_processes": "16",
      "min_wal_size": "512MB",
      "postgres_fdw.subplan_pushdown": "off",
      "shardman.query_engine_mode": "text",
      "shardman.silk_num_workers": "8",
      "shared_buffers": "4GB",
      "shared_preload_libraries": "postgres_fdw, shardman"
     },
     "strictUserHBA": true,
     "pgHBA": [
      "hostssl all postgres 0.0.0.0/0 cert clientcert=verify-full",
      "hostssl all repluser 0.0.0.0/0 cert clientcert=verify-full",
      "hostssl replication postgres 0.0.0.0/0 cert clientcert=verify-full",
      "hostssl replication postgres ::0/0 cert clientcert=verify-full",
      "hostssl replication repluser 0.0.0.0/0 cert clientcert=verify-full",
      "hostssl replication repluser ::0/0 cert clientcert=verify-full",
      "hostnossl all all 0.0.0.0/0 reject",
      "local postgres postgres scram-sha-256",
      "local replication repluser scram-sha-256"
     ],
     "automaticPgRestart": true,
     "masterDemotionEnabled": false
    },
    "FDWOptions": {
     "async_capable": "on",
     "batch_size": "100",
     "connect_timeout": "5",
     "fdw_tuple_cost": "0.2",
     "fetch_size": "50000",
     "tcp_user_timeout": "10000"
    }
 }

Параметры pgpro_stats

pgpro_stats.track_sharded (boolean)

Определяет, должно ли расширение pgpro_stats отслеживать и агрегировать распределённые запросы (то есть запросы к распределённой таблице).

По умолчанию: on.

pgpro_stats.pgss_max_nodes_tracked (integer)

Задаёт максимальное количество узлов, отслеживаемых pgpro_stats для фрагментов запроса.

Фактически устанавливает максимальное количество записей статуса, которые pgpro_stats может хранить для функции pgpro_stats_sdm_stats_updated. Не влияет на сбор статистики.

По умолчанию: 2048.

pgpro_stats.transport_compression (string)

Задаёт алгоритм сжатия при передаче статистики между узлами.

Если параметр указан, выбранный алгоритм используется для сжатия статистических записей, передаваемых узлами сегмента к координатору. Может принимать значения pglz, zlib, lz4, zstd или off.

По умолчанию: pglz.

pgpro_stats.enable_wait_counters (boolean)

Включает или отключает сбор статистики для счётчиков ожидания включением или отключением функций, которые вычисляют метрики событий ожидания.

По умолчанию: off.

pgpro_stats.enable_inval_msgs_counters (boolean)

Включает или отключает сбор статистики для счётчиков сообщений аннулирования включением или отключением функций, которые вычисляют метрики сообщений аннулирования.

Если этот параметр отключён, представление pgpro_stats_inval_status будет пустым.

По умолчанию: off.

pgpro_stats.enable_rusage_counters (boolean)

Включает или отключает сбор статистики для счётчиков использования ресурсов включением или отключением функций, которые вычисляют метрики использования ресурсов ОС.

По умолчанию: off.

pgpro_stats.track_shardman_connections (enum)

Включает или отключает обработку операторов Shardman. У данного параметра есть три возможных значения: none без обработки, normalized (значение по умолчанию) для обработки в обобщённом виде и all для обработки всех операторов.

См. также

shardmanctl

shardmand

shardmand — демон конфигурации Shardman

Синтаксис

shardmand [общие_параметры] [ --system-bus ] [ --user имя_пользователя ]

Здесь общие_параметры могут принимать следующие значения:

[ --cluster-name имя_кластера ] [ --log-level error | warn | info | debug ] [ --retries число_повторов ] [ --session-timeout секунды ] [ --store-endpoints адреса_хранилища ] [ --store-ca-file файл_сертификата_ca ] [ --store-cert-file файл_сертификата_клиента ] [ --store-key частный_ключ_клиента ] [ --store-timeout длительность ] [ --version ] [ -h | --help ] [ --log-format ]

Описание

shardmand — это демон конфигурации Shardman. Он работает на каждом узле в кластере Shardman, подписывается на изменения ключей shardman/cluster0/data/ladle и shardman/cluster0/data/cluster в хранилище etcd (cluster0 — это имя кластера по умолчанию, используемое утилитами Shardman) и управляет процессами Shardman на соответствующих узлах согласно конфигурации, описанной в этих документах JSON.

Расширение shardmand управляет встроенными процессами keeper и sentinel. При запуске и изменении одного из отслеживаемых ключей etcd shardmand перенастраивает их следующим образом:

Вычисляет ожидаемую конфигурацию узла, т. е. список процессов keeper и sentinel, которые должны быть запущены, и их конфигурации из значений shardman/cluster0/data/ladle и shardman/cluster0/data/cluster.

Получает список запущенных процессов keeper и sentinel с их конфигурациями от внутреннего диспетчера процессов.

Останавливает процессы, выполнение которых не ожидается. Это может быть процесс, принадлежащий кластеру с таким же именем, но другим UUID, или процесс, описание которого больше не присутствует в ожидаемой конфигурации узла. Для процессов keeper shardmand очищает их каталог данных.

Если процесс должен быть запущен, но его параметры отличаются от ожидаемых, shardmand обновляет конфигурацию и перезапускает процесс. Если процесс должен быть запущен, но он не запущен, shardmand запускает его.

Кроме того, отдельный поток shardmand периодически обновляет ключ etcd shardman/cluster0/data/shardmand/NODENAME с помощью ClusterUUID последнего кластера, к которому была применена конфигурация. Таким образом, перед тем как команда shardmanctl nodes add попытается инициализировать новые кластеры stolon для звена, она может гарантировать, что на всех узлах звена не осталось ни одного действующего потока stolon из предыдущей конфигурации кластера.

Кроме того, shardmand запускает два HTTP-сервера в отдельных потоках. Если порты серверов совпадают, запускается один сервер, выполняющий обе роли. Первый сервер предоставляет следующие метрики: shardmand_etcd_unavailable_time_секунды, shardmand_healthy_keepers, shardmand_sentinels, shardmand_uptime, shardmand_etcd_errors_total, shardmand_reconfigurations_number_total, shardmand_demotions_number_total. Также сервер предоставляет конечную точку /healthz для проверки работоспособности shardmand. Второй сервер предоставляет следующие конечные точки:

/shardmand/v1/replica — возвращает код состояния 200, если на узле работает резервный экземпляр, код состояния 500, если на узле работает ведущий экземпляр, /shardmand/v1/master — возвращает код состояния 200, если на узле работает ведущий экземпляр, код состояния 500, если на узле работает резервный экземпляр. Если как ведущий, так и резервный экземпляры работают на конечных точках /shardmand/v1/replica и shardmand/v1/master узла, возвращается код состояния 404.

/shardmand/v1/status — получение информации о статусе shardmand.

Все службы Shardman управляются shardmand@cluster0.service, поэтому, когда он запускается, останавливается или перезапускается, он также запускает, останавливает или перезапускает все остальные процессы Shardman (включая экземпляры СУБД).

Справка по командной строке

В этом разделе описываются команды shardmand. Общие параметры команд Shardman описаны в Разделе «Общие параметры».

--log-format

Задаёт формат журнала: json или text. Значение по умолчанию: text.

--system-bus

Не используется. Оставлен для совместимости. Игнорируется.

--user имя_пользователя

Не используется. Оставлен для совместимости. Игнорируется.

Общие параметры

Общие параметры shardmand — это необязательные параметры, не являющиеся специфичными для данной утилиты. Они определяют параметры подключения etcd, имя кластера и некоторые другие параметры. По умолчанию shardmand пытается подключиться к хранилищу etcd 127.0.0.1:2379 и использовать имя кластера cluster0. Уровень журнала по умолчанию — info.

-h, --help

Показывает краткую справочную информацию.

--cluster-name имя_кластера

Указывает имя кластера, где будет работать. По умолчанию указывается имя кластера cluster0.

--log-level уровень

Задаёт уровень детализации журнала. Возможные значения уровня (от минимального до максимального): error, warn, info и debug. По умолчанию используется info.

--retries число

Указывает, сколько раз shardmanctl должен повторять прерванный запрос к etcd. Если запрос etcd прерывается, скорее всего, из-за проблем с подключением, shardmanctl повторяет его указанное количество раз, прежде чем сообщить об ошибке. Значение по умолчанию — 5.

--session-timeout секунды

Указывает таймаут блокировок в сеансе shardmanctl. Если нет связи между shardmanctl и хранилищем etcd в течение указанного количества секунд, блокировка снимается. Значение по умолчанию — 30.

--store-endpoints строка

Задаёт адрес/порт etcd в формате: http[s]://адрес[:порт](,http[s]://адрес[:порт])*. Значение по умолчанию — http://127.0.0.1:2379.

--store-ca-file строка

Проверяет сертификат сервера хранилища etcd с поддержкой HTTPS, используя этот пакет CA.

--store-cert-file строка

Указывает файл сертификата для идентификации клиента в хранилище etcd.

--store-key строка

Указывает файл закрытого ключа для идентификации клиента в хранилище etcd.

--store-timeout длительность

Задаёт тайм-аут для запроса etcd. Значение по умолчанию — 5 секунд.

--monitor-port число

Указывает порт HTTP-сервера shardmand для метрик и точек трассировки. По умолчанию — 15432.

--api-port число

Указывает порт для API HTTP-сервера shardmand. По умолчанию — 15432.

--version

Показывает информацию о версии shardman-utils.

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

Служба shardmand считывает переменные среды из /etc/shardman/shardmand-cluster0.env. Следующие переменные среды влияют на поведение shardmand.

SDM_CLUSTER_NAME

Аналог параметра --cluster-name

SDM_LOG_LEVEL

Аналог параметра --log-level

SDM_RETRIES

Аналог параметра --retries

SDM_SYSTEM_BUS

Аналог параметра --system-bus

SDM_STORE_ENDPOINTS

Аналог параметра --store-endpoints

SDM_STORE_CA_FILE

Аналог параметра --store-ca-file

SDM_STORE_CERT_FILE

Аналог параметра --store-cert-file

SDM_STORE_KEY

Аналог параметра --store-key

SDM_STORE_TIMEOUT

Аналог параметра --store-timeout

SDM_SESSION_TIMEOUT

Аналог параметра --session-timeout

SDM_USER

Аналог параметра --user

Примеры

Настройка службы shardmand

Параметры shardmand обычно указываются в файле /etc/shardman/shardmand-cluster0.env. Если необходимо, чтобы shardmand подключался к кластеру etcd на узлах n1-n3, используя порт 2379, и чтобы все службы Shardman использовали уровень журнала debug, можно использовать следующий файл env:

SDM_STORE_ENDPOINTS=http://n1:2379,http://n2:2379,http://n3:2379
SDM_LOG_LEVEL=debug

Обратите внимание, что необходимо перезапустить службу shardmand@cluster0, чтобы применить новые параметры из файла env.

Отображение журналов shardmand

Чтобы просмотреть журналы shardmand, можно использовать команду journalctl:

$ journalctl -u shardmand@cluster0.service

Перезапуск служб Shardman

Можно перезапустить все службы Shardman на узле, используя команды systemctl:

$ systemctl restart shardmand@cluster0.service

См. также

shardmanctl , sdmspec.json

Глава 7. Внутреннее устройство Shardman

Программное обеспечение Shardman состоит из следующих основных компонентов: ядро PostgreSQL с дополнительными функциями, расширение shardman, службы управления и утилиты. В этом разделе кластер Shardman рассматривается как группа экземпляров или сегментов PostgreSQL. Каждый сегмент также может иметь одну или несколько реплик, и чтобы подчеркнуть это, используется термин группа репликации. Поддержка отказоустойчивых конфигураций в настоящее время осуществляется на уровне инструментов и служб и будет рассмотрена в разделе «Управление».

7.1. Типы таблиц

В распределённой базе данных, управляемой Shardman, используются следующие специальные типы таблиц: сегментированные таблицы и глобальные таблицы.

7.1.1. Сегментированные таблицы

Сегментированные таблицы — это обычные секционированные таблицы PostgreSQL, в которых несколько секций, составляющих сегмент, являются обычными локальными таблицами, а остальные секции — сторонними таблицами, доступными с удалённых серверов через postgres_fdw. Сегментированные таблицы зарегистрированы в словаре shardman.sharded_tables. Используйте оператор CREATE TABLE с параметром distributed_by, чтобы создать сегментированную таблицу. Несколько сегментированных таблиц могут быть созданы как совмещённые. Это означает, что они имеют одинаковое количество секций и что их секции, соответствующие одному и тому же ключу сегментирования, должны располагаться вместе. Во время перебалансировки утилиты управления Shardman гарантируют, что соответствующие секции совмещённых таблиц будут перемещены на один и тот же узел. (Такая перебалансировка происходит, например, при добавлении в кластер нового узла). Совмещение необходимо для того, чтобы объединения нескольких таблиц распространялись на узел, где находятся фактические данные. Чтобы сделать одну сегментированную таблицу совмещённой с другой, сначала создайте одну таблицу, а затем используйте параметр colocate_with оператора CREATE TABLE при создании второй таблицы. Цепочки совмещённых таблиц не поддерживаются, вместо этого все связанные таблицы должны быть помечены как совмещённые с одной из таблиц. Обратите внимание, что свойство colocate_with является симметричным и транзитивным.

7.1.1.1. Секции

Сегментированная таблица состоит из нескольких секций. Некоторые из них являются обычными таблицами, а другие — сторонними. По умолчанию количество секций определяется параметром shardman.num_parts, но может быть перезаписано в параметре num_parts команды CREATE TABLE. Большинство операций DDL ограничены секциями сегментированной таблицы. Чтобы обойти это ограничение, следует изменять родительскую таблицу.

Количество секций в сегментированной таблице задаётся при её создании и не может быть изменено впоследствии. При добавлении новых узлов в кластер некоторые секции перемещаются с существующих узлов на новые, чтобы сбалансировать нагрузку. Таким образом, чтобы обеспечить масштабирование кластеров, начальных секций должно быть достаточно много, но не слишком много, поскольку слишком большое количество секций значительно замедляет планирование запросов. Например, если вы ожидаете, что количество узлов в вашем кластере вырастет максимум в 4 раза, создайте сегментированные таблицы с количеством секций, равным 4 * N, где N — это количество узлов. Предел масштабируемости кластера достигается, когда число узлов кластера достигает числа секций в сегментированной таблице с их минимальным количеством.

7.1.1.2. Подсекции

Секции сегментированной таблицы могут быть секционированы по диапазону. В этом случае каждая секция сегментированной таблицы представляет собой секционированную таблицу, состоящую только из обычных или только из сторонних подсекций. Все подсекции секции расположены на одном узле. Используйте параметр partition_by оператора CREATE TABLE, чтобы указать столбец, который следует использовать в качестве столбца ключа подсекции, и параметр partition_bounds, чтобы установить границы секций таблицы второго уровня. Новые подсекции могут быть добавлены или удалены из таблицы по мере необходимости. Таким образом, вы можете опустить параметр partition_bounds во время создания таблицы и создать секции позже, используя функцию shardman.create_subpart(). Другие функции управления подсекциями позволяют удалять, отсоединять или присоединять подсекции сегментированной таблицы. Управление подсекциями осуществляется на уровне кластера.

7.1.2. Глобальные таблицы

Глобальные таблицы доступны для всех узлов кластера. Сейчас глобальная таблица — это набор обычных таблиц, синхронизированных по триггерам. Основной вариант использования глобальной таблицы — хранение относительно редко обновляемого набора данных, который используется всеми узлами кластера. Когда сегментированная таблица присоединяется к глобальной таблице, соединения между сегментированными секциями таблицы и глобальной таблицей могут выполняться на узлах, где находятся отдельные секции. Реализация репликации на основе триггеров требует, чтобы неоткладываемый первичный ключ был определён в глобальной таблице. В настоящее время при изменении глобальной таблицы срабатывает триггер оператора after, который распространяет изменения на другие узлы кластера через сторонние таблицы. Когда в кластер добавляются новые узлы, данные глобальных таблиц передаются на новые узлы посредством логической репликации. Когда какие-либо узлы удаляются из кластера, глобальные таблицы ненадолго блокируются для записи. Используйте параметр global в команде CREATE TABLE для создания глобальной таблицы. Глобальные таблицы регистрируются в словаре shardman.global_tables. Секционированные глобальные таблицы не поддерживаются.

7.1.3. Распределённый DDL

Расширение Shardman позволяет создавать несколько видов глобальных объектов. Это сегментированные и глобальные таблицы, роли и табличные пространства. Список операций, разрешённых для глобальных объектов, ограничен, в частности, для защиты согласованности глобальной схемы. По той же причине большинство операций над глобальными объектами выполняются на уровне кластера. Список операций на уровне кластера включает:

CREATE для сегментированных и глобальных таблиц, глобальных ролей и табличных пространств или индексов для сегментированных или глобальных таблиц.

DROP для сегментированных и глобальных таблиц, глобальных ролей и табличных пространств или индексов для сегментированных или глобальных таблиц.

ALTER TABLE для сегментированных и глобальных таблиц.

ALTER TABLESPACE для глобальных табличных пространств.

ALTER ROLE для глобальный ролей.

RENAME для сегментированных и глобальных таблиц или построенных по ним индексов.

SET CONSTRAINTS ALL внутри блокировки транзакции.

Эти параметры конфигурации управляют выполнением команд распределённого DDL: shardman.broadcast_ddl и shardman.sync_schema. Первый можно использовать для трансляции всех обычных операций DDL (например, создания схем или функций) на весь кластер. Второй управляет трансляцией операторов, связанных с глобальными объектами, и никогда не должен отключаться без консультации со службой поддержки Postgres Pro Shardman.

7.2. Обработка запросов

Shardman использует стандартный конвейер выполнения запросов PostgreSQL. Доступ к другим узлам в кластере осуществляется через модифицированное расширение postgres_fdw.

Планировщик запросов Shardman использует абстрактное синтаксическое дерево запроса (АСТ) и создаёт план запроса, который используется исполнителем. Оценивая методы выполнения запросов, планировщик оперирует так называемыми путями, которые указывают, как следует обращаться к отношениям. При обработке дерева соединения запроса планировщик рассматривает различные комбинации того, как отношения могут быть соединены. Каждый раз он проверяет соединение двух отношений, одно из которых само может быть отношением соединения. После выбора порядка и стратегий соединения отношений планировщик рассматривает операции группировки, упорядочения и ограничения. Когда выбран самый дешёвый путь, он преобразуется в план запроса. План состоит из дерева узлов, у каждого из которых есть методы для получения одной следующей строки результата (или NULL, если результатов больше нет).

7.2.1. Техника проталкивания

7.2.1.1. Соединения

Эффективность выполнения запросов в распределённой СУБД определяется тем, сколько операций можно выполнить на узлах, содержащих фактические данные. В Shardman много усилий посвящено тому, чтобы проталкивать операции соединения. Когда планировщик находит отношение, доступное через обёртку сторонних данных (FDW), он создаёт ForeignPath для доступа к нему. Позже, когда он контролирует соединение двух отношений, и оба они доступны через ForeignPath с одного и того же стороннего сервера, он может рассматривать возможность передачи этого соединения на сервер и создания так называемого ForeignJoinPath. Планировщик не может этого сделать, если тип соединения не поддерживается, если фильтры, прикреплённые к отношению, должны применяться локально или если результат сканирования отношения содержит поля, которые невозможно оценить на удалённом сервере. Примером неподдерживаемого в настоящее время типа соединения является антисоединение. Локальные фильтры, прикреплённые к отношению, следует применять локально, если удалённое выполнение может привести к другому результату или если модуль postgres_fdw не может создать SQL-выражения для применения некоторых фильтров. Примером полей, которые нельзя оценить на удалённом сервере, являются атрибуты внутреннего отношения полусоединения, недоступные через внешнее отношение. Если параметр конфигурации foreign_join_fast_path включён (это значение по умолчанию), планировщик Shardman прекращает поиск других стратегий соединения двух отношения, как только он находит возможным для них стороннее соединение. Если параметр конфигурации postgres_fdw.enforce_foreign_join включён (что также является значением по умолчанию), стоимость стороннего соединения оценивается таким образом, чтобы всегда быть меньше стоимости локального соединения.

Когда несколько сегментированных таблиц соединяются по ключу сегментирования, возможно посекционное соединение. Это означает, что вместо соединения исходных таблиц можно соединить их соответствующие секции. В настоящее время посекционное соединение применяется только в том случае, если условия соединения включают все ключи секций, которые должны иметь один и тот же тип данных и иметь точно совпадающие наборы дочерних секций. Посекционное соединение имеет решающее значение для эффективного выполнения запросов, поскольку оно позволяет проталкивать соединения секций таблицы. Очевидно, что для соединения нескольких секций эти секции должны находиться на одном узле. Обычно это происходит, когда сегментированные таблицы создаются с одним и тем же параметром num_parts. Однако, чтобы в процессе перебалансировки соответствующие секции были перемещены на одни и те же узлы, сегментированные таблицы должны быть при создании помечены как совмещённые (см. Подраздел 7.1.1). Посекционное соединение включается параметром enable_partitionwise_join, который в Shardman по умолчанию включён.

Когда сегментированная таблица соединяется с простой глобальной таблицей, возможно асимметричное посекционное соединение. Это означает, что вместо соединения исходных таблиц можно соединить каждую секцию сегментированной таблицы с глобальной таблицей. Это позволяет вынести соединение секций сегментированной таблицы с глобальной таблицей на сторонний сервер.

7.2.1.2. Агрегирования

После планирования соединений планировщик рассматривает пути для операций после соединения, таких как агрегирование, ограничение, сортировка и группировка. Не все такие операции достигают логики проталкивания FDW. Например, в настоящее время секционирование эффективно предотвращает проталкивание предложений LIMIT. Существует две эффективные стратегии выполнения агрегатных функций на удалённых узлах. Первый — это агрегирование по секциям, когда предложение GROUP BY включает ключ секционирования, агрегатная функция может быть протолкнуто вместе с предложением GROUP BY (это поведение контролируется параметром enable_partitionwise_aggregate, который по умолчанию включён в Shardman). В качестве альтернативы планировщик может решить выполнять частичное агрегирование для каждой секции сегментированной таблицы, а затем соединить результаты. В Shardman такое частичное агрегирование может быть пропущено, если оно соответствует основному агрегированию. Например, неполная функция sum() всегда может быть протолкнута, а avg() — нет. Также планировщик отказывается проталкивать частичные агрегирования наружу, если они содержат дополнительные предложения, такие как ORDER BY или DISTINCT, или если оператор содержит предложение HAVING.

7.2.1.3. Подзапросы

Как правило, подзапросы нельзя передавать на другие узлы кластера. Однако Shardman использует два подхода для снятия этого ограничения.

Первый — это распаковка подзапросов. В PostgreSQL несвязанные подзапросы могут быть преобразованы в полусоединения. В следующем примере подзапрос ANY к несекционированным таблицам преобразуется в Hash Semi Join:

EXPLAIN (COSTS OFF) SELECT * FROM pgbench_branches WHERE bid = ANY (SELECT bid FROM pgbench_tellers);
                        QUERY PLAN
-----------------------------------------------------------
 Hash Semi Join
   Hash Cond: (pgbench_branches.bid = pgbench_tellers.bid)
   ->  Seq Scan on pgbench_branches
   ->  Hash
         ->  Seq Scan on pgbench_tellers

Когда параметр optimize_correlated_subqueries включён (по умолчанию), планировщик Shardman также пытается преобразовывать связанные подзапросы (т. е. подзапросы, которые ссылаются на отношения верхнего уровня) в полусоединения. Эта оптимизация работает для операторов IN и =. Преобразование имеет некоторые ограничения. Например, оно не выполняется, если подзапрос содержит агрегатные функции или ссылается на отношения верхнего уровня вне предложения WHERE. Эта оптимизация позволяет преобразовывать более сложные подзапросы в полусоединения, как в следующем примере:

EXPLAIN (COSTS OFF) SELECT * FROM pgbench_branches WHERE bid = ANY (SELECT bid FROM pgbench_tellers WHERE tbalance = bbalance);
                                                       QUERY PLAN
------------------------------------------------------------------------------------------------------------------------
 Hash Semi Join
   Hash Cond: ((pgbench_branches.bid = pgbench_tellers.bid) AND (pgbench_branches.bbalance = pgbench_tellers.tbalance))
   ->  Seq Scan on pgbench_branches
   ->  Hash
         ->  Seq Scan on pgbench_tellers
(5 rows)

После применения распаковки подзапросов полусоединение можно вынести для выполнения на удалённый узел.

Второй подход заключается в проталкивании всего подзапроса. Это возможно, когда оптимизатор уже выяснил, что подзапрос ссылается только на секции того же стороннего сервера, что и запрос верхнего уровня, и соответствующие сторонние сканирования не имеют локальных условий. Оптимизация контролируется параметром postgres_fdw.subplan_pushdown (по умолчанию отключено). Когда postgres_fdw принимает решение отправить подзапрос, он должен восстановить этот подзапрос. Подзапрос, содержащий узлы плана, для которых не реализовано восстановление, не будет протолкнут. Пример проталкивания подзапроса выглядит следующим образом:

EXPLAIN (VERBOSE ON, COSTS OFF)
SELECT * FROM pgbench_accounts a WHERE a.bid=90 AND abalance =
    (SELECT min(tbalance) FROM pgbench_tellers t WHERE t.bid=90 and a.bid=t.bid);
                                     QUERY PLAN
--------------------------------------------------------------------------------------
 Foreign Scan on public.pgbench_accounts_5_fdw a
   Output: a.aid, a.bid, a.abalance, a.filler
   Remote SQL: SELECT aid, bid, abalance, filler FROM public.pgbench_accounts_5 r2 WHERE ((r2.bid = 90)) AND ((r2.abalance = ((SELECT min(sp0_2.tbalance) FROM public.pgbench_tellers_5 sp0_2 WHERE ((sp0_2.bid = 90)) AND ((r2.bid = 90))))))
   Transport: Silk
   SubPlan 1
     ->  Finalize Aggregate
           Output: min(t.tbalance)
           ->  Foreign Scan
                 Output: (PARTIAL min(t.tbalance))
                 Relations: Aggregate on (public.pgbench_tellers_5_fdw t)
                 Remote SQL: SELECT min(tbalance) FROM public.pgbench_tellers_5 WHERE ((bid = 90)) AND (($1::integer = 90))
                 Transport: Silk

Обратите внимание, что в приведённом выше плане нет ссылок на SubPlan 1.

7.2.2. Асинхронное выполнение

При обращении к сегментированной таблице планировщик Shardman создаёт планы Append для сканирования всех секций таблицы и объединения результатов. Когда некоторые из секций являются сторонними таблицами, планировщик может решить использовать асинхронное выполнение. Это означает, что когда у узла Append впервые после инициализации запрашиваются кортежи, он посылает асинхронным дочерним узлам команду начать считывание результата. Для узлов postgres_fdw async ForeignScan означает, что объявляется удалённый курсор и на удалённый сервер отправляется запрос на выборку. Если используется транспорт Silk, то запрос отправляется для выполнения на удалённый сервер в виде сообщения MT_SPI.

После отправки запроса на удалённые серверы Append возвращается к выборке данных из синхронных дочерних узлов — локальных узлов сканирования или синхронных узлов ForeignScan. Данные из таких узлов извлекаются блокирующим образом. Когда Append завершает получение данных от синхронных узлов, он проверяет, есть ли данные на асинхронных узлах. Если данных нет, он ожидает результатов от асинхронных узлов.

Shardman может выполнять несколько типов планов асинхронно. Это асинхронные ForeignScans, проекции и тривиальные сканирования подзапросов (select * from subquery) по асинхронным планам.

Асинхронное выполнение включено по умолчанию на уровне стороннего сервера. Оно контролируется параметром async_capable расширения postgres_fdw. На данный момент только планы Append поддерживают асинхронное выполнение, а MergeAppend — нет.

Изучая планы запросов, обратите внимание на наличие в плане неасинхронных узлов ForeignScan. Асинхронное выполнение может значительно увеличивать время выполнения запроса.

Примеры:

EXPLAIN (COSTS OFF) SELECT * FROM pgbench_accounts;
                               QUERY PLAN
-------------------------------------------------------------------------
 Append
   ->  Seq Scan on pgbench_accounts_0 pgbench_accounts_1
   ->  Async Foreign Scan on pgbench_accounts_1_fdw pgbench_accounts_2
   ->  Async Foreign Scan on pgbench_accounts_2_fdw pgbench_accounts_3
   ->  Seq Scan on pgbench_accounts_3 pgbench_accounts_4
   ->  Async Foreign Scan on pgbench_accounts_4_fdw pgbench_accounts_5
   ->  Async Foreign Scan on pgbench_accounts_5_fdw pgbench_accounts_6
   ->  Seq Scan on pgbench_accounts_6 pgbench_accounts_7
   ->  Async Foreign Scan on pgbench_accounts_7_fdw pgbench_accounts_8
   ->  Async Foreign Scan on pgbench_accounts_8_fdw pgbench_accounts_9
   ->  Seq Scan on pgbench_accounts_9 pgbench_accounts_10
   ->  Async Foreign Scan on pgbench_accounts_10_fdw pgbench_accounts_11
   ->  Async Foreign Scan on pgbench_accounts_11_fdw pgbench_accounts_12
   ->  Seq Scan on pgbench_accounts_12 pgbench_accounts_13
   ->  Async Foreign Scan on pgbench_accounts_13_fdw pgbench_accounts_14
   ->  Async Foreign Scan on pgbench_accounts_14_fdw pgbench_accounts_15
   ->  Seq Scan on pgbench_accounts_15 pgbench_accounts_16
   ->  Async Foreign Scan on pgbench_accounts_16_fdw pgbench_accounts_17
   ->  Async Foreign Scan on pgbench_accounts_17_fdw pgbench_accounts_18
   ->  Seq Scan on pgbench_accounts_18 pgbench_accounts_19
   ->  Async Foreign Scan on pgbench_accounts_19_fdw pgbench_accounts_20

Здесь показан типичный асинхронный план. Существуют асинхронные сторонние сканирования и локальные последовательные сканирования, которые выполняются синхронно.

EXPLAIN (COSTS OFF) SELECT * FROM pgbench_accounts ORDER BY aid;
                            QUERY PLAN
-------------------------------------------------------------------
 Merge Append
   Sort Key: pgbench_accounts.aid
   ->  Sort
         Sort Key: pgbench_accounts_1.aid
         ->  Seq Scan on pgbench_accounts_0 pgbench_accounts_1
   ->  Foreign Scan on pgbench_accounts_1_fdw pgbench_accounts_2
   ->  Foreign Scan on pgbench_accounts_2_fdw pgbench_accounts_3
   ->  Sort
         Sort Key: pgbench_accounts_4.aid
         ->  Seq Scan on pgbench_accounts_3 pgbench_accounts_4
   ->  Foreign Scan on pgbench_accounts_4_fdw pgbench_accounts_5
   ->  Foreign Scan on pgbench_accounts_5_fdw pgbench_accounts_6
   ->  Sort
         Sort Key: pgbench_accounts_7.aid
         ->  Seq Scan on pgbench_accounts_6 pgbench_accounts_7
   ->  Foreign Scan on pgbench_accounts_7_fdw pgbench_accounts_8
   ->  Foreign Scan on pgbench_accounts_8_fdw pgbench_accounts_9
   ->  Sort
         Sort Key: pgbench_accounts_10.aid
         ->  Seq Scan on pgbench_accounts_9 pgbench_accounts_10
   ->  Foreign Scan on pgbench_accounts_10_fdw pgbench_accounts_11
   ->  Foreign Scan on pgbench_accounts_11_fdw pgbench_accounts_12
   ->  Sort
         Sort Key: pgbench_accounts_13.aid
         ->  Seq Scan on pgbench_accounts_12 pgbench_accounts_13
   ->  Foreign Scan on pgbench_accounts_13_fdw pgbench_accounts_14
   ->  Foreign Scan on pgbench_accounts_14_fdw pgbench_accounts_15
   ->  Sort
         Sort Key: pgbench_accounts_16.aid
         ->  Seq Scan on pgbench_accounts_15 pgbench_accounts_16
   ->  Foreign Scan on pgbench_accounts_16_fdw pgbench_accounts_17
   ->  Foreign Scan on pgbench_accounts_17_fdw pgbench_accounts_18
   ->  Sort
         Sort Key: pgbench_accounts_19.aid
         ->  Seq Scan on pgbench_accounts_18 pgbench_accounts_19
   ->  Foreign Scan on pgbench_accounts_19_fdw pgbench_accounts_20

Здесь используется merge append, поэтому выполнение не может быть асинхронным.

7.2.3. Альтернатива выборке всех строк

Во многих случаях операции над данными невозможно выполнить удалённо (например, если в фильтрах используется какая-то функция переменной среды, когда несколько сегментированных таблиц объединяются по атрибуту, не являющемуся ключом сегментирования, и проталкивание определённого типа соединения не поддерживается) или когда планировщик считает локальное выполнение более дешёвым. В таких случаях различные операции (выборка, объединение или агрегирование) не проталкиваются, а выполняются локально. Это может привести к неэффективному выполнению запросов из-за большого трафика между кластерами и высокой стоимости обработки на координаторе. Когда такое случается, нужно проверить, есть ли у оптимизатора свежая статистика, подумать о том, чтобы переписать запрос, чтобы извлечь выгоду из различных форм проталкивания, или, по крайней мере, проверить, что предложенный план запроса является подходящим. Чтобы включить в СУБД анализ данных для всего кластера, можно использовать функцию shardman.global_analyze.

7.3. Распределённые транзакции

7.3.1. Видимость и CSN

7.3.1.1. CSN — порядковый номер фиксации

Кластер Shardman использует механизм изоляции снимков для распределённых транзакций. Механизм предоставляет способ синхронизации снимков между различными узлами кластера и способ атомарной фиксации такой транзакции по отношению к другим параллельным глобальным и локальным транзакциям. Эти глобальные транзакции можно координировать, используя предоставленные SQL-функции или посредством postgres_fdw, который прозрачно использует эти функции на удалённых узлах.

Предположим, что каждый узел использует видимость на основе CSN: база данных отслеживает счётчик для каждой фиксации транзакции (CSN). С таким параметром снимок будет состоять из одного числа — копии текущего CSN на момент создания снимка. Правила видимости сводятся к проверке того, меньше ли CSN текущего кортежа, чем CSN нашего снимка.

Предположим, что CSN — это текущее физическое время на узле, и назовём его GlobalCSN. Если физическое время на разных узлах идеально синхронизировано, то такой снимок, полученный на одном узле, можно использовать на других узлах для обеспечения необходимого уровня изоляции транзакций. Но, к сожалению, физическое время никогда не бывает идеально синхронизировано и может смещаться, и это следует учитывать. Кроме того, в распределённой среде нет простого понятия блокировки или атомарной операции, поэтому атомарность фиксации на разных узлах в отношении одновременного получения снимков должна каким-то образом обрабатываться. Эта проблема решается следующим образом:

Для достижения атомарности фиксаций разных узлов вводится промежуточный шаг: при первом запуске транзакция помечается как InDoubt на всех узлах, и только после этого каждый узел фиксирует её и ставит метку с заданным GlobalCSN. Все обработчики, столкнувшиеся с кортежами транзакции InDoubt, должны дождаться её завершения и перепроверить видимость.

Когда координатор помечает транзакции как InDoubt на других узлах, он собирает ProposedGlobalCSN от каждого участника, которые представляют собой местное время на этих узлах. Затем он выбирает максимальное значение всех ProposedGlobalCSN и фиксирует транзакцию на всех узлах с этим максимальным GlobalCSN, даже если это значение больше, чем текущее время на этом узле из-за смещения. Таким образом, GlobalCSN для данной транзакции будет одинаковым на всех узлах. Каждый узел записывает свой последний сгенерированный CSN (last_csn) и не может генерировать CSN > last_csn. Когда узел фиксирует транзакцию с CSN > last_csn, last_csn настраивается для записи этого CSN. Благодаря этому механизму узел не может сгенерировать CSN, который меньше, чем CSN уже совершённых транзакций.

Если локальная транзакция импортирует сторонний глобальный снимок с некоторым GlobalCSN и текущее время на этом узле меньше, чем входящего GlobalCSN, транзакция должна дождаться, когда время этого GlobalCSN наступит локально.

Два последних правила обеспечивают защиту от смещения по времени.

7.3.1.2. Задержка фиксации и внешняя согласованность

Соблюдение вышеприведённых правил по-прежнему не гарантирует актуальность снимков, созданных на узлах, которые не участвуют в транзакции. Операция чтения из такого узла может получить устаревшие данные. Вероятность аномалии напрямую зависит от рассогласования системных часов в кластере Shardman.

Особое внимание следует уделить синхронизации системных часов на всех узлах кластера. Значение рассогласования часов должно быть измерено. Если требуется внешняя согласованность, то такое рассогласование можно компенсировать задержкой фиксации. Эта задержка добавляется перед каждой фиксацией в системе, поэтому она увеличивает задержку транзакций. Эта задержка не влияет на транзакции только для чтения. Задержку можно установить при помощи параметра конфигурации csn_commit_delay.

7.3.1.3. Карта CSN

Описанный выше механизм видимости CSN не является общим способом проверки видимости всех транзакций. Он используется для обеспечения изоляции только распределённых транзакций. В результате каждый узел кластера использует механизм проверки видимости, основанный на xid и xmin. Чтобы иметь возможность использовать снимок CSN, указывающий на прошлое, нужно сохранить старые версии кортежей на всех узлах и, следовательно, отложить их очистку. Для этого каждый узел в кластере Shardman поддерживает сопоставление CSN и xid. Карта называется CSNSnapshotXidMap. Эта карта является циклическим буфером и хранит соответствие между текущими snapshot_csn и xmin в разреженном виде: snapshot_csn округляется до секунд (и здесь используется тот факт, что snapshot_csn — это просто метка времени), а xmin хранится в циклическом буфере, где округлённое значение snapshot_csn действует как смещение из текущего циклического буфера. Размер циклического буфера управляется параметром конфигурации csn_snapshot_defer_time. VACUUM не может очищать кортежи, у которых xmax новее, чем самый старый xmin в CSNSnapshotXidMap.

Когда приходит снимок CSN, проверяется, что его snapshot_csn всё ещё находится в карте, в противном случае приходит сообщение об ошибке «snapshot too old» (снимок слишком старый). Если snapshot_csn успешно сопоставлен, xmin серверной части заполняется значением из карты. Таким образом можно учитывать обслуживающие процессы с импортированным снимком CSN, и старые версии кортежей будут сохранены.

7.3.1.4. Сокращение карты CSN

Для поддержки глобальных транзакций каждый узел хранит старые версии кортежей не менее csn_snapshot_defer_time секунд. При больших значениях csn_snapshot_defer_time это отрицательно сказывается на производительности и связано с тем, что узлы сохраняют все версии строк в течение последних csn_snapshot_defer_time секунд, но в кластере может не быть больше транзакций, которые могут их прочитать. Специальная задача monitor периодически пересчитывает xmin в кластере и устанавливает для него на всех узлах минимально возможное значение. Она позволяет процедуре очистки удалить версию строки, которая больше не представляет интереса для какой-либо транзакции. Параметр конфигурации shardman.monitor_trim_csnxid_map_interval управляет рабочим процессом. Рабочий процесс активируется каждые monitor_interval секунд и выполняет следующие операции:

Проверяет, является ли идентификатор группы репликации текущего узла наименьшим среди всех идентификаторов в кластере. Если это условие не выполняется, то работа на текущем узле прекращается. Таким образом, только один узел в кластере может определять глобальный горизонт.

С каждого узла кластера Shardman координатор собирает самый старый снимок CSN среди всех активных транзакций на узле.

Координатор выбирает наименьшее значение CSN и отправляет его каждому узлу. На каждом узле отбрасываются все значения csnXidMap, которые меньше значения этого CSN.

7.3.2. Разрешение двухфазных и подготовленных транзакций

Shardman реализует протокол двухфазной фиксации для обеспечения атомарности распределённых транзакций. Во время выполнения распределённой транзакции узел-координатор отправляет команду BEGIN узлам-участникам для инициирования их локальных транзакций.

Термин «узлы-участники» здесь и далее относится к подмножеству узлов кластера, которые участвуют в выполнении команды транзакции, пока узел занят записью.

Кроме того, на узле-координаторе создаётся локальная транзакция. Это гарантирует наличие соответствующих локальных транзакций на всех узлах, участвующих в распределённой транзакции.

Во время двухфазной фиксации транзакции узел-координатор отправляет команду PREPARE TRANSACTION узлам-участникам, чтобы инициировать подготовку их локальных транзакций к фиксации. Если подготовка прошла успешно, локальные данные транзакции сохраняются в хранилище на диске, что делает их постоянными. Если все узлы-участники сообщают об успешной подготовке узлу-координатору, узел-координатор фиксирует свою локальную транзакцию. Впоследствии узел-координатор также зафиксирует ранее подготовленные транзакции на узлах-участниках, используя команду COMMIT PREPARED.

Если во время выполнения команды PREPARE TRANSACTION на любом из узлов-участников происходит сбой, распределённая транзакция считается прерванной. Затем узел-координатор транслирует команду отмены ранее подготовленных транзакций ROLLBACK PREPARED. Если локальная транзакция уже была подготовлена, она прерывается. Однако если подготовленной транзакции с указанным именем не было, команда отката просто игнорируется. Впоследствии узел-координатор откатывает свою локальную транзакцию.

После успешной фазы подготовки на каждом из узлов-участников будет объект prepared transaction. Эти объекты фактически являются файлами на диске и записями в памяти сервера.

Возможно наличие подготовленной транзакция, которая была создана ранее посредством двухфазной операции и никогда не будет завершена. Это может произойти, например, если узел-координатор выходит из строя сразу после этапа подготовки, но до этапа фиксации. Это также может произойти в результате проблем с сетевым подключением. Например, если команда COMMIT PREPARED, переданная узлом-координатором узлу-участнику завершается ошибкой, локальные транзакции будут зафиксированы на всех узлах-участниках, кроме узла с ошибкой. Локальная транзакция также будет зафиксирована на узле-координаторе. Все участники, кроме одного с ошибкой, считают, что распределённая транзакция завершена. Однако один участник, всё ещё ожидающий команду COMMIT PREPARED, никогда не получит её, в результате чего подготовленная транзакция никогда не будет завершена.

Подготовленная транзакция потребляет системные ресурсы, такие как память и дисковое пространство. Незавершённая подготовленная транзакция заставляет другие транзакции, которые обращаются к строкам, изменённым этой транзакцией, ожидать завершения распределённой операции. Поэтому необходимо завершить подготовленные транзакции, даже в тех случаях, когда во время фиксации были сбои, чтобы высвободить ресурсы и обеспечить возможность выполнения других транзакций.

Для решения этой проблемы существует механизм разбора подготовленных транзакций, реализованный в составе Shardman monitor. Он реализован как фоновый рабочий процесс, который периодически активируется, действуя как внутреннее задание «crontab». По умолчанию период активации установлен на 5 секунд, но его можно настроить в параметре конфигурации shardman.monitor_dxact_interval. Рабочий процесс проверяет наличие подготовленных транзакций, которые были созданы ранее, через определённое время, указанное в параметре конфигурации shardman.monitor_dxact_timeout (который по умолчанию также равен 5 секундам), на том же узле где работает Shardman monitor.

Когда команда PREPARE TRANSACTION отправляется узлу-участнику, подготовленной транзакции присваивается специальное имя. Это имя содержит полезную информацию, позволяющую идентифицировать узел-координатор и его локальную транзакцию.

Если Shardman monitor обнаруживает устаревшие подготовленные транзакции, он извлекает идентификатор группы репликации координатора и идентификатор локальной транзакции координатора. Затем monitor отправляет запрос координатору

SELECT shardman.xact_status(TransactionId)

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

В случае успешного запроса узел-координатор может ответить с одним из следующих статусов:

committed

Локальная транзакция на узле-координаторе успешно завершена. Поэтому Shardman monitor также фиксирует эту подготовленную транзакцию, используя команду COMMIT PREPARED.

aborted

Локальная транзакция на узле-координаторе была прервана. Поэтому monitor также прерывает эту транзакцию, используя команду ROLLBACK PREPARED.

unknown

Транзакция с таким идентификатором никогда не существовала на узле-координаторе. Поэтому monitor прерывает эту транзакцию командой ROLLBACK PREPARED.

active

Локальная транзакция на узле-координаторе всё ещё находится где-то внутри потока CommitTransaction(). Поэтому monitor ничего не делает с этой транзакцией и повторит попытку с этой транзакцией при следующей активации.

ambiguous

Этот статус может быть возвращён, когда усечение CLOG включено на узле-координаторе. CLOG — это растровое изображение, в котором хранится состояние завершённых локальных транзакций. Когда транзакция фиксируется или прерывается, её статус отмечается в CLOG. Однако CLOG может быть усечён (собран мусор) процессом VACUUM, чтобы отбросить статусы старых транзакций, которые не влияют на видимость данных для любой существующей транзакции.

Когда CLOG усекается, существует вероятность того, что функция shardman.xact_status() не сможет однозначно решить, существовала ли транзакция в прошлом (с некоторым статусом) или никогда не существовала. В таких случаях функция возвращает неоднозначный статус. Это может привести к неопределённости фактического статуса транзакции и затруднить разбор подготовленной транзакции.

Когда функция shardman.xact_status() возвращает статус ambiguous для подготовленной транзакции, узел monitor вносит в журнал предупреждение, указывающее, что статус нельзя определить однозначно. Подготовленная транзакция остаётся нетронутой, и monitor снова попытается использовать эту транзакцию при следующей активации. Важно установить правильное значение параметра min_clog_size со значением 1024000 (что означает «никогда не усекать CLOG»), чтобы избежать неоднозначности в статусе подготовленных транзакций.

В ситуациях, когда механизм разбора подготовленных транзакций не может разобрать подготовленные транзакции из-за постоянных ошибок или неоднозначного статуса, администратору потребуется вручную вмешаться в разбор этих транзакций. Для этого может потребоваться изучить журналы сервера и выполнить операции отката или фиксации для подготовленной транзакции вручную. Обратите внимание, что оставление подготовленных транзакций неразобранными может приводить к проблемам с потреблением ресурсов и производительностью, поэтому важно устранять такие ситуации как можно скорее.

7.4. Silk

7.4.1. Концепция

Silk (Shardman InterLinK) — это экспериментальная транспортная функциональность. Она подключается в тот момент, когда postgres_fdw решает передать восстановленный фрагмент запроса через соединение libpq на удалённый узел, заменяя собой соединение libpq. Эта функциональность предназначена для уменьшения количества незанятых подключений postgres_fdw во время выполнения транзакции, минимизации задержки и повышения общей пропускной способности.

Реализация Silk использует несколько обслуживающих процессов. Основной процесс маршрутизации/мультиплексирования (по одному на экземпляр PostgreSQL) называется silkroad, а группа обслуживающих процессов — silkworms. Хотя postgres_fdw использует libpq, оно порождает несколько подключений libpq от каждого обслуживающего процесса к удалённому узлу (где соответственно порождаются несколько обслуживающих процессов). Но если silk заменяет libpq, каждый процесс silkroad подключается только к одному удалённому процессу silkroad. В этой схеме удалённые silkworms играют роль удалённых обслуживающих процессов, в противном случае порождённых postgres_fdw.

Silkroad связывает локальный обслуживающий процесс с рабочими процессами удалённого узла следующим образом:

Обслуживающий процесс использует обычный API postgres_fdw для доступа к удалённым данным. Но postgres_fdw, когда включён silk, записывает запрос в очередь общей памяти вместо подключения libpq;

Процесс Silkroad анализирует входящую очередь общей памяти от этого обслуживающего процесса и направляет сообщение соответствующему сетевому подключению с удалённым процессом silkroad.

Удалённый процесс silkroad захватывает входящее сообщение из сети и (если оно новое) перенаправляет его в доступную очередь общей памяти рабочего процесса (или в специальную очередь «неназначенных заданий», если все рабочие процессы заняты) .

Наконец, удалённый рабочий процесс получает сообщение через свою очередь общей памяти, выполняет его и отправляет обратно получившиеся кортежи (или ошибку) таким же образом.

Silkroad действует здесь как обычный сетевой коммутатор, перебрасывая пакеты между общей памятью серверной части и соответствующим сетевым сокетом. Этот процесс ничего не знает о содержании сообщения, полагаясь только на его заголовок.

7.4.2. Цикл событий

Процесс Silkroad запускает цикл событий на базе библиотеки libev. Очередь общей памяти каждого обслуживающего процесса отображается в цикле обработки событий с помощью дескриптора eventfd, а каждое сетевое подключение — с помощью дескриптора сокета.

Во время запуска обслуживающий процесс регистрирует себя (свои дескрипторы eventfd) в локальном процессе silkroad. Silkroad отвечает, указывая, какие сегменты памяти использовать для очереди сообщений обслуживающего процесса. С этого момента silkroad будет реагировать на события из очереди, связанной с этим обслуживающим процессом. Сетевые подключения между локальными и удалёнными silkroads будут установлены сразу по первому запросу от обслуживающего процесса к удалённому узлу и будут существовать до тех пор, пока оба участника (процессы silkroad) существуют.

7.4.3. Маршрутизация и мультиплексирование

Для каждого подзапроса ожидается подмножество кортежей и поэтому взаимодействие внутри подзапроса представляется как двунаправленный поток данных. Silkroad использует внутреннюю таблицу маршрутизации для регистрации этих потоков. Уникальный идентификатор потока (в кластере Shardman) формируется как пара «адрес исходного узла, адрес целевого узла» и локально (внутри узла) уникальный номер. Каждый конкретный подзапрос от обслуживающего процесса к удалённым узлам будет зарегистрирован silkroad как такой поток. Таким образом, любой обслуживающий процесс может быть связан со многими потоками одновременно.

Когда локальный процесс silkroad получает от серверной части сообщение с новым идентификатором потока, он регистрирует его в локальной таблице маршрутизации, а затем перенаправляет это сообщение в соответствующий сокет. Если подключение с удалённым silkroad не существует, оно устанавливается с помощью процедуры согласования. Исходное сообщение, инициировавшее согласование, помещается в специальный внутренний буфер до тех пор, пока согласование не завершится успешно. Удалённый процесс silkroad, получив пакет с новым идентификатором, регистрирует его в своей таблице, затем назначает рабочий процесс silkworm из пула доступных рабочих процессов и помещает сообщение в очередь общей памяти рабочего процесса. Если все рабочие процессы silkworm в данный момент заняты, сообщение будет отложено, т. е. помещено в специальную «очередь неназначенных заданий» (обратите внимание, что значение параметра конфигурации shardman.silk_unassigned_job_queue_size равно 1024). Если в очереди нет свободного места, будет сгенерировано сообщение об ошибке, которое будет отправлено обратно исходному обслуживающему процессу. Задание из этой очереди будет позже назначено первому доступному рабочему процессу, когда он освободится от предыдущего задания.

Когда рабочий процесс получает новое «задание», он выполняет его через подсистему SPI, организует получившиеся кортежи в пакеты и отправляет их обратно через общую память локальному процессу silkroad. Остальное тривиально, потому что весь маршрут известен. Последний получившийся пакет с кортежами в потоке помечается как «закрывающий». Это приказ процессам silkroads стереть этот маршрут из своих таблиц.

Обратите внимание, что серверные и удалённые рабочие процессы остаются «подписанными» на свои потоки, пока они не будут явно закрыты. Таким образом, сервер имеет возможность отправить сообщение о прерывании или уведомить удалённый рабочий процесс о преждевременном закрытии транзакции. Это позволяет отбрасывать устаревшие пакеты данных, возможно оставшиеся от предыдущих прерванных транзакций.

Для просмотра текущего состояния процесса silkroad мультиплексора используются диагностические представления Silk, описанные в Подразделе 6.4.2.

7.4.4. Обработка ошибок и целостность маршрута

Кроме того, таблица маршрутизации silkroad отслеживает конечные точки (серверы и сетевые подключения), которые были задействованы в том или ином потоке. Таким образом, когда какое-либо подключение закрывается, все задействованные серверы (и/или рабочие процессы) будут уведомлены об этом событии специальным сообщением об ошибке, а все маршруты/потоки, связанные с этим подключением, будут отклонены. Точно так же, если происходит сбой сервера, его очередь общей памяти отсоединяется, и silkroad реагирует, отправляя сообщения об ошибках удалённым участникам каждого потока, связанного со сбоем сервера. Таким образом, удалённые рабочие процессы не выполняют бесполезную работу, когда инициатор запроса уже неактивен.

7.4.5. Передача/порционирование/разделение данных в сверхбольших кортежах

Получившиеся кортежи передаются silkworm в собственном двоичном режиме. Кортежи с атрибутом хранения external будут удалены из TOAST, но те, которые были сжаты, останутся сжатыми.

Небольшие кортежи будут организованы в порции (примерно по 256 тыс.). Большие кортежи будут разделены на части отправителем и собраны в единое целое принимающим сервером.

7.4.6. Управление потоками

Может возникнуть ситуация, при которой очередное сообщение, полученное от сервера, не помещается в целевом сетевом буфере. Или сообщение, полученное из сети, не помещается в целевую очередь общей памяти. В таком случае поток, вызвавший эту ситуацию, будет «приостановлен». Это означает, что silkroad приостанавливает реакцию на события исходной конечной точки (подключение или сервер) до тех пор, пока целевая конечная точка не обработает все свои сообщения. Остальные серверы и подключения, не затронутые этим маршрутом, продолжают работать. Принимающие модули серверов призваны свести к минимуму подобные ситуации. Сервер периодически проверяет и очищает входящую очередь, даже когда исполнитель плана занят обработкой других узлов плана. Полученные кортежи хранятся в хранилищах кортежей сервера в соответствии с узлами плана до тех пор, пока исполнитель не запросит следующий кортеж для выполнения конкретного узла плана.

Когда в целевой очереди освобождается достаточно места, приостановленный поток возобновляется, события конечной точки разблокируются, а процесс приёма и сортировки пакетов продолжается.

7.4.7. Тонкости реализации

7.4.7.1. Передача состояний и CSN

Когда postgres_fdw работает через транспорт Silk, используется только одно подключение между демонами маршрутизации silkroad для передачи пользовательских запросов рабочим процессам silkworm и получения их ответов. Каждый запрос содержит состояние транзакции, идентификатор группы репликации узла, на котором формируется запрос (координатора), сам запрос и параметры запроса (если они есть). Ответ представляет собой либо сообщение об ошибке с описанием и кодом ошибки, либо группу кортежей, за которыми следует сообщение «end of tuples» (конец кортежей). Это означает, что silkworm должен переключиться на состояние транзакции, полученное вместе с запросом, перед выполнением запроса.

На данный момент транспорт Silk используется исключительно для запросов SELECT только для чтения. Все запросы на изменение обрабатываются через обычное подключение libpq и в основном обрабатываются как все остальные DML-запросы в PostgreSQL postgres_fdw. Единственное отличие состоит в том, что когда DML-запрос обрабатывается postgres_fdw, модуль сбрасывает сохранённое состояние транзакции для записи кеша соединений, соответствующей соединению, в котором отправляется этот запрос. Кроме того, для такой записи в кеше соединений устанавливается флаг только для чтения. Когда запрос отправляется через транспорт Silk, расширение Shardman запрашивает состояние транзакции для пары идентификаторов сервера и пользователя из postgres_fdw. Если такая запись найдена в кеше соединений postgres_fdw, она не является записью кеша только для чтения и в этой записи присутствует состояние транзакции, состояние возвращается. Если его нет, postgres_fdw получает полное состояние транзакции с удалённого сервера, сохраняет его в записи кеша соединений и возвращает в расширение Shardman.

Полное состояние транзакции аналогично состоянию параллельной рабочей транзакции и содержит:

информацию, относящуюся к текущему пользователю (uid, имя пользователя)

идентификатор процесса текущего сервера

временную метку начала транзакции

CSN текущего снимка

флаги, указывающие на наличие событий аннулирования

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

массив ComboCIDs

внутреннее состояние транзакции (полный идентификатор транзакции, уровень изоляции, текущий идентификатор команды и т. д.)

информацию о переиндексированных индексах

Если подключение не найдено в кеше подключений postgres_fdw (т. е. это новое подключение) или запись в кеше подключения помечается как доступная только для чтения, только эти характеристики формируют состояние транзакции:

информация, относящаяся к текущему пользователю (имя пользователя)

временную метку начала транзакции

CSN текущего снимка

флаги, указывающие на наличие событий аннулирования

Используя такие состояния транзакций, silkworm может присоединиться к выполняющейся транзакции или начать новую транзакцию только для чтения с предоставленным снимком CSN и получить результат.

Обратите внимание, что полное состояние транзакции можно импортировать только на тот сервер, который его экспортировал, а также, что из-за этого метода передачи состояния транзакции вы не можете использовать транспорт Silk без включения снимков CSN.

7.4.7.2. Интеграция с асинхронным механизмом FDW

В Подразделе 7.2.2 асинхронные узлы плана ForeignScan были представлены как способ оптимизации извлечения данных с нескольких узлов, если эти узлы плана были расположены под одним узлом Append. В стандартной архитектуре PostgreSQL выполнение планов узла ForeignScan реализовано с использованием сетевого протокола на основе libpq. Чтобы повысить производительность системы при передаче данных и снизить потребление ресурсов, Shardman использует другой метод обмена данными с удалёнными узлами. Механизм выполнения планов узла ForeignScan реализован с использованием протокола Silk.

Чтобы включить транспорт Silk в асинхронный исполнитель, были внесены изменения в расширение postgres_fdw. Подключаемый транспорт был реализован как набор интерфейсных функций, входящих в состав расширения Shardman. Во время выполнения обработчиков, которые взаимодействуют с удалёнными хостами, эти функции вызываются расширением postgres_fdw. Подключаемый транспорт Silk активируется, если предварительно загружено расширение Shardman и у стороннего сервера есть атрибут extended_features (применим для любого сервера FDW в кластере Shardman). В остальных случаях расширение postgres_fdw использует стандартный протокол обмена на основе расширения libpq.

Чтобы деактивировать подключаемый транспорт Silk в кластере Shardman, необходимо установить для параметра конфигурации query_engine_mode значение ENGINE_NONE.

В текущей реализации подключаемый транспорт Silk используется исключительно в запросах только для чтения, в частности во время выполнения планов узла ForeignScan. Для модификации запросов используется стандартный протокол обмена на основе расширения libpq.

При получении строк результатов выполнения запроса с использованием транспорта Silk данные сохраняются в хранилище TupleStoreState в виде полного набора результатов, который имеет тот же размер, что и возвращаемый удалённым узлом. Структура данных хранилища TupleStoreState позволяет передавать данные на диск в случае нехватки памяти. Если удалённый узел возвращает большой набор результатов, это не приводит к нехватке памяти (OOM). Как только набор результатов получен в TupleStoreState, данные копируются в буфер исполнителя ForeignScan в памяти. Размер этого буфера определяется атрибутом fetch_size стороннего сервера. Значение по умолчанию (50000 строк) можно изменить, чтобы найти баланс между производительностью (количество вызовов узла ForeignScan) и потреблением памяти.

Использование подключаемого транспорта Silk для асинхронного ядра FDW приводит к повышению производительности сетевого обмена и снижению потребления системных ресурсов за счёт их лучшего использования, включая количество сетевых подключений.

7.5. Обнаружение распределённых взаимоблокировок

Распределённые взаимоблокировки могут возникать во время обработки распределённых транзакций. Рассмотрим следующий пример:

    create table players(id int, username text, pass text) with (distributed_by='id');
    insert into players select id, 'user_' || id, 'pass_' || id from generate_series(1,1000) id;

Предположим, что запись с id=2 принадлежит node1, а запись с id=3 принадлежит node2.

Выполните следующие команды на разных узлах:

    node1=# begin;
    node1=# update players set pass='someval' where id=3;

    node2=# begin;
    node2=# update players set pass='someval' where id=2;

    -- it should stuck because transaction on node1 locked record with id=3
    node2=# update players set pass='someval2' where id=3;

    -- it should stuck because transaction on node2 locked record with id=2
    node1=# update players set pass='someval2' where id=2;

Распределённая взаимоблокировка возникает, когда транзакции взаимно блокируются друг другом. PostgreSQL имеет внутренний механизм обнаружения взаимоблокировок, который обнаруживает взаимную блокировку между дочерними процессами одного экземпляра PostgreSQL (сервера) и разрешает её. Однако этот механизм неприменим к обнаруженной ситуации, поскольку взаимная блокировка распределена, т. е. задействованы серверы с разных узлов. С точки зрения менеджера блокировок PostgreSQL взаимоблокировка отсутствует, поскольку процессы одного экземпляра не блокируют друг друга. Поэтому Shardman имеет собственный механизм разрешения распределённых взаимоблокировок.

Можно представить взаимодействие между процессами во всем кластере в виде графа. Вершина графа представляет собой процесс (сервер), который можно идентифицировать парой атрибутов {rgid; vxid}, где rgid – идентификатор группы репликации, а vxid — виртуальный идентификатор текущей выполняемой транзакции. Рёбра графа представляют собой направленные связи между вершинами. Каждое подключение направлено от заблокированного процесса к блокирующему процессу.

Очевидно, что любой процесс может быть заблокирован только одним процессом. Другими словами, если сервер ожидает блокировку, то это может быть только его блокировка. С другой стороны, блокирующий процесс может получать несколько блокировок, что означает, что он может одновременно блокировать несколько серверов.

При этом граф блокировок действует как односвязный список. Если этот список содержит замкнутый цикл, то возникает взаимоблокировка. Для обнаружения взаимоблокировок необходимо построить такой список и обнаружить в нём замкнутые циклы.

Детектор распределённых взаимоблокировок в Shardman реализован как отдельная задача внутри Shardman monitor. Если процесс не может получить блокировку в течение заданного периода времени (по умолчанию это одна секунда, но его можно настроить в параметре конфигурации deadlock_timeout), внутренний детектор взаимоблокировок PostgreSQL пытается обнаружить локальную взаимоблокировку. Если локальная взаимоблокировка не обнаружена, активируется детектор распределённых взаимоблокировок.

Детектор распределённых взаимоблокировок строит граф (список) блокировок в кластере. Он запрашивает представления pg_locks и pg_stat_activity на локальном узле и на каждом из удалённых узлов кластера.

Процесс построения списка блокировок включает в себя последовательные запросы к узлам в кластере, и он не является атомарным, поэтому список не является согласованным. Это означает, что у детектора распределённых взаимоблокировок могут быть ложные срабатывания. Во время построения списка может сохраниться блокировка, которая исчезнет до окончания процесса построения списка. Чтобы гарантировать надёжность обнаружения взаимоблокировок, после обнаружения замкнутого цикла необходимо повторно отправить запросы узлам, участвующим в замкнутом цикле.

Найдя замкнутый цикл, детектор распределённых взаимоблокировок выбирает процесс, принадлежащий локальному узлу, и отменяет его. Пользовательский процесс, обслуживаемый отменённым обслуживающим процессом, получит сообщение:

    отмена оператора из-за обнаруженной распределённой взаимоблокировки

В журналы сервера будет записано подробное сообщение об обнаруженной взаимоблокировке:

    LOG:  distributed deadlock detected
    DETAIL:  repgroup 1, PID 95264 (application 'psql'), executed query 'update players set pass='qqq' where id=2;' is blocked by repgroup 1, PID 95283 (application 'pgfdw:2:95278:9/2'), executed query 'UPDATE public.players_0 SET pass = 'qqq'::text WHERE ((id = 2))'
    repgroup 1, PID 95283 (application 'pgfdw:2:95278:9/2'), executed query 'UPDATE public.players_0 SET pass = 'qqq'::text WHERE ((id = 2))' is blocked by repgroup 2, PID 95278 (application 'psql'), executed query 'update players set pass='qqq' where id=3;'
    repgroup 2, PID 95278 (application 'psql'), executed query 'update players set pass='qqq' where id=3;' is blocked by repgroup 2, PID 95267 (application 'pgfdw:1:95264:8/4'), executed query 'UPDATE public.players_1 SET pass = 'qqq'::text WHERE ((id = 3))'
    repgroup 2, PID 95267 (application 'pgfdw:1:95264:8/4'), executed query 'UPDATE public.players_1 SET pass = 'qqq'::text WHERE ((id = 3))' is blocked by repgroup 1, PID 95264 (application 'psql'), executed query 'update players set pass='qqq' where id=2;'

7.6. Глобальные последовательности

Глобальные последовательности в Shardman реализованы поверх обычных последовательностей PostgreSQL с некоторыми дополнительными метаданными на уровне кластера, которые среди прочего содержат интервал глобально неиспользуемых элементов последовательности.

При выполнении команды CREATE SEQUENCE на каждом узле кластера создаётся обычная последовательность PostgreSQL с тем же именем. Диапазон этой локальной последовательности представляет собой ограниченный подынтервал глобальной последовательности (определённый параметрами MINVALUE и MAXVALUE) и содержит количество элементов, не превышающее значение block_size. Функция nextval возвращает значения из локальной последовательности до тех пор, пока она не закончится, затем из глобальной последовательности выделяется новый подынтервал с элементами block_size с использованием трансляции запроса, включающей все узлы кластера. Таким образом, меньшие значения размера блока делают генерируемые числа более однородными по всему кластеру, но влекут за собой снижение производительности, поскольку трансляция запроса может быть довольно дорогой. Можно также описать параметр размера блока иначе: он управляет размером второго уровня кеша, аналогично тому, как работает параметр CACHE, но на уровне всего кластера Shardman.

Также обратите внимание, что каждый раз, когда выделяется новый подынтервал, нижележащая локальная последовательность изменяется (как в ALTER SEQUENCE), что блокирует её на время транзакции и не даёт получать любым другим локальным параллельным транзакциям следующие значения последовательности.

7.7. Точки синхронизации и последовательное резервное копирование

Чтобы обеспечить согласованность двоичного резервного копирования кластера, Shardman реализует механизм точек синхронизации.

Для достижения согласованной видимости распределённых транзакций используется метод глобальных снимков на основе физических часов. Точно так же можно получить согласованный снимок для резервных копий, при этом время, соответствующее глобальному снимку, должно быть сопоставлено с набором LSN для каждого узла. Такой набор согласованных LSN в кластере называется точкой синхронизации.

В кластере Shardman каждый узел может генерировать свой собственный независимый локальный CSN, что не гарантирует глобального упорядочения значений по времени. Поэтому нельзя взять этот произвольный локальный CSN в качестве основы для точки синхронизации. Вместо этого Shardman в качестве основы для точки синхронизации выбирает только те CSN, которые соответствуют записям фиксации распределённых транзакций. Эти CSN обладают свойством глобального упорядочения и могут использоваться для получения точки синхронизации. Основные особенности этого механизма описаны ниже.

Запись фиксации каждой завершённой транзакции в Shardman содержит назначенный CSN для этой транзакции. Это значение вместе с LSN этой записи образует пару значений (CSN, LSN). Каждый из узлов кластера хранит определённое количество таких пар в оперативной памяти в специальной структуре — карте CSNLSNMap. CSNLSNMap — это кольцевой буфер. Каждый элемент карты представляет собой пару (CSN, LSN). Размер карты задаётся параметрами конфигурации csn_lsn_map_size. Пара (CSN, LSN) может быть добавлена в карту, только если на узле нет транзакций, которые могут получить CSN меньше добавленного. Это важное условие гарантирует монотонный рост CSN и LSN в CSNLSNmap, но не гарантирует, что каждая запись фиксации попадёт в карту.

Когда пользователь отправляет запрос на создание точки синхронизации, в каждой CSNLSNMap выполняется поиск максимально возможного CSNg, для которого есть запись (CSN n, LSN) в каждом узле и условие CSNn <= CSNg верно. Свойство монотонного роста каждой CSNLSNMap гарантирует, что каждая найденная пара (CSNn, LSN) соответствует состоянию глобальных данных в момент времени, соответствующий CSNg. Если такое значение CSNg не найдено, операция получения точки синхронизации завершится ошибкой и может быть повторена позже. Если такое значение CSNg найдено, то точка синхронизации генерируется в виде особого типа записи WAL, которая дублируется на всех узлах кластера.

Получив точку синхронизации и взяв из неё LSN для каждого узла в кластере, можно сделать резервную копию каждого узла, которая обязательно должна содержать этот LSN. Также можно восстановить этот LSN, используя механизм восстановления на момент времени (PITR).

7.8. Сбор статистики распределённых операторов расширением pgpro_stats

Во время выполнения распределённых запросов Shardman отправляет производные SQL-запросы на удалённые узлы, содержащие секции данных, задействованные в выполнении запроса. Назовём эти SQL-запросы фрагментами запроса. Shardman отправляет такие запросы, используя расширение postgres_fdw. Узел, который запрашивает распределённую таблицу, называется координатор, а узлы, принимающие фрагменты запроса, называются сегменты.

Когда расширение pgpro_stats включено на узле кластера Shardman, оно собирает статистику по локальным и распределённым запросам. Информация о распределённых запросах, инициированных этим узлом, является неполной, поскольку в ней отсутствуют данные об удалённых фрагментах запроса. Статистика запросов, инициированных другими узлами, также неоднозначна, поскольку у пользователя нет простого способа определить распределённый запрос, которому соответствует фрагмент.

Для решения этих проблем расширение pgpro_stats для Shardman предоставляет агрегирование статистики для распределённых запросов. Доступ к этой агрегированной статистике можно получить с помощью представления pgpro_stats_sdm_statements. Однако каждый узел Shardman также собирает статистику для всех операторов, поэтому представление pgpro_stats_statements может работать так же, как раньше.

Когда узел получает фрагмент запроса, статистика этого узла сохраняется в отдельную общую хеш-таблицу. Периодически и асинхронно каждый узел отправляет эту информацию из отдельной таблицы координатору, который соответствует запросу. Координатор агрегирует статистические данные, полученные из фрагментов запроса, со статистикой своего родительского запроса, который является запросом, инициированным клиентом.

Расширение pgpro_stats запускает отдельный фоновый рабочий процесс. Этот рабочий процесс отвечает за отправку накопленной статистики узлам-координаторам либо каждые 5 секунд, либо при срабатывании защитного механизма. Функция сбора запускает этот механизм, когда хеш-таблица почти заполнена.

Для уменьшения сетевого трафика, инициированного отправителем статистики, к отправляемым статистическим данным применяется сжатие. Метод сжатия можно выбрать с помощью параметра конфигурации pgpro_stats.transport_compression.

Каждый узел хранит общее число записей статистики, полученных от узла сегмента, и метку времени их последнего приёма. Когда узел-координатор получает сообщение статистики, он изменяет соответствующие значения, которые доступны через интерфейс SQL.

В расширениях Shardman есть дополнительные SQL-функции pgpro_stats, описанные в Раздел 6.2, и параметры конфигурации, описанные в «Параметры pgpro_stats».

7.9. Рекомендательные блокировки

PostgreSQL имеет средства создания блокировок, смысл которых определяют сами приложения. Такие блокировки называются рекомендательными, так как система не форсирует их использование, и распространяются на весь кластер. Рекомендательные и глобальные блокировку работают одновременно и не конфликтуют друг с другом. Эти блокировки отражаются в системном представлении pg_locks и в поле locktype имеют значение shradman.

Список функций для работы с рекомендательными блокировками представлен в Разделе 6.3.

Приложение A. Замечания к выпускам

A.1. Postgres Pro Shardman 14.18.2

Дата выпуска: 2025-06-16

Этот выпуск основан на PostgreSQL 14.18 и Shardman 14.18.1, в нём добавлены новые возможности, улучшена производительность и исправлены некоторые ошибки. Важные изменения перечислены ниже.

A.1.1. Ядро и расширения

Переименовано поле is_reply представления shardman.silk_routing, теперь оно называется is_outgoing. Если маршрут был создан исходящим сетевым соединением, поле будет иметь значение true, а если входящим — false.

Обновлены значения по умолчанию параметров конфигурации ведения журнала для всех новых инсталляций Shardman:

logging_collector: on

log_directory: {{dataDir}}

log_filename: postgres-{{cluster}}-{{shard}}-{{host}}-{{keeperID}}.log

Исправлена ошибка, ранее приводившая к сбою функции shardman.execute_query, если использовался нетипичный тип атрибута.

A.1.2. Утилиты управления

Добавлена дополнительная проверка во время работы pg_probackup, которая гарантирует, что текущие ведущие узлы не переключились во время резервного копирования кластера. В противном случае выполнение прерывается.

Изменены значения по умолчанию для флагов -t (--transactions) и -T (--time) команды shardmanctl bench run на 10 и 0 соответственно.

Оптимизирован процесс повышения резервного сервера до ведущего.

Исправлена ошибка, ранее приводившая к зависанию pg_ basebackup. Теперь во время повторной синхронизации слоты репликации автоматически создаются на ведущем узле, если резервный узел отстаёт.

A.2. Postgres Pro Shardman 14.18.1

Дата выпуска: 2025-05-19

Этот выпуск основан на PostgreSQL 14.18 и Shardman 14.17.2, в нём добавлены новые возможности, улучшена производительность и исправлены некоторые ошибки. Важные изменения перечислены ниже.

A.2.1. Ядро и расширения

Обновлена оценка стоимости стороннего сканирования и добавлен параметр postgres_fdw.estimate_indexscan, позволяющий оценивать удалённое сканирование как сканирование индекса. Ранее оценка всегда происходила по последовательному сканированию.

Разрешено удалённое выполнение некоторых функций, зависящих от параметра IntervalStyle. Удалён параметр конфигурации postgres_fdw.enable_always_shippable, теперь его механизм встроен для сторонних серверов Shardman и отключён для любых других сторонних серверов.

Добавлено ограничение для сторонних секций, которые теперь нельзя добавлять в таблицы, включённые в публикации с publish_via_partition_root.

Обновлён планировщик, который теперь рассматривает параметризованное соединение вложенным циклом при создании плана соединения сегментированной таблицы.

Исправлена ошибка, которая ранее приводила к сбою при обновлении или удалении некоторых команд для глобальных таблиц.

Исправлена ошибка проталкивания частичных агрегирований, ранее приводившая к неправильному расчёту sum.

Улучшена работа Silk для более высоких значений shardman.silk_unassigned_job_queue_size.

Обновлена поддерживаемая версия pgpro_stats до 1.9-sdm4.

Обновлена поддерживаемая версия pgpro_pwr до 4.9.

A.2.2. Утилиты управления

Добавлена возможность проверки резервной копии на совместимом кластере.

Обновлены команды shardmanctl shard master set и shardmanctl shard master reset, теперь они требуют подтверждение при переключении ведущего узла. Добавлен параметр --yes, который подтверждает операцию вместо того, чтобы запрашивать подтверждение от стандартного ввода.

Устранена уязвимость CVE-2025-22871.

Устранены уязвимости GO-2025-3503 и GO-2025-3595.

Устранена проблема обновления уровня журнала с помощью файла .env.

A.3. Postgres Pro Shardman 14.17.2

Дата выпуска: 2025-04-14

Этот выпуск основан на PostgreSQL 14.17 и Shardman 14.17.1, в нём добавлены новые возможности, улучшена производительность и исправлены некоторые ошибки. Важные изменения перечислены ниже.

A.3.1. Ядро и расширения

Добавлены параметры конфигурации csn_max_shift и csn_max_shift_error для работы с CSN снимками распределённых запросов и с импортированными снимками.

Добавлен параметр конфигурации shardman.context_log, который позволяет координатору увидеть контекст ошибки рабочего процесса.

Удалены параметры конфигурации csn_max_commit_shift и csn_max_snapshot_shift.

Запрещён доступ к глобальным представлениям с резервных серверов.

Обновлён вывод команды ABORT для рабочих процессов, теперь он показывает подробную информацию о причинах отмены команды на координаторе.

Оптимизировано поведение команды MergeAppend, которая теперь рассматривает самый дешёвый общий путь при сортировке. Ранее планировщик мог не выбрать наиболее эффективный путь.

A.3.2. Утилиты управления

Устранена уязвимость GO-2025-3553.

Исправлено поведение команды shardmanctl nodes. Теперь нельзя указывать один и тот же узел дважды в командах shradmanctl nodes start, shradmanctl nodes stop и shradmanctl nodes restart.

Добавлены параметры конфигурации для работы со слотами репликации: additionalReplicationSlots указывает массив имён слотов репликации, которые будут созданы на ведущем сервере, createSlotsOnFollowers создаёт слоты репликации также и на резервных узлах, additionalSlotsLagLimit ограничивает возможное отставание для дополнительных слотов репликации.

Добавлена поддержка местозаполнителей для параметров pgParameters.

Оптимизирована работа адаптера pgwaldump во избежание отправки всего вывода команды pg_waldump в буфер.

A.4. Postgres Pro Shardman 14.17.1

Дата выпуска: 2025-03-17

Этот выпуск основан на PostgreSQL 14.17 и Shardman 14.15.4, в нём добавлены новые возможности, улучшена производительность и исправлены некоторые ошибки. Важные изменения перечислены ниже.

A.4.1. Ядро и расширения

Отключена возможность изменения параметров shardman.silk_shmem_size, shardman.silk_netbuf_size, shardman.silk_suspend_shmqe_limit, shardman.silk_resume_shmqe_limit, shardman.silk_suspend_netqe_limit и shardman.silk_resume_netqe_limit. Эти параметры используются только в целях обеспечения совместимости.

Добавлено детальное описание следующих параметров конфигурации: shardman.silk_unassigned_job_queue_size, shardman.silk_max_message, shardman.silkworm_fetch_size и shardman.silk_hello_timeout.

Оптимизированы механизмы получения согласованной точки синхронизации.

Улучшена информативность сообщений об ошибках при создании временных сегментированных или глобальных таблиц.

Изменены команды CREATE USER MAPPING, ALTER USER MAPPING, and DROP USER MAPPING, которые теперь запрещены, если сопоставление происходит для сторонних серверов и кластера Shardman.

Изменены каталоги shardman.users and pg_user_mapping , пароли в которых теперь не хранятся в открытом виде.

Исправлено отсутствие обработки команд ALTER INDEX для сегментированных таблиц.

Устранена проблема, связанная с транспортом Silk и ранее приводившая к рекурсивной ошибке и сбою управляющего процесса.

Устранена уязвимость BDU:2025-01601.

A.4.2. Утилиты управления

Добавлен параметр --lock-lifetime для команды probackup backup, позволяющий задать максимальный интервал времени в секундах, в течение которого pg_probackup может удерживать блокировку.

Обновлены команды shardmanctl forall, shardmanctl load и shardmanctl history: теперь они не блокируют другие процессы и могут выполняться одновременно.

Добавлен параметр -n|--node для команд shardmanctl shard stop и shardmanctl shard start, позволяющий задать узел, который необходимо запустить или остановить.

Улучшена информативность сообщений об ошибках при работе с pg_probackup.

Добавлена возможность безопасного восстановление кластера etcd при «холодном» резервном копировании с помощью команды shardmanctl store restore.

Оптимизирован процесс проверки резервных копий с помощью новых параметров--data-validate, -remote-port, --remote-user и --ssh-key команды shardmanctl probackup restore.

Добавлен фильтр restart_required_params для команды shardmanctl status, который проверяет, что все требующие перезапуска экземпляра postgres параметры были применены. В ожидаемом выводе нет неприменённых параметров, требующих перезапуска.

Добавлено автоматическое подтверждение перезапуска для команд shardmanctl probackup archive-command add и probackup backup с помощью параметра -y|--yes.

Улучшен вывод команды shardmanctl history, которая теперь показывает список команд и результат их выполнения: успешно или с ошибкой.

Добавлена возможность автоматического подтверждения перезапуска, необходимого для вступления в силу новых значений параметров: для этого используется параметр -y|--yes команд shardmanctl config update и shardmanctl config set. Если он не указан, а для изменения параметров требуется перезапуск, будет запрошено ручное подтверждение. Если автоматический перезапуск не подтверждён, кластер продолжит работу, однако новые значения параметров вступят в силу только после перезапуска.

Устранена проблема, ранее приводившая к дублированию строк в файле pg_hba.conf.

Устранена ошибка, приводившая к сбою команды shardmanctl status.

Обновлена поддерживаемая версия pg_probackup до 2.8.8.

A.5. Postgres Pro Shardman 14.15.4

Дата выпуска: 2025-02-19

Этот выпуск основан на PostgreSQL 14.15 и Shardman 14.15.4, в нём улучшена производительность и исправлены некоторые ошибки. Важные изменения перечислены ниже:

A.5.1. Ядро и расширения

Исправлена ошибка, ранее приводившая к неправильному переиспользованию памяти трассировки в ходе выполнения подготовленного оператора при включённом параметре shardman.silk_tracepoints.

A.5.2. Утилиты управления

Исправлена ошибка, которая ранее приводила к сбою резервного копирования после переключения ведущих узлов.

Обновлена поддерживаемая версия pg_probackup до 2.8.7.

A.6. Postgres Pro Shardman 14.15.3

Дата выпуска: 2025-02-10

Этот выпуск основан на PostgreSQL 14.15 и Shardman 14.15.2, в нём улучшена производительность и исправлены некоторые ошибки. Важные изменения перечислены ниже.

A.6.1. Ядро и расширения

Добавлено представление shardman.pg_indoubt_xacts, которое отображает информацию о транзакциях в состоянии InDoubt.

Добавлены глобальные представления для системного каталога и статистики.

Добавлены новые поля для представлений shardman.silk_connects, shardman.silk_backends и shardman.silk_routing, отображающие последние события чтения или записи для соединения или рабочего процесса.

Добавлены новые сообщения об ошибке для координатора для случаев, когда размер сообщения MT_SPI превышает значение silk_max_message, если запрос выполняется через Silk.

Добавлены диагностические сообщения для случаев, когда экспортируемый размер состояния транзакции превышает половину значения shardman.silk_max_message.

Повышены максимально допустимые значения для параметров shardman.silk_num_workers, shardman.silk_unassigned_job_queue_size, shardman.silk_max_message, shardman.silk_shmem_size, shardman.silk_netbuf_size, shardman.silk_suspend_shmqe_limit, shardman.silk_resume_shmqe_limit, shardman.silk_suspend_netqe_limit и shardman.silk_resume_netqe_limit.

Добавлена возможность вынесения на удалённый сервер операций преобразования типов.

Добавлено ограничение для сегментированных таблиц, которые могут ссылаться на самих себя, только если внешний ключ ссылается на ту же секцию сегментированной таблицы.

Модуль etcd обновлён до версии 3.5.18.

A.6.2. Утилиты управления

Добавлена новая подкоманда show-config для команды shardmanctl probackup. Выводит все текущие параметры конфигурации pg_probackup, в том числе те, что содержатся в файле pg_probackup.conf, а также те, что были заданы в командной строке.

Добавлены новые параметры подкоманд sharmanctl probackup delete и shardmanctl probackup backup для работы с политиками хранения резервных копий: retention-redundancy, retention-window, wal-depth, delete-expired, merge-expired.

Устранены уязвимости CVE-2024-24790 и CVE-2024-45337.

A.7. Postgres Pro Shardman 14.15.2

Дата выпуска: 2024-12-16

Этот выпуск основан на PostgreSQL 14.15, в нём улучшена производительность и исправлены некоторые ошибки. Важные изменения перечислены ниже.

A.7.1. Ядро и расширения

Добавлены поля in_queue_used и out_queue_used в представление shardman.silk_backends, которые показывают объём данных входящей или исходящей очереди в байтах в общей памяти между рабочим процессом и мультиплексором.

Добавлена новая функция shardman.silk_routing, а также соответствующие представления shardman.silk_routing и gv_silk_routing. Они отображают информацию о текущих активных маршрутах.

Добавлена новая функция shardman.silk_rbc_snap, которая выводит согласованный снимок всех соединений, рабочих процессов и маршрутов, которые могут использоваться функциями silk_connects, silk_backends и silk_routes.

Добавлены представления shardman.silk_state и shardman.silk_statinfo, функция shardman.silk_statinfo_reset() и параметр конфигурации shardman.silk_track_time, которые показывают состояние процессов мультиплексора.

Добавлен новый параметр конфигурации shardman.silk_tracelog, который включает или отключает протоколирование трассировки и отладки для Silk, а также параметр конфигурации shardman.silk_tracelog_category, который определяет, какие категории сообщений Silk протоколировать.

Добавлен новый параметр конфигурации enable_non_equivalence_filters, который позволяет оптимизатору генерировать дополнительные условия, не являющиеся условиями эквивалентности, с использованием классов эквивалентности, а также параметр конфигурации optimize_row_in_expr, который позволяет оптимизатору генерировать дополнительные условия из выражения IN ().

Добавлен новый параметр конфигурации track_xact_time, представление shardman.pg_stat_xact_time и глобальное представление shardman.gv_stat_xact_time для отображения статистики по времени, потраченному на транзакции.

Добавлено поле attached в представление shardman.silk_backends и функция silk_backends для отображения фактического присоединения рабочего процесса к мультиплексору.

Добавлен новый параметр конфигурации shardman.silk_stream_work_mem, задающий базовый максимальный объём памяти, который будет использоваться потоком Silk (как размер буфера), до записи во временные файлы на диске. Если это значение задаётся без единиц измерения, оно считается заданным в килобайтах.

Обновлён вывод команды EXPLAIN, теперь она показывает блоки server и transport в одной строке, если указать значение verbose.

Обновлена поддерживаемая версия pgpro_pwr до 4.8.

Обновлена поддерживаемая версия pg_query_state до 1.1.

Обновлена поддерживаемая версия pgpro_stats до 1.8-sdm4.

Обновлена поддерживаемая версия pg_probackup до 2.8.5.

Ускорено планирование для запросов вида поле = ANY (ARRAY[values]) в массивах с большим количеством записей.

Обновлён тип параметра конфигурации postgres_fdw.foreign_explain с boolean на enum, значение по умолчанию collapsed. Также обновлён вывод команды EXPLAIN для соответствия новым значениям.

Исправлена ошибка, которая ранее приводила к зависанию мультиплексора.

Обновлена функция nextval, которая может использоваться для создания значений последовательности, которые будут уникальными во всём кластере.

A.7.2. Утилиты управления

Исправлена ошибка, которая ранее приводила к игнорированию ключа командной строки, если задана соответствующая ключу переменная окружения.

Устранён сбой shardmanctl bench run при длительной работе, связанный с переполнение буферов памяти.

Устранён сбой shardmanctl bench, который ранее происходил в случаях, когда команда выполнялась не от имени пользователя postgres.

Исправлена ошибка, которая приводила к полной повторной синхронизации реплики и была связана с попадание некорректных данных в postgresql.auto.conf.

Исправлена ошибка, ранее приводившая к сообщению уровня PANIC при попытке вызова команд изменения параметров неинициализированного кластера.

Изменён параметр -f|--file file_name команды shardmanctl bench run, который теперь добавляет в список выполняемых скриптов скрипт транзакции из файла имя_файла, а также задаёт целочисленный вес каждому файлу.

Добавлены параметры -P|--progress, -R|--rate и -M|--protocol в команду shardmanctl bench run.

A.8. Postgres Pro Shardman 14.15.1

Дата выпуска: 2024-11-25

В этом выпуске улучшена производительность, добавлены новые возможности и исправлены некоторые ошибки. Важные изменения перечислены ниже:

A.8.1. Ядро и расширения

Добавлена метрика shardman.pg_stat_csn для подсчёта количества транзакций, превысивших порог ожидания в состоянии inDoubt.

Добавлены новые поля в представление shardman.silk_pending_jobs: query, pending_queue_bytes и pending_queue_messages, которые соответственно показывают первое сообщение в очереди заданий, размер очереди ожидающих заданий в байтах и количество сообщений в очереди заданий.

Добавлена трассировка прохождения запросов через транспорт Silk и параметр конфигурации shardman.silk_tracepoints, включающий эту трассировку.

Изменена функция current_date, которую теперь можно предварительно вычислить на координаторе. Добавлена возможность безопасного проталкивания сравнений timestamp и timestamptz.

Добавлена поддержка pg_query_state.

Добавлена поддержка рекомендательных блокировок — необязательных блокировок на уровне кластера с задаваемыми приложениями значениями. Также добавлен список функций для работы с такими блокировками.

Исправлена ошибка, ранее приводившая к неконтролируемому использованию и распределению памяти со стороны silkworm в ходе обработки сообщений.

Исправлена ошибка, ранее приводившая к нестабильной работе Silk и возможному зависанию запросов при включённом параметре shardman.silk_flow_control.

A.8.2. Утилиты управления

Добавлена команда shardmanctl history, которая позволяет просматривать историю команд модификации кластера. По умолчанию команды отсортированы от самых новых к самым старым.

Обновлена версия etcd до 3.5.13.

Добавлена фаза корректировки в процесс перебалансировки данных, которая позволяет должным образом продолжить перебалансировку, прерванную ранее.

Добавлена возможность включить шифрование при конфигурации порта приложения shardmand в sdmspec.json.

Обновлён механизм проверки параметров PostgreSQL, который теперь использует данные, возвращаемые экземпляром PostgreSQL.

A.9. Postgres Pro Shardman 14.13.4

Дата выпуска: 2024-11-13

В этом выпуске улучшена производительность, добавлены новые возможности и исправлены некоторые ошибки. Важные изменения перечислены ниже:

A.9.1. Ядро и расширения

Добавлена поддержка асинхронного выполнения операций ForeignScan под MergeAppend, контролируемых параметром enable_async_merge_append, который по умолчанию включён. Если операции под MergeAppend допускают асинхронное выполнение, запросы рассылаются асинхронно в начале выполнения MergeAppend, а результаты кешируются по мере их получения. В дальнейшем они используются так же, как и в синхронном MergeAppend для сортировки слиянием.

Добавлена возможность использования сортировки на удалённом сервере, если возможно её использование для выполнения операции MergeJoin или MergeAppend. Это контролируется параметром postgres_fdw.additional_ordered_paths, который по умолчанию включён при новых установках, но при обновлении кластера требует явного включения.

Добавлена поддержка проталкивания предложений LIMIT под Append и MergeAppend для случаев, когда узел плана сортировки находится между LIMIT и Append, если строки подпланов Append и MergeAppend уже отсортированы в правильном порядке.

Ускорены операции вставки, обновления и удаления для глобальных таблиц. Добавлен новый параметр конфигурации shardman.gt_batch_size, который определяет размер буфера для команд INSERT и DELETE в глобальных таблицах.

Запрещено создание сегментированных и локальных секционированных таблиц по одному и тому же атрибуту.

Добавлена новая функция shardman.broadcast_query, которая возвращает результаты исполняемого выражения SQL.

Добавлено новое поле CSNXidMap_last_trim в представление shardman.pg_stat_csn, которое показывает время последнего вызова функции shardman.trim_csnxid_map().

Улучшены проверки согласованности состояний в расширении shardman.

Исправлена проблема неправильного распределения ресурсов, которая ранее могла вызывать ошибки в некоторых случаях вытеснения кортежей на диск.

Исправлена ошибка в приложении pg_rewind при повышении реплики, приводившая к полной синхронизации предыдущего ведущего сервера.

Обновлена поддерживаемая версия pgpro_pwr до 4.7.

A.9.2. Утилиты управления

Добавлено протоколирование изменений параметров, если они приводят к перезапуску postgresql.

Улучшена логика получения состояния экземпляра PostgreSQL.

Улучшены сообщения в журнале приложения shardmand.

Исправлена ошибка подключения через shardmanctl psql.

Добавлена поддержка уровней сжатия в зависимости от алгоритма сжатия при создании резервной копии командой shardmanctl probackup backup.

Добавлена зависимость количества записей pgbench_branches от количества узлов в рамках тестов производительности shardmanctl. Это позволяет более равномерно распределять данные по узлам.

Добавлена команда shardmanctl shard reset, позволяющая вывести узлы репликационной группы из состояния зависания.

Добавлена команда shardmanctl daemon set, позволяющая изменить параметры журналирования без перезапуска.

A.10. Postgres Pro Shardman 14.13.3

Дата выпуска: 2024-10-28

В этом выпуске улучшена производительность, добавлены новые возможности и исправлены некоторые ошибки. Важные изменения перечислены ниже:

A.10.1. Ядро и расширения

Добавлены параметры конфигурации, позволяющие управлять сбором информации о сбоях сервера. Параметр crash_info включает эту функциональность, а crash_info_dump и crash_info_location указывают содержимое и расположение файлов с информацией о сбоях соответственно.

A.10.2. Утилиты управления

Исправлена ошибка переключения с главного сервера на реплику в случае, когда не удаётся получить параметры конфигурации сервера.

A.11. Postgres Pro Shardman 14.13.2

Дата выпуска: 2024-10-22

В этом выпуске улучшена производительность, добавлены новые возможности и исправлены некоторые ошибки. Важные изменения перечислены ниже:

A.11.1. Ядро и расширения

Добавлен новый параметр конфигурации shardman.silk-flow-control, который управляет обработкой событий чтения. Возможные значения: none, round_robin и shortest_job_first.

Добавлено представление shardman.pg_stat_foreign_stat_bytes, в котором отображается объём статистики для сторонних отношений, передаваемый по сети между узлами кластера Shardman. Также добавлено соответствующее глобальное представление shardman.gv_stat_foreign_bytes.

Добавлен новый параметр конфигурации shardman.sync_cluster_settings, который управляет синхронизацией всех выставленных пользователем в кластере параметров конфигурации.

Добавлен новый параметр конфигурации shardman.sync_cluster_settings_blacklist, исключающий параметры удалённого кластера, которые не нужно синхронизировать.

Добавлен новый параметр конфигурации enable_sql_func_custom_plans. Включение этого параметра позволяет создавать специализированные планы для выполнения функций на языке SQL. По умолчанию включён для новых кластеров и выключен для старых.

Исправлена ошибка, ранее приводившая к зависанию shardmand в случае потери кворума со стороны etcd.

Добавлена поддержка команды ALTER COLUMN SET STATISTICS для глобальных и сегментированных таблиц.

Добавлено ограничение по управлению правами доступа на глобальные таблицы на уровне столбцов.

Добавлено ограничение для глобальных таблиц, которые не могут наследовать другие таблицы.

Снято ограничение на использование DEFERRABLE для глобальных таблиц.

Добавлено новое поле CSNXidMap_last_trim, которое выводит время последнего вызова функции shardman.trim_csnxid_map(), в представление shardman.pg_stat_csn.

A.11.2. Утилиты управления

Добавлена команда shardmanctl psql, которая без заданных параметров по умолчанию создаёт подключение к первому доступному главному узлу. Если указано значение параметра --shard, подключение происходит к текущему главному узлу сегмента.

Добавлен метод сжатия lz4 для параметра default_toast_compression.

Устранена ошибка, ранее приводившая к сбою команды shardmanctl probackup checkdb при указании пользовательского порта в конфигурации Shardman.

Исправлена ошибка, приводившая к падению shardmand с ошибкой уровня PANIC в случае недостаточных прав для доступа к каталогу DataDir.

Исправлена ошибка, приводившая к переключение между ведущим сервером и репликой после перезагрузки. Также для команды shardmanctl restart добавлен новый параметр --no-wait.

A.12. Postgres Pro Shardman 14.13.1

Дата выпуска: 2024-09-12

В этом выпуске улучшена производительность, добавлены новые возможности и исправлены некоторые ошибки. Важные изменения перечислены ниже:

A.12.1. Ядро и расширения

Добавлена возможность проталкивать запросы соединения JOIN UNIQUE INNER на удалённый сервер.

Добавлены следующие представления: shardman.pg_stat_monitor, которое показывает метрики Shardman monitor; shardman.pg_stat_net_usage, которое показывает совокупный сетевой трафик между узлами кластера Shardman; shardman.gv_lock_graph, которое показывает граф блокировок, в том числе внешних, между процессами на узлах кластера Shardman.

Добавлено представление shardman.oldest_csn, которое показывает csn, xid и rgid кортежей с CSN и XID самой старой транзакции кластера, а также номер группы репликации транзакции.

Добавлен параметр конфигурации csn_max_snapshot_shift, который включает проверку снимков, импортированных функцией pg_csn_snapshot_import().

Добавлены новые ограничения на виды таблиц, которые могут быть включены в логическую репликацию.

Обновлена поддерживаемая версия pg_probackup до 2.8.3.

A.12.2. Утилиты управления

Обновлен текст сообщения, отображаемый при попытке получить конфигурацию топологии командой shardmanctl cluster topology на неинициализированном кластере. Также понижен уровень сообщений для этого сценария.

Устранена ошибка в команде shardmanctl bench run, ранее приводившая к значительной задержке перед выполнением команды.

Добавлена команда shardmanctl config update credentials для изменения пароля или сертификата/ключа пользователя для подключения к кластеру Shardman.

Добавлены команды shardmanctl config revisions, shardmanctl config rollback, shardmanctl config revisions rm и shardmanctl config get, а также вывод в консоль информации об узле, с которого команда выполнена, и пользователе, который её выполнил.

Команда shardmanctl config rollback выполняет откат конфигурации Shardman к одному из предыдущих состояний. При откате к версии конфигурации, имеющей параметры max_connections, max_prepared_transactions или max_worker_processes, реплики переинициализируются.

Команда shardmanctl config revisions выводит revision_id — временную метку операции, вызвавшей изменение конфигурации Shardman, host — узел, с которого операция выполнена, user — пользователя, выполнившего операцию, и command — саму операцию.

Команда shardmanctl config revisions set позволяет задать длину истории версий конфигурации. Добавлен лимит истории версий для одной конфигурации кластера Shardman. Это значение не может быть меньше 5. Для кластеров, где история версий конфигурации ранее не отслеживалась, длина автоматически устанавливается на 20.

Команда shardmanctl config get выгружает текущую полную спецификацию кластера или конфигурацию указанной версии. Параметр --choose-revision включает интерактивный режим выбора конфигурации указанной версии.

Добавлена команда shardmanctl config revisions rm, которая удаляет указанную версию конфигурации из истории.

Изменено описание ролей в sdmspec.json.

A.13. Postgres Pro Shardman 14.12.2

Дата выпуска: 2024-08-01

В этом выпуске улучшена производительность, добавлены новые возможности и исправлены некоторые ошибки. Важные изменения перечислены ниже:

A.13.1. Ядро и расширения

Добавлена возможность создавать глобальную или сегментированную таблицу на основе другой глобальной, сегментированной или локальной таблицы. На данный момент есть ограничения на создание таблиц на основе локальных.

Исправлена обработка параметра IF NOT EXISTS команды CREATE TABLE для глобальных и секционированных таблиц. Раньше была вероятность создания таблицы с неправильной структурой, если секционированная таблица с идентичным именем уже существовала на одном из узлов кластера.

Обновлено значение по умолчанию для параметра хранения num_parts на 24 для достижения более равномерного распределения данных для кластеров с 2, 3, 4, 6 и 8 узлами.

Добавлен параметр конфигурации enable_merge_append, который включает или отключает использование планировщиком планов MergeAppend. В частности позволяет отключить использование этих планов, если они слишком дорогие.

Добавлен параметр конфигурации pgpro_stats.track_shardman_connections, который включает или отключает обработку операторов Shardman.

Добавлена возможность проталкивать запросы соединения с VALUES на удалённый сервер.

Удалено ограничение в 64 тысячи на количество таблиц в запросе.

Добавлено представление shardman.pg_stat_monitor, которое предоставляет статистику работы детектора распределённых взаимоблокировок и служб разрешения подготовленных транзакций.

Добавлено глобальное представление shardman.gv_stats_sdm_statements, которое предоставляет доступ к агрегированной статистике для распределённых запросов.

Обновлено представление pgpro_stats pgpro_stats_sdm_statements. Теперь оно содержит статистику только по запросам, задействующим сегментированные таблицы.

Обновлена поддерживаемая версия pg_probackup до 2.8.2.

A.13.2. Утилиты управления

Добавлена возможность резервного копирования кластера с табличными пространствами. Теперь табличные пространства находятся в каталоге резервной копии.

Добавлена возможность восстанавливать полностью или частично работающий кластер из резервной копии, сделанной на частично работающем кластере, с использованием shardmanctl probackup.

Введён параметр --no-wait для команды shardmanctl shard add, с которым команда shardmanctl не ждёт запуска сегмента и снимает блокировку с других команд.

Введён параметр s|--scale для команды shardmanctl bench run. Задаёт коэффициент масштабирования, на который умножается количество сгенерированных строк.

Добавлена команда shardmanctl script, которая выполняет нетранзакционные команды из файла или командной строки на указанных сегментах.

Изменён файл конфигурации sdmspec.json, генерируемый командой shardmanctl config generate. Теперь из него исключены параметры, зависящие от ресурсов системы и рабочей нагрузки на узел кластера. Эти параметры сохраняют значения по умолчанию. Раньше инициализация кластера могла завершиться ошибкой на узлах с меньшими ресурсами из-за слишком высоких значений этих параметров.

Добавлена возможность восстанавливать из резервной копии одного кластера другие, если у них одинаковая топология. Добавлена команда shardmanctl config update ip, которая обновляет IP-адреса указанных узлов кластера.

Добавлен параметр --log-format в shardmand, который задаёт формат журнала: json или text.

A.14. Postgres Pro Shardman 14.12.1

Дата выпуска: 2024-06-06

В этом выпуске улучшена производительность, добавлены новые возможности и исправлены некоторые ошибки. Важные изменения перечислены ниже:

A.14.1. Ядро и расширения

Добавлен параметр REMOTE команды EXPLAIN, который разрешает вывод EXPLAIN по запросам, выполняемым на удалённом сервере. По умолчанию включён.

Реализована собственная логика оценки стоимости планов. Она позволяет планировщику чаще выбирать общие планы при схожести общего и специализированного планов.

Добавлена поддержка первоначального устранения в узлах плана, выполняющих агрегацию данных на сторонних серверах.

Добавлены накопительные метрики по величине сетевого трафика между узлами кластера Shardman в представлении shardman.pg_stat_netusage.

Обновлено представление pg_stat_activity. Теперь оно показывает статус обслуживающих процессов Shardman.

A.14.2. Утилиты управления

Устранены уязвимости CVE-2023-45288 и CVE-2023-44487.

Устранена ошибка в команде shardmanctl cleanup, ранее приводившая к невозможности удаления групп репликации.

Улучшен вывод команды shardmanctl forall при пустом результате.

Устранён сбой утилиты shardmand, ранее возникавший, если кластер Shardman не полностью сконфигурирован.

A.15. Postgres Pro Shardman 14.11.2

Дата выпуска: 2024-04-18

В этом выпуске улучшена производительность, добавлены новые возможности и исправлены некоторые ошибки. Важные изменения перечислены ниже:

A.15.1. Ядро и расширения

Добавлен параметр foreign_analyze_interval, определяющий интервал сбора статистики по сторонним отношениям во время автоочистки (задаётся в секундах).

Реализована возможность создавать внешний ключ с действием ON DELETE CASCADE между сегментированной и глобальной или двумя глобальными таблицами.

Добавлена поддержка устранения узла MergeAppend в общих планах.

Добавлена поддержка удалённого выполнения функций to_timestamp.

Реализованы глобальные представления. В результате запроса к глобальному представлению выводится объединение строк из соответствующих локальных представлений и строк, полученных с каждого узла кластера.

Добавлено описание представлений для диагностики мультиплексора Silk.

Улучшена информативность сообщений об ошибках, связанных с изменениями параметров кластера.

A.15.2. Утилиты управления

Добавлены параметры --no-validate и --skip-block-validation для команды shardmanctl probackup restore.

Улучшена процедура восстановления из резервной копии в кластер, совместимый с исходным, с помощью команды restore.

Добавлена команда shardmanctl probackup checkdb для проверки кластера Shardman на наличие физических повреждений или логических нарушений.

Реализована возможность выполнять команды shardmanctl set и config update для кластера, остановленного командой shardmanctl stop.

Введён параметр --all для команды shardmanctl getconnstr, добавляющий информацию о репликах в результат команды.

В утилиту shardmanctl добавлены команды nodes start, nodes restart и nodes stop для узлов, а также команды start и stop для сегментов.

Расширены права на каталог данных shardmand.

A.16. Postgres Pro Shardman 14.11.1

Дата выпуска: 2024-03-14

В этом выпуске улучшена производительность, добавлены новые возможности и исправлены некоторые ошибки. Важные изменения перечислены ниже:

A.16.1. Ядро и расширения

Улучшены возможности расширения pgpro_stats для понимания того, какие системные ресурсы используются для распределённых запросов. Теперь в обычном представлении pgpro_stats_statements показывается статистика, собранная для отдельных операторов на текущем узле Shardman (они могут быть частью распределённого запроса), а в представлении pgpro_stats_sdm_statements показывается статистика, собранная для распределённых запросов, исходящих из текущего узла, то есть агрегированная по всем участвующим узлам.

Добавлен пакет pgpro_pwr, совместимый с Shardman и позволяющий пользователям собирать отчёты о нагрузке.

Улучшена информативность команды EXPLAIN. Если план запроса содержит узлы ForeignScan, теперь в вывод команды EXPLAIN может быть включён вывод EXPLAIN по запросам, выполняемым на удалённом сервере.

Добавлен новый параметр конфигурации enable_partition_pruning_extra, управляющий расширенной логикой отсечения секций подплана при построении и выполнении общих планов, в которых набор полезных секций зависит от параметров подготовленного запроса. Этот параметр позволяет Shardman выполнять первоначальное отсечение секций в сложных подпланах, соединениях и частичных агрегированиях.

В представление shardman.pg_stat_csn добавлены метрики, показывающие задержки глобального горизонта и транзакцию, которая может их вызывать. Они могут быть полезны для исследования проблем автоочистки.

A.16.2. Утилиты управления

Значительно улучшено резервное копирование и восстановление с помощью команды shardmanctl probackup. Основные изменения представлены ниже:

Добавлена поддержка создания резервных копий в S3-совместимом объектном хранилище.

Реализовано выборочное архивирование WAL подкомандой probackup в заданных сегментах.

Добавлены две новые команды: shardmanctl probackup delete и shardmanctl probackup merge. Команда delete удаляет резервную копию с указанным ID и ставшие ненужными заархивированные файлы WAL. Команда merge объединяет резервные копии, принадлежащие общей инкрементальной цепочке резервных копий.

Добавлена новая команда shardmanctl probackup set-config, с помощью которой в файле pg_probackup.conf можно создавать новые параметры или изменять существующие.

Добавлен новый параметр log-to-console для подкоманды validate. Размер файла журнала установлен равным 20 МБ. По достижении этого лимита происходит ротация журнала при запуске команды validate или backup.

Увеличено количество повторных попыток выполнения некоторых подкоманд во избежание сбоев резервного копирования из-за больших размеров баз данных.

Добавлена проверка совместимости топологии текущего кластера Shardman с кластером в каталоге резервных копий при выполнении подкоманд backup и restore.

Установлено значение по умолчанию для количества одновременных процессов pg_probackup, равное количеству логических ЦП в системе.

Исправлена очистка данных после сбоя подкоманды backup. Ранее некоторые данные резервного копирования, закончившегося сбоем, могли оставаться в репозитории.

Устранено зависание, которое могло возникать при восстановлении только метаданных кластера Shardman.

Устранена проблема в pg_probackup, которая могла возникать в процессе восстановления схемы.

Изменено поведение процесса восстановления только метаданных во избежание потери кластера. Теперь кластер останавливается перед выполнением такого восстановления и вновь запускается после его завершения. Кластер без узлов не может быть восстановлен из резервной копии etcd, и если ID резервной копии кластера отличается от ID текущего кластера, то пользователя просят подтвердить, что необходимо выполнить восстановление кластера с отличающимся ID.

Добавлены новые параметры для команды archive-command: --compress, --compress-algorithm, --compress-level, --batch-size и -j|--jobs. Эти параметры помогают уменьшить размер WAL.

Улучшена информативность вывода команды show. Добавлены новые флаги: -archive для вывода информации о журнале, -instance и -i|--backup-id для вывода информации об указанных экземплярах и резервных копиях.

Изменено поведение команд getconnstr и cluster topology так, что они не вызывают блокировку других процессов. Ранее из-за таких блокировок некоторые команды не могли получить строку подключения.

Устранена ошибка уровня panic, которая могла возникать в кластере Shardman с конфигурацией PlacementPolicy = manual при выполнении пользователем команды shardmanctl cluster repfactor set.

Убраны неинформативные предупреждения, выводящиеся pg_dump во время выполнения команд shardmanctl nodes add и shardmanctl probackup backup.

Убрана блокировка, требовавшаяся для команды shardmanctl status. Ранее shardmanctl status не предоставляла полезной информации о зависании процесса из-за ожидания блокировки.

Добавлен параметр конфигурации forceSuUserLocalPeerAuth. При включённом параметре для пользователя postgres устанавливается аутентификация peer через сокет Unix, если для strictUserHBA не установлено значение true. За подробностями обратитесь к sdmspec.json.

Добавлен URL-адрес обнаружения служб системы Prometheus в shardmand.

A.17. Postgres Pro Shardman 14.10.3

Дата выпуска: 2024-02-02

Этот выпуск основан на Shardman 14.10.2, в нём улучшена производительность и исправлены некоторые ошибки. Важные изменения перечислены ниже.

Устранена проблема, из-за которой СУБД Shardman не могла работать с утилитой pg_probackup при запуске PostgresSQL на порте, отличном от 5432.

Устранена проблема в Shardman, не позволявшая утилите pg_probackup запускаться на узле, который не входит в кластер Shardman.

Устранено зависание функции shardmanctl probackup restore, происходившее в некоторых случаях.

Добавлена очистка каталога резервных копий в случае сбоя команды shardmanctl probackup init.

Улучшена обработка ошибок резервного копирования probackup. Теперь, если резервное копирование вызывает ошибку в одном сегменте, оно прерывается и на остальных.

Улучшено поведение команды shardmanctl probackup show: теперь при отсутствии файла backup_info выводится сообщение об отсутствии резервных копий.

A.18. Postgres Pro Shardman 14.10.2

Дата выпуска: 2024-01-25

Это первая версия программного обеспечения Shardman, выпущенная в виде пакетов, которые включают саму СУБД Shardman и утилиты управления.

СУБД Shardman основана на PostgreSQL с дополнительными улучшениями, большая часть функциональности которых реализована в расширениях shardman и postgres_fdw.

Основные возможности данных утилит перечислены ниже:

Распределённые ACID транзакции.

Распределённый DDL для управления объектами всего кластера, включая сегментированные и глобальные таблицы, последовательности и пользователей.

Эффективный мультиплексирующий транспорт для связи между узлами внутри кластера.

Эффективное планирование и выполнение распределённых запросов.

Автоматическое разрешение подготовленных транзакций и обнаружение распределённых взаимоблокировок.

Сбор статистики распределённых операторов и внутренних метрик сети в расширении pgpro_stats.

Поддержка глобальных табличных пространств и сжатой файловой системы (CFS).

Утилиты управления реализованы в виде службы shardmand и инструмента shardmanctl . Они используют стороннюю службу etcd для хранения глобальной конфигурации кластера и обмена информацией.

Основные возможности данных утилит перечислены ниже:

Первоначальная конфигурация и настройка кластера.

Отображение и управление текущей конфигурацией сегментов и реплик.

Изменение и управление параметрами в кластере.

Обеспечение отказоустойчивости сегментов.

Согласованное резервное копирование и восстановление данных (поддержка pg_basebackup и pg_probackup).

Быстрая загрузка данных и автоматическая миграция схемы.

Инструменты для тестирования производительности.

Обновление метаданных при обновлениях СУБД.

Приложение B. Глоссарий

Ниже представлен список терминов и их значений в контексте Shardman. Термины, используемые в этом документе в общем контексте PostgreSQL и реляционных баз данных, описаны в разделе Глоссарий PostgreSQL.

ACID

Atomicity (Атомарность), Consistency (Согласованность), Isolation (Изолированность) и Durability (Надёжность). Этот набор свойств транзакций в базе данных должен гарантировать корректность операций при параллельном выполнении, а также в случае ошибок, при отключении питания и т. п. За дополнительными сведениями обратитесь к глоссарию PostgreSQL.

Silk (Shardman InterLinK)

Экспериментальная транспортная система, которую можно использовать в кластере Shardman для связи между узлами.

etcd

Надёжное распределённое хранилище пар ключ-значение для наиболее важных данных распределённой системы. Больше информации можно найти на сайте etcd.

stolon

Облачно-ориентированная программа управления PostgreSQL для обеспечения отказоустойчивости. Больше информации можно найти на по ссылке.

Глобальная роль

Роль, операции которой всегда выполняются на всех группах репликации одновременно.

Глобальный пользователь

Пользователь, операции которого всегда выполняются на всех группах репликации одновременно.

Группа репликации

Кластер stolon с одним ведущим и одним или несколькими резервными серверами. Группы репликации (часто обозначаемые в утилитах Shardman как repgroups) организованы в звенья.

Звено

Набор узлов, где на каждом узле находится экземпляр PostgreSQL, который является ведущим для одной из групп репликации, и экземпляры PostgreSQL, которые являются резервным для всех других групп репликации. Общее число узлов в звене равно коэффициенту репликации.

Сегмент

В сегментировании — несколько секций таблицы, которые хранятся на одном узле, являющимся для них ведущим.

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

Принцип проектирования баз данных, при котором строки таблицы хранятся отдельно друг от друга в разных БД, которые потенциально управляются разными экземплярами СУБД.

Сегментированная таблица

Секционированная таблица, в которой некоторые секции являются обычными локальными таблицами, формирующими сегмент, а другие секции — сторонними таблицами, которые доступны с удалённых серверов через postgres_fdw.

Точка синхронизации

Набор согласованных LSN в кластере, относящихся к глобальному снимку.

Приложение C. Часто задаваемые вопросы

C.1. Основные вопросы

C.1.1. Что такое Shardman?

Shardman — это распределённая система управления базами данных (СУБД) на основе PostgreSQL, реализующая сегментирование. Сегментированием называется принцип проектирования баз данных, при котором строки таблицы хранятся отдельно друг от друга в разных БД, потенциально управляемых разными экземплярами СУБД. Основная задача Shardman — повысить эффективность выполнения запросов к сегментированным распределённым БД и упростить управление ими.

C.1.2. Из чего состоит Shardman?

Shardman состоит из следующих программных компонентов:

СУБД PostgreSQL 14 с набором изменений.

Расширение Shardman.

Инструменты и службы управления, включая встроенный менеджер stolon для обеспечения отказоустойчивости.

C.1.3. Когда использовать Shardman?

Рабочий объём данных не помещается в оперативную память одного сервера, но может поместиться в память нескольких сегментов (или хотя бы читаться параллельно).

Количество сеансов слишком велико для одного экземпляра PostgreSQL.

Интенсивно используется запись в WAL.

Сложная логика потребляет слишком много ресурсов процессора, и одного сервера недостаточно.

C.1.4. Когда не рекомендуется использовать Shardman?

Если с памятью, сеансом, загрузкой процессора справляется один сервер PostgreSQL — это и быстрее, и проще. (Это относится и к тестированию!).

C.1.5. Сколько узлов требуется для развёртывания Shardman?

Для развёртывания Shardman требуется как минимум три узла. Для кластера etcd требуется один узел (кластер etcd с одним узлом) и как минимум два узла для кластера РСУБД. Минимальное развёртывание можно сократить до двух узлов, разместив etcd на одном из узлов кластера РСУБД. Минимальное развёртывание описано в разделе Начало работы с Shardman.

C.1.6. Отказоустойчив ли Shardman?

Да, Shardman отказоустойчив на уровне каждого сегмента. Каждый сегмент представляет собой отказоустойчивый кластер.

C.1.7. Как устроено сегментирование?

В Shardman таблицы разделены на секции, а секции распределены между сегментами.

C.1.8. Можно ли изменить количество секций?

Нет, количество секций сегментированных таблиц задаётся при их создании и остаётся неизменным. Если ожидается, что объём имеющихся данных значительно вырастет, следует заранее создать необходимое количество секций (по умолчанию — 20).

C.1.9. Поддерживает ли Shardman повторное сегментирование?

Нет, в Shardman на данный момент не поддерживается автоматическое изменение ключа сегментирования. Для изменения ключа сегментирования необходимо создать новые таблицы с новым ключом сегментирования и перенести в них данные из старых таблиц.

C.1.10. Можно ли преобразовать несегментированную (локальную) таблицу в сегментированную?

Нет, в Shardman на данный момент не поддерживается эта функция.

C.1.11. Поддерживает ли Shardman добавление и удаление сегментов?

Минимальная конфигурация кластера Shardman — один узел без отказоустойчивости, но такая конфигурация не имеет особого смысла. Можно добавлять или удалять сегменты, Shardman будет автоматически (по умолчанию, но это настраивается) перераспределять данные между узлами. Можно добавить в Shardman реплики, чтобы сделать сегменты отказоустойчивыми.

C.1.12. Каков статус балансировки данных?

При добавлении новых сегментов данные будут перераспределяться между всеми сегментами, включая новые.

C.1.13. Как осуществляется доступ к кластеру Shardman?

К Shardman можно получить доступ через любой узел в кластере, все узлы в кластере равны. Используйте команду shardmanctl getconnstr, чтобы получить строку подключения к кластеру.

C.1.14. Как реализована балансировка между узлами кластера?

На данный момент нет встроенного решения для балансировки. Но можно организовать балансировку на уровне приложения, например, с помощью параметров драйвера JDBC (loadBalanceHosts). Для libpq эта функция будет реализована в версии PostgreSQL 16.

C.1.15. Поддерживается ли массовая загрузка данных в Shardman?

Да, этот функционал встроен в утилиту управления — см. shardmanctl load.

C.2. Базы данных

C.2.1. Можно ли создать несколько баз данных в кластере Shardman?

На данный момент сегментирование работает только для базы данных с именем postgres (по умолчанию), создание других баз данных находится в разработке.

C.3. Таблицы

C.3.1. Какие таблицы есть в Shardman?

Помимо локальных типов таблиц Shardman поддерживает распределённые таблицы: глобальные и сегментированные.

C.3.2. Что такое глобальные таблицы?

Глобальная таблица в Shardman — это таблица с одинаковой схемой и содержимым во всех сегментах кластера. Глобальные таблицы создаются так:

CREATE TABLE g(id bigint PRIMARY KEY, t text) WITH(global);

Копия такой таблицы создаётся в каждом сегменте. Репликация данных глобальных таблиц основана на триггерах. При вставке данных в такую таблицу на любом узле кластера происходит репликация данных на другие узлы. При создании глобальной таблицы необходимо указать неоткладываемый первичный ключ.

C.3.3. Для чего используются глобальные таблицы?

Глобальные таблицы подходят для каталогов и других относительно небольших и редко изменяемых таблиц. Глобальные таблицы НЕ подходят для хранения больших объёмов данных и интенсивной нагрузки при выполнении INSERT/UPDATE/DELETE, особенно при высококонкурентном доступе (витринах, очередях и т. д.).

C.3.4. Что такое сегментированные таблицы?

Сегментированные таблицы — это таблицы, части которых размещены в разных сегментах. Каждый сегмент хранит свою часть данных из такой таблицы. Сегментированная таблица может быть создана следующим образом:

CREATE TABLE ... WITH(distributed_by = 'column_name', num_parts = number_of_partitions);

Здесь:

distributed_by — поле таблицы, являющееся ключом сегментирования.

num_parts — (default = 24) количество секций, на которые изначально разбита таблица.

Затем эти части распределяются по сегментам.

C.3.5. Какие параметры секционирования оптимальны при создании сегментированной таблицы?

Количество секций должно быть не меньше количества сегментов, включая те, которые могут добавиться позже. Рекомендуется выбирать число с большим количеством делителей, например 12 или 24, чтобы можно было равномерно разделить таблицу на 2, 3, 4 или 6 сегментов. Большое количество секций увеличивает нагрузку на планирование и выполнение запросов, поэтому желательно увеличивать количество секций до разумных пределов.

C.3.6. Что такое совмещённые таблицы?

Совмещённые таблицы используются, когда таблица часто соединяется с другой сегментированной таблицей (обычно по внешним ключам) и поэтому лучше физически размещать их части в одних и тех же сегментах.

C.3.7. Как создать совмещённую таблицу?

CREATE TABLE ... WITH(distributed_by = 'column_name', num_parts = number_of_partitions, colocate_with = 'distributed_table');

Здесь:

distributed_by = 'column_name' — это имя ключа сегментирования, которое вызывается в создаваемой совмещённой таблице (не таблицы, с которой будет совмещение),

colocate_with = 'distributed_table' — имя таблицы, с которой нужно совместить части совмещённой таблицы.

C.3.8. Что такое локальные таблицы?

Локальная таблица — это таблица, размещённая только в том сегменте, где она была создана.

C.3.9. Есть ли в Shardman поддержка внешних ключей?

Внешние ключи используются в Shardman, но с некоторыми ограничениями:

С глобальными таблицами, как из сегментированных таблиц, так и из других глобальных таблиц

Между сегментированными совмещёнными таблицами

Внешние ключи запрещены:

Из глобальных в сегментированные таблицы

Между сегментированными таблицами, если они не совмещённые

C.4. Последовательности

C.4.1. Поддерживаются ли в Shardman глобальные последовательности?

Да, поддерживаются. Однако есть особенности их работы, которые следует учитывать. Глобальные последовательности по сути являются регулярными последовательности на каждом сегменте, и им выделяются последовательные блоки (65536 номеров по умолчанию). Когда выдаются числа, локальный последовательный блок передаётся локальному последовательному блоку в сегменте. То есть числа из глобальных последовательностей уникальны, но строгой монотонности в них нет (в отличие от PostgreSQL). Но могут быть «дыры» в значениях, выдаваемых генератором последовательностей.

C.4.2. Как создать глобальную последовательность?

CREATE SEQUENCE ... WITH (GLOBAL);

Функцию nextval можно использовать для получения следующего значения последовательности:

SELECT nextval('acl_id_seq'::regclass);

Типы данных bigserial, smallserial и serial (автоматическое создание последовательностей и вывод из неё значений по умолчанию) реализованы и работают как для сегментированных, так и для глобальных таблиц. Рекомендуется использовать bigserial при отсутствии особых требований.

C.5. Управление пользователями

C.5.1. Поддерживает ли Shardman глобальные роли пользователей?

Да, глобальные роли пользователей поддерживаются.

C.5.2. Как создать глобального пользователя в Shardman?

postgres=# create role my_user with login password 'my_user123' in role global;
CREATE ROLE

C.5.3. Как предоставить права доступа глобальному пользователю?

Следующие команды могут быть выполнены в одном сегменте и будут автоматически отправлены другим сегментам:

GRANT\REVOKE
CREATE ROLE ... IN ROLE GLOBAL / ALTER ROLE (for global role)

postgres=# grant CONNECT on DATABASE postgres TO my_user;
GRANT ROLE
postgres=# grant pg_monitor TO my_user;
GRANT ROLE
postgres=# \du
                                     List of roles
 Role name |                         Attributes                         |  Member of
-----------+------------------------------------------------------------+--------------
 my_user   |                                                            | {pg_monitor}
 postgres  | Superuser, Create role, Create DB, Replication, Bypass RLS | {}
 repluser  | Replication                                                | {}

Список каскадируемых команд дорабатывается и будет изменён в следующих версиях Shardman.

C.6. Полезные функции и таблицы

C.6.1. Как посмотреть, какие таблицы и последовательности являются распределёнными?

Ниже перечислены некоторые полезные внутренние таблицы Shardman.

shardman.sequence — список глобальных последовательностей

shardman.sharded_tables — список сегментированных таблиц

shardman.global_tables — список глобальных таблиц

Например:

postgres=# select * from shardman.sequence;
 seqns  | seqname | seqmin |       seqmax        | seqblk
--------+---------+--------+---------------------+--------
 public | s       |      1 | 9223372036854775807 |  65536
(1 row)

postgres=# select * from shardman.sharded_tables;
  rel  | nparts | colocated_with | relname | nspname
-------+--------+----------------+---------+---------
 16648 |     20 |                | d       | public
 16741 |     20 |          16648 | c       | public
(2 rows)

postgres=# select * from shardman.global_tables;
 relid | main_rgid | relname | nspname
-------+-----------+---------+---------
 16636 |           | g       | public
(1 row)

C.6.2. Как мне выполнить SQL-команду на всех узлах в кластере?

Для этого используйте функцию shardman.broadcast_all_sql и параметр shardmanctl forall. Например:

postgres$ shardmanctl forall --sql "select name,setting from pg_settings where name = 'max_connections'"
SQL: select name,setting from pg_settings where name = 'max_connections'
Node 1 says:
[max_connections 90]
Node 2 says:
[max_connections 90]

C.6.3. Как получить параметры конфигурации Shardman на выбранном узле?

Стандартную команду SHOW можно использовать для получения уникальных параметров Shardman, которые перечислены в section.

Кроме того, можно использовать команду shardmanctl config get для получения конфигурации кластера из etcd. Можно ознакомиться с параметрами этой команды, но настраивать их рекомендуется только после консультации с инженерами Posgres Pro.

C.6.4. Как обновить параметры конфигурации Shardman?

Можно использовать функцию shardmanctl config update, см. пример.

C.7. Требования к катастрофоустойчивому кластеру

Описываемая функциональность находится в разработке. Для внедрения в промышленную эксплуатацию обратитесь в поддержку.

C.7.1. Основные понятия и сокращения

БД — база данных.

СУБД — система управления базами данных.

ЦОД — центр обработки данных.

ОЦОД — основной центр обработки данных.

РЦОД — резервный центр обработки данных.

ОУК — отказоустойчивый кластер.

КУК — катастрофоустойчивый кластер.

C.7.2. Общее описание решения

В ОЦОД заказчика размещаются основные сегменты кластера и кластер etcd. Сегмент представляет собой отказоустойчивый кластер из двух узлов с экземплярами СУБД Postgres Pro, один из которых в режиме ведущего, а другой в режиме синхронного резервного. На каждом узле сегмента запущена служба shardmand , которая проверяет экземпляры СУБД Postgres Pro и обменивается информацией с кластером etcd, обеспечивая кластеризацию Shardman. Кластер etcd состоит из трёх узлов, тем самым обеспечивая кворум.

Для обеспечения катастрофоустойчивости в РЦОД заказчика размещается кластер с идентичной конфигурацией и набором компонентов. По умолчанию узлы СУБД резервного кластера Shardman выключены. Непрерывная доставка журналов из ОЦОД в РЦОД осуществляется в асинхронном режиме. При этом используется протокол физической репликации с помощью утилиты pg_receivewal из стандартной поставки СУБД Shardman. Она записывает WAL в стандартный каталог экземпляра $PGDATA/pg_wal. Управление утилитой обеспечивается кластерным программным обеспечением. Узлы СУБД резервного кластера Shardman запускаются службой shardmand, когда обнаруживается точка синхронизации в резервном etcd кластере, в результате чего осуществляется синхронизация изменений WAL до LSN, полученного из точки синхронизации. Кластеры etcd в разных ЦОД изолированы друг от друга, в связи с этим передача информации о появлении новой точки синхронизации осуществляется скриптом периодически на стороне ОЦОД в etcd РЦОД.

C.7.3. Топология репликации

Потоковая физическая репликация обеспечивается в следующих случаях:

Между узлами сегментов СУБД Postgres Pro в ОЦОД (синхронная)

Между узлами сегментов СУБД Postgres Pro в РЦОД (синхронная)

Между узлами сегментов СУБД Postgres Pro разных ЦОД (асинхронная)

C.7.4. Требования к оборудованию и сети

В ОЦОД и РЦОД оборудование должно быть идентичным по системным ресурсам и конфигурации для всех компонентов катастрофоустойчивого кластера.

Связанность сети между ЦОД должна обеспечиваться прямой оптоволоконной линией. Пропускная способность канала должна быть не менее 20 Гбит/с. Также необходимо предусмотреть резервный канал.

C.7.5. Механизмы репликации

Для обеспечения работы ОУК/КУК Shardman используется встроенный в Postgres Pro протокол потоковой физической репликации. Репликация на РЦОД асинхронная.

Автоматическое восстановление ОУК Shardman после сбоя обеспечивается кластерным программным обеспечением.

Восстановление КУК после сбоя предусмотрено только в ручном полуавтоматическом режиме.

C.7.6. Мониторинг и управление

Мониторинг и управление кластером Shardman в рамках ЦОДа обеспечивается с помощью утилиты shardmanctl.

C.7.7. Безопасность

C.7.7.1. Шифрование данных при передаче (TLS/SSL)

Требуется обеспечить защищённый канал между ЦОДами.

C.7.7.2. Аутентификация и авторизация между узлами

Аутентификация между узлами обеспечивается штатными средствами СУБД Postgres Pro.

C.7.7.3. Защита от несанкционированного доступа к резервным серверам

Защита от несанкционированного доступа к резервным серверам обеспечивается средствами ОС и сети.

C.7.8. Тестирование и откат

Рекомендуется периодически производить тестовое переключение.

C.7.8.1. Проверка целостности данных после аварийного переключения

Проверка целостности данных после аварийного переключения обеспечивается утилитой резервного копирования shardmanctl probackup.

C.7.8.2. Переключение на РЦОД

При отказе основного ЦОД, администратор убеждается в его недоступности и инициирует процедуру повышения резервных узлов до состояния рабочих. Для этого резервный кластер переводится из режима standby в режим master. Данная операция осуществляются централизованно с помощью командной утилиты shardmanctl, никаких дополнительных ручных операций не требуется.

C.7.8.3. Восстановление ОЦОД

Для восстановления географически удалённых узлов в ОЦОД требуется создать резервную копию основного кластера и восстановить её на данные узлы. Резервная копия может быть создана любым способом – холодная РК, РК с использованием репозитория pg_probackup. Каждый из этих способов подразумевает перенос резервной копии в ОЦОД. После восстановления каталога БД из резервной копии, запускается pg_receivewal, который подключается к специально созданному слоту репликации ведущего или резервного сегмента в РЦОД и начинает приём WAL сегментов в асинхронном режиме, записывая их сразу в каталог $PGDATA/pg_wal основного узла.

На кластере РЦОД раз в заданный интервал времени скриптом создаётся точка синхронизации, которая записывается в etcd РЦОД, а также отправляется в etcd ОЦОД. Узлы резервного кластера в ОЦОД при появлении записи о точке синхронизации в etcd проверяют, получен ли WAL, содержащий данную запись. При наличии записи в WAL на всех узлах резервного кластера в ОЦОД кластерным ПО выполняется запуск сервера СУБД в режиме восстановления с проигрыванием журналов до точки синхронизации. По достижении резервным узлом точки синхронизации применение WAL останавливается, производится проверка, что все узлы успешно применили записи, после чего сервер СУБД останавливается и повторяются цикл получения WAL, проверки наличия точки синхронизации, запуск СУБД в режиме восстановления.

C.7.8.4. Переключение обратно на ОЦОД

Чтобы переключиться обратно на ОЦОД, создаётся и переносится резервная копия кластера из РЦОД в ОЦОД, запускаются узлы в режиме резерва, после получения недостающих WAL происходит выключение узлов кластера в РЦОД и повышение узлов кластера в основном ЦОД.

C.7.9. Резервное копирование в рамках георезервирования

В рамках географически распределённой системы для кластера РЦОД необходимо предусмотреть аналогичное хранилище резервных копий, как и для ОЦОД, а также настроить регулярную синхронизацию основного хранилища в резервное.

C.7.9.1. Хранение резервных копий в географически распределённых хранилищах

Глубина хранения резервных копий определяется политикой резервного копирования.

C.7.10. Документация и регламенты

За более подробной информацией по аварийному переключению и инструкциями по штатному переключению обратитесь в поддержку Prostres Pro.

Предметный указатель

Символы

Глобальные представления для работы с системным каталогом, Глобальные представления для работы с системным каталогом

Глобальные представления для работы со статистикой, Глобальные представления для работы со статистикой

параметр конфигурации crash_info, Параметры PostgreSQL, специфичные для Shardman

параметр конфигурации crash_info_dump, Параметры PostgreSQL, специфичные для Shardman

параметр конфигурации crash_info_location, Параметры PostgreSQL, специфичные для Shardman

параметр конфигурации csn_commit_delay, Параметры PostgreSQL, специфичные для Shardman

параметр конфигурации csn_lsn_map_size, Параметры PostgreSQL, специфичные для Shardman

параметр конфигурации csn_max_shift, Параметры PostgreSQL, специфичные для Shardman

параметр конфигурации csn_max_shift_error, Параметры PostgreSQL, специфичные для Shardman

параметр конфигурации csn_snapshot_defer_time, Параметры PostgreSQL, специфичные для Shardman

параметр конфигурации enable_async_merge_append, Параметры PostgreSQL, специфичные для Shardman

параметр конфигурации enable_csn_snapshot, Параметры PostgreSQL, специфичные для Shardman

параметр конфигурации enable_custom_cache_costs, Параметры PostgreSQL, специфичные для Shardman

параметр конфигурации enable_merge_append, Параметры PostgreSQL, специфичные для Shardman

параметр конфигурации enable_non_equivalence_filters, Параметры PostgreSQL, специфичные для Shardman

параметр конфигурации enable_partition_pruning_extra, Параметры PostgreSQL, специфичные для Shardman

параметр конфигурации enable_sql_func_custom_plans, Параметры PostgreSQL, специфичные для Shardman

параметр конфигурации foreign_analyze_interval, Параметры PostgreSQL, специфичные для Shardman

параметр конфигурации foreign_join_fast_path, Параметры PostgreSQL, специфичные для Shardman

параметр конфигурации optimize_correlated_subqueries, Параметры PostgreSQL, специфичные для Shardman

параметр конфигурации optimize_row_in_expr, Параметры PostgreSQL, специфичные для Shardman

параметр конфигурации pgpro_stats.enable_inval_msgs_counters, Параметры pgpro_stats

параметр конфигурации pgpro_stats.enable_rusage_counters, Параметры pgpro_stats

параметр конфигурации pgpro_stats.enable_wait_counters, Параметры pgpro_stats

параметр конфигурации pgpro_stats.pgss_max_nodes_tracked, Параметры pgpro_stats

параметр конфигурации pgpro_stats.track_sharded, Параметры pgpro_stats

параметр конфигурации pgpro_stats.track_shardman_connections, Параметры pgpro_stats

параметр конфигурации pgpro_stats.transport_compression, Параметры pgpro_stats

параметр конфигурации port, Параметры PostgreSQL, специфичные для Shardman

параметр конфигурации postgres_fdw.additional_ordered_paths, Параметры PostgreSQL, специфичные для Shardman

параметр конфигурации postgres_fdw.enforce_foreign_join, Параметры PostgreSQL, специфичные для Shardman

параметр конфигурации postgres_fdw.estimate_as_hashjoin, Параметры PostgreSQL, специфичные для Shardman

параметр конфигурации postgres_fdw.estimate_indexscan, Параметры PostgreSQL, специфичные для Shardman

параметр конфигурации postgres_fdw.foreign_explain, Параметры PostgreSQL, специфичные для Shardman

параметр конфигурации postgres_fdw.optimize_cursors, Параметры PostgreSQL, специфичные для Shardman

параметр конфигурации postgres_fdw.remote_plan_cache, Параметры PostgreSQL, специфичные для Shardman

параметр конфигурации postgres_fdw.subplan_pushdown, Параметры PostgreSQL, специфичные для Shardman

параметр конфигурации postgres_fdw.use_twophase, Параметры PostgreSQL, специфичные для Shardman

параметр конфигурации shardman.broadcast_ddl, Параметры PostgreSQL, специфичные для Shardman

параметр конфигурации shardman.context_log, Параметры PostgreSQL, специфичные для Shardman

параметр конфигурации shardman.database, Параметры PostgreSQL, специфичные для Shardman

параметр конфигурации shardman.enable_limit_pushdown, Параметры PostgreSQL, специфичные для Shardman

параметр конфигурации shardman.gt_batch_size, Параметры PostgreSQL, специфичные для Shardman

параметр конфигурации shardman.monitor_deadlock_interval, Параметры PostgreSQL, специфичные для Shardman

параметр конфигурации shardman.monitor_dxact_interval, Параметры PostgreSQL, специфичные для Shardman

параметр конфигурации shardman.monitor_dxact_timeout, Параметры PostgreSQL, специфичные для Shardman

параметр конфигурации shardman.monitor_interval, Параметры PostgreSQL, специфичные для Shardman

параметр конфигурации shardman.monitor_trim_csnxid_map_interval, Параметры PostgreSQL, специфичные для Shardman

параметр конфигурации shardman.num_parts, Параметры PostgreSQL, специфичные для Shardman

параметр конфигурации shardman.plan_cache_mem, Параметры PostgreSQL, специфичные для Shardman

параметр конфигурации shardman.query_engine_mode, Параметры PostgreSQL, специфичные для Shardman

параметр конфигурации shardman.rgid, Параметры PostgreSQL, специфичные для Shardman

параметр конфигурации shardman.silkroad_sched_priority, Параметры PostgreSQL, специфичные для Shardman

параметр конфигурации shardman.silkworm_fetch_size, Параметры PostgreSQL, специфичные для Shardman

параметр конфигурации shardman.silkworm_sched_priority, Параметры PostgreSQL, специфичные для Shardman

параметр конфигурации shardman.silk_flow_control, Параметры PostgreSQL, специфичные для Shardman

параметр конфигурации shardman.silk_hello_timeout, Параметры PostgreSQL, специфичные для Shardman

параметр конфигурации shardman.silk_listen_ip, Параметры PostgreSQL, специфичные для Shardman

параметр конфигурации shardman.silk_max_message, Параметры PostgreSQL, специфичные для Shardman

параметр конфигурации shardman.silk_num_workers, Параметры PostgreSQL, специфичные для Shardman

параметр конфигурации shardman.silk_scheduler_mode, Параметры PostgreSQL, специфичные для Shardman

параметр конфигурации shardman.silk_set_affinity, Параметры PostgreSQL, специфичные для Shardman

параметр конфигурации shardman.silk_stream_work_mem, Параметры PostgreSQL, специфичные для Shardman

параметр конфигурации shardman.silk_tracelog, Параметры PostgreSQL, специфичные для Shardman

параметр конфигурации shardman.silk_tracelog_category, Параметры PostgreSQL, специфичные для Shardman

параметр конфигурации shardman.silk_tracepoints, Параметры PostgreSQL, специфичные для Shardman

параметр конфигурации shardman.silk_track_time, Параметры PostgreSQL, специфичные для Shardman

параметр конфигурации shardman.silk_unassigned_job_queue_size, Параметры PostgreSQL, специфичные для Shardman

параметр конфигурации shardman.silk_use_ip, Параметры PostgreSQL, специфичные для Shardman

параметр конфигурации shardman.silk_use_port, Параметры PostgreSQL, специфичные для Shardman

параметр конфигурации shardman.sync_cluster_settings, Параметры PostgreSQL, специфичные для Shardman

параметр конфигурации shardman.sync_cluster_settings_blacklist, Параметры PostgreSQL, специфичные для Shardman

параметр конфигурации shardman.sync_schema, Параметры PostgreSQL, специфичные для Shardman

параметр конфигурации shardman.trim_csnxid_map_naptime, Параметры PostgreSQL, специфичные для Shardman

параметр конфигурации track_fdw_wait_timing, Параметры PostgreSQL, специфичные для Shardman

параметр конфигурации track_xact_time, Параметры PostgreSQL, специфичные для Shardman

параметр хранения colocate_with, Параметры хранения

параметр хранения distributed_by, Параметры хранения

параметр хранения global, Параметры хранения, Параметры хранения

параметр хранения num_parts, Параметры хранения

параметр хранения partition_bounds, Параметры хранения

параметр хранения partition_by, Параметры хранения

параметры хранения, Параметры хранения, Параметры хранения

A

ALTER SEQUENCE, ALTER SEQUENCE

ALTER TABLE, ALTER TABLE

C

CREATE SEQUENCE, CREATE SEQUENCE

CREATE TABLE, CREATE TABLE

CREATE TABLESPACE, CREATE TABLESPACE

N

NETWORK, параметр команды EXPLAIN ANALYZE, Параметры EXPLAIN

R

REMOTE, параметр команды EXPLAIN, Параметры EXPLAIN

S

shardman-spec-config, sdmspec.json

shardman.am_coordinator(), Функции

shardman.attach_subpart, Функции

shardman.broadcast_all_sql, Функции

shardman.broadcast_query, Функции

shardman.broadcast_sql, Функции

shardman.create_subpart, Функции

shardman.detach_subpart, Функции

shardman.drop_subpart, Функции

shardman.get_partition_for_value, Функции

shardman.global_analyze, Функции

shardman.gv_global_tables, shardman.gv_global_tables

shardman.gv_sharded_tables, shardman.gv_sharded_tables

shardman.oldest_csn, shardman.oldest_csn

shardman.pg_indoubt_xacts, shardman.pg_indoubt_xacts

shardman.pg_stat_csn, shardman.pg_stat_csn

shardman.pg_stat_foreign_stat_bytes, shardman.pg_stat_foreign_stat_bytes

shardman.pg_stat_monitor, shardman.pg_stat_monitor

shardman.pg_stat_netusage, shardman.pg_stat_netusage

shardman.pg_stat_xact_time, shardman.pg_stat_xact_time

shardman.silk_backends, shardman.silk_backends

shardman.silk_connects, shardman.silk_connects

shardman.silk_pending_jobs, shardman.silk_pending_jobs

shardman.silk_rbc_snap, Функции

shardman.silk_routes, shardman.silk_routes

shardman.silk_routing, Функции, shardman.silk_routing

shardman.silk_state, shardman.silk_state

shardman.silk_statinfo, shardman.silk_statinfo

shardman.silk_statinfo_reset(), Функции

shardmanctl, shardmanctl

shardmand, shardmand