Bucardo: Multimaster репликация

в 7:09, , рубрики: bucardo, master-master, postgresql, репликация, Чулан

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

Немного вводной. Чтобы Bucardo заработал, мы должы:
1) Сказать ему какие базы-участники на каких серверах вообще существуют.
2) Сказать ему какие таблицы участвуют в репликации.
Внимание: если разработчики добавят в приложение новую таблицу, мы должны об этом сообщить bucardo.
Тоже самое касается изменения схемы существующих таблиц.

3) Сказать ему какие группы таблиц существуют и какие таблицы попадают в какие группы. Группы нужны на тот случай, если между разными серверами надо реплицировать разные таблицы. Удобнее работать с группой, чем каждую отдельно указывать (очень похоже на группы в Nagios).
4) Сказать ему какие группы баз данных существуют. Цель — та же, что и для таблиц.

Перейдем к установке. Вариант для Debian 7.

Подразумевается, что пакеты postgresql-9.1 и postgresql-client-9.1 уже установлены.

Предварительная подготовка.

Серверы будут называться node1 и node2.

Обязательно также проверить, чтобы все участвующие PostreSQL-серверы слушали внешние интерфейсы:

# netstat -plnt4 | grep 5432
tcp        0      0 0.0.0.0:5432            0.0.0.0:*               LISTEN      12345/postgres

Устанавливаем пакет Bucardo и поддержку PL/Perl для PostgreSQL на каждом из серверов:

# apt-get install bucardo postgresql-plperl-9.1

Активируем на каждом из серверов:

# sed -i 's/ENABLED=0/ENABLED=1/' /etc/default/bucardo

Мейнтенеры пакета почему-то не догадались создать директорию под PID, поэтому создадим ее сами на каждом из серверов:

# mkdir /var/run/bucardo

Удостоверяемся, что мы можем подключиться через TCP-сокет к СУБД на каждом из серверов:

# psql -U postgres -h 127.0.0.1

Если не помните пароль, то простейшая инструкция здесь.
Если PG не хочет принимать запросы с конкретного адреса конкретного пользователя, то настройте /etc/postgresql/9.1/main/pg_hba.conf

Далее будет происходить инициализация базы. Она будет создана пользователем postgres, но наполнена пользователем bucardo, поэтому можно упереться в проблему подключения.
Дабы ее избежать, заранее внесем строку для него в /etc/postgresql/9.1/main/pg_hba.conf. Кроме того, уже в процессе работы Bucardo будет обращаться не только к своей ноде кластера, но и к парной. Поэтому ее тоже не забываем. Если у Вас в кластере серверов больше, то не забудьте о них. На каждом из серверов:

host    all             bucardo         127.0.0.1/32              trust
host    all             bucardo         SECOND.NODE.IP.ADDRESS/32 password

После этого рестартанем СУБД:

# pg_ctlcluster 9.1 main restart
Установка Bucardo.

Утилита bucardo_ctl в последних версиях Debian была заменена на bucardo, поэтому мы будем использовать ее.
Инициализируем базу данных:

# bucardo install

Диалог выглядит примерно так:

# bucardo install
This will install the bucardo database into an existing Postgres cluster.
Postgres must have been compiled with Perl support,
and you must connect as a superuser

Current connection settings:
1. Host:           localhost
2. Port:           5432
3. User:           postgres
4. Database:       postgres
5. PID directory:  /var/run/bucardo
Enter a number to change it, P to proceed, or Q to quit: P

Password for user postgres:
Postgres version is: 9.1
Password for user postgres:
Creating superuser 'bucardo'
Password for user postgres:
Attempting to create and populate the bucardo database and schema
Password for user postgres:
Database creation is complete

Updated configuration setting "piddir"
Installation is now complete.
If you see errors or need help, please email bucardo-general@bucardo.org

You may want to check over the configuration variables next, by running:
bucardo show all
Change any setting by using: bucardo set foo=bar

В процесс инициализации база была создана из файла /usr/share/bucardo/bucardo.schema, поэтому нет необходимости ее заполнять руками, как это описано в мануалах прошлых версий.

Bucardo установлен, можно его запустить:

# bucardo start
Настройка репликации.

Прежде, чем настроить репликацию, создадим тестовые базы, которые будем реплицировать.
На каждом из серверов:

# psql -U postgres -c "CREATE DATABASE mydb;"
# psql -U postgres mydb -c "CREATE TABLE mytable ( num123 integer PRIMARY KEY, abc varchar(10) );"

Еще один важный момент касательно безопасности. После добавления реплицируемой базы в настройку, Bucardo впишет пароль пользователя в базу. А так как при установке он его не запросил, то сделал его точно таким же, как у пользователя postgres. Другими словами у нас в базе bucardo будет храниться в открытом виде пароль от суперпользователя, что несколько опасно.
Поэтому сделаем ему другой пароль. На каждом из серверов:

# psql -U postgres -c "ALTER USER bucardo WITH PASSWORD 'eiP4uSash5';"

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

ВНИМАНИЕ: Это мы делаем на сервере node1. И вообще далее работаем только с node1 пока не уточнено, что надо делать на обоих.

Добавим локальную (mydb_node1) и ее удаленную копию (mydb_node2) с сервера node2:

# bucardo add database mydb_node1 dbname=mydb dbhost=127.0.0.1 dbuser=bucardo dbpass=eiP4uSash5
Added database "mydb_node1"

# bucardo add database mydb_node2 dbname=mydb dbhost=node2.example.com dbuser=bucardo dbpass=eiP4uSash5
Added database "mydb_node2"

Здесь:
mydb_nodeX — внутренее обозначение базы. Это имя Bucardo использует во внутренних работах с базой.
dbname=mydb — реальное имя базы в PostgreSQL, на которое ссылается mydb_nodeX.
dbuser=bucardo — под кем Bucardo будет подключаться к СУБД, чтобы работать с этой базой.

Результат мы можем видеть так:

# bucardo list database
Database: mydb_node1  Status: active  Conn: psql -p  -U bucardo -d mydb -h 127.0.0.1
Database: mydb_node2  Status: active  Conn: psql -p  -U bucardo -d mydb -h node2.example.com

Эти настройки берутся из таблицы db базы bucardo, где и сидит упомянутый выше пароль:

# psql -U postgres bucardo -c "SELECT name,dbname,dbhost,dbuser,dbpass,status FROM db;"
    name    | dbname |      dbhost       | dbuser  |   dbpass   | status
------------+--------+-------------------+---------+------------+--------
 mydb_node1 | mydb   | 127.0.0.1         | bucardo | eiP4uSash5 | active
 mydb_node2 | mydb   | node2b.forbet.net | bucardo | eiP4uSash5 | active
(2 rows)

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

# bucardo add table all --db=mydb_node1 --herd=mydb_herd
Creating herd: mydb_herd
Added table public.mytable to herd mydb_herd
New tables added: 1

Здесь:
--herd=mydb_herd — имя группы таблиц, чтобы потом настраивать синхронизацию не к каждой отдельно, а всем скопом.

И сразу можем ее посмотреть:

# bucardo list tables
1. Table: public.mytable  DB: mydb_node1  PK: num123 (int4)
Здесь нужно заострить внимание на PK. Bucardo, похоже, не работает с таблицами без первичных ключей. Вы потом не сможете синк сделать.

И группу тоже видно:

# bucardo list herd
Herd: mydb_herd  DB: mydb_node1  Members: public.mytable

Тоже самое касается последовательностей. В нашем примере их нет, но вдруг кто использует. Группу под них свою создавать не будем, чтобы не усложнять. Вероятность того, что таблицы реплицируются в одном направлении, а последовательности в другом — чрезвычайно мала. Поэтому пусть будет одна группа для таблиц и последовательностей:

# bucardo add sequence all --db=mydb_node1 --herd=mydb_herd
Sorry, no sequences were found
New sequences added: 0

Следующая наша задача создать репликационную группу. В этой группе мы скажем какая база будет источником, а какая реципиентом данных. Создадим сначала саму группу, пока пустую:

# bucardo add dbgoup other_mydb_servers
Created database group "mydb_servers_group"

Добавляем оба наших сервера в группу, указывая кто какую роль будет исполнять. Это единственная точка, где отличаеся настройка master-slave от master-master.
Изначально можно подумать, что source — это источник, а target — это реципиент. На самом деле это не совсем так. source — это тот, кто работает и как источник и как реципиент, а target — только реципиент.
То есть если у нас master-slave, то указываем одного source, а второго target. А если у нас master-master, то оба будут source, а target'ов не будет вообще.

Вариант для MASTER-->SLAVE:

# bucardo add dbgroup mydb_servers_group mydb_node1:source
Added database "mydb_node1" to group "mydb_servers_group" as source

# bucardo add dbgroup mydb_servers_group mydb_node2:target
Added database "mydb_node2" to group "mydb_servers_group" as target
Вариант для MASTER<-->MASTER:

# bucardo add dbgroup mydb_servers_group mydb_node1:source
Added database "mydb_node1" to group "mydb_servers_group" as source

# bucardo add dbgroup mydb_servers_group mydb_node2:source
Added database "mydb_node2" to group "mydb_servers_group" as source

Все! У нас написано какие есть базы. Написано какие есть в них таблицы. Написано кто в какой группе. Осталось сказать заключительный штрих — сказать какая группа таблиц будет «курсировть» между базами какой группы. Другими словами — создать «синк»:

# bucardo add sync mydb_sync herd=mydb_herd dbs=mydb_servers_group
Added sync "mydb_sync"

Можем посмотреть, что у нас получилось:

# bucardo list sync
Sync: mydb_sync  Herd: mydb_herd [Active]
  DB group mydb_servers_group: mydb_node1 (source) mydb_node2 (source или target - как настроили)

После изменения настроек обязательно рестартовать Bucardo:

# bucardo restart

========

Проверка:

на первой ноде node1 запускаем:

# psql -U postgres mydb -c "INSERT INTO mytable VALUES (1, 'a');"

а на второй node2 проверяем:

# psql -U postgres mydb -c "SELECT * FROM mytable;"

кто сделал multimaster, тому надо и в обратном направлении проверять. Создаете на node2, а проверяете на node1.

========

Вопросы, которые возникнут у большинства людей:
1) Что будет с таблицей на target-базе, если таблица на source-базе была изменена пока Bucardo был выключен или сеть была недоступна?

Ответ: все Ok. При старте или при появлении сети Bucardo передаст данные на target-сервер. Так что target-сервер может ломаться как угодно. Единственное требование — на нем должна быть та же схема данных (структура таблиц), что и на первом.
__
2) Если база большая (десятки-сотни гигабайт), Bucardo «отламывается» и не синхронизирует до конца. Как быть?

Ответ: переведите sync в состояние неактивного. Но Bucardo должен быть включен для source-базы для логивания запросов.
bucardo update sync mydb_sync status=inactive (для multimaster на всех нодах)
Далее делаете pg_dump/pg_restore руками и возвращаете синк в активный режим (для multimaster сначала на той, куда шли новые запросы после запуска дампа).

Автор: Singaporian

Источник

* - обязательные к заполнению поля