Comments 70
Попробую параллельно поднять ваш конфиг и сравнить.
Хотел сам написать, да как то руки не доходили :)
Мы использовали patroni, засунув его с postgresql в Docker контейнер.
Кстати, какие проблемы в эксплуатации выявили? Интересует именно аспект контейнеризации.
Мне кажется что для кустов микросервисов контейнеры подходят больше чем для таких тяжелых вещей.
Хотя в целом у меня с контейнерами пока и опыта богатого нет. :)
Я только пробовал подключать docker volume как Azure File System. Однако из-за отсутствия поддержки симлинков в Azure File System, постгрес не хотел работать :)
Patroni тоже выберут нового мастера, т.к. перестанет обновляться тикет в DCS.
Текущий мастер будет изолирован, и начнет отставать по базе.
После восстановления коннективити нужно будет просто перезапустить Patroni на старом мастере, и он должен штатно догнаться до слейва.
Замечание: ansible фейлит на zabbix на задаче скопировать скрипты. Их Вы не выложили в репозиторий. Если можно — выложите. Если нет, обойдемся.
Спасибо за труд!
Впрочем мне не жалко, и ничего секретного там нет. Выложил в репозиторий.
Как пример пойдет.
Теперь ругается на /etc/ansible/files/mysql/.my.cnf, так как его тоже нет. Подкиньте еще пожалуйста этот файлик, чтоб не ругался больше.
Спасибо!
«rm -rf /var/lib/pgsql/9.6/data», и перезапустить Patroni. Она сольет базу с мастера целиком.
Хотите повторить опыт Gitlab? :) Пожалуйста, НИКОГДА так не делайте. Специально для таких случаев мы придумали patronictl reinit <cluster> <node>
Эта команда абсолютна безопасна, текущий мастер просто откажется её выполнять.
Реплика-же сделает всё как нужно: Patroni вначале остановит postgres, удалит data директорию, заберёт новый pg_basebackup с мастера и снова запустит postgres.
Огромное Вам спасибо за статью от Zalando!
service: name=ntpd state=stopped enabled=no
Зачем Вы так жестоко ломаете ntp?
Текущий мастер будет изолирован, и начнет отставать по базе.
После восстановления коннективити нужно будет просто перезапустить Patroni на старом мастере, и он должен штатно догнаться до слейва.
Что если в мастер попали данные, на слейв улететь не успели и мастер потерял сеть? Один из слейвов все равно поднимется в мастер, а бывший мастер при возврате в сеть затрет уникальные данные и станет слейвом?
2) Это проблема асинхронной репликации: транзакции которые не успеют считать слейвы будут потеряны.
Именно поэтому у меня репликация синхронная, у нас такие потери недопустимы.
Синхронная репликация обеспечивает консистентность на уровне транзакций.
Недавно тут бы прекрасный был пост про CAP теорему, там эта проблема расписана в деталях.
Синхронная репликация обеспечивает консистентность на уровне транзакций.
А если ляжет слэйв, мастер продолжит выполнять транзакции?
Если совсем не будет слейвов, patroni отключит синхронную репликацию.
Вот цитата из документации:
On each HA loop iteration Patroni re-evaluates synchronous standby choice. If the current synchronous standby is connected and has not requested its synchronous status to be removed it remains picked. Otherwise the cluster member avaiable for sync that is furthest ahead in replication is picked.
Если совсем не будет слейвов, patroni отключит синхронную репликацию.
Вот это интересовало. Спасибо.
Всё верно, но скоро ещё добавим synchronous_mode_strict
.
В этом случае мастер не будет выполнять транзакции если нет synchronous standby
Но не забывайте, это поведение по умолчанию, и клиент всегда может решить что ему не нужна синхронная репликация и отключить её: SET local synchronous_commit = 'local';
В этом случае мастер не будет выполнять транзакции если нет synchronous standby
гибко регулировать можно будет? Типа из пяти слейвов в кластере минимум два должны быть с синхронной репликацией, чтобы мастер принимал транзакции?
Хорошая статья, спасибо автору. Я писал тоже про кластер postgres только с repmgr. Не рассматривали repmgr?
https://habrahabr.ru/company/etagi/blog/314000/
С Patroni подобная же схема, на мой взгляд гораздо проще и прозрачнее.
Отличная статья. Спасибо. надо попробовать.
Делали здесь
У нас таких проблем не возникало.
Я попытался сделать реализацию с 2 лбл. Если на мастере перезапустить нетворк — тогда шаред ИР станет недоступным.
Хотел бы уточнить одну вещь — в шаблоне для haproxy вижу такие строки:
server {{ patroni_node_name }} {{ patroni_node_name }}.local:5432 maxconn 300 check port 8008
server {{ patroni_node_name }} {{ patroni_node_name }}.local:5432 maxconn 300 check port 8008
server {{ patroni_node_name }} {{ patroni_node_name }}.local:5432 maxconn 300 check port 8008
Разве сюда не будет вставляться одно и то же значение 3 раза?
Поправил в репозитории на более явное определение серверов.
Нужно сделать строки соответствующие всем серверам кластера, чтобы хапрокси мог их простукивать и проксировать трафик на мастер:
backend postgres-patroni
option httpchk
http-check expect status 200
default-server inter 3s fall 3 rise 2
server cluster-pgsql-01 cluster-pgsql-01.local:5432 maxconn 300 check port 8008
server cluster-pgsql-02 cluster-pgsql-02.local:5432 maxconn 300 check port 8008
server cluster-pgsql-03 cluster-pgsql-03.local:5432 maxconn 300 check port 8008
В некоторых статьях вместе с haproxy используется pgbouncer. Есть ли смысл добавлять его в эту схему?
Скажите, в чем причина использования ядра 4 версии?
Чем не устроило дефолтное центосовское ядро?
EtcdKeyNotFound: Key not found: /service/my-db-cluster/leader
Traceback (most recent call last):
File "/usr/lib/python2.7/site-packages/patroni/dcs/consul.py", line 154, in refresh_session
return self.retry(self._do_refresh_session)
File "/usr/lib/python2.7/site-packages/patroni/dcs/consul.py", line 116, in retry
return self._retry.copy()(*args, **kwargs)
File "/usr/lib/python2.7/site-packages/patroni/utils.py", line 269, in __call__
raise RetryFailedError("Exceeded retry deadline")
RetryFailedError: 'Exceeded retry deadline'
2017-09-07 18:47:05,073 INFO: waiting on consul
2017-09-07 18:47:20,057 ERROR: refresh_session
INFO: waiting on consul
Поэтому решение с Patroni достаточно мутное, хотите нормальный PostgreSQL кластер не лепите велосипед, надо брать Postgres Pro Enterprise.
# cat /etc/patroni/postgres.yml
name: db01
scope: &scope db
consul:
host: 127.0.0.1:8500
restapi:
listen: 0.0.0.0:8080
connect_address: 172.16.128.70:8080
auth: 'username:test'
bootstrap:
dcs:
ttl: &ttl 30
loop_wait: &loop_wait 10
maximum_lag_on_failover: 1048576 # 1 megabyte in bytes
postgresql:
use_pg_rewind: true
use_slots: true
parameters:
archive_mode: "on"
wal_level: hot_standby
archive_command: mkdir -p ../wal_archive && cp %p ../wal_archive/%f
max_wal_senders: 10
wal_keep_segments: 8
archive_timeout: 1800s
max_replication_slots: 5
hot_standby: "on"
wal_log_hints: "on"
pg_hba: # Add following lines to pg_hba.conf after running 'initdb'
- host replication replicator 172.16.0.0/12 md5
- host all all 0.0.0.0/0 md5
postgresql:
listen: 0.0.0.0:5432
connect_address: 172.16.128.70:5432
data_dir: /var/lib/pgsql/9.6/data
pg_rewind:
username: superuser
password: test
pg_hba:
- host all all 0.0.0.0/0 md5
- hostssl all all 0.0.0.0/0 md5
replication:
username: replicator
password: test
network: 172.16.0.0/12
superuser:
username: superuser
password: test
admin:
username: admin
password: test
restore: /usr/bin/patroni_wale_restore
# netstat -nap | grep consul
tcp 0 0 127.0.0.1:8400 0.0.0.0:* LISTEN 2737/consul
tcp 0 0 127.0.0.1:8500 0.0.0.0:* LISTEN 2737/consul
tcp 0 0 127.0.0.1:8600 0.0.0.0:* LISTEN 2737/consul
tcp6 0 0 :::8300 :::* LISTEN 2737/consul
tcp6 0 0 :::8301 :::* LISTEN 2737/consul
tcp6 0 0 :::8302 :::* LISTEN 2737/consul
udp 0 0 127.0.0.1:8600 0.0.0.0:* 2737/consul
udp6 0 0 :::8301 :::* 2737/consul
udp6 0 0 :::8302 :::* 2737/consul
unix 3 [ ] STREAM CONNECTED 83481 2737/consul
Вот что journalctl говорит по поводу consul:
Sep 11 15:09:23 db01.localdomain consul[2737]: 2017/09/11 15:09:23 [ERR] agent: failed to sync remote state: No cluster leader
Sep 11 15:09:27 db01.localdomain consul[2737]: 2017/09/11 15:09:27 [ERR] agent: coordinate update error: No cluster leader
Sep 11 15:09:44 db01.localdomain consul[2737]: 2017/09/11 15:09:44 [ERR] agent: coordinate update error: No cluster leader
Sep 11 15:09:52 db01.localdomain consul[2737]: 2017/09/11 15:09:52 [ERR] agent: failed to sync remote state: No cluster leader
# consul members
Node Address Status Type Build Protocol DC
db01.localdomain 172.16.128.70:8301 alive server 0.6.4 2 dc1
Мне всё-таки очень интересно запустить этот «автомат» master-slave.
У меня такое ощущение судя по либам patroni, что он сам должен был с consul'ом разобраться
Проблема не в Patroni, а в Consul, он конечно запущен (процесс живой) и даже порт слушает, но при этом неконсистентен и Patroni не может в него ничего записать ни прочитать из него.
К сожалению с кластеризацией Consul я вряд-ли смогу помочь.
Рекомендую на счёт Consul почитать: https://www.consul.io/docs/guides/bootstrapping.html и https://www.consul.io/intro/getting-started/join.html
P.S. обычно выбирают тот DCS кластер которого уже настроен и работает.
Думаю что да, но есть несколько тонкостей:
- Во первых надо запустить Consul кластер на 3 хостах (иначе не будет HA)
- Consul agent должен работать на всех машинах где планируется запускать Patroni + Postgres. При этом этот агент не обязательно должен участвовать в кворуме.
- Patroni использует Consul исключительно как KV Store.
Может лучше попробовать etcd? Там кластеризация в 100 раз проще: https://github.com/coreos/etcd/blob/master/Documentation/op-guide/clustering.md#static
Если планируется запускать больше двух нод с Patroni+Postgres, то можно попробовать https://github.com/zalando/patroni/pull/375, он не требует внешнего DCS
keepalived_priority должны отличаться на единицу ?
Кластер PostgreSQL высокой надежности на базе Patroni, Haproxy, Keepalived