Данная статья может быть интересна тем, кто уже имеет поверхностное представление о видах и проблематике репликации внутри кластера PostgreSQL, а так же тем, кто решил использовать стриминговую СУБД PipelineDB в качестве реплики в подобном кластере.
PipelineDB — одна из реализаций ныне набирающих популярность стриминговых СУБД. О преимуществах стриминговых СУБД в различных кейсах Вы можете без труда прочитать сегодня на множестве ресурсов. Очень просто принцип их работы визуализирован на сайте www.pipelinedb.com в разделе “How It Works”.
Конкретно PipelineDB это форк PostgreSQL с дополнительной функциональностью, позволяющей хранить только агрегированные данные, рассчитывая дельту из поступающего стрима (отсюда и название этого типа СУБД) на лету. Эти данные хранятся в специальных объектах PipelineDB, называемых continuous views. Сам же стрим в простейшем случае формируется из обычных таблиц, хранимых в этой же БД. Использование данного инструмента позволяет нам избавиться от необходимости создания и поддержки ETL-слоя при подготовке данных для систем отчетности, и может сэкономить Вам кучу времени и нервов. Но я полагаю, что раз Вы это читаете, то Вы уже что-то знаете об этом в объеме достаточном для появления интереса к описываемым здесь событиям.
Мы рассмотрим кейс, в котором на продуктовой среде у нас уже работает СУБД PostgreSQL версии 9.4+, а нам нужно получить ее риалтайм (ну или практически риалтайм) реплику для того, чтобы разгрузить основную базу от множественных и тяжелых SELECT-запросов, получаемых от, например, систем отчетности, DWH или наших витрин данных. И после изучения вопроса Вы можете решить, что именно стриминговая СУБД очень хорошо подходит для такой задачи.
Но вот незадача — какой же механизм репликации использовать? После дополнительного изучения вопроса мы приходим к выводу, что замечательный встроенный механизм потоковой асинхронной (физической) репликации PostgreSQL, который появился в PostgreSQL версии 9.0 и постоянно развивается, не подходит в силу своих ограничений, а именно:
а) мастер и реплика должны иметь одинаковую мажорную версию PostgreSQL, а по возможности и крутиться на идентичном “железе”
б) реплика при этом работает в режиме “hot standby”, в котором она доступна только для чтения
в) при использовании физической репликации мы можем иметь только полную «один-в-один» реплику мастера
В моем случае первое ограничение помешало бы мне поднять на PipelineDB реплику мастер-сервера, работающего под управлением Postgre 9.6, т.к. версия Postgre, от которой «отпочковалась» используемая мной последняя версия PipelineDB, только 9.5. Если у Вас мастер работает под управлением Postgre 9.5, то Вы можете попробовать такой фокус, но есть большая вероятность, что мастер-сервер просто не распознает PipelineDB как полноценный и равный себе PostgreSQL — механизм физической репликации очень капризен в этом плане.
Второе ограничение более существенное. Как мы уже выяснили, PipelineDB пишет в базу свои данные. Как минимум это continuous views, ради которых мы с нем и заморочились. Но второе ограничение разрешает нашей реплике быть только полной — один в один — копией базы мастера без возможности в нее писать. Что нас совершенно не устраивает.
Таким образом, так как физическая репликация нам не подходит, мы понимаем, что нам нужно смотреть в сторону логической репликации. Не лишенной своих недостатков, но полностью устраняющей эти два ограничения, а именно:
а) логическая репликация позволяет нам работать с различными версиями СУБД на мастере и слейве
б) логическая репликация позволяет делать реплику только тех данных, которые нам нужны, а не всех данных мастера один-в-один, и не блокирует слейв на запись
И тут перед нами открывается целый океан возможностей.
При первом ознакомлении с перечнем различных инструментов для создания логической репликации и разнообразием методик самой репликации первое желание, которое возникает, это желание сменить вид деятельности. Но первый шок проходит, и мы начинаем вылавливать из этого океана достойных кандидатов на пост инструмента нашей мечты.
Одни из самых популярных инструментов, используемых для этого это slony (trigger-based) и pgpool/pgpool-II (middleware).
Сразу скажу, что попытка решить эту задачу с помощью очень известной и популярной утилиты Slony версии 2.2.5 за две недели успехом так и не увенчалась — даже в случае когда для целей пруф-оф-концепт и мастер и реплика работали под управлением одинаковой версии PostgreSQL. Демон slony упорно не хотел запускаться и перезагружался сразу при запуске из-за segmentation fault, причину которого найти не удалось. Да и неблагодарное это дело искать причины segmentation faults в ПО сторонних поставщиков. Более того та же самая картина наблюдалась и при компиляции этой утилиты из исходных кодов и при установке ее из родного репозитория Alpine Linux.
Этот эксперимент проводился с такими отправными данными:
— docker-контейнеры
— и мастер и слейв: postgre 9.6 на Alpine Linux
Вполне возможно, что сами исходные условия стали причиной неудачи — использование докера или конкретно этот дистрибутив линукс — но в моем случае таковы были правила игры. Так же я допускаю, что проблема могла скрываться в нестабильности последней версии самого Slony, которую я использовал. В любом случае это решение не заработало, и Slony отправился на покой. Возможно в другой системной конфигурации или с другой версией Slony у Вас это получится.
Впрочем после прочтения статьи дальше Вы можете не захотеть колупаться в этой древней утилите. Да и не стоит забывать об этом: howfuckedismydatabase.com/postgres/slony.php
До второй утилиты pgpool я так и не добрался, потому что по дороге я нашел то, что и стало в конечном итоге моим решением: утилита pglogical от 2ndQuadrant.
Чтение документации по утилите и осознание кто же такие 2ndQuadrant сразу расположило меня к этому решению. Забегая вперед скажу, что судя по всему это решение может вообще войти в готовящуюся 10 версию PostgreSQL как штатное решение для логической репликации. Так что было решено играться с ним, подвинув в очереди на исследование pgpool.
Я решил сразу собирать систему на тех компонентах, которые и предполагалось позже отправить в продакшн, минуя стадию пруф-оф-концепт:
Мастер: докер-контейнер из того же образа, что и в первом случае
Реплика: докер-контейнер PipelineDB из другого образа, который вроде как является официальным образом этого проекта, хоть и оформлен как-то странно. Образ собран на базе дистрибутива Debian, а не Alpine.
Итак я начал копаться в pglogical. Практически сразу же меня ждало горькое разочарование: в репозитории APT эта утилита существует только для PostgreSQL версий 9.4, 9.5 и 9.6, и никакими PipelineDB там и не пахнет. Утилита наотрез отказалась устанавливаться на хост с PipelineDB, сообщая об unmet dependency postgresql-9.5. Т.о. замечательный эксперимент закончился так по сути и не начавшись.
Но осознание того факта, что PipelineDB это все таки тот же самый PostgreSQL — структура каталогов базы, конфигурационных файлов, встроенных команд и сервисных утилит это наглядно доказывала — и что это должно меня привести к чему-то позитивному, меня не покидало. И я решился на небольшую хитрость.
На хост с PipelineDB утилита pglogical устанавливается следующим образом (все делалось в docker-контейнере под рутом):
Добавляем репозиторий и скачиваем пакеты утилиты:
Устанавливаем необходимые библиотеки и сам пакет с игнорированием зависимостей(!), решая нашу проблему нежелания утилиты устанавливаться на что-либо кроме Postgre:
Удаляем запись о зависимости из файла /var/lib/dpkg/status, чтобы при дальнейшей работе apt-get она не ругалась на ненайденную зависимость и не предлагала нам удалить pglogical:
Все! Утилита установлена на хост, с PipelineDB. Но вот снова незадача — утилита устанавливается в папки с именами postgresql, а PipelineDB имеет аналогичную структуру папок, но с именами pipelinedb. Ну так не будем по этому поводу унывать и переместим файлы утилиты в соответствующие папки уже PipelineDB:
Вот и все. Мы получили работающий сервер с PipelineDB с установленной утилитой pglogical, которую мы можем начинать использовать.
После непродолжительной настройки кластера мастер-слейв (настраиваете реплику PipelineDB точно так же, как и обычный PostgreSQL), описание которой можно найти на миллионе ресурсов, включая документацию Postgre, и после прохождения простеньких шагов настройки самой утилиты мы можем убедиться, что репликация работает.
UPD: Исходники конфигураций и скриптов инициализации для докера можно найти здесь: https://github.com/akrymets/pg-replication
Буду рад услышать замечания по сути и предложения по повествованию. Самые лучшие предложения будут реализованы в виде правок к статье.
PipelineDB — одна из реализаций ныне набирающих популярность стриминговых СУБД. О преимуществах стриминговых СУБД в различных кейсах Вы можете без труда прочитать сегодня на множестве ресурсов. Очень просто принцип их работы визуализирован на сайте www.pipelinedb.com в разделе “How It Works”.
Конкретно PipelineDB это форк PostgreSQL с дополнительной функциональностью, позволяющей хранить только агрегированные данные, рассчитывая дельту из поступающего стрима (отсюда и название этого типа СУБД) на лету. Эти данные хранятся в специальных объектах PipelineDB, называемых continuous views. Сам же стрим в простейшем случае формируется из обычных таблиц, хранимых в этой же БД. Использование данного инструмента позволяет нам избавиться от необходимости создания и поддержки ETL-слоя при подготовке данных для систем отчетности, и может сэкономить Вам кучу времени и нервов. Но я полагаю, что раз Вы это читаете, то Вы уже что-то знаете об этом в объеме достаточном для появления интереса к описываемым здесь событиям.
Мы рассмотрим кейс, в котором на продуктовой среде у нас уже работает СУБД PostgreSQL версии 9.4+, а нам нужно получить ее риалтайм (ну или практически риалтайм) реплику для того, чтобы разгрузить основную базу от множественных и тяжелых SELECT-запросов, получаемых от, например, систем отчетности, DWH или наших витрин данных. И после изучения вопроса Вы можете решить, что именно стриминговая СУБД очень хорошо подходит для такой задачи.
Но вот незадача — какой же механизм репликации использовать? После дополнительного изучения вопроса мы приходим к выводу, что замечательный встроенный механизм потоковой асинхронной (физической) репликации PostgreSQL, который появился в PostgreSQL версии 9.0 и постоянно развивается, не подходит в силу своих ограничений, а именно:
а) мастер и реплика должны иметь одинаковую мажорную версию PostgreSQL, а по возможности и крутиться на идентичном “железе”
б) реплика при этом работает в режиме “hot standby”, в котором она доступна только для чтения
в) при использовании физической репликации мы можем иметь только полную «один-в-один» реплику мастера
В моем случае первое ограничение помешало бы мне поднять на PipelineDB реплику мастер-сервера, работающего под управлением Postgre 9.6, т.к. версия Postgre, от которой «отпочковалась» используемая мной последняя версия PipelineDB, только 9.5. Если у Вас мастер работает под управлением Postgre 9.5, то Вы можете попробовать такой фокус, но есть большая вероятность, что мастер-сервер просто не распознает PipelineDB как полноценный и равный себе PostgreSQL — механизм физической репликации очень капризен в этом плане.
Второе ограничение более существенное. Как мы уже выяснили, PipelineDB пишет в базу свои данные. Как минимум это continuous views, ради которых мы с нем и заморочились. Но второе ограничение разрешает нашей реплике быть только полной — один в один — копией базы мастера без возможности в нее писать. Что нас совершенно не устраивает.
Таким образом, так как физическая репликация нам не подходит, мы понимаем, что нам нужно смотреть в сторону логической репликации. Не лишенной своих недостатков, но полностью устраняющей эти два ограничения, а именно:
а) логическая репликация позволяет нам работать с различными версиями СУБД на мастере и слейве
б) логическая репликация позволяет делать реплику только тех данных, которые нам нужны, а не всех данных мастера один-в-один, и не блокирует слейв на запись
И тут перед нами открывается целый океан возможностей.
При первом ознакомлении с перечнем различных инструментов для создания логической репликации и разнообразием методик самой репликации первое желание, которое возникает, это желание сменить вид деятельности. Но первый шок проходит, и мы начинаем вылавливать из этого океана достойных кандидатов на пост инструмента нашей мечты.
Годная статья, в которой хорошо рассматриваются вопросы и репликации и обеспечивающих ее утилит в том числе: postgresql.leopard.in.ua/html/#репликация
Одни из самых популярных инструментов, используемых для этого это slony (trigger-based) и pgpool/pgpool-II (middleware).
Сразу скажу, что попытка решить эту задачу с помощью очень известной и популярной утилиты Slony версии 2.2.5 за две недели успехом так и не увенчалась — даже в случае когда для целей пруф-оф-концепт и мастер и реплика работали под управлением одинаковой версии PostgreSQL. Демон slony упорно не хотел запускаться и перезагружался сразу при запуске из-за segmentation fault, причину которого найти не удалось. Да и неблагодарное это дело искать причины segmentation faults в ПО сторонних поставщиков. Более того та же самая картина наблюдалась и при компиляции этой утилиты из исходных кодов и при установке ее из родного репозитория Alpine Linux.
Этот эксперимент проводился с такими отправными данными:
— docker-контейнеры
— и мастер и слейв: postgre 9.6 на Alpine Linux
Вполне возможно, что сами исходные условия стали причиной неудачи — использование докера или конкретно этот дистрибутив линукс — но в моем случае таковы были правила игры. Так же я допускаю, что проблема могла скрываться в нестабильности последней версии самого Slony, которую я использовал. В любом случае это решение не заработало, и Slony отправился на покой. Возможно в другой системной конфигурации или с другой версией Slony у Вас это получится.
Впрочем после прочтения статьи дальше Вы можете не захотеть колупаться в этой древней утилите. Да и не стоит забывать об этом: howfuckedismydatabase.com/postgres/slony.php
До второй утилиты pgpool я так и не добрался, потому что по дороге я нашел то, что и стало в конечном итоге моим решением: утилита pglogical от 2ndQuadrant.
Чтение документации по утилите и осознание кто же такие 2ndQuadrant сразу расположило меня к этому решению. Забегая вперед скажу, что судя по всему это решение может вообще войти в готовящуюся 10 версию PostgreSQL как штатное решение для логической репликации. Так что было решено играться с ним, подвинув в очереди на исследование pgpool.
Я решил сразу собирать систему на тех компонентах, которые и предполагалось позже отправить в продакшн, минуя стадию пруф-оф-концепт:
Мастер: докер-контейнер из того же образа, что и в первом случае
Реплика: докер-контейнер PipelineDB из другого образа, который вроде как является официальным образом этого проекта, хоть и оформлен как-то странно. Образ собран на базе дистрибутива Debian, а не Alpine.
Итак я начал копаться в pglogical. Практически сразу же меня ждало горькое разочарование: в репозитории APT эта утилита существует только для PostgreSQL версий 9.4, 9.5 и 9.6, и никакими PipelineDB там и не пахнет. Утилита наотрез отказалась устанавливаться на хост с PipelineDB, сообщая об unmet dependency postgresql-9.5. Т.о. замечательный эксперимент закончился так по сути и не начавшись.
Но осознание того факта, что PipelineDB это все таки тот же самый PostgreSQL — структура каталогов базы, конфигурационных файлов, встроенных команд и сервисных утилит это наглядно доказывала — и что это должно меня привести к чему-то позитивному, меня не покидало. И я решился на небольшую хитрость.
На хост с PipelineDB утилита pglogical устанавливается следующим образом (все делалось в docker-контейнере под рутом):
Добавляем репозиторий и скачиваем пакеты утилиты:
echo "deb [arch=amd64] http://packages.2ndquadrant.com/pglogical/apt/ jessie-2ndquadrant main" > /etc/apt/sources.list.d/2ndquadrant.list
wget --quiet -O - http://packages.2ndquadrant.com/pglogical/apt/AA7A6805.asc | apt-key add -
apt-get update && apt-get download libpq5 postgresql-9.5-pglogical
Устанавливаем необходимые библиотеки и сам пакет с игнорированием зависимостей(!), решая нашу проблему нежелания утилиты устанавливаться на что-либо кроме Postgre:
dpkg -i --ignore-depends=postgresql-9.5 libpq5_9.4.10-0+deb8u1_amd64.deb
dpkg -i --ignore-depends=postgresql-9.5 postgresql-9.5-pglogical_1.2.2-1jessie_amd64.deb
Удаляем запись о зависимости из файла /var/lib/dpkg/status, чтобы при дальнейшей работе apt-get она не ругалась на ненайденную зависимость и не предлагала нам удалить pglogical:
sed 's/, postgresql-9.5//g' /var/lib/dpkg/status > /var/lib/dpkg/status-new && \
mv /var/lib/dpkg/status /var/lib/dpkg/status.bkp && \
mv /var/lib/dpkg/status-new /var/lib/dpkg/status
Все! Утилита установлена на хост, с PipelineDB. Но вот снова незадача — утилита устанавливается в папки с именами postgresql, а PipelineDB имеет аналогичную структуру папок, но с именами pipelinedb. Ну так не будем по этому поводу унывать и переместим файлы утилиты в соответствующие папки уже PipelineDB:
mv /usr/lib/postgresql/9.5/lib/* /usr/lib/pipelinedb/lib/pipelinedb/
mv /usr/lib/postgresql/9.5/bin/* /usr/lib/pipelinedb/bin/
mv /usr/share/postgresql/9.5/extension/* /usr/lib/pipelinedb/share/pipelinedb/extension/
Вот и все. Мы получили работающий сервер с PipelineDB с установленной утилитой pglogical, которую мы можем начинать использовать.
После непродолжительной настройки кластера мастер-слейв (настраиваете реплику PipelineDB точно так же, как и обычный PostgreSQL), описание которой можно найти на миллионе ресурсов, включая документацию Postgre, и после прохождения простеньких шагов настройки самой утилиты мы можем убедиться, что репликация работает.
UPD: Исходники конфигураций и скриптов инициализации для докера можно найти здесь: https://github.com/akrymets/pg-replication
Буду рад услышать замечания по сути и предложения по повествованию. Самые лучшие предложения будут реализованы в виде правок к статье.