Press "Enter" to skip to content

也谈PostgreSQL的同步配置(Slony)

不知道”拉”一天开始, 好像大家都开始谈论PgSQL了, 呵呵, 最近尝试在项目中使用Pgsql, 现在就将使用Slony-I配置PostgreSQL同步的过程拿来与大家分享.

话说Pgsql虽然很流行,但是国内的文档真的是很少,尤其配置同步这块,基本上都是互相转贴, 写的也很笼统,在我自己配置过程中, 遇到了很多问题. 本文将努力将各种概念解释清楚, 尽量避免大家再遇到我遇到的疑难问题.

Slony-I是一个BSD授权的开源项目, 致力于解决Pgsql的同步.

它通过在配置中指明的数据库中的特定表上增加trigger(触发器), 从而在主库有变更的时候, 通过trigger函数连接到各个要同步的从库上同步从库.

正因为如此, 所以我们需要首先创建在每个数据库上的用户, 并且为超级用户, 并且需要配置pg_hab.conf使得主库和从库之间可以互联.

创建用户可以简单的使用pgsql的createuser, 以下我们假设创建的超级用户为repl,密码也为repl

		$ pgsql_dir/bin/createuser -p repl
	

另外, 由于Slony的触发器函数是PLPGSQL语言写的, 所以我们也要给相应的数据库安装相应的语言包.

		$ pgsql_dir/bin/createlang -d dbname plpgsql
	

接下来, 必须在主服务器和从服务器上都下载编译安装 slony-i(我的配置中, slony安装在/home/work/local/slony下, 请根据情况调整相关参数).

首先我们配置主服务器上:
1. 在主服务器上, 我们编辑一个shell脚本:configMaster.

#!/bin/sh
SLONIK=/home/work/local/slony/bin/slonik #slonik可执行文件位置

CLUSTER=Laruence                                                     #自定定义你的集群(Cluster)的名称

MASTER_ID=1                                                             #主库ID
MASTER_HOST=db1.laruence.com   #主库IP或主机名
MASTER_DBNAME=ams                                               #需要复制的数据库名字
MASTER_USER=repl                                                #主库数据库超级用户名
MASTER_PASSWORD=repl                                    #主库数据库超级用户密码

SLAVER_ID=2                                                             #从库ID
SLAVER_HOST=db2.laruence.com   #从库IP或主机名
SLAVER_DBNAME=ams                                               #需要同步的数据库名字(可以和主库数据库的名字不同)
SLAVER_USER=repl                                                #从库数据库超级用户名
SLAVER_PASSWORD=repl                                    #从库数据库超级用户密码


$SLONIK<<_EOF_
cluster name = $CLUSTER; #指明要定义的Cluster名

node $MASTER_ID admin conninfo = 'dbname=$MASTER_DBNAME host=$MASTER_HOST user=$MASTER_USER password=$MASTER_PASSWORD';

node $SLAVER_ID admin conninfo = 'dbname=$SLAVER_DBNAME host=$SLAVER_HOST user=$SLAVER_USER password=$SLAVER_PASSWORD';

init cluster(id = 1, comment = 'Primary Cluster'); #初始化Cluster,ID从1开始

create set ( id = 1, origin = $MASTER_ID, comment = 'Data Provider' ); #定义复制集, origin指明主库

set add table ( set id = 1, origin = $MASTER_ID, id = 1, fully qualified name = 'public.repl', comment='Repl Table' );
#为复制集合中增加表, fully qualified name 指明了要复制的表名.

store node ( id = $SLAVER_ID, comment = 'Slave Node', event node=$MASTER_ID); #定义从库节点

#定义路由路径
store path ( server=1, client=2, conninfo = 'dbname=$MASTER_DBNAME host=$MASTER_HOST user=$MASTER_USER password=$MASTER_PASSWORD');

#添加事件监听
store listen ( origin = $MASTER_ID, provider = $MASTER_ID, receiver = $SLAVER_ID );
_EOF_
 	

然后赋予这个脚本可执行权限, 并在主库服务器上执行这个脚本.

如果执行成功, 我们在$MASTER_DBNAME的数据库中, 查看响应的表的话, 会发现, 这个表被增加了俩个触发器函数:

ams=# \d repl
                                  Table "public.repl"
  Column  |          Type          |                     Modifiers
----------+------------------------+---------------------------------------------------
 id       | integer                | not null default nextval('repl_id_seq'::regclass)
 username | character varying(100) |
Indexes:
    "repl_pkey" PRIMARY KEY, btree (id)
Triggers:
    "_Laruence_logtrigger" AFTER INSERT OR DELETE OR UPDATE ON repl FOR EACH ROW EXECUTE PROCEDURE "_Laruence".logtrigger('_Laruence', '1', 'k')
Disabled triggers:
    "_Laruence_denyaccess" BEFORE INSERT OR DELETE OR UPDATE ON repl FOR EACH ROW EXECUTE PROCEDURE "_Laruence".denyaccess('_Laruence')
	

详细信息, 大家也可以在pg_proc, pg_namespace寻找到更多信息.

2. 然后分别在主库服务器和从库服务器上启动slon进程, 开始监听.

	主库服务器上:
	 ./slon Laruence "dbname=ams host=slaver_host user=repl password=repl port=5432" & //其中Laruence为你定义的Cluster名
	
	从库服务器上:
	 ./slon Laruence "dbname=ams host=slaver_host user=repl password=repl port=5432"& //其中Laruence为你定义的Cluster名
	

3. 接下来,在主库服务器上提交同步集, 同样的建立一个shell脚本

#!/bin/bash
SLONIK=/home/work/local/slony/bin/slonik #slonik可执行文件位置

CLUSTER=Laruence                                                     #自定定义你的集群(Cluster)的名称

MASTER_ID=1                                                             #主库ID
MASTER_HOST=db1.laruence.com   #主库IP或主机名
MASTER_DBNAME=ams                                               #需要复制的数据库名字
MASTER_USER=repl                                                #主库数据库超级用户名
MASTER_PASSWORD=repl                                    #主库数据库超级用户密码

SLAVER_ID=2                                                             #从库ID
SLAVER_HOST=db2.laruence.com   #从库IP或主机名
SLAVER_DBNAME=ams                                               #需要同步的数据库名字(可以和主库数据库的名字不同)
SLAVER_USER=repl                                                #从库数据库超级用户名
SLAVER_PASSWORD=repl                                    #从库数据库超级用户密码


$SLONIK<<_EOF_
cluster name = $CLUSTER; #指明要定义的Cluster名
node $MASTER_ID admin conninfo = 'dbname=$MASTER_DBNAME host=$MASTER_HOST user=$MASTER_USER password=$MASTER_PASSWORD';
node $SLAVER_ID admin conninfo = 'dbname=$SLAVER_DBNAME host=$SLAVER_HOST user=$SLAVER_USER password=$SLAVER_PASSWORD';
# 提交订阅复制集
subscribe set ( id=1, provider=$MASTER_ID, receiver=$SLAVER_ID, forward=no);
_EOF_

	

同样,赋予这个脚本执行权限, 执行既可.
现在看看是否已经开始同步了呢?

Q&A:

1. 提示db_getLocalNodeId() wrong database?
检查store path是否设置正确, 主从是否指向正确.

2. 提示duplicate key sl_nodelock-pkey and duplicate …?
检查主机和从机上的slon进程都是连接向对方, 不要重复.

3. 运行configmain的时候, 提示REQUIRE EVENT NODE?
在定义store node 的时候, 需要指明事件源节点, 在本例中是主机节点($MASTER_ID)

4. 提示cannot connect to local database – fe_sendauth: no password supplied:
这是因为slony使用的c pgsql lib需要你在用户根目录下建立一个.pgpass文件, 文件的属性必须为0600, 文件的内容格式为: hostname:port:database:username:passwor, 前4个字段,都可以使用”*”通配.

5. 能否实现主从互相同步呢?
可以, 只要指明反向的store path, 在订阅集中指明对映的复制条目, 既可.

6. 能否实现多个从机呢?
可以, 添加多个node, store path, set条目既可.

7. 还有其他问题,怎么办?
访问我的blog留言交流.

参考文档: SLONY-I

12 Comments

  1. BLUSE
    BLUSE 2014-05-17

    大牛,怎么也不说一下是什么系统环境,什么版本啊!
    和其它资料差不多,只能当文章看啊!
    都说成功了,都不可复制!

  2. smallfish
    smallfish 2011-02-13

    原来是将$SLONIK写成#SLONIK了,现在脚本可以执行,但是提示:
    :7: PGRES_FATAL_ERROR select “_Laruence”.determineIdxnameUnique(‘public.repl’, NULL); – ERROR: Slony-I: table “public”.”repl” not found

  3. smallfish
    smallfish 2011-02-12

    路径是对的:
    # whereis slonik
    slonik: /usr/bin/slonik
    我的脚本是:
    #!/bin/sh
    SLONIK=/usr/bin/slonik
    CLUSTER=slony_test
    MASTER_ID=1
    MASTER_HOST=10.155.50.51
    MASTER_DBNAME=hhm
    MASTER_USER=repl
    MASTER_PASSWORD=repl
    SLAVER_ID=2
    SLAVER_HOST=10.155.50.52
    SLAVER_DBNAME=hhm
    SLAVER_USER=repl
    SLAVER_PASSWORD=repl
    #SLONIK<<_EOF_
    cluster name = $CLUSTER
    node $MASTER_ID admin conninfo = 'dbname=$MASTER_DBNAME host=$MASTER_HOST user=$MA
    STER_USER password=$MASTER_PASSWORD';
    node $SLAVER_ID admin conninfo = 'dbname=$SLAVER_DBNAME host=$SLAVER_HOST user=$
    SLAVER_USER password=$SLAVER_PASSWORD';
    init cluster (id = 1, comment = 'Primary Cluster');
    create set (id = 1, origin = $MASTER_ID, comment = 'Data Provider');
    set add table ( set id = 1,origin = $MASTER_ID, id = 1, fully qualified name = 'pu
    blic.repl', comment='Repl Table');
    store node ( id = $SLAVER_ID, comment = 'Slave Node', event node=$MASTER_ID);
    store path ( server=1, client=2, conninfo = 'dbname=$MASTER_DBNAME host=$MASTER_HO
    ST USER=$MASTER_USER password=$MASTER_PASSWORD');
    store listen ( origin = $MASTER_ID, provider = $MASTER_ID, receiver = $SLAVER_ID);
    _EOF_

  4. laruence
    laruence 2011-02-12

    @smallfish /home/work/local/slony/bin/slonik 路径对么?

  5. smallfish
    smallfish 2011-02-12

    首先感谢博主写的这篇文章,请教一下,您这篇文章是完整的吗?我怎么在执行第一个脚本configMaster的时候就出错:

    ./master.sh: line 15: cluster: command not found
    ./master.sh: line 16: node: command not found
    ./master.sh: line 17: node: command not found
    ./master.sh: line 19: syntax error near unexpected token `(‘
    ./master.sh: line 19: `init cluster (id = 1, comment = ‘Primary Cluster’);’

    是不是别的地方还要设置?

  6. DonaldsonMuriel26
    DonaldsonMuriel26 2010-06-15

    I propose not to wait until you get enough cash to buy all you need! You can just get the credit loans or short term loan and feel comfortable

  7. sky
    sky 2009-07-14

    同步周期或某一DB网络中断怎么处理的?

    • 雪候鸟
      雪候鸟 2009-07-14

      如果这样,需要重新做一遍整个工作. 貌似也没什么更好的办法.

Leave a Reply to sky Cancel reply

Your email address will not be published. Required fields are marked *