April 27, 2010

Установка Londiste в подробностях

Этот пост содержит подробное пошаговое описание процесса настройки репликации на основе Londiste, системы асинхронной мастер-слэйв репликации из пакета SkyTools от Skype.

Допустим есть 2 сервера - host1 и host2. На host1 работает кластер с одной или несколькими базами, которые необходимо реплицировать на host2. Другими словами host1 будет мастером, а host2 слейвом.

Прежде всего необходимо установить пакет SkyTools. Его исходники можно найти на официальном сайте проекта или в wiki. Там же найдёте всю документацию и ссылки на дополнительные материалы. Советую обращаться к ним если захотите узнать дополнительные подробности о вещах, которых я буду в данной статье касаться поверхностно.

Итак, всё ПО необходимое для репликации установлено, но, прежде чем начать настройку, хочу рассказать о принципах работы Londiste в очень общих словах.

Londiste базируется на механизме очередей PgQ, который тоже входит в пакет SkyTools. Информация об изменениях данных попадает в эти очереди из спец-триггеров, навешиваемых на реплицируемые таблицы. PgQ, в свою очередь, основывается на пакетной обработке и использует так называемый ticker, утилиту (демон), генерирующую события готовности пачек данных. Эти события слушает демон Londiste и по их наступлению переносит пачки с мастера на слейв.

Репликация на базе Londiste может работать по схеме - один мастер на несколько слейвов. В связи с этим я буду делать пометки, различающие установку репликации первого слейва и последующих. Также я буду различать репликацию отдельной базы и кластера целиком.

Описанный процесс не требует даунтайма.

Замечание:

В данном описании будут часто встречаются обобщения более узких ситуаций, которые не тестировались во всех возможных вариантах. Так что прежде чем внедрять её в продакшн, тщательно протестируйте ваш процесс. Если вы найдёте какую-нибудь ошибку или не рабочую ситуацию, буду благодарен если сообщите.


1. Первым делом подготовим мастер-сервер

Замечание:

Пропустите этот пункт если репликация мастер-сервера уже есть.


1.1. Права на мастере

В данном примере все утилиты будут работать под системным пользователем postgres. Операции с БД я доверю также пользователю postgres (который в базе). Но в реальности будет правильнее сделать отдельного пользователя для этих утилит, смотрите по вашей ситуации.

Дадим пользователю postgres доверительный доступ (без пароля) к базам на мастере со слейва.

/var/lib/postgres/8.4/data/pg_hba.conf:
...
# TYPE DATABASE USER CIDR-ADDRESS METHOD
# host2 IP
host db1 postgres 192.168.10.2/32 trust
...


Если реплицируются конкретные базы, а не весь инстанс, то добавьте такие записи для каждой из них. В случае же репликации всего инстанса достаточно одной записи, где в колонке DATABASE указываем all. Не забудьте сделать reload серверу.

1.2. Настрока ticker-а

Далее создадим файл конфигурации ticker-а.

/etc/skytools/db1-ticker.ini:
[pgqadm]
job_name = db1-ticker
db = dbname=db1

# Задержка между запусками обслуживания (ротация очередей и т.п.) в секундах
maint_delay = 600

# Задержка между проверками наличия активности (новых пакетов данных) в секундах
loop_delay = 0.1
logfile = /var/log/skytools/%(job_name)s.log
pidfile = /var/run/skytools/%(job_name)s.pid


Создайте подобные конфигурации для каждой реплицируемой базы.

1.3. Запускаем ticker

Теперь необходимо инсталлировать служебный код (SQL) и запустить ticker как демона для каждой из баз. Делается это с помощью утилиты pgqadm.py следующими командами:

python pgqadm.py /etc/skytools/db1-ticker.ini install
python pgqadm.py /etc/skytools/db1-ticker.ini ticker -d


Проверим, что в логах (/var/log/skytools/db1-tickers.log) всё нормально. На данном этапе там должны быть редкие записи (раз в минуту).

2. Далее настроим слейв

2.1. Убедимся что Londiste остановлен

Замечание:

Это действие необходимо если вы раньше работали с Londiste на этом слейве.


python londiste.py -s /etc/skytools/db1-londiste.ini

Повторите для всех реплицируемых баз.

2.2. Востанавливаем схему базы

Замечание:

В данном примере подразумевается что целевой инстанс не содержит баз с такими же именами как у реплицируемых.


Если реплицируются отдельные базы, то прежде всего необходимо создать пользователей, идентичных тем, которые работали с ними на мастере. Далее переносим схемы этих баз на слейв (повторяем для каждой):

pg_dump -s -C -h host1 -U postgres db1 |
psql -U postgres 1>db1-restore.stdout 2>db2-restore.stderr


Если реплицируем инстанс целиком, то достаточно один раз сделать так:

pg_dumpall -s -h host1 -U postgres |
psql -U postgres 1>all-restore.stdout 2>all-restore.stderr


Убедимся, что в лог-файлах *-restore.stderr отсутствуют ошибки кроме "роль postgres уже существует" (ч.г. не могу понять для чего вообще pg_dumpall дампит эту роль).

2.3. Создаём конфигурацию репликатора

Для каждой из реплицируемых баз создадим конфигурационные файлы:

/etc/skytools/db1-londiste.ini:
[londiste]
job_name = db1-londiste

provider_db = dbname=db1 port=5432 host=host1
subscriber_db = dbname=db1

# Это будет использоваться в качестве SQL-идентификатора, т.ч. не используйте
# точки и пробелы.
# ВАЖНО! Если есть живая репликация на другой слейв, именуем очередь так-же
pgq_queue_name = db1-londiste-queue

logfile = /var/log/skytools/%(job_name)s.log
pidfile = /var/run/skytools/%(job_name)s.pid

log_size = 5242880
log_count = 3


2.4. Устанавливаем Londiste в базы на мастере и слейве

Теперь необходимо установить служебный SQL для каждой из созданных в предыдущем пункте конфигураций.

Устанавливаем код на стороне мастера:

Замечание:

Если установка Londiste на эту базу мастера уже была то для него не делаем.


python londiste.py /etc/skytools/db1-londiste.ini provider install

и подобным образом на стороне слейва:

python londiste.py /etc/skytools/db1-londiste.ini subscriber install

После этого пункта на мастере будут созданы очереди для репликации.

2.5. Запускаем процессы Londiste

Для каждой реплицируемой базы делаем:

python londiste.py /etc/skytools/db1-londiste.ini replay -d

Таким образом запустятся слушатели очередей репликации, но, т.к. мы ещё не указывали какие таблицы хотим реплицировать, они пока будут работать в холостую.

Убедимся что в логах нет ошибок (/var/log/skytools/db1-londistes.log).

2.6. Добавляем реплицируемые таблицы

Для каждой конфигурации указываем что будем реплицировать с мастера:

Замечание:

Если указывали эти таблицы на мастере для другой репликации, то на мастере не делать.


python londiste.py /etc/skytools/db1-londiste.ini provider add --all

и что со слейва:

python londiste.py /etc/skytools/db1-londiste.ini subscriber add --all

В данном примере я использую спец-параметр --all, который означает все таблицы, но вместо него вы можете перечислить список конкретных таблиц, если не хотите реплицировать все.

2.7. Добавляем реплицируемые последовательности (sequence)

Так же для всех конфигураций.

Для мастера:

Замечание:

Опять же, если они уже добавлены на мастере, то не добавляем их там.


python londiste.py /etc/skytools/db1-londiste.ini provider add-seq --all

Замечание:

В версиях SkyTools до 2.1.9 включительно был обнаружен баг при добавлением последовательностей на мастере используя параметр --all, т.ч. если у вас такая версия используйте следующий хак:

for seq in $(
psql -t -A -U postgres toozla -c "\ds" |
awk -F '|' '{ if ($1 != "pgq" && $1 != "londiste") { print $1"."$2 } }');
do
python londiste.py /etc/skytools/db1-londiste.ini provider add-seq $seq;
done


Для слейва:

python londiste.py /etc/skytools/db1-londiste.ini subscriber add-seq --all

Точно также как и с таблицами можно указать конкретные последовательности вместо --all.

2.8. Проверка

Итак, всё что надо сделано. Теперь Londiste запустит так называемый bulk copy процесс, который массово (с помощью COPY) зальёт присутствующие на момент добавления таблиц данные на слейв, а затем перейдёт в состояние обычной репликации.

Мониторим логи на предмет ошибок:

less /var/log/skytools/db1-londiste.log

Если всё хорошо, смотрим состояние репликации. Данные уже синхронизированы для тех таблиц, где статус отображается как "ok".

python londiste.py /etc/skytools/db1-londiste.ini subscriber tables

Table State
public.table1 ok
public.table2 ok
public.table3 in-copy
public.table4 -
public.table5 -
public.table6 -
...


Для удобства представляю следующий трюк с уведомление в почту об окончании первоначального копирования (мыло поменять на своё ;):

(
while [ $(
python londiste.py /etc/skytools/db1-londiste.ini subscriber tables |
tail -n+2 | awk '{print $2}' | grep -v ok | wc -l) -ne 0 ];
do sleep 60; done; echo '' | mail -s 'Replication done EOM' user@domain.com
) &


Ссылки на публикации, которые мне помогли в написании этой статьи:

SkyTools - PostgreSQL Wiki
http://wiki.postgresql.org/wiki/Skytools

SkyTools - Skype Developer Zone
https://developer.skype.com/SkypeGarage/DbProjects/SkyTools

PostgreSQL master slave(s) asynchronous replication - tail -f /dev/dim
http://tapoueh.org/skytools.html

2 comments:

Artyom Nosov said...

2-а важных замечания:
1. При выполнение п. 2.2, а именно, команды
pg_dump[all] ... | psql ...

Важно помнить, что до этого на основной базе не должно существовать триггеров londiste. Иными словами, если у вас уже существует репликация master -> slave c использованием londiste необходимо пропустить pg_dump через следующий pipe:
sed -i '/CREATE TRIGGER "имя_триггера_londiste"/,/EXECUTE PROCEDURE/d'

2. Репликация londiste базируется на PRIMARY KEYS, соответственно каждая добавляемая в репликацию таблица должна иметь первичный ключ.

grayhemp said...

Спасибо, Артём. Обязательно скорректирую текст с учётом этих замечания.

Post a Comment