Репликация миграций в PostgreSQL

203 views
Skip to first unread message

Alexander Oryol

unread,
Mar 25, 2009, 10:29:06 AM3/25/09
to RubyOnRails to russian
Всем привет.

Как я понял, самое частое решение для репликации - Slony-I. Но как
быть с миграциями?
Кто как решает?

--
Alexander Oryol <eagle...@gmail.com>

Max Lapshin

unread,
Mar 25, 2009, 11:03:15 AM3/25/09
to ror...@googlegroups.com


2009/3/25 Alexander Oryol <eagle...@gmail.com>

Всем привет.

Как я понял, самое частое решение для репликации - Slony-I. Но как
быть с миграциями?
Кто как решает?

У меня продакшн запусков постгреса сейчас нет, но как я понял, надо что-то типа такого:

сделать что бы cap deploy:migrate прокатывался на всех ролях :db и добавить все слейвы в :db.


Ivan Evtuhovich

unread,
Mar 25, 2009, 11:16:31 AM3/25/09
to ror...@googlegroups.com
Привет.

Попробуй Londiste, они гораздо проще в настройке. Мы два раза
переезжали с сервера на сервер, использую Londiste.

Londiste написан компанией skype на базе их реализации очередей PgQ.

Насчет миграций -- сложнее, стандартного решения нет.

2009/3/25 Max Lapshin <max.l...@gmail.com>:

eagleas

unread,
Mar 25, 2009, 11:22:47 AM3/25/09
to RubyOnRails to russian
Т.е. никуда не денешься от того чтобы держать деплой-юзера, ruby/gems
и копию кода на слейвах?
Именно этого и хотелось избежать.

On 25 мар, 18:03, Max Lapshin <max.laps...@gmail.com> wrote:
> 2009/3/25 Alexander Oryol <eagle.a...@gmail.com>

--
Alexander Oryol <eagle...@gmail.com>

Max Lapshin

unread,
Mar 25, 2009, 11:27:45 AM3/25/09
to ror...@googlegroups.com


2009/3/25 eagleas <eagle...@gmail.com>

Т.е. никуда не денешься от того чтобы держать деплой-юзера, ruby/gems
и копию кода на слейвах?
Именно этого и хотелось избежать.

Видимо, да. Не настраивать же PGpool исключительно для репликации DDL-выражений!
 

Ivan Evtuhovich

unread,
Mar 25, 2009, 11:34:35 AM3/25/09
to ror...@googlegroups.com
Вообще, копию кода можно держать только на одном сервере. А оттуда
коннектиться ко всем нужным базам и прогонять миграции.

В любом случае, придется что-то дописывать, почему бы не дописать в таком ключе.

2009/3/25 eagleas <eagle...@gmail.com>:

Max Lapshin

unread,
Mar 25, 2009, 11:37:13 AM3/25/09
to ror...@googlegroups.com


2009/3/25 Ivan Evtuhovich <evtuh...@gmail.com>

Вообще, копию кода можно держать только на одном сервере. А оттуда
коннектиться ко всем нужным базам и прогонять миграции.

В любом случае, придется что-то дописывать, почему бы не дописать в таком ключе.

Разумно, кстати. Добавить несколько environment-ов, в которых прокатывать миграции

Alexander Oryol

unread,
Mar 25, 2009, 11:44:32 AM3/25/09
to RubyOnRails to russian
On 25 мар, 18:34, Ivan Evtuhovich <evtuhov...@gmail.com> wrote:
> Вообще, копию кода можно держать только на одном сервере. А оттуда
> коннектиться ко всем нужным базам и прогонять миграции.
>
> В любом случае, придется что-то дописывать, почему бы не дописать в таком ключе.

Вот именно это я и спрашивал, может кто-то уже делал?
И пока у меня не складывается четкой картинки как рецептами капистрано
это сделать.

> 2009/3/25 eagleas <eagle.a...@gmail.com>:


> > Т.е. никуда не денешься от того чтобы держать деплой-юзера, ruby/gems
> > и копию кода на слейвах?
> > Именно этого и хотелось избежать.

--
Alexander Oryol <eagle...@gmail.com>

Nikolay Grebnev

unread,
Mar 25, 2009, 12:02:50 PM3/25/09
to ror...@googlegroups.com
А можно по-подробнее рассказать про переезд с сервера на сервер с помощью Londiste ????

2009/3/25 Ivan Evtuhovich <evtuh...@gmail.com>

Max Lapshin

unread,
Mar 25, 2009, 12:04:24 PM3/25/09
to ror...@googlegroups.com
config/database.yml:

production:
 ...
slave_1:
    ...
slave_2:
    ...

config/deploy.rb:

namespace :deploy do
  desc "Task that run current migrations"
  task :migrate, :roles => :db do
    envs = %w(production slave1 slave2)
    run "cd #{deploy_to} ; " + envs.map {|env| "RAILS_ENV=#{env} rake db:migrate"}.join(";")
  end
end



ну как-то так. 

Alexander Oryol

unread,
Mar 25, 2009, 12:16:50 PM3/25/09
to RubyOnRails to russian
On 25 мар, 18:16, Ivan Evtuhovich <evtuhov...@gmail.com> wrote:
> Привет.
>
> Попробуй Londiste, они гораздо  проще в настройке. Мы два раза
> переезжали с сервера на сервер, использую Londiste.
>
> Londiste написан компанией skype на базе их реализации очередей PgQ.


Цитата из http://postgresmen.ru/articles/view/25 про Londiste:
"К недостаткам можно отнести:
* отсутствие поддержки sequence делает невозможным поддержание
failover-сервера актуальным (для этой цели нужно использовать WalMgr)"

Что имеется ввиду под "отсутствие поддержки sequence" ?

>
> Насчет миграций -- сложнее, стандартного решения нет.
>

> 2009/3/25 Max Lapshin <max.laps...@gmail.com>:
>
>
>
> > 2009/3/25 Alexander Oryol <eagle.a...@gmail.com>


>
> >> Всем привет.
>
> >> Как я понял, самое частое решение для репликации - Slony-I. Но как
> >> быть с миграциями?
> >> Кто как решает?
>
> > У меня продакшн запусков постгреса сейчас нет, но как я понял, надо что-то
> > типа такого:
> > сделать что бы cap deploy:migrate прокатывался на всех ролях :db и добавить
> > все слейвы в :db.

--
Alexander Oryol <eagle...@gmail.com>

Alexander Oryol

unread,
Mar 25, 2009, 12:26:50 PM3/25/09
to RubyOnRails to russian

О, спасибо. Сегодня тестим с :roles, завтра попробуем это решение.

--
Alexander Oryol <eagle...@gmail.com>

Ivan Evtuhovich

unread,
Mar 26, 2009, 5:27:00 AM3/26/09
to ror...@googlegroups.com
Привет.

В той же статье внизу:
Apr 2007

Как я понимаю, раньше не реплицировались sequences, а теперь с этим
всё в порядке.

Более подробно про Londiste рассказать не могу, так как оба раза
репликацию настраивал мой коллега. В планах у нас поднять
failover-кластер как раз с использованием Londiste.

2009/3/25 Alexander Oryol <eagle...@gmail.com>:

andrey....@gmail.com

unread,
Mar 28, 2009, 6:35:12 AM3/28/09
to RubyOnRails to russian
Репликация базы с помощью londiste:

Все делается на master-сервере, на slave надо будет только развернуть
свежий дамп для ускорения процесса начальной синхронизации баз.

1. Ставим последние skytools (http://pgfoundry.org/projects/skytools/)

2. Создаем файл ticker.ini (конфиг для pgq тикера)

[pgqadm]
job_name = pgqadm_master_db
db = dbname=master_db user=pgsql
# how often to run maintenance [seconds]
maint_delay = 600
# how often to check for activity [seconds]
loop_delay = 0.1
logfile = /usr/db/pgsql/data/pg_log/%(job_name)s.log
pidfile = /usr/db/pgsql/data/pg_log/%(job_name)s.pid

3. Создаем файл replic.ini (конфиг для londiste)

[londiste]
job_name = myproject_master_db_to_slave
provider_db = dbname=master_db
subscriber_db = dbname=slave_db host=slave_host
# it will be used as sql ident so no dots/spaces
pgq_queue_name = replika
logfile = /usr/db/pgsql/data/pg_log/%(job_name)s.log
pidfile = /usr/db/pgsql/data/pg_log/%(job_name)s.pid

3. Запускаем pgq-тикер:

pgqadm.py ticker.ini install
pgqadm.py ticker.ini ticker -d

4. Разворачиваем дамп мастера на subscriber_db и запускаем репликацию:

pg_dump/pg_restore

londiste.py replic.ini provider install
londiste.py replic.ini subscriber install
londiste.py replic.ini replay -d

5. Указываем таблицы и последовательности для репликации:

londiste.py replic.ini provider add `echo "\dt" | psql -t master_db
pgsql | awk '{print $3}'`
londiste.py replic.ini provider add-seq `echo "\ds" | psql -t
master_db pgsql | awk '{print $3}'`

londiste.py replic.ini subscriber add `echo "\dt" | psql -t master_db
pgsql | awk '{print $3}'`
londiste.py replic.ini subscriber add-seq `echo "\ds" | psql -t
master_db pgsql | awk '{print $3}'`

6. Контролируем процесс

Смотрим состояние синхронизации таблиц:

londiste.py replic.ini subscriber tables

Следим за активностью londiste:

tail -f /usr/db/pgsql/data/pg_log/%(job_name)s.log


Примерно так :)

Nikolay Grebnev

unread,
Mar 28, 2009, 10:09:44 AM3/28/09
to ror...@googlegroups.com
Круто. Вам надо опубликовать это где-то. Первое вменяемое описание работы с londiste .
Вопрос навскидку - А что такое "свежий дамп" . Как и когда его делать, если база постоянно обновляется???

andrey....@gmail.com

unread,
Mar 28, 2009, 10:40:01 AM3/28/09
to RubyOnRails to russian

On Mar 28, 5:09 pm, Nikolay Grebnev <nikolaygreb...@gmail.com> wrote:
> Круто. Вам надо опубликовать это где-то. Первое вменяемое описание работы с
> londiste .

Спасибо за предложение, пожалуй стоит с посгресменами(postgresmen.ru)
обсудить.

> Вопрос навскидку - А что такое "свежий дамп" . Как и когда его делать, если
> база постоянно обновляется???
>

Это надо сделать один раз при настройке. После уже на таблицах master-
базы будут висеть триггеры,
которые будут сбрасывать изменения в pgq-очереди, а скрипт
londiste.py будет
реплицировать их в slave-базу.

Max Lapshin

unread,
Mar 29, 2009, 6:25:10 AM3/29/09
to ror...@googlegroups.com


2009/3/28 Nikolay Grebnev <nikolay...@gmail.com>

Круто. Вам надо опубликовать это где-то. Первое вменяемое описание работы с londiste .
Вопрос навскидку - А что такое "свежий дамп" . Как и когда его делать, если база постоянно обновляется???

Так на сайте скайтулзов это же и написано =) 

Nikolay Grebnev

unread,
Mar 29, 2009, 6:32:06 AM3/29/09
to ror...@googlegroups.com
Несколько месяцев назад не было. Была ссылка на
http://pgsql.tapoueh.org/site/html/londiste/londiste.html
Где описание не совсем членоразденое. (может и нет, но тогда применения у себя по этому описанию я не усмотрел)

2009/3/29 Max Lapshin <max.l...@gmail.com>

Max Lapshin

unread,
Mar 29, 2009, 6:43:54 AM3/29/09
to ror...@googlegroups.com


2009/3/29 Nikolay Grebnev <nikolay...@gmail.com>

Несколько месяцев назад не было. Была ссылка на
http://pgsql.tapoueh.org/site/html/londiste/londiste.html
Где описание не совсем членоразденое. (может и нет, но тогда применения у себя по этому описанию я не усмотрел)

Аа, ясно. Я где-то с месяц назад экспериментировал со скайтулзами, там вроде уже что-то почленораздельнее было.

Alexander Oryol

unread,
Mar 30, 2009, 10:24:27 AM3/30/09
to RubyOnRails to russian
Отчет :-)

Во-первых пришлось все же перепрыгнуть на Londiste, т.к. Slony-I лочит
реплицируемые таблицы на slave, и с этим ничего нельзя поделать, кроме
как оборачивать все миграции в "EXECUTE SCRIPT", что несерьезно.

On 25 мар, 20:26, Alexander Oryol <eagle.a...@gmail.com> wrote:
> On 25 мар, 19:04, Max Lapshin <max.laps...@gmail.com> wrote:
> > config/database.yml:
> > production:
> >  ...
> > slave_1:
> >     ...
> > slave_2:
> >     ...

Это все так.

>
> > config/deploy.rb:
>
> > namespace :deploy do
> >   desc "Task that run current migrations"
> >   task :migrate, :roles => :db do
> >     envs = %w(production slave1 slave2)
> >     run "cd #{deploy_to} ; " + envs.map {|env| "RAILS_ENV=#{env} rake
> > db:migrate"}.join(";")
> >   end
> > end
>
> > ну как-то так.

А это так:


namespace :deploy do
desc "Task that run current migrations"
task :migrate, :roles => :db do

migrate_target = fetch(:migrate_target, :latest)
directory = case migrate_target.to_sym
when :current then current_path
when :latest then current_release
else raise ArgumentError, "unknown migration target #
{migrate_target.inspect}"
end
version = ENV['VERSION'] ? "VERSION=#{ENV['VERSION']}" : ""
envs = ["#{stage}", "#{stage}_slave1"]
run "cd #{directory} && " + envs.map {|env| "(echo '==
environment: #{env} =='; RAILS_ENV=#{env} rake db:migrate #
{version})"}.join(' && ')
end
end

Мы используем capistrano multistage поэтому подмешана stage
переменная. Для того чтобы можно было указывать версию - протаскиваем
VERSION внутрь.

> О, спасибо. Сегодня тестим с :roles, завтра попробуем это решение.

Вариант с ролями оказался самый геморройный. Ну вот нафига на хосте
накотором только PostgreSQL - руби, рельсы, репозиторий проекта и все
внешние гемы к нему (да, про vendor/gems в курсе, туда просто не все
запихивается)...
А т.к. гемы подразумевают компиляцию - еще и gcc, gpp и прочая...

Осталась нерешенной одна проблема - после создания в миграции новой
таблицы нужно запускать от системного юзера postgres на хосте базы
команды:
londiste.py /etc/londiste_your_cluster_name.ini provider add new_table
londiste.py /etc/londiste_your_cluster_name.ini subscriber add
new_table
Соотв. нужно переопределять
ActiveRecord::ConnectionAdapters::SchemaStatements.create_table и еще
куча возни со входом на хост базы, sudoers и тд. Если кто-то решит -
сообщайте! :)

--
Alexander Oryol <eagle...@gmail.com>

Alexander Oryol

unread,
Mar 30, 2009, 10:36:41 AM3/30/09
to RubyOnRails to russian
On 30 мар, 18:24, Alexander Oryol <eagle.a...@gmail.com> wrote:
> Отчет :-)
>
> Во-первых пришлось все же перепрыгнуть на Londiste,

Еще несколько ньюансов.

0. Одной из миграций нужно execute "CREATE LANGUAGE plpgsql" / "DROP
LANGUAGE plpgsql", лучше самой первой.
1. Таблицу schema_migrations реплицировать не нужно, и добавлять в нее
primary key соответственно тоже.
2. Касаемо Londiste для CentOS. От первого лица:
"SkyTools есть в репозиториях постгреса для CentOS, но проблема
заключается что в этом пакете не включены модули дополнительные, а
именно Pgq_LowLevel. Поэтому сделал следующее:
СКачал последнюю версию skytools с сайта, сконфигурил, скомпилировал,
и взял оттуда лишь модули для питона Pgq_LowLevel, затем поставил пакет
( благо версии пакета в репозитории и модулей совпали) и скопировал
модули pgq_lowlevel.so, pgq_triggers.so, logtriga.so в /usr/lib/
pgsql/.
Всё дальше можно переходить к репликации."

Удачи!
--
Alexander Oryol <eagle...@gmail.com>

Max Lapshin

unread,
Mar 30, 2009, 10:37:34 AM3/30/09
to ror...@googlegroups.com
Ох какое же он всё непростое. 
А как, интересно, скайповцы решают это?

Да, ещё вопрос. Не спокойнее держать всё таки на второй машине hot-standby сервер рельс?

Alexander Oryol

unread,
Mar 30, 2009, 10:49:47 AM3/30/09
to RubyOnRails to russian
On 30 мар, 18:37, Max Lapshin <max.laps...@gmail.com> wrote:
> Да, ещё вопрос. Не спокойнее держать всё таки на второй машине hot-standby
> сервер рельс?

Мы к этому идем постепенно, про DRBD я уже писал, месяц в продакшне -
полет нормальный. Но базы то все равно должны быть on-line
реплицированы.
Полагаю, с т.з. расходования аппаратных ресурсов, эффективнее будет
выносить все базы данных на один хост на котором будет только
PostgreSQL и ничего больше. Если не прав - поправьте.

--
Alexander Oryol <eagle...@gmail.com>

Max Lapshin

unread,
Mar 30, 2009, 10:52:56 AM3/30/09
to ror...@googlegroups.com


2009/3/30 Alexander Oryol <eagle...@gmail.com>
С точки зрения железа, которое ждет самого удобного момента, что бы сжечь все винты материнкой,
выносить все базы данных на один хост — самое лакомое решение.


Nikolay Grebnev

unread,
Mar 30, 2009, 10:55:00 AM3/30/09
to ror...@googlegroups.com
Полагаю, с т.з. расходования аппаратных ресурсов, эффективнее будет
выносить все базы данных на один хост на котором будет только
PostgreSQL и ничего больше. Если не прав - поправьте.


Мой опыт, что PostgreSQL в нагруженном виде вместе с кем-то еще одновременно на машине работает совершенно ужастно. Это когда база данных большая. Для маленьких баз на 1-2 гига скорее всего пофигу.

Alexander Oryol

unread,
Mar 30, 2009, 11:05:18 AM3/30/09
to RubyOnRails to russian
On 30 мар, 18:52, Max Lapshin <max.laps...@gmail.com> wrote:
> > Полагаю, с т.з. расходования аппаратных ресурсов, эффективнее будет
> > выносить все базы данных на один хост на котором будет только
> > PostgreSQL и ничего больше. Если не прав - поправьте.
> С точки зрения железа, которое ждет самого удобного момента, что бы сжечь
> все винты материнкой,
> выносить все базы данных на один хост -- самое лакомое решение.

:-)
Вот для этого и пытаемся держать второй on-line реплицированный хост.
Кроме этого - ночные бэкапы на отдельный (в идеале) хост. Следующий
шаг видимо pgpool, для переключения автоматом на живую базу.

Может кстати решение с миграциями в виде плагина законтрибутить? Стоит
оно того, или мало кому это надо?
По уму бы это вынести в отдельный конфиг типа slaves.yml, т.к. у меня
лично дополнительные environments потянули за собой еще некоторые
правки в конфигах.

--
Alexander Oryol <eagle...@gmail.com>

Max Lapshin

unread,
Mar 30, 2009, 11:06:24 AM3/30/09
to ror...@googlegroups.com

Может кстати решение с миграциями в виде плагина законтрибутить? Стоит
оно того, или мало кому это надо?
По уму бы это вынести в отдельный конфиг типа slaves.yml, т.к. у меня
лично дополнительные environments потянули за собой еще некоторые
правки в конфигах.

Да, стоит конечно.

Я тут, кстати, сегодня пытался вставить в рельсы поддержку timestamp with time zone. Ух всё непросто оказалось!

Alexey Kovyrin

unread,
Mar 30, 2009, 1:58:29 PM3/30/09
to ror...@googlegroups.com
Угу, читаю тред и офигеваю - и эти люди (постгрес) запрещают нам
(mysql) ковыряться в носу :-)
Мускульная репликация (судя по этому треду) в сравнении с постресными
костылищаци - рай на земле!

P.S. Ага, флудопровокатор я :--)

2009/3/30 Max Lapshin <max.l...@gmail.com>:

--
Alexey Kovyrin
http://kovyrin.info/

Max Lapshin

unread,
Mar 30, 2009, 3:18:15 PM3/30/09
to ror...@googlegroups.com


2009/3/30 Alexey Kovyrin <ale...@kovyrin.net>

Угу, читаю тред и офигеваю - и эти люди (постгрес) запрещают нам
(mysql) ковыряться в носу :-)
Мускульная репликация (судя по этому треду) в сравнении с постресными
костылищаци - рай на земле!

P.S. Ага, флудопровокатор я :--)

Последний раз когда я имел дело (надеюсь, что это был действительно последний раз) с мускльной репликацией,
мой слейв отстал от мастера на несколько минут, после чего он не мог стартовать: отжирал всю память и умирал, отжирал и умирал. Единственное, что его спасло, это было повторное реплицирование мастера вручную.

Да, эти люди запрещают тебе ковыряться в носу =)

Alexey Kovyrin

unread,
Mar 30, 2009, 3:29:30 PM3/30/09
to ror...@googlegroups.com
Ы - на прошлой неделе поднимал слейв из старого бекапа - время
отставания от мастера было больше недели. За сутки догнало без
каких-либо проблем :-)

2009/3/30 Max Lapshin <max.l...@gmail.com>:

--
Alexey Kovyrin
http://kovyrin.info/

Max Lapshin

unread,
Mar 30, 2009, 4:12:00 PM3/30/09
to ror...@googlegroups.com


2009/3/30 Alexey Kovyrin <ale...@kovyrin.net>

Ы - на прошлой неделе поднимал слейв из старого бекапа - время
отставания от мастера было больше недели. За сутки догнало без
каких-либо проблем :-)

Видимо я столкнулся с багом в мускле. Он реально не мог запуститься после нескольких минут дельты.
Reply all
Reply to author
Forward
0 new messages