Восстановление кластера ETCD - с примером: различия между версиями

Материал из support.qbpro.ru
(Новая страница: «==ВВЕДЕНИЕ== * Предполагаем несколько аварийных ситуаций где используется ETCD + Patroni + PostgreSQL/PRO * В данной статье рассматривается решение проблем конкретно ETCD, а Patroni + PostgreSQL/PRO - являются сопутствующим ПО. * Данные которые хранит ETCD - используются дальше в Patroni...»)
 
 
(не показаны 2 промежуточные версии этого же участника)
Строка 9: Строка 9:


==РАБОТА С ПРОБЛЕМАМИ==
==РАБОТА С ПРОБЛЕМАМИ==
1. '''Пример:''' Потеря одного участника в кластере, база данных etcd испорчена, бакапа - нет.<br>
1. '''Пример:''' Потеря одного участника в кластере, база данных '''etcd''' испорчена, '''бакапа''' - нет.<br>
* На арбитре делаем запрос состояния кластера:
* На арбитре делаем запрос состояния кластера:
  ETCDCTL_API=2 etcdctl cluster-health
  ETCDCTL_API=2 etcdctl cluster-health
Строка 18: Строка 18:


* Пояснение:
* Пояснение:
  ptrcs1 - арбитр
  '''ptrcs1''' - арбитр
  ptrpg1 - нода1
  '''ptrpg1''' - нода1
  ptrpg2 - нода2
  '''ptrpg2''' - нода2
* Посмотреть историю обмена ключами:
* Посмотреть историю обмена ключами:
  <nowiki>ETCDCTL_API=2 etcdctl get /data/cspgpro/history|sed 's/\,/\n/g'|sed 's/\[//;s/\[//;s/\]]//;s/\]//'</nowiki>
  <nowiki>ETCDCTL_API=2 etcdctl get /data/cspgpro/history|sed 's/\,/\n/g'|sed 's/\[//;s/\[//;s/\]]//;s/\]//'</nowiki>
Строка 65: Строка 65:
  <nowiki>edbaafd55c6a0b67: name=ptrpg2 peerURLs=http://ptrpg2.local.int:2380 clientURLs=http://ptrpg2.local.int:2379 isLeader=false</nowiki>
  <nowiki>edbaafd55c6a0b67: name=ptrpg2 peerURLs=http://ptrpg2.local.int:2380 clientURLs=http://ptrpg2.local.int:2379 isLeader=false</nowiki>


* ВЫВОД: Исходное состояние кластера - в рабочем состоянии, все участники присутствуют и идет обмен ключами.  
* '''ВЫВОД''': Исходное состояние кластера - в рабочем состоянии, все участники присутствуют и идет обмен ключами.  
* Теперь создаем прецедент - вторая нода ptrpg2 - теряется из кластера etcd, архива базы нет:
* Теперь создаем прецедент - вторая нода '''ptrpg2''' - теряется из кластера '''etcd''', архива базы нет:
** на ноде ptrpg2 останавливаем patroni, etcd и удаляем базу etcd (/var/lib/etcd/default/member)
** на ноде '''ptrpg2''' останавливаем '''patroni''', '''etcd''' и удаляем базу '''etcd''' (/var/lib/etcd/default/member)
  systemctl stop patroni
  systemctl stop patroni
  systemctl stop etcd
  systemctl stop etcd
  rm -r /var/lib/etcd/default/member/*
  rm -r /var/lib/etcd/default/member/*
* На арбитре ptrcs1 смотрим состояние кластера:
* На арбитре '''ptrcs1''' смотрим состояние кластера:
  ETCDCTL_API=2 etcdctl cluster-health
  ETCDCTL_API=2 etcdctl cluster-health
** Результат:
** Результат:
Строка 80: Строка 80:
  <nowiki>http://ptrpg2.local.int:2379] are all unreachable</nowiki>
  <nowiki>http://ptrpg2.local.int:2379] are all unreachable</nowiki>
  ...
  ...
** Видно, что нода2 (ptrpg2) - стала недоступна...
** Видно, что '''нода2''' ('''ptrpg2''') - стала недоступна...
Запуск etcd на ptrpg2 - ни чего не даст, кроме ошибок..<br>
Запуск '''etcd''' на '''ptrpg2''' - ни чего не даст, кроме ошибок..<br>
Поэтому для корректного восстановления нужно на арбитре, который сейчас является Leader - удалить ключ ptrpg2,<br>
Поэтому для корректного восстановления нужно на арбитре, который сейчас является '''Leader''' - удалить ключ '''ptrpg2''',<br>
или попросту убрать ноду из кластера и после этого снова ее добавить, не трогая при этом patroni!
или попросту убрать ноду из кластера и после этого снова ее добавить, не трогая при этом '''patroni'''!
* На арбитре (который сейчас Leader) ptrcs1 - удаляем ноду:
* На арбитре (который сейчас '''Leader''') '''ptrcs1''' - удаляем ноду:
  ETCDCTL_API=3 etcdctl --user="root" member remove '''edbaafd55c6a0b67'''
  ETCDCTL_API=3 etcdctl --user="root" member remove '''edbaafd55c6a0b67'''
** Команда выполняется с авторизацией и потребует сообщить пароль пользователя root (etcd)
** Команда выполняется с авторизацией и потребует сообщить пароль пользователя '''root''' (etcd)
* Проверяем состояние кластера:
* Проверяем состояние кластера:
  ETCDCTL_API=2 etcdctl cluster-health
  ETCDCTL_API=2 etcdctl cluster-health
Строка 95: Строка 95:
  ...
  ...
** Видно что в списке нет '''ptrpg2'''!
** Видно что в списке нет '''ptrpg2'''!
* Теперь нужно заново добавить ptrpg2 в кластер, перед выполнением добавления, на ptrpg2 - etcd должен быть выключен!
* Теперь нужно заново добавить '''ptrpg2''' в кластер, перед выполнением добавления, на '''ptrpg2''' - '''etcd''' должен быть выключен!
** На ptrcs1 выполняем команду добавления:
** На '''ptrcs1''' выполняем команду добавления:
  ETCDCTL_API=3 etcdctl --user="root" --endpoints=ptrcs1.local.int:2379,ptrpg1.local.int:2379 member add ptrpg2 --peer-<nowiki>urls=http://ptrpg2.local.int:2380</nowiki>
  ETCDCTL_API=3 etcdctl --user="root" --endpoints=ptrcs1.local.int:2379,ptrpg1.local.int:2379 member add ptrpg2 --peer-<nowiki>urls=http://ptrpg2.local.int:2380</nowiki>
** Результат:
** Результат:
Строка 106: Строка 106:
  ETCD_INITIAL_CLUSTER_STATE="existing"  
  ETCD_INITIAL_CLUSTER_STATE="existing"  
  ...
  ...
** После этой команды, на ptrcs1 (который сейчас Leader) - etcd ждет подключения хоста ptrpg2
** После этой команды, на '''ptrcs1''' (который сейчас '''Leader''') - '''etcd''' ждет подключения хоста '''ptrpg2'''
* Запускаем третьего участника заново в кластер сначала в etcd:
* Запускаем третьего участника заново в кластер сначала в '''etcd''' - на '''ptrpg2''':
  systemctl start etcd
  systemctl start etcd
** Проверяем что он в кластере, на ptrcs1 выполняем:
** Проверяем что он в кластере, на '''ptrcs1''' выполняем:
  ETCDCTL_API=2 etcdctl cluster-health
  ETCDCTL_API=2 etcdctl cluster-health
** Результат:
** Результат:
Строка 118: Строка 118:
  ...
  ...
** Как видно все участники в кластере.
** Как видно все участники в кластере.
* Теперь на ptrpg2 - запускаем patroni:
* Теперь на '''ptrpg2''' - запускаем '''patroni''':
  systemctl start patroni
  systemctl start patroni
** Проверяем ptroni:
** Проверяем '''patroni''':
  patronictl -c /etc/patroni/patronictl.yml list
  patronictl -c /etc/patroni/patronictl.yml list
** Результат:
** Результат:
Строка 126: Строка 126:
  | Member  | Host              | Role    | State  | TL | Lag in MB |
  | Member  | Host              | Role    | State  | TL | Lag in MB |
  +---------+-------------------+---------+---------+----+-----------+
  +---------+-------------------+---------+---------+----+-----------+
  | ptrpg1 | ptrpg1.local.int | Leader  | running | 11 |          |
  | ptrpg1 | ptrpg1.local.int | Leader  | running | 11 |          |
  | ptrpg2 | ptrpg2.local.int | Replica | running | 11 |        0 |
  | ptrpg2 | ptrpg2.local.int | Replica | running | 11 |        0 |
  +---------+-------------------+---------+---------+----+-----------+
  +---------+-------------------+---------+---------+----+-----------+
  ...
  ...
** Как видно кластер работает и идет синхронизация без ошибок.
** Как видно кластер работает и идет синхронизация без ошибок.
<br>
<br>
==ДОПОЛНИТЕЛЬНО==
==ДОПОЛНИТЕЛЬНО==

Текущая версия от 16:40, 9 октября 2025

ВВЕДЕНИЕ

  • Предполагаем несколько аварийных ситуаций где используется ETCD + Patroni + PostgreSQL/PRO
  • В данной статье рассматривается решение проблем конкретно ETCD, а Patroni + PostgreSQL/PRO - являются сопутствующим ПО.
  • Данные которые хранит ETCD - используются дальше в Patroni + PostgreSQL/PRO для обмена и взаимодействия между участниками кластера.
  • Схема стенда кластера:


ClusterPG.png

РАБОТА С ПРОБЛЕМАМИ

1. Пример: Потеря одного участника в кластере, база данных etcd испорчена, бакапа - нет.

  • На арбитре делаем запрос состояния кластера:
ETCDCTL_API=2 etcdctl cluster-health
    • Результат:
member c410a7d6456910ab is healthy: got healthy result from http://ptrcs1.local.int:2379
member e59a90ef17ed6871 is healthy: got healthy result from http://ptrpg1.local.int:2379
member '''edbaafd55c6a0b67''' is healthy: got healthy result from http://ptrpg2.local.int:2379
  • Пояснение:
ptrcs1 - арбитр
ptrpg1 - нода1
ptrpg2 - нода2
  • Посмотреть историю обмена ключами:
ETCDCTL_API=2 etcdctl get /data/cspgpro/history|sed 's/\,/\n/g'|sed 's/\[//;s/\[//;s/\]]//;s/\]//'
    • Результат:
...
1
21133688
"no recovery target specified"
"2025-09-24T02:43:00.783823+03:00"
"ptrpg2"
2
50333648
"no recovery target specified"
"2025-09-24T03:03:11.812345+03:00"
"ptrpg1"
3
50333984
"no recovery target specified"
"2025-09-24T19:37:33.206983+03:00"
"ptrpg2"
...
  • Посмотреть все ключи кластера:
ETCDCTL_API=2 etcdctl ls  --recursive
    • Результат:
...
/data
/data/cspgpro
/data/cspgpro/config
/data/cspgpro/failover
/data/cspgpro/failsafe
/data/cspgpro/history
/data/cspgpro/initialize
/data/cspgpro/leader
/data/cspgpro/members
/data/cspgpro/members/ptrpg2
/data/cspgpro/members/ptrpg1
/data/cspgpro/status
...
  • Смотрим кто сейчас является Leader, так как любое внесение изменений делается от него:
ETCDCTL_API=2 etcdctl member list
    • Результат:
c410a7d6456910ab: name=ptrcs1 peerURLs=http://ptrcs1.local.int:2380 clientURLs=http://ptrcs1.local.int:2379 isLeader=true'
e59a90ef17ed6871: name=ptrpg1 peerURLs=http://ptrpg1.local.int:2380 clientURLs=http://ptrpg1.local.int:2379 isLeader=false
edbaafd55c6a0b67: name=ptrpg2 peerURLs=http://ptrpg2.local.int:2380 clientURLs=http://ptrpg2.local.int:2379 isLeader=false
  • ВЫВОД: Исходное состояние кластера - в рабочем состоянии, все участники присутствуют и идет обмен ключами.
  • Теперь создаем прецедент - вторая нода ptrpg2 - теряется из кластера etcd, архива базы нет:
    • на ноде ptrpg2 останавливаем patroni, etcd и удаляем базу etcd (/var/lib/etcd/default/member)
systemctl stop patroni
systemctl stop etcd
rm -r /var/lib/etcd/default/member/*
  • На арбитре ptrcs1 смотрим состояние кластера:
ETCDCTL_API=2 etcdctl cluster-health
    • Результат:
member c410a7d6456910ab is healthy: got healthy result from http://ptrcs1.local.int:2379
member e59a90ef17ed6871 is healthy: got healthy result from http://ptrpg1.local.int:2379
failed to check the health of member edbaafd55c6a0b67 on http://ptrpg2.local.int:2379: Get 
"http://ptrpg2.local.int:2379/health": dial tcp 10.9.9.175:2379: i/o timeout member edbaafd55c6a0b67 is unreachable: 
http://ptrpg2.local.int:2379] are all unreachable
...
    • Видно, что нода2 (ptrpg2) - стала недоступна...

Запуск etcd на ptrpg2 - ни чего не даст, кроме ошибок..
Поэтому для корректного восстановления нужно на арбитре, который сейчас является Leader - удалить ключ ptrpg2,
или попросту убрать ноду из кластера и после этого снова ее добавить, не трогая при этом patroni!

  • На арбитре (который сейчас Leader) ptrcs1 - удаляем ноду:
ETCDCTL_API=3 etcdctl --user="root" member remove edbaafd55c6a0b67
    • Команда выполняется с авторизацией и потребует сообщить пароль пользователя root (etcd)
  • Проверяем состояние кластера:
ETCDCTL_API=2 etcdctl cluster-health
    • Результат:
...
member c410a7d6456910ab is healthy: got healthy result from http://ptrcs1.local.int:2379
member e59a90ef17ed6871 is healthy: got healthy result from http://ptrpg1.local.int:2379
...
    • Видно что в списке нет ptrpg2!
  • Теперь нужно заново добавить ptrpg2 в кластер, перед выполнением добавления, на ptrpg2 - etcd должен быть выключен!
    • На ptrcs1 выполняем команду добавления:
ETCDCTL_API=3 etcdctl --user="root" --endpoints=ptrcs1.local.int:2379,ptrpg1.local.int:2379 member add ptrpg2 --peer-urls=http://ptrpg2.local.int:2380
    • Результат:
Member b10724c2f8e66abd added to cluster 85466bb104b9e4e5

ETCD_NAME="ptrpg2"
ETCD_INITIAL_CLUSTER="ptrpg2=http://ptrpg2.local.int:2380,ptrcs1=http://ptrcs1.local.int:2380,ptrpg1=http://ptrpg1.local.int:2380"
ETCD_INITIAL_ADVERTISE_PEER_URLS="http://ptrpg2.local.int:2380"
ETCD_INITIAL_CLUSTER_STATE="existing" 
...
    • После этой команды, на ptrcs1 (который сейчас Leader) - etcd ждет подключения хоста ptrpg2
  • Запускаем третьего участника заново в кластер сначала в etcd - на ptrpg2:
systemctl start etcd
    • Проверяем что он в кластере, на ptrcs1 выполняем:
ETCDCTL_API=2 etcdctl cluster-health
    • Результат:
member b10724c2f8e66abd is healthy: got healthy result from http://ptrpg2.local.int:2379
member c410a7d6456910ab is healthy: got healthy result from http://ptrcs1.local.int:2379
member e59a90ef17ed6871 is healthy: got healthy result from http://ptrpg1.local.int:2379
cluster is healthy
...
    • Как видно все участники в кластере.
  • Теперь на ptrpg2 - запускаем patroni:
systemctl start patroni
    • Проверяем patroni:
patronictl -c /etc/patroni/patronictl.yml list
    • Результат:
+ Cluster: cspgpro -----------+---------+---------+----+-----------+
| Member  | Host              | Role    | State   | TL | Lag in MB |
+---------+-------------------+---------+---------+----+-----------+
| ptrpg1  | ptrpg1.local.int  | Leader  | running | 11 |           |
| ptrpg2  | ptrpg2.local.int  | Replica | running | 11 |         0 |
+---------+-------------------+---------+---------+----+-----------+
...
    • Как видно кластер работает и идет синхронизация без ошибок.


ДОПОЛНИТЕЛЬНО