воскресенье, 13 ноября 2011 г.

PostgreSQL Slony - настройка асинхронной master/slave репликации


(ОС: 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 сервере. Если все хорошо, то на этом тестовая настройка репликации закончена.

Комментариев нет:

Отправить комментарий