Поддержка Citus
Эта страница переведена при помощи нейросети GigaChat.
Patroni делает развертывание кластеров Multi-Node Citus чрезвычайно простым.
TL;DR
Есть всего несколько простых правил, которым нужно следовать:
-
Расширение базы данных
Citusдля PostgreSQL должно быть доступно на всех узлах. Абсолютная минимальная поддерживаемая версия Citus — 10.0, но, чтобы получить все преимущества от прозрачных переключений и перезапусков рабочих узлов, рекомендуется использовать как минимум Citus 11.2. -
Имя кластера (
scope) должно быть одинаковым для всех узлов Citus! -
Учетные данные суперпользователя должны быть одинаковыми на координаторе и всех рабочих узлах, а
pg_hba.confдолжен разрешать доступ суперпользователя между всеми узлами. -
Доступ к REST API должен быть разрешен с рабочих узлов на координатор. Например, учетные данные должны быть одинаковыми, и если настроено, клиентские сертификаты с рабочих узлов должны приниматься координатором.
-
Добавьте следующий раздел в
patroni.yaml:citus:
group: X # 0 для координатора и 1, 2, 3 и так далее для рабочих узлов
database: citus # должно быть одинаковым на всех узлах
После этого потребуется просто запустить Patroni, и он позаботится об остальном:
- Patroni установит
bootstrap.dcs.synchronous_modeв режимquorum, если он явно не установлен в другое значение. - Расширение
citusбудет автоматически добавлено вshared_preload_libraries. - Если
max_prepared_transactionsявно не задан в глобальной динамической конфигурации, Patroni автоматически установит его в2*max_connections. - Значение GUC
citus.local_hostnameбудет изменено сlocalhostна значение, которое Patroni использует для подключения к локальному экземпляру PostgreSQL. Это значение иногда должно отличаться отlocalhost, потому что PostgreSQL может не прослушивать этот адрес. - База данных
citus.databaseбудет автоматически создана, за ней последует выполнениеCREATE EXTENSION citus. - Текущие учетные данные суперпользователя будут добавлены в таблицу
pg_dist_authinfoдля обеспечения межузловой связи. Необходимо обновить их, если позже будет решено изменить имя пользователя, пароль, sslcert или sslkey суперпользователя! - Первичный узел координатора автоматически обнаружит первичные рабочие узлы и добавит их в таблицу
pg_dist_nodeс помощью функцииcitus_add_node(). - Patroni также будет поддерживать актуальность
pg_dist_nodeв случае, если на кластерах координатора или рабочих узлов происходит failover/switchover.
patronictl
Кластеры координатора и рабочих узлов физически представляют собой разные кластеры PostgreSQL/Patroni, которые логически объединены с помощью расширения базы данных Citus для PostgreSQL. Поэтому в большинстве случаев управлять ими как единым целым невозможно.
Это приводит к двум основным отличиям в поведении patronictl, когда в patroni.yaml присутствует раздел citus, по сравнению с обычным случаем:
- Команды
listиtopologyпо умолчанию выводят всех участников формирования Citus (координаторы и рабочие узлы). Новый столбецGroupуказывает, к какой группе Citus они принадлежат. - Для всех команд
patronictlвведена новая опция--group. Для некоторых команд значение группы по умолчанию может браться изpatroni.yaml. Например, :ref:patronictl_pauseпо умолчанию включит режим обслуживания дляgroup, заданного в разделеcitus, но, например, для :ref:patronictl_switchoverили :ref: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 | <IP-address> | Replica | running | 1 | 0/41C0368 | 0 | 0/41C0368 | 0 |
| 0 | coord2 | <IP-address> | Quorum Standby | running | 1 | 0/41C0368 | 0 | 0/41C0368 | 0 |
| 0 | coord3 | <IP-address> | Leader | running | 1 | | | | |
| 1 | work1-1 | <IP-address> | Quorum Standby | running | 1 | 0/31D3198 | 0 | 0/31D3198 | 0 |
| 1 | work1-2 | <IP-address> | Leader | running | 1 | | | | |
| 2 | work2-1 | <IP-address> | Quorum Standby | running | 1 | 0/31CDFC0 | 0 | 0/31CDFC0 | 0 |
| 2 | work2-2 | <IP-address> | 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 | <IP-address> | Replica | running | 1 | 0/41C0368 | 0 | 0/41C0368 | 0 |
| coord2 | <IP-address> | Quorum Standby | running | 1 | 0/41C0368 | 0 | 0/41C0368 | 0 |
| coord3 | <IP-address> | 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 | <IP-address> | Quorum Standby | running | 1 | 0/31D3198 | 0 | 0/31D3198 | 0 |
| work1-2 | <IP-address> | Leader | running | 1 | | | | |
+---------+--------------+----------------+---------+----+-------------+-----+------------+-----+
Переключение (switchover) рабочего узла 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 | <IP-address> | Replica | running | 1 | 0/41C0368 | 0 | 0/41C0368 | 0 |
| 0 | coord2 | <IP-address> | Quorum Standby | running | 1 | 0/41C0368 | 0 | 0/41C0368 | 0 |
| 0 | coord3 | <IP-address> | Leader | running | 1 | | | | |
| 1 | work1-1 | <IP-address> | Leader | running | 1 | | | | |
| 1 | work1-2 | <IP-address> | Quorum Standby | running | 1 | 0/31D3198 | 0 | 0/31D3198 | 0 |
| 2 | work2-1 | <IP-address> | Quorum Standby | running | 1 | 0/31CDFC0 | 0 | 0/31CDFC0 | 0 |
| 2 | work2-2 | <IP-address> | 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 | <IP-address> | Quorum Standby | running | 1 | 0/31CDFC0 | 0 | 0/31CDFC0 | 0 |
| work2-2 | <IP-address> | 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 | <IP-address> | Leader | running | 1 | | | | |
| work2-2 | <IP-address> | 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 | <IP-address> | Replica | running | 1 | 0/41C0368 | 0 | 0/41C0368 | 0 |
| 0 | coord2 | <IP-address> | Quorum Standby | running | 1 | 0/41C0368 | 0 | 0/41C0368 | 0 |
| 0 | coord3 | <IP-address> | Leader | running | 1 | | | | |
| 1 | work1-1 | <IP-address> | Leader | running | 1 | | | | |
| 1 | work1-2 | <IP-address> | Quorum Standby | running | 1 | 0/31D3198 | 0 | 0/31D3198 | 0 |
| 2 | work2-1 | <IP-address> | Leader | running | 2 | | | | |
| 2 | work2-2 | <IP-address> | Quorum Standby | running | 2 | 0/31CDFC0 | 0 | 0/31CDFC0 | 0 |
+-------+---------+--------------+----------------+---------+----+-------------+-----+------------+-----+
А вот как это выглядит со стороны координатора:
# Первичный рабочий узел уведомляет координатор, что собирается выполнить "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))
# С этого момента весь трафик приложения на координаторе к рабочей группе 2 приостанавливается.
# Старый первичный рабочий узел назначается как вторичный.
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))
# Будущий первичный рабочий узел уведомляет координатор, что он захватил блокировку лидера в DCS и собирается выполнить "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))
# Новый первичный рабочий узел только что завершил promote и уведомляет координатор, что готов принимать трафик на чтение-запись.
2024-08-26 07:02:41,485 DEBUG: query(COMMIT, ())
# С этого момента трафик приложения на координаторе к рабочей группе 2 разблокируется.
Вторичные узлы
Начиная с Patroni v4.0.0, вторичные узлы Citus без тега noloadbalance также регистрируются в pg_dist_node. Однако для использования вторичных узлов для запросов только на чтение приложениям необходимо изменить GUC citus.use_secondary_nodes.
Внутри DCS
Кластер Citus (координатор и рабочие узлы) хранится в DCS как флот кластеров Patroni, логически сгруппированных вместе:
/service/batman/ # scope=batman
/service/batman/0/ # citus.group=0, координатор
/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, рабочий узел
/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 # ConfigMap лидера для координатора
batman-0-config # ConfigMap, содержащий "ключи" initialize, config и history
batman-1-leader # ConfigMap лидера для рабочей группы 1
batman-1-config
То есть шаблон именования: ${scope}-${citus.group}-${type}.
Все объекты Kubernetes обнаруживаются Patroni с помощью label selector, поэтому все Pod с Patroni и Citus и Endpoints/ConfigMaps должны иметь схожие метки, а Patroni должен быть настроен на их использование с помощью настроек Kubernetes или переменных окружения.
Пара примеров конфигурации Patroni с использованием переменных окружения Pod:
-
Для кластера координатора:
apiVersion: v1
kind: Pod
metadata:
labels:
application: patroni
citus-group: "0"
citus-type: coordinator
cluster-name: citusdemo
name: citusdemo-0-0
namespace: default
spec:
containers:
- env:
- name: PATRONI_SCOPE
value: citusdemo
- name: PATRONI_NAME
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: metadata.name
- name: PATRONI_KUBERNETES_POD_IP
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: status.podIP
- name: PATRONI_KUBERNETES_NAMESPACE
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: metadata.namespace
- name: PATRONI_KUBERNETES_LABELS
value: '{application: patroni}'
- name: PATRONI_CITUS_DATABASE
value: citus
- name: PATRONI_CITUS_GROUP
value: "0" -
Для кластера рабочих узлов из группы 2:
apiVersion: v1
kind: Pod
meta
labels:
application: patroni
citus-group: "2"
citus-type: worker
cluster-name: citusdemo
name: citusdemo-2-0
namespace: default
spec:
containers:
- env:
- name: PATRONI_SCOPE
value: citusdemo
- name: PATRONI_NAME
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: metadata.name
- name: PATRONI_KUBERNETES_POD_IP
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: status.podIP
- name: PATRONI_KUBERNETES_NAMESPACE
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: metadata.namespace
- name: PATRONI_KUBERNETES_LABELS
value: '{application: patroni}'
- name: PATRONI_CITUS_DATABASE
value: citus
- name: PATRONI_CITUS_GROUP
value: "2"
Как можно заметить, в обоих примерах установлена метка citus-group. Эта метка позволяет Patroni идентифицировать объект как принадлежащий определенной группе Citus. В дополнение к этому существует также переменная окружения PATRONI_CITUS_GROUP, которая имеет то же значение, что и метка citus-group. Когда Patroni создает новые объекты Kubernetes — ConfigMaps или Endpoints — он автоматически добавляет на них метку citus-group: ${env.PATRONI_CITUS_GROUP}:
apiVersion: v1
kind: ConfigMap
meta
name: citusdemo-0-leader # Генерируется как ${env.PATRONI_SCOPE}-${env.PATRONI_CITUS_GROUP}-leader
labels:
application: patroni # Устанавливается из ${env.PATRONI_KUBERNETES_LABELS}
cluster-name: citusdemo # Автоматически устанавливается из ${env.PATRONI_SCOPE}
citus-group: '0' # Автоматически устанавливается из ${env.PATRONI_CITUS_GROUP}
Полный пример развертывания Patroni в Kubernetes с поддержкой Citus можно найти в папке kubernetes репозитория Patroni.
Особое внимание следует уделить двум файлам:
Dockerfile.cituscitus_k8s.yaml
Обновления Citus и мажорные обновления PostgreSQL
Для обновлений Citus и мажорных обновлений PostgreSQL:
Сначала, пожалуйста, прочтите об обновлении версии Citus в документации. В процессе есть одно незначительное изменение. При выполнении обновления следует использовать patronictl_restart вместо systemctl restart для перезапуска PostgreSQL.
Мажорное обновление PostgreSQL с Citus немного сложнее. Потребуется объединить техники, используемые в документации Citus о мажорных обновлениях, и документацию Patroni о мажорном обновлении PostgreSQL. Пожалуйста, имейте в виду, что кластер Citus состоит из множества кластеров Patroni (координатор и рабочие узлы), и все они должны быть обновлены независимо.