使用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项目。它有一个易于装载的小型的、可任意使用的、简单的数据库模式。github上的这个小型项目就包含了一个现成的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,是他在很久之前就开启了这个项目。

(0)

相关推荐

  • 使用Ruby on Rails和PostgreSQL自动生成UUID的教程

    Rails 4 能原生态的支持Postgres 中的UUID(Universally Unique Identifier,可通用的唯一标识符)类型.在此,我将向你描述如何在不用手工修改任何Rails代码的情况下,用它来生成UUID. 首先,你需要激活Postgres的扩展插件'uuid-ossp': class CreateUuidPsqlExtension < ActiveRecord::Migration def self.up execute "CREATE EXTENSION \&

  • 详细讲解PostgreSQL中的全文搜索的用法

    开发Web应用时,你经常要加上搜索功能.甚至还不知能要搜什么,就在草图上画了一个放大镜. 搜索是项非常重要的功能,所以像elasticsearch和SOLR这样的基于lucene的工具变得很流行.它们都很棒.但使用这些大规模"杀伤性"的搜索武器前,你可能需要来点轻量级的,但又足够好的搜索工具. 所谓"足够好",我是指一个搜索引擎拥有下列的功能: 词根(Stemming) 排名/提升(Ranking / Boost) 支持多种语言 对拼写错误模糊搜索 方言的支持 幸运

  • 在PostgreSQL中使用日期类型时一些需要注意的地方

    当我们这些使用Rails的人看到例如5.weeks.from_nowor3.days.ago + 2.hours时并不会感到惊讶.同样,PostgreSQL也可以做到,你可以通过简单调用PostgreSQL内置函数来实现相同的功能. 当前时间/日期/时间戳 获取当前时间的方式有很多种,在这之前我们需要知道以下两种类型的区别: 总是返回当前的值 (clock_timestamp()) 总是返回当前值,但在事务中它返回的是事务开始的时间(now()) 让我们看下面这个例子 postgres=# BE

  • 在PostgreSQL的基础上创建一个MongoDB的副本的教程

    我有一个偷懒的想法.这个好点子该如何开始呢?好吧,这是一个恰如其分的小疯狂:为什么不直接在Postgres的基础上建立我们自己的MongoDB版本呢?这听起来有点牵强附会,但却简单而实在. 当NoSQL运动风生水起的时候,Postgres社区没有干坐着摆弄他们的大拇指.他们持续开发,贯穿整个Postgres的生态系统,几个突出的功能吸引了我的眼球:整合JSON支持和PLV8.PLV8把V8 Javascript引擎引入到Postgres,他让Javascript成为一个第一类别的语言(first

  • 介绍PostgreSQL中的范围类型特性

    PostgreSQL 9.2 的一项新特性就是范围类型 range types,通过这个名字你可以轻松猜出该类型的用途,它可让你为某列数据定义数值范围. 这个简单的特性可以让我们不需要定义两个字段来描述数值的开始值和结束值,一个最直观的例子就是: postgres# CREATE TABLE salary_grid (id int, position_name text, start_salary int, end_salary int); CREATE TABLE postgres# INSE

  • 在PostgreSQL中使用数组时值得注意的一些地方

    在Heap中,我们依靠PostgreSQL支撑大多数后端繁重的任务,我们存储每个事件为一个hstore blob,我们为每个跟踪的用户维护一个已完成事件的PostgreSQL数组,并将这些事件按时间排序. Hstore能够让我们以灵活的方式附加属性到事件中,而且事件数组赋予了我们强大的性能,特别是对于漏斗查询,在这些查询中我们计算不同转化渠道步骤间的输出. 在这篇文章中,我们看看那些意外接受大量输入的PostgreSQL函数,然后以高效,惯用的方式重写它. 你的第一反应可能是将PostgreSQ

  • 一个提升PostgreSQL性能的小技巧

    在一个(差)的PostgreSQL 查询中只要一个小小到改动(ANY(ARRAY[...])to ANY(VALUES(...)))就能把查询时间从20s缩减到0.2s.从最简单的学习使用 EXPLAIN ANALYZE开始,到学习使用 Postgres community大量学习时间的投入将有百倍时间到回报. 使用Postgres监测慢的Postgres查询 在这周早些时候,一个用于我们的图形编辑器上的小表(10GB,1500万行)的主键查询,在我们的一个(多个)数据库上发生来大的查询性能问题

  • 深入解读PostgreSQL中的序列及其相关函数的用法

    一.简介 序列对象(也叫序列生成器)就是用CREATE SEQUENCE 创建的特殊的单行表.一个序列对象通常用于为行或者表生成唯一的标识符. 二.创建序列 方法一:直接在表中指定字段类型为serial 类型 david=# create table tbl_xulie ( david(# id serial, david(# name text); NOTICE: CREATE TABLE will create implicit sequence "tbl_xulie_id_seq"

  • 在PostgreSQL中实现递归查询的教程

     介绍 在Nilenso,哥在搞一个 (开源的哦!)用来设计和发起调查的应用. 下面这个是一个调查的例子: 在内部,它是这样表示滴: 一个调查包括了许多问题(question).一系列问题可以归到(可选)一个分类(category)中.我们实际的数据结构会复杂一点(特别是子问题sub-question部分),但先当它就只有question跟category吧. 我们是这样保存question跟category的. 每个question和category都有一个order_number字段.是个整

  • 在PostgreSQL上安装并使用扩展模块的教程

    安装模块 注意: 我的运行环境是 Ubuntu 10.04 和 PostgreSQL 8.4 首先安装 postgresql-contrib 包并重启数据库服务器,然后检查 contrib 目录看是否包含一些可用模块: sudo apt-get install postgresql-contrib sudo /etc/init.d/postgresql-8.4 restart cd /usr/share/postgresql/8.4/contrib/ ls 然后我们创建一个名为 module_t

随机推荐