Bucardo: Multi-Master PostgreSQL Cluster!
Создаем мульти-мастер PostgreSQL кластер на примере двух нод PostgreSQL сервера в FreeBSD Jail's. Кластеризовать будем базу данных Zabbix мониторинга, который будет также жить на двух разных хостах внутри FreeBSD Jail's.
Итак, разберемся, что у нас что, и зачем мы это делаем...
1. Bucardo - грубо говоря, это скрипт на Perl, реализующий потоковую репликацию между PostgreSQL серверами, и дарящий нам счастливую возможность иметь 48 мастер нод PostgreSQL. Единственная тонкость, что все реплицируемые таблицы должны иметь Primary key, иначе таблицу не удастся включить в кластерную репликацию: Bucardo home site
Собственно, реализации multi-master репликаций для PostgreSQL без Primary key существуют, например BDR, но он еще не дошел до стабильной стадии, так что пока я его не пробовал. Но в целом, весьма интересная разработка. Когда BDR появится в портах, я его обязательно попробую ;)
2. FreeBSD и Jails - ну а как иначе... Все сервисы должны жить изолированно из соображений безопасности и просто удобства. FreeBSD со своими Jails подходит для этого идеально. Опять же, ZFS пока в нормальном виде только во FreeBSD, в Linux ZFS еще не на такой стадии интеграции, хотя я и на Linux уже активно использую ZFS.
3. Zabbix - его я выбрал чисто для примера. Это не обязательно делать для Zabbix. Вы можете таким образом кластеризовать что угодно! Например можно кластеризовать Asterisk, заставив его хранить экстеншены и все основные настройки в PgSQL. Но и Zabbix, если у вас огромная сеть с кучей устройств для мониторинга, будет не лишним кластеризовать в multi-master варианте :) Разнеся его по разным серверам и сегментам сети.
Создаем свой первый jail для PostgreSQL:
Я использую для управления джейлами QJail. Вполне удобная утилита, "очеловечивающая" работу с джейлами.
Итак, поехали (все операции выполняются парно на двух серверах!!!):
1. Если джейлы вы раньше не использовали, но у вас есть ZFS, то первым делом перед инициализацией джейлов надо создать датасет для них:
zfs create -o compression=lz4 system/usr/jails
По поводу компрессии: lz4 очень быстрый алгоритм, потому его можно использовать везде по-умолчанию. Потерь по производительности нет, а всякие текстовые файлы и логи сжимаются практически в два раза. Учитывая то, что данные перед записью на диск сжимаются - растет скорость записи на диск - в общем одни плюсы.
2. Инициализируем jails' при помощи qjail:
qjail install
3. Создаем датасет для jail с PostgreSQL:
zfs create system/usr/jails/pgsql0X (pgsql 01 на первой ноде, pgsql02 на второй ноде)
4. А теперь самый важный датасет! Датасет для данных PostgreSQL.
zfs create -p -o mountpoint=/usr/jails/pgsql0X/usr/local/pgsql -o recordsize=8K system/usr/jails/pgsql0X/pgsql (X=1 для первой ноды и X=2 для второй)
Параметр recordsize=8K задан для того, что бы размер блока файловой системы и размер блока который пишет PostgreSQL совпадали. PostgreSQL пишет как раз блоками по 8Kb.
5. Создаем Jail:
qjail create -4 em0|192.168.0.X,lo1|127.0.1.1 pgsql0X (X=1 для первой ноды и X=2 для второй)
Интерфейс можно использовать основной, к которому у вас подключена локальная сеть, тогда вам не придется ничего больше делать, только открыть доступ в файрволле. Или можно использовать LoopBack - это более секьюрно, но тогда вам потребуется настроить NAT в PF или IPFW, для доступа к джейлу.
Так же создаем LoopBack для самого джейла, что бы нам было проще взаимодействовать с Bucardo и PostgreSQL: lo1.
Создать lo1 в системе очень просто, для этого нужно в файл /etc/rc.conf добавить: cloned_interfaces="lo1"
И сделать: service netif cloneup
После чего данный интерфейс появится в системе.
6. Джейл создали, теперь идет в /usr/local/etc/qjail.config, ищем там файл с конфигурацией нашего jail (pgsql01 или pgsql02) и вписываем туда параметр "allow.sysvipc;". Без этой опции PostgreSQL не сможет стартовать с ругательствами на невозможность выделения shared memory.
7. После этого запускаем jail:
qjail start pgsql0X
8. После старта джейла можем действовать двумя путями.Через jexec (это правильнее) или через qjail console (что удобнее на первом этапе):
jexec pgsql0X pkg update
jexec pgsql0X pkg install postgresql94-server postgresql94-client postgresql94-plperl p5-Bucardo
9. Если вы планируете несколько PostgreSQL в нескольких джейлах в пределах одного сервера, то нужно перед запуском PgSQL сменить UID его пользователя на другой. UID пользователей pgsql должен различаться во всех джейлах, иначе у вас будут проблемы.
vipw
ee /etc/groups
10. После чего переписать права на все, что принадлежало этому юзеру:
chown -R /usr/local/etc/pgsql
или
find / -uid 70 -exec sh -c 'chown pgsql {} \+'
find / -gid 70 -exec sh -c 'chown :pgsql {} \+'
11. Активируем запуск PostgreSQL и Bucardo:
sysrc postgresql_enable=YES
sysrc bucardo_enable=YES (Только на одном из серверов, на втором Bucardo должен быть выключен до тех пор, пока на первой ноде будет работать Bucardo)
12. Далее инициализируем DB:
service postgresql initdb
13. Меняем параметр отвечающий за прослушиваемые интерфейсы в postgresql.conf:
listen_addresses = '*'
14. Меняем по вкусу pg_hba.conf, но не забываем разрешить полный доступ ко всем базам для пользователя bucardo c IP первого и второго джейлов:
service postgresql start
16. Если PostgreSQL стартовал, подключаемся к нему по адресу LoopBack:
psql -U pgsql -h 127.0.1.1 postgres
17. Меняем пароль для юзера pgsql и создаем все необходимое для Bucardo:
Запускаем bucardo install и задаем все нужные параметры:
20. Создаем юзера и базу для zabbix:
25. Создаем группу баз. Source означает, что из этой базы будут браться измененные данные. Если вы напишете target, то в этом случае получите master-slave кластер.
В целом настройка CARP и RelayD чрезвычайно проста, подробнее о настройке лоад баланса в Nginx можно найти в поисковике, а по RelayD есть отличный пример на сайте: calomel.org
на примере Zabbix
Создаем мульти-мастер PostgreSQL кластер на примере двух нод PostgreSQL сервера в FreeBSD Jail's. Кластеризовать будем базу данных Zabbix мониторинга, который будет также жить на двух разных хостах внутри FreeBSD Jail's.
Итак, разберемся, что у нас что, и зачем мы это делаем...
1. Bucardo - грубо говоря, это скрипт на Perl, реализующий потоковую репликацию между PostgreSQL серверами, и дарящий нам счастливую возможность иметь 48 мастер нод PostgreSQL. Единственная тонкость, что все реплицируемые таблицы должны иметь Primary key, иначе таблицу не удастся включить в кластерную репликацию: Bucardo home site
Собственно, реализации multi-master репликаций для PostgreSQL без Primary key существуют, например BDR, но он еще не дошел до стабильной стадии, так что пока я его не пробовал. Но в целом, весьма интересная разработка. Когда BDR появится в портах, я его обязательно попробую ;)
2. FreeBSD и Jails - ну а как иначе... Все сервисы должны жить изолированно из соображений безопасности и просто удобства. FreeBSD со своими Jails подходит для этого идеально. Опять же, ZFS пока в нормальном виде только во FreeBSD, в Linux ZFS еще не на такой стадии интеграции, хотя я и на Linux уже активно использую ZFS.
3. Zabbix - его я выбрал чисто для примера. Это не обязательно делать для Zabbix. Вы можете таким образом кластеризовать что угодно! Например можно кластеризовать Asterisk, заставив его хранить экстеншены и все основные настройки в PgSQL. Но и Zabbix, если у вас огромная сеть с кучей устройств для мониторинга, будет не лишним кластеризовать в multi-master варианте :) Разнеся его по разным серверам и сегментам сети.
Создаем свой первый jail для PostgreSQL:
Я использую для управления джейлами QJail. Вполне удобная утилита, "очеловечивающая" работу с джейлами.
Итак, поехали (все операции выполняются парно на двух серверах!!!):
1. Если джейлы вы раньше не использовали, но у вас есть ZFS, то первым делом перед инициализацией джейлов надо создать датасет для них:
zfs create -o compression=lz4 system/usr/jails
По поводу компрессии: lz4 очень быстрый алгоритм, потому его можно использовать везде по-умолчанию. Потерь по производительности нет, а всякие текстовые файлы и логи сжимаются практически в два раза. Учитывая то, что данные перед записью на диск сжимаются - растет скорость записи на диск - в общем одни плюсы.
2. Инициализируем jails' при помощи qjail:
qjail install
3. Создаем датасет для jail с PostgreSQL:
zfs create system/usr/jails/pgsql0X (pgsql 01 на первой ноде, pgsql02 на второй ноде)
zfs create -p -o mountpoint=/usr/jails/pgsql0X/usr/local/pgsql -o recordsize=8K system/usr/jails/pgsql0X/pgsql (X=1 для первой ноды и X=2 для второй)
Параметр recordsize=8K задан для того, что бы размер блока файловой системы и размер блока который пишет PostgreSQL совпадали. PostgreSQL пишет как раз блоками по 8Kb.
5. Создаем Jail:
qjail create -4 em0|192.168.0.X,lo1|127.0.1.1 pgsql0X (X=1 для первой ноды и X=2 для второй)
Интерфейс можно использовать основной, к которому у вас подключена локальная сеть, тогда вам не придется ничего больше делать, только открыть доступ в файрволле. Или можно использовать LoopBack - это более секьюрно, но тогда вам потребуется настроить NAT в PF или IPFW, для доступа к джейлу.
Так же создаем LoopBack для самого джейла, что бы нам было проще взаимодействовать с Bucardo и PostgreSQL: lo1.
Создать lo1 в системе очень просто, для этого нужно в файл /etc/rc.conf добавить: cloned_interfaces="lo1"
И сделать: service netif cloneup
После чего данный интерфейс появится в системе.
6. Джейл создали, теперь идет в /usr/local/etc/qjail.config, ищем там файл с конфигурацией нашего jail (pgsql01 или pgsql02) и вписываем туда параметр "allow.sysvipc;". Без этой опции PostgreSQL не сможет стартовать с ругательствами на невозможность выделения shared memory.
7. После этого запускаем jail:
qjail start pgsql0X
8. После старта джейла можем действовать двумя путями.Через jexec (это правильнее) или через qjail console (что удобнее на первом этапе):
jexec pgsql0X pkg update
jexec pgsql0X pkg install postgresql94-server postgresql94-client postgresql94-plperl p5-Bucardo
9. Если вы планируете несколько PostgreSQL в нескольких джейлах в пределах одного сервера, то нужно перед запуском PgSQL сменить UID его пользователя на другой. UID пользователей pgsql должен различаться во всех джейлах, иначе у вас будут проблемы.
vipw
ee /etc/groups
10. После чего переписать права на все, что принадлежало этому юзеру:
chown -R /usr/local/etc/pgsql
или
find / -uid 70 -exec sh -c 'chown pgsql {} \+'
find / -gid 70 -exec sh -c 'chown :pgsql {} \+'
11. Активируем запуск PostgreSQL и Bucardo:
sysrc postgresql_enable=YES
sysrc bucardo_enable=YES (Только на одном из серверов, на втором Bucardo должен быть выключен до тех пор, пока на первой ноде будет работать Bucardo)
12. Далее инициализируем DB:
service postgresql initdb
13. Меняем параметр отвечающий за прослушиваемые интерфейсы в postgresql.conf:
listen_addresses = '*'
14. Меняем по вкусу pg_hba.conf, но не забываем разрешить полный доступ ко всем базам для пользователя bucardo c IP первого и второго джейлов:
# TYPE DATABASE USER ADDRESS METHOD local all all trust host all all 127.0.1.1/32 trust host all all ::1/128 trust host all bucardo 127.0.1.1/32 trust host all bucardo <ip pg jail 01>/32 trust host all bucardo <ip pg jail 02>/32 trust
service postgresql start
16. Если PostgreSQL стартовал, подключаемся к нему по адресу LoopBack:
psql -U pgsql -h 127.0.1.1 postgres
17. Меняем пароль для юзера pgsql и создаем все необходимое для Bucardo:
ALTER USER pgsql WITH PASSWORD 'PASSWORD';
CREATE USER bucardo WITH PASSWORD 'PASSWORD' SUPERUSER;
CREATE DATABASE bucardo WITH OWNER bucardo;
\q
18. Наконец-то переходим к Bucardo:Запускаем bucardo install и задаем все нужные параметры:
Current connection settings:
1. Host: 127.0.1.1
2. Port: 5432
3. User: pgsql
4. Database: bucardo
5. PID directory: /var/run/bucardo
Enter a number to change it, P to proceed, or Q to quit:
19. Жмем 'P' to proceed и все готово! Bucardo наполнит свою базу и можно переходить к конфигурированию Bucardo и базы Zabbix.20. Создаем юзера и базу для zabbix:
CREATE USER zabbix WITH PASSWORD 'PASSWORD';
CREATE DATABASE zabbix OWNER zabbix;
21. Добавляем в pg_hba.conf записи разрешающие коннект к базе zabbix юзера zabbix из джейлов с заббиксом:host zabbix zabbix <ip zabbix jail 01>/32 md5
host zabbix zabbix <ip zabbix jail
02>/32 md5
service postgresql reload
22. Наполняем базы zabbix. *.sql файлы берем из соседнего джейла с zabbix, который вы создали самостоятельно:
cat schema.sql | psql -U zabbix -h <PgSQL.HOST> zabbix
cat images.sql | psql -U zabbix -h <PgSQL.HOST> zabbix
cat data.sql | psql -U zabbix -h <PgSQL.HOST> zabbix
23. И вот тут выплывает мое упоминание про Primary key для всех реплицируемых таблиц... Дело в том, что в схеме заббикса некоторые таблицы не имеют Primary key, и тут нам надо решить, что мы собираемся делать. Тут у нас два варианта:
A. Сделать, что бы всегда работал только один Zabbix, тогда нам нужно создать primary key для таблиц которые его не имеют:
ALTER TABLE history_uint ADD PRIMARY KEY (itemid,clock);
ALTER TABLE history_str ADD PRIMARY KEY (itemid,clock);
ALTER TABLE history ADD PRIMARY KEY (itemid,clock);
B. Сделать два работающих мастера Zabbbix, тогда нам нужно исключить таблицы куда пишется статистика и всякое разное заббиксом на основе данных от мониторимых узлов. Вот список этих таблиц:
alerts
escalations
events
history
history_log
history_str
history_text
history_uint
trends
trends_uint
Итак, конфигурим bucardo! Все что мы делали до этого, мы делали на двух нодах. Теперь же делаем все на первой!
25. Добавляем наши базы в Bucardo:
bucardo add database zabbix_pg01 dbname=zabbix dbhost=127.0.1.1 dbuser=bucardo dbpass=PASSWORD
bucardo add database zabbix_pg02 dbname=zabbix dbhost=<IP pgsql02> dbuser=bucardo dbpass=PASSWORD
bucardo list database
# Database: zabbix_pg01 Status: active Conn: psql -U bucardo -d zabbix -h 127.0.1.1
# Database: zabbix_pg02 Status: active Conn: psql -U bucardo -d zabbix -h <ip pgsql02>
25. Создаем группу баз. Source означает, что из этой базы будут браться измененные данные. Если вы напишете target, то в этом случае получите master-slave кластер.
bucardo add dbgroup zabbix_servers zabbix_pg01:source zabbix_pg02:source
# Created dbgroup "zabbix_servers"
# Added database "zabbix_pg01" to dbgroup "zabbix_servers" as source
# Added database "zabbix_pg02" to dbgroup "zabbix_servers" as source
26. Добавляем к репликации все:
bucardo add table all db=zabbix_pg01 relgroup=zabbix_herd
bucardo add sequences all db=zabbix_pg01 relgroup=zabbix_herd
27. А вот теперь, если вы выбрали второй вариант, с двума работающими Zabbix, нужно выкинуть из репликации некоторые таблицы, чтоб избежать конфликтов:
bucardo remove table public.xxx
bucardo remove table public.alerts
bucardo remove table public.escalations
bucardo remove table public.events
bucardo remove table public.history
bucardo remove table public.history_log
bucardo remove table public.history_str
bucardo remove table public.history_text
bucardo remove table public.history_uint
bucardo remove table public.trends
bucardo remove table public.trends_uint
И независима от вашего варианта, исключаем базу dbversion, так как она не имеет ключа, и в целом нам не нужна ;)
bucardo remove table public.dbversion
И независима от вашего варианта, исключаем базу dbversion, так как она не имеет ключа, и в целом нам не нужна ;)
bucardo remove table public.dbversion
28. Добавляем теперь собственно синхронизацию:
bucardo add sync zabbix_sync herd=zabbix_herd dbs=zabbix_servers
29. Все, теперь у нас больше не будет конфликтов. Перезапускаем, или просто запускаем Bucardo. Предварительно убедившись, что оба PostgreSQL работают :)
service bucardo start
30. Смотрим статус Bucardo:
bucardo status zabbix_sync
======================================================================
Last good : Aug 31, 2016 19:43:04 (time to run: 1s)
Rows deleted/inserted/conflicts : 1,864 / 1,864 / 1,140
Last bad : Aug 31, 2016 19:43:03 (time until fail: 1s)
Sync name : zabbix_sync
Current state : Good
Source relgroup/database : zabbix_herd / zabbix_pg01
Tables in sync : 105
Status : Stalled
Check time : None
Overdue time : 00:00:00
Expired time : 00:00:00
Stayalive/Kidsalive : Yes / Yes
Rebuild index : No
Autokick : Yes
Onetimecopy : No
Post-copy analyze : Yes
Last error: :
======================================================================
31. Тестируем! Можно попробовать менять содержимое таблицы users. На одной ноде что-то изменили, тут же поглядели на второй - измениться должно и там. Вот например:
Главное, не запускать два Bucardo на двух нодах одновременно! Сделайте, что бы
- Node1
psql -U zabbix -h 127.0.1.1 zabbix
:
zabbix=> select userid,alias,surname from users;
userid | alias | surname
--------+-------+---------------
1 | Admin | Administrator
2 | guest |
(2 rows)
zabbix=> insert into users (userid,alias) values (3,'test');
INSERT 0 1
zabbix=> select userid,alias,surname from users;
userid | alias | surname
--------+-------+---------------
1 | Admin | Administrator
2 | guest |
3 | test |
(3 rows)
- Node2
psql -U zabbix -h 127.0.1.1 zabbix
:
zabbix=> select userid,alias,surname from users;
userid | alias | surname
--------+-------+---------------
1 | Admin | Administrator
2 | guest |
3 | test |
(3 rows)
zabbix=> delete from users where userid=3;
DELETE 1
- Node1
psql -U zabbix -h 127.0.1.1 zabbix
:
zabbix=> select userid,alias,surname from users;
userid | alias | surname
--------+-------+---------------
1 | Admin | Administrator
2 | guest |
(2 rows)
Все, если вы видели изменения на обеих нодах, то у вас все получилось !;)Главное, не запускать два Bucardo на двух нодах одновременно! Сделайте, что бы
Bucardo работал всегда на одной, а на второй (если у вас всего две ноды) он и не нужен будет. Если у вас больше двух нод, придумайте, как поднимать второй в случае падения первой. Я для себя придумал использовать UP/DOWN скрипты на CARP интерфейсе. Если пришел карп на другую ноду, то запускается Bucardo.
Ну собственно все ;) По-скольку статья про Bucardo и PostgreSQL, то настройка заббикса будет вашим домашним заданием ;) Опишу лишь несколько тонкостей работы:
1. Вносить новые хосты и изменять все что угодно можно на двух заббиксах.
2. Агенты должны коннектиться к двум серверам одновременно, так как статистика не реплицируется, и ее нужно откуда-то брать. В целом это fault-tolerance на уровне приложения, за что zabbix честь и хвала!
Пример конфига zabbix клиента:
Ну собственно все ;) По-скольку статья про Bucardo и PostgreSQL, то настройка заббикса будет вашим домашним заданием ;) Опишу лишь несколько тонкостей работы:
1. Вносить новые хосты и изменять все что угодно можно на двух заббиксах.
2. Агенты должны коннектиться к двум серверам одновременно, так как статистика не реплицируется, и ее нужно откуда-то брать. В целом это fault-tolerance на уровне приложения, за что zabbix честь и хвала!
Пример конфига zabbix клиента:
Hostname=server1
Include=/usr/local/etc/zabbix3/zabbix_agentd.d/
LogFile=/var/log/zabbix/zabbix_agentd.log
PidFile=/var/run/zabbix/zabbix_agentd.pid
Server=zabbix01.example.com,zabbix02.example.com
ServerActive=zabbix01.example.com,zabbix02.example.com
LogFileSize=0
Timeout=30
3. History, events и т.д. не реплицируются, так что конфликтов репликации не будет. Из-за этого на каждом хосте будут видны только свои события. Но это не беда, так как агенты все равно все будут дублировать в оба заббикса ;)
Ну вот и все тонкости. Не забудьте засунуть zabbix так же в джейлы, а для джейла сделать датасет, только тюнинг датасету под заббикс не нужен.
В конфиге джейла для zabbix нужно будет включить опцию: allow.raw_sockets = "1";
В целом это негативно сказывается на безопасности, но без нее zabbix не сможет посылать ICMP.
Обращается каждый заббикс к своему PgSQL. Т.е. у нас получаются эдакие полностью независимые серверы, при этом реплицирующиеся между собой.
Баланс входящих между двумя заббиксами я бы сделал при помощи двух CARP IP. Один IP мастер на одном сервере, второй на другом. Если один сервер падает, то IP уходит на запасной, и тогда zabbix все равно работает незаметно для пользователя.
Баланс входящих между двумя заббиксами я бы сделал при помощи двух CARP IP. Один IP мастер на одном сервере, второй на другом. Если один сервер падает, то IP уходит на запасной, и тогда zabbix все равно работает незаметно для пользователя.
Естественно DNS имя должно ссылаться на оба CARP IP сразу.
Баланс HTTP трафика можно сделать при помощи двух Nginx с двумя upstreams или при помощи RelayD. Смысл в том, что Nginx либо RelayD имеют два дестинейшена, и даже если CARP не переехал на другой хост, а Zabbix упал, то Nginx поймет это и отфорвардит вас на другой хост. RelayD для этого имеет отличную функцию "check http", которая может не только потыкаться в порт, но и запросить URL, тем самым вы можете проверить одним запросом не только живость HTTP, но и всей системы вместе с БД.
В целом настройка CARP и RelayD чрезвычайно проста, подробнее о настройке лоад баланса в Nginx можно найти в поисковике, а по RelayD есть отличный пример на сайте: calomel.org
No comments :
Post a Comment