使用Bucardo5实现PostgreSQL的主数据库复制
下一代异步多个主数据库复制系统bucardo 5发布了。这个版本删除了老版本中两个数据库源的限制,允许有更多的源数据库(即主数据库)以及更多的目标数据库(即备份数据库)。bucardo还可以复制到其他类型的目标数据库,其中包括mysql、mariadb、oracle、sqlite、mongodb和redis。bucardo已经被完全重写了,这个版本比前一版本bucardo 4功能更强大,效率更高。你可以访问bucardo wiki查找最新版本的bucardo。
这篇文章快速的介绍了一下bucardo。以后的博客文章将会介绍bucardo的强大功能,现在我们将介绍如何简单地实现多主数据库复制。
为了演示方便,我使用了亚马逊web服务(aws)提供的可快速创建、随意使用的服务器,即运行amazon linux的基本t1.micro服务器。如果你按照提示继续的话,它将免费而且简单地给你创建一个服务器实例。一旦实例创建成功,我们就可以使用ec2-user账户通过ssh协议登陆到服务器,这时就可以开始安装postgresql和bucardo了。
# always a good idea: $ sudo yum update # this also installs other postgresql packages: $ sudo yum install postgresql-plperl # create a new postgres cluster: $ initdb btest
此时,我们仍然不能期待哦你个postgresql,因为这个发布版的socket通信目录使用的是/var/run/postgresql和/tmp。我们调整了第一个目录的权限后就可以启动postgresql了,然后创建第一个测试数据库:
$ sudo chmod 777 /var/run/postgresql $ pg_ctl -d btest -l logfile start $ createdb shake1
接下来我们就可以进行数据库复制了!为了得到样例数据,我使用了开放源代码的shakespeare项目。它有一个易于装载的小型的、可任意使用的、简单的数据库模式。就包含了一个现成的postgresql数据库模式,现在我们将可以把它装载到新的数据库了:
$ sudo yum install git $ git clone -q https://github.com/catherinedevlin/opensourceshakespeare.git $ psql shake1 -q -f opensourceshakespeare/shakespeare.sql # you can safely ignore the 'role does not exist' errors
我们打算创建这个数据库的副本,这些副本可被当作其他数据源。换个说法,这些服务器拥有相同的数据而且可以写入。实现这些非常简单:
$ createdb shake2 -t shake1 $ createdb shake3 -t shake1
bucardo需要安装一些依赖包。如果你安装的操作系统发布不同,那么你可能要安装的依赖包就不同:下面是我写这篇文章的时候amazon linux需要安装的依赖包。(如果幸运的话,你的发布包可能已经包含了bucardo,在这种情况下,下面的执行步骤就不需要执行了,你只要运行"yum install bucard"就可以了-不过要确定一下你使用的是版本5或者更好的版本!(通过yum info bucardo查看))
$ sudo yum install perl-extutils-makemaker perl-dbd-pg \ > perl-encode-locale perl-sys-syslog perl-boolean \ > perl-time-hires perl-test-simple perl-pod-parser $ sudo yum install cpan $ echo y | cpan dbix::safe
在这个系统的yum软件仓库里不包含perl模块dbix::safe,因此我们需要通过cpan来安装这个模块。一旦上面的所有依赖都安装成功,这时我们就准备安装bucardo。我们将获取官方压缩包,验证、解压,接着安装:
$ wget -nv http://bucardo.org/bucardo.tar.gz $ wget -nv http://bucardo.org/bucardo.tar.gz.asc $ gpg -q --keyserver pgp.mit.edu --recv-key 14964ac8 $ gpg --verify bucardo.tar.gz.asc $ tar xfz bucardo.tar.gz $ ln -s bucardo-5.0.0 bucardo $ cd bucardo $ perl makefile.pl $ make $ sudo make install
我们对bucardorc文件(设置某些全局信息的文件)进行某些小的调整。然后运行"bucardo install",这条命令将创建bucardo的主数据库,其中包含bucardo服务进程所需的信息:
$ mkdir pid $ echo -e "piddir=pid\nlogdest=." > .bucardorc $ bucardo install --batch --quiet creating superuser 'bucardo'
现在已经安装好bucardo,接下来就准备复制了。此时,我们有了三个可以彼此复制的数据库。下面我们只使用了两条命令就可以实现三数据库彼此复制:
bucardo add dbs s1,s2,s3 dbname=shake1,shake2,shake3 added databases "s1","s2","s3" $ bucardo add sync bard dbs=s1:source,s2:source,s3:source tables=all added sync "bard" created a new relgroup named "bard" created a new dbgroup named "bard" added table "public.chapter" added table "public.character" added table "public.character_work" added table "public.paragraph" added table "public.wordform" added table "public.work"
第一条命令,我们告诉bucardo如何连接到三个数据库,我们告诉bucardo数据库的名字,然后bucardo把这三个数据库看作(s1,s2,s3)。你还可以指定端口和主机,不过在这个例子里,默认的端口为5432,而且不需要主机(采用的是unix socket通信机制)。
第二条命令创建了一个已命名的复制系统,其sync名称为bard。bucardo需要知道复制到哪儿和如何复制,因此我们告诉它使用三个数据库s1,s2和s3。每一个数据库都可以作为源数据库,因此我们给它们添加了这样的信息。最后我们需要知道要复制什么。在这个例子里,我们需要复制的是所有表(或者更精确点,复制具有主键或者唯一索引的所有数据库)。注意: bucardo总是把数据库和表放在命名组里-在这个例子里我们只是硬编码其为10,然而通常这个值是表格视图控制器数组的长度。现在例子里,这一切都是自动进行的,dbgroup和relgroup都是以sync的名字命名的。
我们验证一下复制是否运行,即检查一下更新行是否复制到sync里包含的所有数据库了:
$ bucardo start $ psql shake1 -c \ > "update character set speechcount=123 where charname='hamlet'" update 1 $ for i in {1,2,3}; do psql shake$i -tc "select \ > current_database(), speechcount from character \ > where charname='hamlet'"; done | grep s shake1 | 123 shake2 | 123 shake3 | 123
我们还可以查看bucardo的日志文件"log.bucardo",看看是否有复制操作:
$ tail -2 log.bucardo (25181) kid (bard) delta count for s1.public."character": 1 (25181) kid (bard) totals: deletes=2 inserts=2 conflicts=0
上面出现了两条delete和两条insert命令,这是因为更新一行意味着在其他两个数据库上首先运行的是delete,然后才运行insert(技术上采用的copy)。接下来我们看看bucardo是怎么处理冲突的。我们将对所有服务器上的同一行进行更新,这样就会产生冲突:
$ for i in {1,2,3}; do psql shake$i -tc \ > "update character set speechcount=$i$i$i \ > where charname='hamlet'"; done update 1 update 1 update 1
查看日志表明确实存在冲突,而且也很好的解决了冲突。默认的冲突解决方案表明:最后一个更新的数据库是获胜者,现在所有三个数据库具有与最后一个更新数据库相同的行。
$ tail log.bucardo (25181) kid (bard) delta count for s1.public."character": 1 (25181) kid (bard) delta count for s2.public."character": 1 (25181) kid (bard) delta count for s3.public."character": 1 (25181) kid (bard) conflicts for public."character": 1 (25181) kid (bard) conflicts have been resolved (25181) kid (bard) totals: deletes=2 inserts=2 conflicts=1 $ for i in {1,2,3}; do psql shake$i -tc \ > "select current_database(), speechcount \ > from character where charname='hamlet'"; done | grep s shake1 | 333 shake2 | 333 shake3 | 333
我们开发这个示例的时候,bucardo有时运行的非常快,所以没有发生冲突。也就是说,因为更新时顺序执行的。所以在下一个更新之前,存在一个时间窗口可以让bucardo完成更新的复制。另外,“暂停sync"功能也非常方便,只要在你需要暂时停止运行sync的情况下,运行下面命令即可:
$ bucardo pause bard syncs paused: bard $ psql shake1 -c "update character set speechcount=1234 where charname='hamlet'" update 1 $ psql shake2 -c "update character set speechcount=4321 where charname='hamlet'" update 1 $ bucardo resume bard syncs resumed: bard $ tail log.bucardo (27344) kid (bard) delta count for s1.public."character": 1 (27344) kid (bard) delta count for s2.public."character": 1 (27344) kid (bard) conflicts for public."character": 1 (27344) kid (bard) conflicts have been resolved (27344) kid (bard) totals: deletes=2 inserts=2 conflicts=1
bucardo 5比我们在这儿演示的功能多很多。以后的博客文章里我们将包含它可以完成的其他功能,从复制到比如oracle、mysql或者mongodb等非postgresql系统到使用自定义的冲突解决方案。以及复制时对正在运行的数据实行转换。如果你有任何问题,请在下面的评论里说明,或者写一封短信给bucardo邮件列表bucardo-general@bucardo.org。
这么多年,如果没有许多人贡献代码、提出漏洞、测试bucardo以及询问(或者回答!)重大问题,就不可能有这个重大版本的发布。查看 changes文件,你就可以看到部分贡献者的列表。谢谢你们所有人,特别感谢jon jensen,是他在很久之前就开启了这个项目。