Поддержка Citus
Patroni делает развертывание кластеров Multi-Node Citus чрезвычайно простым.
TL;DR
Существует лишь несколько простых правил, которым необходимо следовать:
- Расширение базы данных Citus для PostgreSQL должно быть доступно на всех узлах. Абсолютно минимальная поддерживаемая версия Citus — 10.0, но для использования всех преимуществ прозрачных плановых переключений и перезапусков рабочих узлов рекомендуется как минимум Citus 11.2.
- Имя кластера (
scope) должно быть одинаковым для всех узлов Citus! - Учётные данные суперпользователя должны быть одинаковыми на координаторе и всех рабочих узлах, а
pg_hba.confдолжен разрешать доступ суперпользователя между всеми узлами. - REST API доступ должен быть разрешён с узлов-работников к координатору. E.g, учётные данные должны быть одинаковыми, и, если настроены, клиентские сертификаты с узлов-работников должны быть приняты координатором.
- Добавьте следующий раздел в
patroni.yaml:
После этого вам нужно просто запустить Patroni, и он сам займётся остальным:
- Patroni установит
bootstrap.dcs.synchronous_modeв quorum , если значение не задано явно другим образом. - Расширение citus
будет автоматически добавлено в
shared_preload_libraries. - Если
max_prepared_transactionsне задано явно в глобальной динамической конфигурации , Patroni автоматически установит его в2*max_connections. - Значение
citus.local_hostnameGUC будет скорректировано сlocalhostна значение, используемое Patroni для подключения к локальному экземпляру PostgreSQL. Значение иногда должно отличаться отlocalhost, поскольку PostgreSQL может не слушать на нём. - Узел
citus.databaseбудет автоматически создан послеCREATE EXTENSION citus. - Текущие учётные данные суперпользователя credentials
будут добавлены в таблицу
pg_dist_authinfoдля обеспечения взаимодействия между узлами. Не забудьте обновить их, если позже вы решите изменить имя пользователя/пароль/sslcert/sslkey суперпользователя! - Координирующий первичный узел автоматически обнаружит рабочие первичные узлы и добавит их в таблицу
pg_dist_nodeс использованием функцииcitus_add_node(). - Patroni также будет поддерживать
pg_dist_nodeв случае переключения при отказе/планового переключения в координирующем или рабочем кластерах.
patronictl
Координаторские и рабочие кластеры — это физически разные кластеры PostgreSQL/Patroni, которые логически объединены с помощью расширения базы данных Citus для PostgreSQL. Следовательно, в большинстве случаев невозможно управлять ими как единым целым.
Это приводит к двум основным различиям в поведении patronictl
при наличии секции patroni.yaml с citus
по сравнению со стандартным поведением:
- Параметры
listиtopologyпо умолчанию выводят всех участников формирования Citus (координаторов и рабочих). Новая колонкаGroupуказывает, к какой группе Citus они принадлежат. - Для всех команд patronictl
введён новый параметр, называемый
--group. Для некоторых команд значение по умолчанию для группы может быть взято изpatroni.yaml. Например, команда patronictl_pause по умолчанию включит режим обслуживания дляgroup, указанного в секции citus , но, например, для patronictl_switchover или patronictl_remove группа должна быть указана явно.
Пример вывода patronictl_list для кластера Citus:
postgres@coord1:~$ patronictl list demo
+ Citus cluster: demo ----------+----------------+---------+----+-------------+-----+------------+-----+
| Group | Member | Host | Role | State | TL | Receive LSN | Lag | Replay LSN | Lag |
+-------+---------+-------------+----------------+---------+----+-------------+-----+------------+-----+
| 0 | coord1 | 172.27.0.10 | Replica | running | 1 | 0/41C0368 | 0 | 0/41C0368 | 0 |
| 0 | coord2 | 172.27.0.6 | Quorum Standby | running | 1 | 0/41C0368 | 0 | 0/41C0368 | 0 |
| 0 | coord3 | 172.27.0.4 | Leader | running | 1 | | | | |
| 1 | work1-1 | 172.27.0.8 | Quorum Standby | running | 1 | 0/31D3198 | 0 | 0/31D3198 | 0 |
| 1 | work1-2 | 172.27.0.2 | Leader | running | 1 | | | | |
| 2 | work2-1 | 172.27.0.5 | Quorum Standby | running | 1 | 0/31CDFC0 | 0 | 0/31CDFC0 | 0 |
| 2 | work2-2 | 172.27.0.7 | Leader | running | 1 | | | | |
+-------+---------+-------------+----------------+---------+----+-------------+-----+------------+-----+
Если добавить параметр --group, вывод изменится следующим образом:
postgres@coord1:~$ patronictl list demo --group 0
+ Citus cluster: demo (group: 0, 7179854923829112860) -+-------------+-----+------------+-----+
| Member | Host | Role | State | TL | Receive LSN | Lag | Replay LSN | Lag |
+--------+-------------+----------------+---------+----+-------------+-----+------------+-----+
| coord1 | 172.27.0.10 | Replica | running | 1 | 0/41C0368 | 0 | 0/41C0368 | 0 |
| coord2 | 172.27.0.6 | Quorum Standby | running | 1 | 0/41C0368 | 0 | 0/41C0368 | 0 |
| coord3 | 172.27.0.4 | Leader | running | 1 | | | | |
+--------+-------------+----------------+---------+----+-------------+-----+------------+-----+
postgres@coord1:~$ patronictl list demo --group 1
+ Citus cluster: demo (group: 1, 7179854923881963547) -+-------------+-----+------------+-----+
| Member | Host | Role | State | TL | Receive LSN | Lag | Replay LSN | Lag |
+---------+------------+----------------+---------+----+-------------+-----+------------+-----+
| work1-1 | 172.27.0.8 | Quorum Standby | running | 1 | 0/31D3198 | 0 | 0/31D3198 | 0 |
| work1-2 | 172.27.0.2 | Leader | running | 1 | | | | |
+---------+------------+----------------+---------+----+-------------+-----+------------+-----+
Плановое переключение рабочего узла Citus
Когда для рабочего узла Citus выполняется плановое переключение, Citus позволяет сделать его практически прозрачным для приложения. Приложение подключается к координатору, а тот — к рабочим узлам, поэтому Citus может приостановить трафик SQL на координаторе для шардов, размещённых на рабочем узле. Затем плановое переключение выполняется, пока трафик удерживается на координаторе, и возобновляется, как только новый первичный рабочий узел будет готов принимать запросы на чтение и запись.
Пример patronictl_switchover на рабочем кластере:
postgres@coord1:~$ patronictl switchover demo
+ Citus cluster: demo ----------+----------------+---------+----+-------------+-----+------------+-----+
| Group | Member | Host | Role | State | TL | Receive LSN | Lag | Replay LSN | Lag |
+-------+---------+-------------+----------------+---------+----+-------------+-----+------------+-----+
| 0 | coord1 | 172.27.0.10 | Replica | running | 1 | 0/41C0368 | 0 | 0/41C0368 | 0 |
| 0 | coord2 | 172.27.0.6 | Quorum Standby | running | 1 | 0/41C0368 | 0 | 0/41C0368 | 0 |
| 0 | coord3 | 172.27.0.4 | Leader | running | 1 | | | | |
| 1 | work1-1 | 172.27.0.8 | Leader | running | 1 | | | | |
| 1 | work1-2 | 172.27.0.2 | Quorum Standby | running | 1 | 0/31D3198 | 0 | 0/31D3198 | 0 |
| 2 | work2-1 | 172.27.0.5 | Quorum Standby | running | 1 | 0/31CDFC0 | 0 | 0/31CDFC0 | 0 |
| 2 | work2-2 | 172.27.0.7 | Leader | running | 1 | | | | |
+-------+---------+-------------+----------------+---------+----+-------------+-----+------------+-----+
Citus group: 2
Primary [work2-2]:
Candidate ['work2-1'] []:
When should the switchover take place (e.g. 2024-08-26T08:02 ) [now]:
Current cluster topology
+ Citus cluster: demo (group: 2, 7179854924063375386) -+-------------+-----+------------+-----+
| Member | Host | Role | State | TL | Receive LSN | Lag | Replay LSN | Lag |
+---------+------------+----------------+---------+----+-------------+-----+------------+-----+
| work2-1 | 172.27.0.5 | Quorum Standby | running | 1 | 0/31CDFC0 | 0 | 0/31CDFC0 | 0 |
| work2-2 | 172.27.0.7 | Leader | running | 1 | | | | |
+---------+------------+----------------+---------+----+-------------+-----+------------+-----+
Are you sure you want to switchover cluster demo, demoting current primary work2-2? [y/N]: y
2024-08-26 07:02:40.33003 Successfully switched over to "work2-1"
+ Citus cluster: demo (group: 2, 7179854924063375386) --------+---------+------------+---------+
| Member | Host | Role | State | TL | Receive LSN | Lag | Replay LSN | Lag |
+---------+------------+---------+---------+----+-------------+---------+------------+---------+
| work2-1 | 172.27.0.5 | Leader | running | 1 | | | | |
| work2-2 | 172.27.0.7 | Replica | stopped | | unknown | unknown | unknown | unknown |
+---------+------------+---------+---------+----+-------------+---------+------------+---------+
postgres@coord1:~$ patronictl list demo
+ Citus cluster: demo ----------+----------------+---------+----+-------------+-----+------------+-----+
| Group | Member | Host | Role | State | TL | Receive LSN | Lag | Replay LSN | Lag |
+-------+---------+-------------+----------------+---------+----+-------------+-----+------------+-----+
| 0 | coord1 | 172.27.0.10 | Replica | running | 1 | 0/41C0368 | 0 | 0/41C0368 | 0 |
| 0 | coord2 | 172.27.0.6 | Quorum Standby | running | 1 | 0/41C0368 | 0 | 0/41C0368 | 0 |
| 0 | coord3 | 172.27.0.4 | Leader | running | 1 | | | | |
| 1 | work1-1 | 172.27.0.8 | Leader | running | 1 | | | | |
| 1 | work1-2 | 172.27.0.2 | Quorum Standby | running | 1 | 0/31D3198 | 0 | 0/31D3198 | 0 |
| 2 | work2-1 | 172.27.0.5 | Leader | running | 2 | | | | |
| 2 | work2-2 | 172.27.0.7 | Quorum Standby | running | 2 | 0/31CDFC0 | 0 | 0/31CDFC0 | 0 |
+-------+---------+-------------+----------------+---------+----+-------------+-----+------------+-----+
И так выглядит это со стороны координатора:
# The worker primary notifies the coordinator that it is going to execute "pg_ctl stop".
2024-08-26 07:02:38,636 DEBUG: query(BEGIN, ())
2024-08-26 07:02:38,636 DEBUG: query(SELECT pg_catalog.citus_update_node(%s, %s, %s, true, %s), (3, '172.19.0.7-demoted', 5432, 10000))
# From this moment all application traffic on the coordinator to the worker group 2 is paused.
# The old worker primary is assigned as a secondary.
2024-08-26 07:02:40,084 DEBUG: query(SELECT pg_catalog.citus_update_node(%s, %s, %s, true, %s), (7, '172.19.0.7', 5432, 10000))
# The future worker primary notifies the coordinator that it acquired the leader lock in DCS and about to run "pg_ctl promote".
2024-08-26 07:02:40,085 DEBUG: query(SELECT pg_catalog.citus_update_node(%s, %s, %s, true, %s), (3, '172.19.0.5', 5432, 10000))
# The new worker primary just finished promote and notifies coordinator that it is ready to accept read-write traffic.
2024-08-26 07:02:41,485 DEBUG: query(COMMIT, ())
# From this moment the application traffic on the coordinator to the worker group 2 is unblocked.
Вторичные узлы
Начиная с Patroni v4.0.0 вторичные узлы Citus без noloadbalance тега
также регистрируются в pg_dist_node. Однако для использования вторичных узлов в запросах только для чтения приложениям необходимо изменить citus.use_secondary_nodes
GUC.
Загляните в DCS
Кластер Citus (координатор и рабочие узлы) хранится в DCS в виде флота кластеров Patroni, логически объединённых вместе:
/service/batman/ # scope=batman
/service/batman/0/ # citus.group=0, coordinator
/service/batman/0/initialize
/service/batman/0/leader
/service/batman/0/members/
/service/batman/0/members/m1
/service/batman/0/members/m2
/service/batman/1/ # citus.group=1, worker
/service/batman/1/initialize
/service/batman/1/leader
/service/batman/1/members/
/service/batman/1/members/m3
/service/batman/1/members/m4
...
Такой подход был выбран потому, что для большинства DCS становится возможным получить весь кластер Citus с помощью одного рекурсивного запроса на чтение. Только координирующие узлы Citus читают всю дерево, поскольку им необходимо обнаружить рабочие узлы. Рабочие узлы читают только поддерево для собственной группы, а в некоторых случаях — поддерево группы координатора.
Citus на Kubernetes
Поскольку Kubernetes не поддерживает иерархические структуры, нам пришлось включить группу citus во все объекты K8s, которые создает Patroni:
batman-0-leader # the leader config map for the coordinator
batman-0-config # the config map holding initialize, config, and history "keys"
...
batman-1-leader # the leader config map for worker group 1
batman-1-config
...
I.e., шаблон имён имеет вид: ${scope}-${citus.group}-${type}.
Patroni обнаруживает все объекты Kubernetes с помощью селектора меток
, поэтому все Pods с Patroni&Citus, а также Endpoints/ConfigMaps должны иметь одинаковые метки, а Patroni необходимо настроить на их использование через параметры
Kubernetes или environment variables <kubernetes_environment>.
Несколько примеров конфигурации Patroni с использованием переменных среды Pod:
- для кластера-координатора
- для рабочего кластера из группы 2
Как вы могли заметить, в обоих примерах установлен метка citus-group. Эта метка позволяет Patroni определять объект как принадлежащий определённой группе Citus. Кроме того, существует также переменная среды PATRONI_CITUS_GROUP, значение которой совпадает со значением метки citus-group. При создании новых объектов Kubernetes — ConfigMaps или Endpoints — Patroni автоматически добавляет им метку citus-group: ${env.PATRONI_CITUS_GROUP}:
Вы можете найти полный пример развёртывания Patroni на Kubernetes с поддержкой Citus в папке kubernetes репозитория Patroni.
Для вас существуют два важных файла:
- Dockerfile.citus
- citus_k8s.yaml
Обновление Citus и обновление PostgreSQL версии
Сначала ознакомьтесь с обновлением версии Citus в документации
. В процессе имеется незначительное изменение. При выполнении обновления необходимо использовать patronictl_restart
вместо systemctl restart для перезапуска PostgreSQL.
Обновление основной версии PostgreSQL с использованием Citus требует более сложных действий. Вам необходимо объединить методы, описанные в документации Citus по обновлению основных версий, и документации Patroni по PostgreSQL major upgrade<major_upgrade>. Учитывайте, что кластер Citus состоит из множества кластеров Patroni (координаторов и рабочих узлов), и каждый из них должен быть обновлён независимо.