[PostgreSQL, DevOps] Заряжай Patroni. Тестируем Patroni + Zookeeper кластер (Часть вторая)
Автор
Сообщение
news_bot ®
Стаж: 6 лет 9 месяцев
Сообщений: 27286
Кадр из фильма «Терминатор 2: Судный день»В первой части мы остановились на том, что у нас есть отказоустойчивый кластер и теперь вроде бы все работает. Мы уже можем зайти в базу данных через лидера и что-нибудь туда записать. Последняя проблема, которую нужно решить — программно узнать, где находится лидер. Неужели нужно будет каждый раз делать эту проверку после падения, чтобы понять через какую ноду подключаться к базе?Это было бы настолько скверно, что испортило бы все решение. Но не беспокойтесь, с помощью HA Proxy вопрос решается довольно легко и незатейливо.HA ProxyТакже как с Patroni, сначала сделаем отдельную директорию под билд/деплой файлы и начнем их там создавать:
- haproxy.cfg
Это файл конфига, который мы положим в наш кастомный образ.haproxy.cfg
global
maxconn 100
stats socket /run/haproxy/haproxy.sock
stats timeout 2m # Wait up to 2 minutes for input
defaults
log global
mode tcp
retries 2
timeout client 30m
timeout connect 4s
timeout server 30m
timeout check 5s
listen stats
mode http
bind *:7000
stats enable
stats uri /
listen postgres
bind *:5000
option httpchk
http-check expect status 200
default-server inter 3s fall 3 rise 2 on-marked-down shutdown-sessions
server patroni1 patroni1:5432 maxconn 100 check port 8091
server patroni2 patroni2:5432 maxconn 100 check port 8091
server patroni3 patroni3:5432 maxconn 100 check port 8091
DetailsВ этих строчках мы назначаем порты, по которым будет получать доступ:
// этот для вывода статистики
listen stats
mode http
bind *:7000
//этот для подключения к postgres
listen postgres
bind *:5000
А здесь мы просто перечисляем все сервисы Patroni, которые создали ранее:
server patroni1 patroni1:5432 maxconn 100 check port 8091
server patroni2 patroni2:5432 maxconn 100 check port 8091
server patroni3 patroni3:5432 maxconn 100 check port 8091
И последнее. Эта строка нужна, если мы хотим проверять состояние кластера с помощью специальной утилиты из контейнера с HA Proxy:
stats socket /run/haproxy/haproxy.sock
- Dockerfile
Dockerfile выглядит довольно просто и, думаю, не требует комментариев: Dockerfile
FROM haproxy:1.7
COPY haproxy.cfg /usr/local/etc/haproxy/haproxy.cfg
RUN mkdir /run/haproxy &&\
apt-get update -y &&\
apt-get install -y hatop &&\
apt-get clean
- docker-compose-haproxy.yml
Compose файл выглядит тоже достаточно просто:docker-compose-haproxy.yml
version: "3.7"
networks:
patroni_patroni:
external: true
services:
haproxy:
image: haproxy-patroni
networks:
- patroni_patroni
ports:
- 5000:5000
- 7000:7000
hostname: haproxy
deploy:
mode: replicated
replicas: 1
placement:
constraints: [node.hostname == floitet]
Когда все файлы готовы, можно и задеплоить весь этот сет:
// build
docker build -t haproxy-patroni
// deploy
docker stack deploy --compose-file docker-compose-haproxy.yml
Когда HА Proxy запустится, можно будет в контейнере посмотреть статистику кластера специальной командой:
sudo docker ps | grep haproxy
sudo docker exec -ti $container_id /bin/bash
hatop -s /var/run/haproxy/haproxy.sock
Выполнив эти три шага, мы увидим прямо в консоли красивый вывод статистики. Сам я предпочитаю смотреть статистику через patronictl либо Patroni API, но HA Proxy тоже один из вариантов и почему бы не настроить и его заодно.А теперь немного о Patroni API.Patroni APIЯ обещал показать три способа смотреть статистику кластера, и вот добрался-таки до последнего. Вывод статистики через API хорош тем, что он дает самую полную информацию о кластере (и вообще через него можно делать всё). Более подробно почитать про API можно в доках, а здесь я покажу самые основные вещи: стандартные запросы и как их выполнить в нашем сетапе. Также как с подключением к БД, мы не сможем обращаться к API, не находясь в сети ’patroni_patroni’. Так что нам придется слать все наши запросы из контейнера. Чтобы читать вывод json в приятном человеческому глазу формате, сделаем кастомный имейдж с curl’ом и jq. Dockerfile
FROM alpine:3.10
RUN apk add --no-cache curl jq bash
CMD ["/bin/sh"]
И потом запустим контейнер с этим образом, подключив его к нужной сети:
docker run --rm -ti --network=patroni_patroni curl-jq
Теперь мы можем обращаться к API Patroni нод по их именам и получать cтаты в таком вот виде:Работа с API
// Статистика ноды
curl -s patroni1:8091/patroni | jq
{
"patroni": {
"scope": "patroni",
"version": "2.0.1"
},
"database_system_identifier": "6893104757524385823",
"postmaster_start_time": "2020-11-15 19:47:33.917 UTC",
"timeline": 10,
"xlog": {
"received_location": 100904544,
"replayed_timestamp": null,
"replayed_location": 100904544,
"paused": false
},
"role": "replica",
"cluster_unlocked": false,
"state": "running",
"server_version": 110009
}
// Статистика кластера
curl -s patroni1:8091/cluster | jq
{
"members": [
{
"port": 5432,
"host": "10.0.1.5",
"timeline": 10,
"lag": 0,
"role": "replica",
"name": "patroni1",
"state": "running",
"api_url": "http://10.0.1.5:8091/patroni"
},
{
"port": 5432,
"host": "10.0.1.4",
"timeline": 10,
"role": "leader",
"name": "patroni2",
"state": "running",
"api_url": "http://10.0.1.4:8091/patroni"
},
{
"port": 5432,
"host": "10.0.1.3",
"lag": "unknown",
"role": "replica",
"name": "patroni3",
"state": "running",
"api_url": "http://10.0.1.3:8091/patroni"
}
]
}
Как тестировать?Основная идея, что теперь мы можем ставить свои эксперименты с Patroni кластером так, как если бы это был кластер с тремя реальными серверами. Достаточно просто выключать и включать сервисы Patroni, чтобы сымитировать падения серверов. Если лидер у нас patroni3, то мы делаем:
docker service scale patroni_patroni3=0
И отключаем его, убивая его единственный контейнер. Теперь можно глянуть состояние кластера и убедиться, что лидер перешел на здоровую ноду:
postgres@patroni1:/$ patronictl -c /etc/patroni.yml list patroni
+ Cluster: patroni (6893104757524385823) --+----+-----------+
| Member | Host | Role | State | TL | Lag in MB |
+----------+-----------+---------+---------+----+-----------+
| patroni1 | 10.0.1.93 | Leader | running | 9 | |
| patroni2 | 10.0.1.91 | Replica | running | 9 | 0 |
+----------+-----------+---------+---------+----+-----------+
Если сделать scale для patroni3 на ’1′, то он вернется в кластер и займет роль реплики. Теперь вы можете запускать все тесты и проверять, как Patroni кластер будет реагировать на критические ситуации. БонусКак и обещал, ниже небольшой скрипт для тестов, а также инструкции как с ним работать. Так что, если вам нужно что-то уже готовое для быстрого теста, добро пожаловать. Если же у вас есть свои идеи и сценарии и вам не требуется готовое решение, просто пропустите спойлер. Тестируем Patroni clusterДля тех читателей, кто хочет потестировать кластер Patroni на каком-то готовом примере прямо сейчас, я сделал вот этот скрипт. Он супер простой, и я уверен у вас не возникнет проблем с тем, чтобы понять, как он работает. По сути, он просто пишет в базу текущее время каждую секунду. Ниже я шаг за шагом покажу, как его запустить и какие результаты теста были у меня.
- Шаг 1
Допустим, вы уже скачали скрипт и положили его где-то у себя на машине. Если нет, то проделайте эту подготовку. Теперь нам нужно запустить Docker контейнер с официальным образом Miscrosoft SDK такой командой:
docker run --rm -ti --network=patroni_patroni -v /home/floitet/Documents/patroni-test-script:/home mcr.microsoft.com/dotnet/sdk /bin/bash
Два момента. Первое, как и раньше мы хотим подключиться к сети ’patroni_patroni’ и второе, мы делаем mount к той директории, где уже лежит готовый скрипт. Таким образом мы сможем запускать его из контейнера.
- Шаг 2
Теперь мы хотим, чтобы у нас появился единственный dll, который нужен чтобы скрипт взлетел. Заходим в контейнер и находясь в директории ’/home’ создаем папку ’patroni-test’ для консольного приложения. Заходим в нее и выполняем следующую команду:
dotnet new console
// видим такие строчки
Processing post-creation actions...
Running 'dotnet restore' on /home/patroni-test/patroni-test.csproj...
Determining projects to restore...
Restored /home/patroni-test/patroni-test.csproj (in 61 ms).
Restore succeeded.
И теперь мы можем добавить в проект нужный нам для работы пакет:
dotnet add package npgsql
А потом просто упаковываем проект:
dotnet pack
Если все прошло удачно, то мы получим ’Npgsql.dll’ по адресу: ’patroni-test/bin/Debug/net5.0/Npgsql.dll’.Этот путь мы и добавляем как референс в скрипте, так что если у вас он отличается от моего, то в скрипте это нужно подправить. А дальше просто запускаем скрипт:
dotnet fsi /home/patroni-test.fsx
// и в output мы увидим как скрипт пошел писать время:
11/18/2020 22:29:32 +00:00
11/18/2020 22:29:33 +00:00
11/18/2020 22:29:34 +00:00
Важно не закрывать терминал со скриптом, пока идет тест.
- Шаг 3
Давайте посмотрим, где сейчас находится лидер, чтобы знать кого ронять. Можно использовать любой из трёх способов, я смотрел через patronictl:
+ Cluster: patroni (6893104757524385823) --+----+-----------+
| Member | Host | Role | State | TL | Lag in MB |
+----------+-----------+---------+---------+----+-----------+
| patroni1 | 10.0.1.18 | Replica | running | 21 | 0 |
| patroni2 | 10.0.1.22 | Leader | running | 21 | |
| patroni3 | 10.0.1.24 | Replica | running | 21 | 0 |
+----------+-----------+---------+---------+----+-----------+
Теперь нам нужно открыть новый терминал и «убить» лидера:
docker service ls | grep patroni
docker service scale $patroni2-id=0
Через какое-то время в окне со скриптом мы увидим сообщения об ошибке:
// давайте запомним время последней удачной записи
11/18/2020 22:33:06 +00:00
Error
Error
Error
Если мы проверим статус кластера, то можем заметить некоторую задержку — он всё ещё показывает patroni2 в качестве лидера. Но спустя n секунд он все-таки перестроится и, пройдя короткую стадию по выбору лидера, придет в такое состояние:
+ Cluster: patroni (6893104757524385823) --+----+-----------+
| Member | Host | Role | State | TL | Lag in MB |
+----------+-----------+---------+---------+----+-----------+
| patroni1 | 10.0.1.18 | Replica | running | 21 | 0 |
| patroni3 | 10.0.1.24 | Leader | running | 21 | |
+----------+-----------+---------+---------+----+-----------+
Если же вернемся к терминалу со скриптом, то увидим, что соединение наконец-то восстановлено и запись возобновилась:
Error
Error
Error
11/18/2020 22:33:48 +00:00
11/18/2020 22:33:49 +00:00
11/18/2020 22:33:50 +00:00
11/18/2020 22:33:51 +00:00
- Шаг 4
Теперь проверим, как там поживает сама база данных и всё ли с ней в порядке после падения лидера:
docker run --rm -ti --network=patroni_patroni postgres:11 /bin/bash
psql --host haproxy --port 5000 -U approle -d postgres
postgres=> \c patronitestdb
You are now connected to database "patronitestdb" as user "approle".
// Я установил время чуть раньше, чем произошла авария
patronitestdb=> select * from records where time > '22:33:04' limit 15;
time
-----------------
22:33:04.171641
22:33:05.205022
22:33:06.231735
// как мы видим в моем случае Patroni понадобилось 42 секунды
// чтобы восстановить соединение
22:33:48.345111
22:33:49.36756
22:33:50.374771
22:33:51.383118
22:33:52.391474
22:33:53.399774
22:33:54.408107
22:33:55.416225
22:33:56.424595
22:33:57.432954
22:33:58.441262
22:33:59.449541
Вывод по тестамИз этого небольшого эксперимента мы можем заключить, что Patroni справился со своей задачей. После того, как лидера упал, произошли перевыборы, и мы смогли подсоединиться к базе. Все предыдущие данные также оказались в целости. Возможно, мы могли бы пожелать, чтобы восстановление произошло быстрее, чем за 42 секунды, но, в конце концов, это не так критично.ПослесловиеПолагаю, на этом можно считать туториал завершенным. Надеюсь, он помог вам разобраться с основными моментами в настройке и работе с Patroni и в целом был полезен. Спасибо за внимание и да хранит Patroni ваши данные, отстреливаясь от багов и героически поднимаясь после падений!За помощь в настройке этого решения отдельное спасибо коллеге Андрею Юрченко. Без этого отзывчивого парня мои Patroni застряли бы в магазине/стволе и не убили бы ни одного врага.Все файлы использованные во второй части здесь.
===========
Источник:
habr.com
===========
Похожие новости:
- [.NET, ASP, C#, Разработка под Linux, DevOps] Как готовить Cake, используя только Frosting
- [Open source, DevOps, Kubernetes] Безопасность конфиденциальных данных с Traefik Enterprise и Vault (перевод)
- [Хостинг, Программирование, DevOps, Микросервисы] Технология Serverless: снова привет, 1970-е (перевод)
- [PostgreSQL, DevOps] Заряжай Patroni. Тестируем Patroni + Zookeeper кластер (Часть первая)
- [Java, Git, DevOps] Trunk Based Development и Spring Boot, или ветвись оно все по абстракции
- [Open source, Виртуализация, Kubernetes, Openshift] 7 вещей, которые нужно проработать, прежде чем запускать OpenShift в продакшн
- [Анализ и проектирование систем, IT-инфраструктура, DevOps] Как избежать гниения ПО (перевод)
- [DevOps, Kubernetes] k0s: Kubernetes в одном бинарном файле (перевод)
- [Системное администрирование, Карьера в IT-индустрии, DevOps] После DevOps: как стать SRE и устроиться на работу в Google
- [Информационная безопасность, Совершенный код, Управление продуктом, Софт] Строим безопасную разработку в ритейлере. Итоги одного большого проекта
Теги для поиска: #_postgresql, #_devops, #_postgresql, #_patroni, #_zookeeper, #_haproxy, #_devops, #_cluster, #_docker_swarm, #_blog_kompanii_vs_robotics (
Блог компании VS Robotics
), #_postgresql, #_devops
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 20:56
Часовой пояс: UTC + 5
Автор | Сообщение |
---|---|
news_bot ®
Стаж: 6 лет 9 месяцев |
|
Кадр из фильма «Терминатор 2: Судный день»В первой части мы остановились на том, что у нас есть отказоустойчивый кластер и теперь вроде бы все работает. Мы уже можем зайти в базу данных через лидера и что-нибудь туда записать. Последняя проблема, которую нужно решить — программно узнать, где находится лидер. Неужели нужно будет каждый раз делать эту проверку после падения, чтобы понять через какую ноду подключаться к базе?Это было бы настолько скверно, что испортило бы все решение. Но не беспокойтесь, с помощью HA Proxy вопрос решается довольно легко и незатейливо.HA ProxyТакже как с Patroni, сначала сделаем отдельную директорию под билд/деплой файлы и начнем их там создавать:
global
maxconn 100 stats socket /run/haproxy/haproxy.sock stats timeout 2m # Wait up to 2 minutes for input defaults log global mode tcp retries 2 timeout client 30m timeout connect 4s timeout server 30m timeout check 5s listen stats mode http bind *:7000 stats enable stats uri / listen postgres bind *:5000 option httpchk http-check expect status 200 default-server inter 3s fall 3 rise 2 on-marked-down shutdown-sessions server patroni1 patroni1:5432 maxconn 100 check port 8091 server patroni2 patroni2:5432 maxconn 100 check port 8091 server patroni3 patroni3:5432 maxconn 100 check port 8091 // этот для вывода статистики
listen stats mode http bind *:7000 //этот для подключения к postgres listen postgres bind *:5000 server patroni1 patroni1:5432 maxconn 100 check port 8091
server patroni2 patroni2:5432 maxconn 100 check port 8091 server patroni3 patroni3:5432 maxconn 100 check port 8091 stats socket /run/haproxy/haproxy.sock
FROM haproxy:1.7
COPY haproxy.cfg /usr/local/etc/haproxy/haproxy.cfg RUN mkdir /run/haproxy &&\ apt-get update -y &&\ apt-get install -y hatop &&\ apt-get clean
version: "3.7"
networks: patroni_patroni: external: true services: haproxy: image: haproxy-patroni networks: - patroni_patroni ports: - 5000:5000 - 7000:7000 hostname: haproxy deploy: mode: replicated replicas: 1 placement: constraints: [node.hostname == floitet] // build
docker build -t haproxy-patroni // deploy docker stack deploy --compose-file docker-compose-haproxy.yml sudo docker ps | grep haproxy
sudo docker exec -ti $container_id /bin/bash hatop -s /var/run/haproxy/haproxy.sock FROM alpine:3.10
RUN apk add --no-cache curl jq bash CMD ["/bin/sh"] docker run --rm -ti --network=patroni_patroni curl-jq
// Статистика ноды
curl -s patroni1:8091/patroni | jq { "patroni": { "scope": "patroni", "version": "2.0.1" }, "database_system_identifier": "6893104757524385823", "postmaster_start_time": "2020-11-15 19:47:33.917 UTC", "timeline": 10, "xlog": { "received_location": 100904544, "replayed_timestamp": null, "replayed_location": 100904544, "paused": false }, "role": "replica", "cluster_unlocked": false, "state": "running", "server_version": 110009 } // Статистика кластера curl -s patroni1:8091/cluster | jq { "members": [ { "port": 5432, "host": "10.0.1.5", "timeline": 10, "lag": 0, "role": "replica", "name": "patroni1", "state": "running", "api_url": "http://10.0.1.5:8091/patroni" }, { "port": 5432, "host": "10.0.1.4", "timeline": 10, "role": "leader", "name": "patroni2", "state": "running", "api_url": "http://10.0.1.4:8091/patroni" }, { "port": 5432, "host": "10.0.1.3", "lag": "unknown", "role": "replica", "name": "patroni3", "state": "running", "api_url": "http://10.0.1.3:8091/patroni" } ] } docker service scale patroni_patroni3=0
postgres@patroni1:/$ patronictl -c /etc/patroni.yml list patroni
+ Cluster: patroni (6893104757524385823) --+----+-----------+ | Member | Host | Role | State | TL | Lag in MB | +----------+-----------+---------+---------+----+-----------+ | patroni1 | 10.0.1.93 | Leader | running | 9 | | | patroni2 | 10.0.1.91 | Replica | running | 9 | 0 | +----------+-----------+---------+---------+----+-----------+
docker run --rm -ti --network=patroni_patroni -v /home/floitet/Documents/patroni-test-script:/home mcr.microsoft.com/dotnet/sdk /bin/bash
dotnet new console
// видим такие строчки Processing post-creation actions... Running 'dotnet restore' on /home/patroni-test/patroni-test.csproj... Determining projects to restore... Restored /home/patroni-test/patroni-test.csproj (in 61 ms). Restore succeeded. dotnet add package npgsql
dotnet pack
dotnet fsi /home/patroni-test.fsx
// и в output мы увидим как скрипт пошел писать время: 11/18/2020 22:29:32 +00:00 11/18/2020 22:29:33 +00:00 11/18/2020 22:29:34 +00:00
+ Cluster: patroni (6893104757524385823) --+----+-----------+
| Member | Host | Role | State | TL | Lag in MB | +----------+-----------+---------+---------+----+-----------+ | patroni1 | 10.0.1.18 | Replica | running | 21 | 0 | | patroni2 | 10.0.1.22 | Leader | running | 21 | | | patroni3 | 10.0.1.24 | Replica | running | 21 | 0 | +----------+-----------+---------+---------+----+-----------+ docker service ls | grep patroni
docker service scale $patroni2-id=0 // давайте запомним время последней удачной записи
11/18/2020 22:33:06 +00:00 Error Error Error + Cluster: patroni (6893104757524385823) --+----+-----------+
| Member | Host | Role | State | TL | Lag in MB | +----------+-----------+---------+---------+----+-----------+ | patroni1 | 10.0.1.18 | Replica | running | 21 | 0 | | patroni3 | 10.0.1.24 | Leader | running | 21 | | +----------+-----------+---------+---------+----+-----------+ Error
Error Error 11/18/2020 22:33:48 +00:00 11/18/2020 22:33:49 +00:00 11/18/2020 22:33:50 +00:00 11/18/2020 22:33:51 +00:00
docker run --rm -ti --network=patroni_patroni postgres:11 /bin/bash
psql --host haproxy --port 5000 -U approle -d postgres postgres=> \c patronitestdb You are now connected to database "patronitestdb" as user "approle". // Я установил время чуть раньше, чем произошла авария patronitestdb=> select * from records where time > '22:33:04' limit 15; time ----------------- 22:33:04.171641 22:33:05.205022 22:33:06.231735 // как мы видим в моем случае Patroni понадобилось 42 секунды // чтобы восстановить соединение 22:33:48.345111 22:33:49.36756 22:33:50.374771 22:33:51.383118 22:33:52.391474 22:33:53.399774 22:33:54.408107 22:33:55.416225 22:33:56.424595 22:33:57.432954 22:33:58.441262 22:33:59.449541 =========== Источник: habr.com =========== Похожие новости:
Блог компании VS Robotics ), #_postgresql, #_devops |
|
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 20:56
Часовой пояс: UTC + 5