вторник, 2 октября 2012 г.

Установка и настройка londiste 3.1 (skytools) в debian squeeze из исходников

Дабы не реплицировать весь кластер решил прибегнуть к репликации с помощью Londiste и шило в одном месте захотело именно последнюю версию. Ну что ж, раз хочется - сделаем. Версия самого постгреса - 9.2 из репозитория. Возможно что-то будет сделано религиозно неправильно и не православно, но так уж сделал, извиняйте.
Итак, приступим:
Установим пакеты, необходимые для сборки skytools:
 apt-get install build-essential libpq-dev postgresql-server-dev-9.2 python2.6-dev python-psycopg2 rsync  
Если есть желание собрать deb-пакет (у меня было) потребуется установить ещё несколько пакетов:
 apt-get install devscripts autotools-dev xmlto asciidoc python-all-dev postgresql-server-dev-all libevent-dev automake libtool  
Идём на сайт проекта на pgfoundry.org и качаем последний релиз:
 # su - postgres
 ~$ mkdir build && cd build
 ~/build$ wget http://pgfoundry.org/frs/download.php/3321/skytools-3.1.tar.gz
 ~/build$ tar xvf skytools-3.1.tar.gz
 ~/build/skytools-3.1$ cd skytools-3.1
На момент написания заметки в файле debian/rules была допущена ошибка в указании пути к pg_buildext (или я не правильно понял механизм сборки), чтобы её быстренько исправить воспользуемся sed'ом:
 ~/build/skytools-3.1$ sed -i 's/..debian\/pg_buildext/\/usr\/bin\/pg_buildext/' debian/rules  
Но это ещё не все баги в текущем архиве, подправить нужно ещё 2 файла, иначе londiste и pgq не установятся в базу данных:
 ~/build/skytools-3.1$ sed -i 's/pgq.upgrade.2to3.sql/pgq.upgrade.sql/' python/pgq/cascade/admin.py  
 ~/build/skytools-3.1$ sed -i 's/londiste.upgrade.2to3.sql/londiste.upgrade.sql/' python/londiste/setup.py  
Вот теперь можно приступать к сборке deb-пакетов (разработчики skytools об этом заранее позаботились, спасибо им):
 ~/build/skytools-3.1$ make deb
После успешных компиляции и сборки получаем в директории на уровень выше несколько deb-пакетов:
 ~/build/skytools-3.1$ cd ..  
 ~/build$ ls -1 *deb  
 postgresql-8.3-pgq3_3.1_i386.deb  
 postgresql-8.4-pgq3_3.1_i386.deb  
 postgresql-9.0-pgq3_3.1_i386.deb  
 postgresql-9.1-pgq3_3.1_i386.deb  
 postgresql-9.2-pgq3_3.1_i386.deb  
 python-pgq3_3.1_i386.deb  
 python-skytools3_3.1_i386.deb  
 skytools3_3.1_i386.deb  
 skytools3-ticker_3.1_i386.deb  
 skytools3-walmgr_3.1_i386.deb  
Вуаля, теперь можно установить deb'ы (не забываем что делать это нужно от рута):
 # dpkg -i *.deb  
После установки компонентов skytools можно приступить настройке londiste.
Архитектура работы Londiste следующая: на хосте с мастер-базой находится провайдер, который отправляет данные подписчикам, т.е. другим хостам (точнее инстансам/кластерам постгреса, которые могут выполнятся и на одном хосте). Настройку и провайдера и подписчика можно производить с одного хоста, главное чтобы с него можно было подключаться ко второй базе. В моём случае все действия производятся исключительно на мастере, но skytools должен быть установлен на обоих серверах. Установка на второй хост deb-пакетов ничем не отличается от установки на первый, за исключением того что вы можете воспользоваться уже собранными deb-пакетами ;)
Удобства ради рекомендую создать файл .pgpass с учётными данными для подключения к базам данных, формат файла предельно прост:
 hostname:port:database:username:password  
Любую часть можно заменить звёздочкой (*).

Для начала нужно добавить londiste и pgq в нашу базу. Для этого воспользуемся утилитой qadmin, которая была добавлена в skytools3:
 su - postres
 ~$ qadmin -h localhost -U postgres -d domains -c "install londiste"  
 Server version 9.2.0  
 INSTALL  
Далее перенесём схему базы на второй сервер (на втором хосте нужно прописать соответствующие правила в pg_hba.conf):
 ~$ pg_dump -s -C domains | psql -h <второй_хост> -U postgres  
Создадим каталоги для лог- и pid-файлов провайдера и подписчика, а затем изменим владельца этих каталогов на пользователя postgres (т.к. я запускал демонов londiste и pgq именно из-под него во время экспериментов):
 # mkdir -p /var/log/skytools/pgsql  
 # mkdir -p /var/run/skytools/pgsql  
 # chown postgres:postgres /var/log/skytools/pgsql  
 # chown postgres:postgres /var/run/skytools/pgsql  
Теперь нужно создать конфигурационный файл провайдера (мастера). У меня он получился такой:
 ~$ cat /etc/skytools/replication_master.ini   
 [londiste3]  
 job_name = replication_src  
 db = host=localhost dbname=domains user=postgres  
 queue_name = replica  
 logfile = /var/log/skytools/pgsql/dns_msc.log  
 pidfile = /var/run/skytools/pgsql/dns_msc.pid  
Далее произведём инициализацию провайдера:
 # su - postgres  
 ~$ londiste3 /etc/skytools/replication_master.ini create-root master-server 'dbname=domains host=localhost'  
Где master-server - это имя провайдера (мастера).
Конфиг для слэйва получился почти такой же:
 ~$ cat /etc/skytools/dns_msc_replication_slave.ini   
 [londiste3]  
 job_name = replication_dst  
 db = dbname=domains host=<имя/адрес хоста мастера> user=postgres  
 queue_name = replica  
 logfile = /var/log/skytools/pgsql/dns_msc_slave.log  
 pidfile = /var/run/skytools/pgsql/dns_msc_slave.pid  
Имя очереди (queue_name) на мастере и подписчике должно совпадать! Подключаем потребителя (подписчика) к провайдеру (мастеру):
 ~$ londiste3 /etc/skytools/replication_slave.ini create-leaf slave-server 'dbname=domains host=<имя/адрес хоста мастера>' --provider='dbname=domains host=localhost'  
Теперь настроим непосредственно pgq (он же ticker), ту самую очередь на которой построена репликация. Конфиг pgqd:
 ~$ cat /etc/skytools/pgqd.ini   
 [pgqd]  
 logfile = /var/log/skytools/pgsql/pgqd.log  
 pidfile = /var/run/skytools/pgsql/pgqd.pid  
 base_connstr = host=localhost user=postgres  
 initial_database = domains  
Запускаем демоны londiste и pgq:
 postgres@master:~$ pgqd -d /etc/skytools/pgqd.ini  
 postgres@master:~$ londiste -d /etc/skytools/replication_master.ini worker  
 postgres@master:~$ londiste -d /etc/skytools/replication_slave.ini worker  
Проверяем что все сервисы живы-здоровы:
 postgres@host1:~$ londiste3 /etc/skytools/replication_master.ini status  
 Queue: replica  Local node: master-server  
   
 master-server (root)  
  |              Tables: 0/0/0  
  |              Lag: 6s, Tick: 13311  
  +--slave-server (leaf)  
                Tables: 0/0/0  
                Lag: 6s, Tick: 13311  
   
 postgres@host1:~$ londiste3 /etc/skytools/replication_master.ini members  
 Member info on master-server@replica:  
 node_name    dead       node_location  
 --------------- --------------- -------------------------------------------  
 slave-server    False      dbname=domains host=host2  
 master-server    False      dbname=domains host=localhost user=postgres  
   
Радуемся тому что оно таки заработало (я был очень счастлив), но никакой репликации ещё пока не запущено :) Нужно обяснить londiste какие таблицы реплицировать, однако в моём случае не нужно было реплицировать все таблицы, более того имена таблиц у меня будут различаться:
master -> slave
------------------------
domains -> domains
records_master -> records

Итак, ознакомившись в очередной раз с документацией, приступим. Сначала объясним мастеру какие таблицы будем отдавать:
 postgres@host1:~$ londiste3 /etc/skytools/replication_master.ini add-table domains  
 postgres@host1:~$ londiste3 /etc/skytools/replication_master.ini add-table records_slave  
Затем слэйву какие таблицы забирать у мастера и исправим имя принимающей таблицы:
 postgres@host1:~$ londiste3 /etc/skytools/replication_slave.ini add-table domains  
 postgres@host1:~$ londiste3 /etc/skytools/replication_slave.ini add-table records_slave --dest-table=records  
Теперь нужно подождём некоторое время чтобы завершилась начальная репликация и проверим состояние:
 postgres@host1:~$ londiste3 /etc/skytools/replication_master.ini status  
 Queue: replica  Local node: master-server  
   
 master-server (root)  
  |              Tables: 2/0/0  
  |              Lag: 3s, Tick: 13326  
  +--slave-server (leaf)  
                Tables: 2/0/0  
                Lag: 3s, Tick: 13326  
Одинаковые строчки "Tables: 2/0/0" говорят о том что всё пучком. Если нет, то идём в документацию и узнаём что же означают эти цифры x/y/z:
  • x - количество таблиц в состоянии ok (replicated), если на мастере - то они нормально отдаются слэйвам, если на слэйве - нормально прилетают с мастера;
  • y - количество таблиц в состоянии half (initial copy not finnished), у мастера должно быть 0, у промежуточного в каскадной репликации и слэйва - указывает количество таблиц в процессе копирования
  • z - количество таблиц в состоянии ignored (table not replicated locally), у мастера 0, у слэйва - количество таблиц, которые не добавлены для репликации с мастера (т.е. мастер отдает, а слэйв их просто не забирает)

Возможные грабли:
  • Ошибка "OperationalError: could not access file "$libdir/pgq_lowlevel": No such file or directory" - не установлен пакет postgresql-x.x-pgq3_3.1_i386.deb, возможно он даже не собрался, проверьте что собрались все deb'ы. У меня они не собирались как раз из-за неправильного пути к pg_buildext
  • ERROR Job <имя задачи из конфига> crashed: File not found: pgq.upgrade.2to3.sql - не исправлен pgq/cascade/admin.py как указано ввыше


Если есть какие-либо вопросы или что-то не получается - спрашивайте в комментариях.

4 комментария:

  1. Доброго дня!
    С подобной ошибклй не сталкивались?

    londiste3 /etc/skytools/londiste-master.ini create-root host0 'dbname=testdb host=host0'
    2015-08-13 23:46:37,444 2228 INFO plpgsql is installed
    2015-08-13 23:46:37,447 2228 INFO pgq is installed
    2015-08-13 23:46:37,450 2228 INFO Installing pgq.get_batch_cursor
    2015-08-13 23:46:37,452 2228 INFO Reading from /usr/share/skytools3/pgq.upgrade.2to3.sql
    2015-08-13 23:46:37,483 2228 ERROR Job postgres_rep got error on connection 'db': column "queue_disable_insert" of relation "queue" already exists. Query: alter table pgq.queue add column queue_disable_insert boolean;
    Traceback (most recent call last):
    File "/usr/lib/python2.7/site-packages/skytools/scripting.py", line 568, in run_func_safely
    return func()
    File "/usr/lib/python2.7/site-packages/skytools/adminscript.py", line 62, in work
    fn(*cmdargs)
    File "/usr/lib/python2.7/site-packages/pgq/cascade/admin.py", line 147, in cmd_create_root
    return self.create_node('root', args)
    File "/usr/lib/python2.7/site-packages/pgq/cascade/admin.py", line 198, in create_node
    self.install_code(db)
    File "/usr/lib/python2.7/site-packages/londiste/setup.py", line 29, in install_code
    CascadeAdmin.install_code(self, db)
    File "/usr/lib/python2.7/site-packages/pgq/cascade/admin.py", line 425, in install_code
    skytools.db_install(db.cursor(), objs, self.log)
    File "/usr/lib/python2.7/site-packages/skytools/sqltools.py", line 531, in db_install
    obj.create(curs, log)
    File "/usr/lib/python2.7/site-packages/skytools/sqltools.py", line 490, in create
    curs.execute(stmt)
    File "/usr/lib/python2.7/site-packages/psycopg2/extras.py", line 120, in execute
    return super(DictCursor, self).execute(query, vars)
    ProgrammingError: column "queue_disable_insert" of relation "queue" already exists

    !? :( Как бы это победить?

    ОтветитьУдалить
  2. а у меня вот такая ошибка в логе слэйва:

    2015-08-18 11:39:13,529 17409 ERROR Job slave01_account_l3 got error on connection '_provider_db': schema "pgs_distribution_metadata" does not exist. Query:
    SELECT n.nspname||'.'||c.relname AS name
    ...
    Traceback (most recent call last):
    File "/usr/lib64/python2.6/site-packages/skytools/scripting.py", line 568, in run_func_safely
    return func()
    File "/usr/lib64/python2.6/site-packages/londiste/table_copy.py", line 229, in work
    return Replicator.work(self)
    File "/usr/lib64/python2.6/site-packages/pgq/cascade/consumer.py", line 199, in work
    return BaseConsumer.work(self)
    File "/usr/lib64/python2.6/site-packages/pgq/baseconsumer.py", line 257, in work
    self._launch_process_batch(db, batch_id, ev_list)
    File "/usr/lib64/python2.6/site-packages/pgq/baseconsumer.py", line 286, in _launch_process_batch
    self.process_batch(db, batch_id, list)
    File "/usr/lib64/python2.6/site-packages/pgq/cascade/consumer.py", line 172, in process_batch
    self.process_remote_batch(src_db, tick_id, event_list, dst_db)
    File "/usr/lib64/python2.6/site-packages/londiste/playback.py", line 377, in process_remote_batch
    self.sync_tables(src_db, dst_db)
    File "/usr/lib64/python2.6/site-packages/londiste/playback.py", line 433, in sync_tables
    res = self.sync_from_copy_thread(cnt, src_db, dst_db)
    File "/usr/lib64/python2.6/site-packages/londiste/playback.py", line 585, in sync_from_copy_thread
    self.do_copy(t, src_db, dst_db)
    File "/usr/lib64/python2.6/site-packages/londiste/table_copy.py", line 165, in do_copy
    stats = p.real_copy(src_real_table, src_curs, dst_curs, common_cols)
    File "/usr/lib64/python2.6/site-packages/londiste/handler.py", line 238, in real_copy
    write_hook = _write_hook)
    File "/usr/lib64/python2.6/site-packages/skytools/sqltools.py", line 446, in full_copy
    src_curs.copy_expert(sql_to, buf)
    ProgrammingError: schema "pgs_distribution_metadata" does not exist

    ОтветитьУдалить
  3. Разобрался. Теперь все работает. Надо было включить extension pg_shard.

    ОтветитьУдалить
  4. Вопрос такой - на таблице-приемнике висит другой триггер на BEFORE INSERT, и он почему-то не срабатывает...какие могут быть варианты?

    ОтветитьУдалить