redmine

Added two articles for clsync

++ Введение
Нередко могут возникать ситуации, требующие атомарной синхронизации используемых файловых данных. В качестве утрированного примера представить, что имеется большая директория «/var/www» и необходимо перенести её содержимое на другой сервер в целостном виде без долгой сервисов.
Многие администраторы в таких случаях применяют циклический rsync, в результате работы которого ОС накапливают дисковый кеш, в результате чего последующие итерации rsync выполняются всё быстрее и быстрее. После того, как время досинхронизации станет достаточно малым, чтобы downtime таких масштабов был допустим, работу сервисов (использующих «/var/www») останавливают, дожидаются дополнительной итерации rsync, после чего запускают сервисы уже на другом узле.
Однако данный метод обладает достаточно ограниченной применимостью. Дискового кеша или других ресурсов может оказаться недостаточным, чтобы время итерации rsync сократилось до приемлемых величин.
Предполагается, что rsync администратор способен настроить самостоятельно, поэтому подробности его настройки в данном тексте не рассматриваются.
++ Решение
Решение достаточно простое:
ionice -c 3 clsync --exit-on-no-events=1 --max-iterations=20 --exit-hook=/root/stop-here-start-there.sh --mode=rsyncshell --ignore-exitcode=23 --retries=3 -W /var/www -S /root/rsync.sh -L /dev/shm/clsync
Далее создаём /root/rsync.sh примерно следующего содержания:
exec rsync --password-file="/root/rsync.pass" -aHv --timeout=3600 --delete-before --exclude-from="$4" --include-from="$3" --exclude='*' /var/www/ rsync://clsync@другой_узел/var/www/ 2>/tmp/clsync-rsync-"$LABEL"-brother.err
clsync произведёт полную синхронизацию, после чего будет отлавливать изменения на файловой системе внутри «/var/www» и производить досинхронизации только по нужным файлам/директориям. Досинхронизации прекратятся как только будет нéчего синхронизировать (за время последней досинхронизации ничего не изменилось) или завершится 20-ая итерации синхронизации (чтобы процесс не длился вечно).
После окончания синхронизаций clsync запустит скрипт «/root/stop-here-start-there.sh». Предполагается, что в данном скрипте будет описан сценарий остановки сервисов на старом узле и их запуска на новом узле. Таким образом downtime будет минимизирован.
Установить clsync можно следующим образом:
# Debian
apt-get install clsync
# Gentoo
layman -a bircoph
emerge --sync
emerge =app-admin/clsync-0.3
# FreeBSD
git clone https://github.com/xaionaro/clsync
cd clsync/freebsd/usr/ports/sysutils/clsync && make install
# Other
pushd /tmp
git clone https://github.com/xaionaro/clsync
cd clsync
autoreconf -fi
./configure
make install
... ...
... ... @@ -758,7 +758,7 @@ srv-1 — seth
STOPPED
Первая «R» внутри «[ R ]» означает, что контейнер находится в синхронном состоянии на соседнем узле, а вторая «[ R ]» — что узел находится в синхронном состоянии на сервере резервного копирования.
Сами квадратные скобки «[» и «]» означают, что репликация осуществуется с _данного узла_.
Сами квадратные скобки «[» и «]» означают, что репликация осуществляется с _данного узла_.
Если посмотреть на «lxc-list» со стороны соседнего узла, то можно увидеть:
g[17:01:01] [root@seth ~]# lxc-list
... ... @@ -1035,4 +1035,4 @@ Percona Server -> wsrep hooks -> galera plugin -> система коммуни
++ Пара слов об ipw
Если вы произвели изменение конфига ipw, то достаточно набрать "ipw fix", чтобы его применить.
\ No newline at end of file
Если вы произвели изменение конфига ipw, то достаточно набрать "ipw fix", чтобы его применить.
... ...
++ Введение
Достаточно типичной задачей в системной администрировании является поддержание определённых файлов в синхронном состоянии на большом количестве узлов.
В рамках рассмотренных ниже примеров синхронизация будет производится по схеме master-slave для файлов из директории /opt/global (на master-узле) в директорию /opt/production (на slave-узлах).
++ Установка clsync
Установить clsync можно следующим образом:
# Debian
apt-get install clsync
# Gentoo
layman -a bircoph
emerge --sync
emerge clsync
# FreeBSD
git clone https://github.com/xaionaro/clsync
cd clsync/freebsd/usr/ports/sysutils/clsync && make install clean
# Other
pushd /tmp
git clone https://github.com/xaionaro/clsync
cd clsync
autoreconf -fi
./configure
make install
++ pdcp
pdcp - это утилита позволяющая производить копирование файла на множество узлов посредством ssh.
Установка (на master-узле):
# Debian:
apt-get install pdsh
# Gentoo:
emerge pdsh
# FreeBSD
cd /usr/ports/sysutils/pdsh && make install clean
Подготовка (обычно этот этап не требуется, так как такие кластера делаются методом клонирования системы, однако для наглядности пример команд с master-узла):
ssh-keygen -t ecdsa -b 521
# Копирование ключей на все узлы
for HOST in $(seq 16 31); do
IP=192.168.0."$host"
echo "$IP n${HOST}.example.org n${HOST}" >> /etc/hosts
echo "$HOST" >> /etc/machines
ssh-copy-id "$IP"
done
Подготовка master-узла:
cat > /root/pdcp-handler.c << EOF
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <clsync/clsync.h>
#include <clsync/configuration.h>
#include <clsync/malloc.h>
#include <clsync/error.h>
struct ctx *ctx_p;
int clsyncapi_init(struct ctx *_ctx_p, struct indexes *_indexes_p) {
ctx_p = _ctx_p;
return 0;
}
int clsyncapi_sync(int n, api_eventinfo_t *ei) {
size_t argv_size;
char **argv;
debug(3, "n == %i", n);
if(n == 0)
return 0;
argv_size = n+4; // "pdcp" + "-a" + n*path + NULL
argv = xmalloc(argv_size * sizeof(char *));
argv[0] = "/usr/bin/pdcp";
argv[1] = "-a";
int i = 2;
int j = 0;
while (i < n) {
if(ei[j].path_len)
argv[i++] = (char*)ei[j].path;
j++;
}
argv[i++] = NULL;
int pid = clsyncapi_fork(ctx_p);
switch(pid) {
case -1:
critical("got error while clsyncapi_fork()");
case 0:
execv(argv[0], argv);
critical("got error while execv()");
}
int status;
if(waitpid(pid, &status, 0) != pid)
critical("got error while waitpid()");
int exitcode = WEXITSTATUS(status);
free(argv);
return exitcode;
}
EOF
gcc -march=native -O2 -funswitch-loops -fpredictive-commoning -fgcse-after-reload -ftree-vectorize -ftree-loop-linear -ftree-loop-im -fweb -frename-registers -fomit-frame-pointer -fexcess-precision=fast -pipe --std=gnu11 -Wall -fPIC -shared -Wl,-O1,--as-needed /root/pdcp-handler.c -o /root/pdcp-handler.so
Запуск на master-узле:
clsync --mode=so --sync-handler=/root/pdcp-handler.so --watch-dir=/opt/global --background=1 --output=syslog
Готово, можно попробовать:
date >> /opt/global/test.log
++ uftp
uftp - это утилита позволяющая организовывать передачу файлов посредством multicast, что может быть удобным при передаче больших объёмов информации на очень большое количество узлов.
Установка зависимостей (на всех узлах)
# Debian:
apt-get install libssl-dev
Установка (на всех узлах):
wget 'http://sourceforge.net/projects/uftp-multicast/files/source-tar/uftp-4.3.tar'
tar -xvf uftp-4.3.tar
cd uftp
make install
Подготовка (на всех узлах):
mkdir -p /opt/global /opt/production
# Linux
echo net.ipv4.igmp_max_memberships=256 >> /etc/sysctl.conf
sysctl -f
Запуск на slave-узлах:
uftpd -M 248.225.233.1 -D /opt/production
# если у вас настроено использование pdsh, то тогда:
# pdsh -a echo uftpd -M 248.225.233.1 -D /opt/production \> /etc/rc.local # или в другое место, в зависимости от вашей системы
# pdsh -a uftpd -M 248.225.233.1 -D /opt/production
Доподготовка master-узла:
cat > /root/uftp-handler.c << EOF
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <clsync/clsync.h>
#include <clsync/configuration.h>
#include <clsync/malloc.h>
#include <clsync/error.h>
struct ctx *ctx_p;
int clsyncapi_init(struct ctx *_ctx_p, struct indexes *_indexes_p) {
ctx_p = _ctx_p;
return 0;
}
int clsyncapi_sync(int n, api_eventinfo_t *ei) {
size_t argv_size;
char **argv;
debug(3, "n == %i", n);
if(n == 0)
return 0;
argv_size = n+5; // "uftp" + "-M" + ip-address + n*path + NULL
argv = xmalloc(argv_size * sizeof(char *));
argv[0] = "/usr/local/bin/uftp";
argv[1] = "-M";
argv[2] = "248.225.233.1";
int i = 3;
int j = 0;
while (i < n) {
if(ei[j].path_len)
argv[i++] = (char*)ei[j].path;
j++;
}
argv[i++] = NULL;
int pid = clsyncapi_fork(ctx_p);
switch(pid) {
case -1:
critical("got error while clsyncapi_fork()");
case 0:
execv(argv[0], argv);
critical("got error while execv()");
}
int status;
if(waitpid(pid, &status, 0) != pid)
critical("got error while waitpid()");
int exitcode = WEXITSTATUS(status);
free(argv);
return exitcode;
}
EOF
gcc -march=native -O2 -funswitch-loops -fpredictive-commoning -fgcse-after-reload -ftree-vectorize -ftree-loop-linear -ftree-loop-im -fweb -frename-registers -fomit-frame-pointer -fexcess-precision=fast -pipe --std=gnu11 -Wall -fPIC -shared -Wl,-O1,--as-needed /root/uftp-handler.c -o /root/uftp-handler.so
Запуск на master-узле:
clsync --mode=so --sync-handler=/root/uftp-handler.so --watch-dir=/opt/global --background=1 --output=syslog
Готово, можно попробовать:
date >> /opt/global/test.log
... ...