(ОС: Debian 6.0 x64, PostgreSQL 8.4, Slony 2.0)
Терминология:
- кластер – набор баз данных;
- нода – база данных, которая может быть распределена;
- репликационный набор – набор таблиц, которые могут быть реплицированы между нодами кластера;
- источник (или провайдер) и подписчик – у каждой репликации есть одна нода-источник, остальные ноды могут быть подписчиками;
- slon – демон, присутствующий на каждой ноде и управляющий ее репликациями;
- slonik – командная утилита для общего управления нодами.
Устанавливаем ПО на master сервер:
apt-get install postgresql-8.4 slony1-2-bin
(при инсталляции slony1-2-bin как рекомендательный пакет притянет в установку postgresql-8.4-slony1-2)
Устанавливаем ПО на slave сервер:
apt-get install postgresql-8.4 postgresql-8.4-slony1-2
Разрешаем на master сервере сетевые подключения с slave сервера, открываем /etc/postgresql/8.4/main/pg_hba.conf и прописываем
host all slony 172.16.0.101/16 md5
где slony это спец.пользователь из под которого будет действовать slony, а 172.16.0.101 это IP адрес slave сервера
Разрешаем на slave сервере сетевые подключения с master сервера, открываем /etc/postgresql/8.4/main/pg_hba.conf и прописываем
host all slony 172.16.0.102/16 md5
где slony это спец.пользователь из под которого будет действовать slony, а 172.16.0.102 это IP адрес master сервера
На обоих серверах в /etc/postgresql/8.4/main/postgresql.conf
listen_addresses = '*'
Создаем postgres пользователя slony на обоих серверах и выдаем ему привилегии суперпользователя (такие привилегии это требования самого slony)
postgres=# create user slony with password 'slony_pass';
postgres=# alter user slony createuser;
Создаем целевую базу (ту которую планируем реплицировать) на master сервере и импортируем в нее данные
postgres=# create database of_db;
root@postgresql-1:~# psql -U postgres -f of_db.sql of_db
включаем поддержку pl/pgsql для этой базы
root@postgresql-1:~# createlang -U postgres -d of_db plpgsql
в данном примере будем реплицировать несколько таблиц, ofvcard и ofuserprop вышеозвученной базы, смотрим наличие индексов у этих таблиц
of_db=# \d ofvcard;
Table "public.ofvcard"
Column | Type | Modifiers
----------+-----------------------+-----------
username | character varying(64) | not null
vcard | text | not null
Indexes:
"ofvcard_pk" PRIMARY KEY, btree (username)
of_db=# \d ofuserprop;
Table "public.ofuserprop"
Column | Type | Modifiers
-----------+------------------------+-----------
username | character varying(64) | not null
name | character varying(100) | not null
propvalue | text | not null
Indexes:
"ofuserprop_pk" PRIMARY KEY, btree (username, name)
обязательное наличие индексов у таблиц которые будут реплицироваться это требование slony (и любой нормальной базы). Как видим индексы у данных таблиц есть (если индексов нет, то slony можете сам их добавить, хотя его разработчики и не рекомендуют использовать данный функционал slony по понятным причинам)
Теперь на slave сервере создаем базу данных, таблицы которой в дальнейшем будут реплицироваться
postgres=# create database of_db;
включаем поддержку pl/pgsql и для этой базы
root@postgresql-2:~# createlang -U postgres -d of_db plpgsql
на master сервере выполняем экспорт структуры базы и импортируем ее на slave сервер в одноименную базу
root@postgresql-1:~#pg_dump -U postgres -s of_db > of_db.sql
root@postgresql-2:~# psql -U postgres -f of_db.sql of_db
теперь можно с помощью утилиты slonik инициализировать наш кластер, slonik это cli утилита принимающая команды с файла или stdin
создаем аналогичный скрипт и запускаем его на master сервере
#!/bin/bash
slonik <<_EOF_
cluster name = simple_cluster;
node 1 admin conninfo = 'dbname=of_db host=172.16.0.102 user=slony password=slony_pass';
node 2 admin conninfo = 'dbname=of_db host=172.16.0.101 user=slony password=slony_pass';
init cluster ( id=1, comment = 'Master Node');
create set (id=1, origin=1, comment='of_db replication set');
set add table (set id=1, origin=1, id=1, fully qualified name = 'public.ofvcard', comment='card');
set add table (set id=1, origin=1, id=2, fully qualified name = 'public.ofuserprop', comment='prop');
store node (id=2, comment = 'Slave node', event node=1);
store path (server = 1, client = 2, conninfo='dbname=of_db host=172.16.0.102 user=slony password=slony_pass');
store path (server = 2, client = 1, conninfo='dbname=of_db host=172.16.0.101 user=slony password=slony_pass');
_EOF_
после его выполнения запускаем следующий скрипт, который подпишет slave сервер на репликационный набор
#!/bin/bash
slonik <<_EOF_
cluster name = simple_cluster;
node 1 admin conninfo = 'dbname=of_db host=172.16.0.102 user=slony password=slony_pass';
node 2 admin conninfo = 'dbname=of_db host=172.16.0.101 user=slony password=slony_pass';
subscribe set ( id = 1, provider = 1, receiver = 2, forward = no);
_EOF_
готово, теперь на master сервере прописываем настройки в конфиг.файлы slony, сначала в /etc/slony1/slon_tools.conf
if ($ENV{"SLONYNODES"}) {
require $ENV{"SLONYNODES"};
} else {
$CLUSTER_NAME = 'simple_cluster';
$LOGDIR = '/var/log/slony1';
$MASTERNODE = 1;
$DEBUGLEVEL = 2;
add_node(node => 1,
host => '172.16.0.102',
dbname => 'of_db',
port => 5432,
user => 'slony',
password => 'slony_pass');
add_node(node => 2,
host => '172.16.0.101',
dbname => 'of_db',
port => 5432,
user => 'slony',
password => 'slony_pass');
}
$SLONY_SETS = {
"set1" => {
"set_id" => 1,
"table_id" => 1,
"pkeyedtables" => ["public.ofvcard", "public.ofuserprop"],
},
};
if ($ENV{"SLONYSET"}) {
require $ENV{"SLONYSET"};
}
1;
потом в файл /etc/default/slony1 прописываем ноды
SLON_TOOLS_START_NODES="1 2"
запускаем slon'а
invoke-rc.d slony1 start
Видим что к реплицируемым таблицам добавились триггеры
of_db=# \d ofvcard;
Table "public.ofvcard"
Column | Type | Modifiers
----------+-----------------------+-----------
username | character varying(64) | not null
vcard | text | not null
Indexes:
"ofvcard_pk" PRIMARY KEY, btree (username)
Triggers:
_simple_cluster_logtrigger AFTER INSERT OR DELETE OR UPDATE ON ofvcard FOR EACH ROW EXECUTE PROCEDURE _simple_cluster.logtrigger('_simple_cluster', '1', 'k')
Disabled triggers:
_simple_cluster_denyaccess BEFORE INSERT OR DELETE OR UPDATE ON ofvcard FOR EACH ROW EXECUTE PROCEDURE _simple_cluster.denyaccess('_simple_cluster')
of_db=# \d ofuserprop;
Table "public.ofuserprop"
Column | Type | Modifiers
-----------+------------------------+-----------
username | character varying(64) | not null
name | character varying(100) | not null
propvalue | text | not null
Indexes:
"ofuserprop_pk" PRIMARY KEY, btree (username, name)
Triggers:
_simple_cluster_logtrigger AFTER INSERT OR DELETE OR UPDATE ON ofuserprop FOR EACH ROW EXECUTE PROCEDURE _simple_cluster.logtrigger('_simple_cluster', '2', 'kk')
Disabled triggers:
_simple_cluster_denyaccess BEFORE INSERT OR DELETE OR UPDATE ON ofuserprop FOR EACH ROW EXECUTE PROCEDURE _simple_cluster.denyaccess('_simple_cluster')
Проверяем работу репликации, на master сервере добавляем/удаляем какие нибудь данные в наших целевых таблицах и проверяем чтобы эти данные синхронизировались и в базе на slave сервере. Если все хорошо, то на этом тестовая настройка репликации закончена.