- PVSM.RU - https://www.pvsm.ru -
Если вы когда-нибудь задумывались о доверии и надежде, то скорее всего, не испытывали этого ни к чему так же сильно, как к системам управления базами данных. Ну и действительно, это же База Данных! В названии содержится весь смысл — место, где хранятся данные, основная задача ХРАНИТЬ. И что самое печальное, как всегда, однажды, эти убеждения разбиваются об останки такой одной умершей БД на 'проде'.
И что же делать? — спросите вы. Не деплоить на сервера ничего, — отвечаем мы. Ничего, что не умеет само себя чинить, хотя бы временно, однако надежно и быстро!
В этой статье я попробую рассказать о своем опыте настройки почти бессмертного Postgresql кластера внутри другого отказоустойчивого решения от Google — Kubernates (aka k8s)
Статья вышла немного больше чем ожидалось, а потому в коде много ссылок, в основном на код, в контексте которого идет речь.
Дополнительно прилагаю оглавление, в том числе для нетерпеливых, чтобы сразу перейти к результатам:
Потребность иметь хранилище с данными для почти любого приложения — необходимость. А иметь это хранилище устойчивым к невзгодам в сети или на физических серверах — хороший тон грамотного архитектора. Другой аспект — высокая доступность сервиса даже при больших конкурирующих запросах на обслуживание, что означает легкое масштабирование при необходимости.
Итого получаем проблемы для решения:
Дополнительные пункты, обусловленные спецификой религиозных убеждений автора:
На схеме это будет выглядеть примерно так:
master (primary node1) --
|- slave1 (node2) --- / balancer
| |- slave2 (node3) ----|---| |----client
|- slave3 (node4) ---/ balancer /
|- slave4 (node5) --/
При условии входных данных:
Будучи, искушенным в решении IT проблем, человеком, я решил спросить у коллективного разума: "postgres cluster kubernetes" — куча мусора, "postgres cluster docker" — куча мусора, "postgres cluster" — несколько вариантов, из которых пришлось воять.
Что меня расстроило, так это отсутствие вменяемых Docker сборок и описание любого варианта для кластеризации. Не говоря уже о Kubernetes. Кстати говоря, для Mysql вариантов было не много, но все же были. Как минимум понравился пример в официальном репозитории k8s для Galera(Mysql cluster) [10]
Гугл дал ясно понять, что проблемы придется решать самому и в ручном режиме..."но хоть с помощью разрозненных советов и статей" — выдохнул я.
Сразу замечу, что все пункты в этом параграфе могут быть субъективными и, вполне даже, жизнеспособными. Однако, полагаясь на свой опыт и чутье, мне пришлось их отсечь.
Когда кто-то делает универсальное решение (для чего бы то ни было), мне всегда кажется, что такие вещи громоздки, неповоротливы и тяжелы в обслуживании. Так же вышло и с Pgpool, который умеет почти все:
Первые четыре пункта я нашел полезными, и остановился на том, поняв и обдумав проблемы остальных:
Собственно, тоже почитав и сравнив найденное [11] с уже знакомой и работающей "из коробки" поточной репликацией (Streaming Replication [12]), легко далось решение даже не думать о Слонах.
Да и ко всему прочему, на первой же странице сайта проекта ребята пишут что, с postgres 9.0+ вам не нужны Slony при условии отсутствия неких специфичных требований к системе:
Вообщем, мне кажется Slony не торт… как минимум если у вас нет этих самых трех специфичных задач.
Осмотревшись вокруг [13] и разобравшись в вариантах подхода идеальной двусторонней репликации, оказалось, что жертвы не совместимы с жизнью некоторых приложений. Не говоря о скорости, есть ограничения в работе с транзакциями, сложными запросами (SELECT FOR UPDATE
и другие).
Вполне вероятно, я не так искушен именно в этом вопросе, но увиденного мне хватило, чтобы тоже оставить эту идею. И еще раскинув мозгами, мне показалось, что для системы с усиленной операцией записи нужны совершенно другие технологии, а не реляционные базы данных.
В примерах я буду говорить о том, как принципиально должно выглядеть решение, а в коде — как это вышло у меня. Для создания кластера вовсе не обязательно иметь Kubernetes (есть пример docker-compose) или Docker в принципе. Просто тогда, все описанное будет полезно, не как решение типа CPM (Copy-Paste-Modify), а как руководство по установке cо снипетами.
Почему же коллеги из Postgresql отказались от терминов "Master" и "Slave"?.. хм, могу ошибаться, но ходил слух, что из-за не-полит-корректности, мол, что рабство это плохо [14]. Ну и правильно.
Первое что нужно сделать — включить Primary сервер, за ним первый слой Standby, а за тем второй — все согласно поставленной задачи. Отсюда получаем простую процедуру по включению обычного Postgresql сервера в режиме Primary/Standby с конфигурацией для включения Streaming Replication [15]
wal_level = hot_standby
max_wal_senders = 5
wal_keep_segments = 5001
hot_standby = on
Все параметры в комментариях имеют краткое описание, но если вкратце, эта конфигурация дает серверу понять, что он отныне часть кластер и, в случае чего, нужно позволить читать WAL логи [16] другим клиентам. Плюс разрешить запросы во время восстановления. Отличное описание по подробной настройке такого рода репликации можно найти на Postgresql Wiki [12].
Как только мы получили первый сервер кластера, можем включать Stanby, который знает, где находится его Primary.
Моя задача здесь свелась к сборке универсального образа Docker Image [17], который включается в работу, в зависимости от режима, как то так:
postgresql.conf
) и открывает доступ пользователям извне(pg_hba.conf
)repmgrd
— демон от Repmgr для мониторинга репликации (о нем тоже позже)$PGDATA
директорию)repmgrd
Для всех этих операций важна последовательность, и посему в коде [20] напиханы sleep
. Знаю — не хорошо, но так удобно конфигурировать задержки через ENV переменные, когда нужно разом стартануть все контейнеры (например через docker-compose up
)
Все переменные к этому образу описаны в docker-compose
файле [21].
Вся разница первого и второго слоя Standby сервисов в том, что для второго мастером является любой сервис из первого слоя, а не Primary. Не забываем, что второй эшелон должен стартовать после первого с задержкой во времени.
Split brain [22] — ситуация, в которой разные сегменты кластера могут создать/избрать нового Master-a и думать, что проблема решена.
Это одна, но далеко не единственная проблема, которую мне помог решить Repmgr [23].
По сути это менеджер, который умеет делать следующее:
В нашем случае на помощь приходит repmgrd
который запускается основным процессом в контейнере и следит за целостностью кластера. При ситуации, когда пропадает доступ к Master серверу, Repmgr пытается проанализировать текущую структуру кластера и принять решение о том, кто станет следующим Master-ом. Естественно Repmgr достаточно умен чтобы не создать ситуацию Split Brain и выбрать единственно правильного Master-а.
Последняя часть системы — Pgpool. Как я писал в разделе о плохих решениях, сервис все же делает свою работу:
Как исход, у меня получился довольно простой Docker Image [25], который при старте конфигурирует себя на работу с набором узлов и пользователей, у которых будет возможность проходить md5 авторизацию сквозь Pgpool (c этим тоже, как оказалось, не все просто [26])
Очень часто возникает задача избавиться от единой точки отказа, и в нашем случае — этой точкой является pgpool сервис, который проксирует все запросы и может стать самым слабым звеном на пути доступа к данным.
К счастью, в этом случае нашу проблему решает k8s и позволяет сделать столько репликаций сервиса сколько нужно.
В примере для Kubernetes [27] к сожалению этого нет, но если вы знакомы c тем как работает Replication Controller [28] и/или Deployment [29], то провернуть вышеописанное вам не составит труда.
Эта статья — не пересказ скриптов для решения задачи, но описание структуры решения этой самой задачи. Что означает — для более глубокого понимания и оптимизации решения придется почитать код, как минимум README.md в github [30], который пошагово и дотошно рассказывает как запустить кластер для docker-compose и Kubernetes. Ко всему прочему, для тех, кто проникнется и решится с этим двигаться дальше, я готов протянуть виртуальную руку помощи [31].
Надеюсь, что изложенный материал будет полезен и подарит немного позитива перед началом лета! Удачи и хорошего настроения, коллеги ;)
Автор: ZmeeeD
Источник [35]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/postgresql/124340
Ссылки в тексте:
[1] Задача: #task
[2] Решение методом "Гугления": #solution_google
[3] Плохие и непреемлимые решения: #solution_bad
[4] Консолидация и сборка решения: #solution_my
[5] Primary и Standby вместо Master и Slave: #solution_my_streaming
[6] Split-brain и выборы нового лидера в кластере: #solution_my_repmgr
[7] Pgpool-II — swiming pool of connections: #solution_my_pgpool
[8] Результат: #result
[9] Документация и использованный материал: #doc
[10] для Galera(Mysql cluster): https://github.com/kubernetes/kubernetes/tree/master/examples/mysql-galera
[11] найденное: http://www.slony.info/
[12] Streaming Replication: https://wiki.postgresql.org/wiki/Streaming_Replication
[13] Осмотревшись вокруг: https://wiki.postgresql.org/wiki/Replication,_Clustering,_and_Connection_Pooling
[14] мол, что рабство это плохо: https://youtu.be/0O5h4enjrHw?t=140
[15] с конфигурацией для включения Streaming Replication: https://github.com/paunin/postgres-docker-cluster/blob/master/configs/postgresql.conf
[16] WAL логи: https://www.postgresql.org/docs/9.5/static/wal-intro.html
[17] Docker Image: https://hub.docker.com/r/paunin/postgresql-cluster-pgsql/
[18] Для Primary: https://github.com/paunin/postgres-docker-cluster/blob/master/bin/primary.entrypoint.sh
[19] Для Standby: https://github.com/paunin/postgres-docker-cluster/blob/master/bin/standby.entrypoint.sh
[20] в коде: https://github.com/paunin/postgres-docker-cluster/tree/master/bin
[21] docker-compose
файле: https://github.com/paunin/postgres-docker-cluster/blob/master/docker-compose.yml#L15
[22] Split brain: https://en.wikipedia.org/wiki/Split-brain_(computing)
[23] Repmgr: https://github.com/2ndQuadrant/repmgr
[24] событиях внутри кластера: https://github.com/2ndQuadrant/repmgr#generating-event-notifications-with-repmgrrepmgrd
[25] Docker Image: https://hub.docker.com/r/paunin/postgresql-cluster-pgpool/
[26] c этим тоже, как оказалось, не все просто: http://www.pgpool.net/docs/latest/pgpool-en.html#md5
[27] примере для Kubernetes: https://github.com/paunin/postgres-docker-cluster/tree/master/k8s
[28] Replication Controller: http://kubernetes.io/docs/user-guide/replication-controller/
[29] Deployment: http://kubernetes.io/docs/user-guide/deployments/
[30] README.md в github: https://github.com/paunin/postgres-docker-cluster#streaming-replication-cluster-for-pgsql--pgpool2
[31] виртуальную руку помощи: mailto:d.m.paunin@gmail.com
[32] Исходники и документация на GitHub: https://github.com/paunin/postgres-docker-cluster
[33] Pgpool2: http://www.pgpool.net/docs/latest/pgpool-en.html
[34] Kubernetes: http://kubernetes.io/
[35] Источник: https://habrahabr.ru/post/301370/?utm_source=habrahabr&utm_medium=rss&utm_campaign=best
Нажмите здесь для печати.