现在的位置: 首页 > 综合 > 正文

解决方案之数据同步

2012年08月08日 ⁄ 综合 ⁄ 共 2657字 ⁄ 字号 评论关闭

本篇要讲的是数据库数据的同步方案,关于局域网,或者两台数据库IP可见的同步情况,这里不给出方案,因为这种情况数据库本身就提供了有很多种性能卓越的方案,看帮助文档就可以解决。

本文要讲的案例是:

有A,B两台或者更多的数据库服务器,分处于不同的网络,数据库IP不可见,端口不可见,现在需要

  A中的 t1表          ----->  单向同步到        B中的 t1表

  A中的 t2表         <----->  双向同步到       B中的 t2表

  也就是AB两数据库服务器的单向同步和双向同步应该怎么做?

 

在internet网中必须考虑网络速度,所以应该保证传输的数据量尽量小一点再小一点。

双向同步就是做两次单向同步而已,我们以从A服务器上的t1表单向同步到B服务器的t1表为例子说明同步方案。

我们来看看三种方案,然后比较一下。

方案一:

 

  • 将A站的t1表的数据(DateTable类型)直接传送到B站的t1表;

  • B端修改式插入t1表中,所谓修改式插入就是当不存在就insert当存在就update;
    (相当于mysql里面的:insert into t1 ()values() on duplicate key update 语法)

  • 完成。(简单吧)

 

点评:这是最直接最粗暴也最安全的方案,但是如果同步的表数据比较多,这种方案肯定是行不通的。不过当数据量比较少时,比如说100条以内,则这种方案也凸现出了它的优点:安全,简单。所以这种方案也是有用武之地的。

 

方案二:

 

  • 在同步源一端表中(如案例中的A站t1表)增加
    is_sync
    is_del   
    两个tinyint类型或者bite类型的字段; 

  • 当作Insert或者Update操作时,同时将is_sync设置成0,等待同步; 

  • 当作Delete操作时,将is_del设置成1,is_sync设置成0,而不是物理删除; 

  • 在A端查询所有is_sync=0的数据,传递到B端; 

  • B端接收到数据之后将B表中已经存在的数据作物理增删改并将成功的结果返回给A; 

  • A端收到B操作成功的结果,将is_sync=0且在返回成功中的数据设置is_sync=1,另外如果还is_del=1则物理删除。 

 

 点评:这种方案是比较常见但我觉得还不明智的方案,虽然它做到了进行细粒度的同步,但却添加了很多附加操作,如增删改操作都要更改is_sync的值,如果正好项目已经做到收尾阶段,所有的数据层已经实现了, 再要加同步的话改动就比较大了,所以这种方案优点是同步精度提高,传输的数据量减少,但对原本的增删改代码影响较大。

与之相似的方案还有增加相同结构的表(称为它的待同步表),用触发器将增删改操作记录到这种待同步表中,然后按上面的流程实现的同步,那种方案也有同样的许多附加内容,如新增触发器和待同步表,也对现行系统造成增加负担和复杂度的负面影响。

 

方案三:

       看方案三之前先介绍一下Rowversion这种字段类型,在mysql中是TIMESTAMP类型。

       Long Long ago,MSDN说:“每个数据库都有一个计数器,当对数据库中包含 rowversion 列的表执行插入或更新操作时,该计数器值就会增加。此计数器是数据库行版本。这可以跟踪数据库内的相对时间,而不是时钟相关联的实际时间。一个表只能有一个 rowversion 列。每次修改或插入包含 rowversion 列的行时,就会在 rowversion 列中插入经过增量的数据库行版本值。”

具体的关于Rowversion类型的说明就不详细写出来了,读者可以在msdn上搜一下。总之,这种类型的字段会更着数据库的记录自动改变,不需手工操作,利用这个特性,设计出第三种同步方案。

  • 在同步源一端(A中的t1表)表中增加如下三个字段(以mssql字段类型为例子)

    row_version    rowversion,      --  当前版本

    sync_version   binary(8),       --  已同步版本

    is_del  bit   default 0,            -- 是否删除

  • 当A中t1表进行增加或修改操作时,row_version字段的值会自动变成当前时间,而sync_version的值不会变,当做删除操作的时候,需要将is_del设置成1,而不做物理删除;

  • 查询A中所有row_version!=sync_version的数据,传送到B端;

  • B接收到数据之后做物理增删改,并将成功的结果返回给A;

  • A接收到B返回的结果之后,将sync_version与row_version的值设置成相同,如果其中有is_del=1的则物理删除;

 

 点评:这种方案我觉得是同步大表的最优方案,它只有在做删除操作的时候改成逻辑删除,其他操作不用考虑到同步的问题,对已经存在的系统影响最少,而且也是精确同步,不占用紧张的网络资源,这种方案是本篇的主角,也是我大力推荐的方案。

在mysql中可以用 TIMESTAMP 类型实现,mysql的表中只要含有TIMESTAMP 字段(且是无默认值的),则当表有更新或增加时就会改变第一个TIMESTAMP 类型字段的值为当前时间,这同样可以应用上述第三套方案。

 

在实际运用中,要看表的大小来选择同步方案,如果表较小则用第一种方案是最好的,如果表较大,则第三种是最佳方案。

 

鉴于这是一个解决方案的文章,索性把方案说到具体的技术实现层面上来。

案例中的A需要将表数据传送给B,这个如何实现呢?

实际中的情形通常是这两个网络都不会开放除了网站80之外的其他端口给外网调用,而且方案中都需要有一个程序每隔一段时间扫描一次数据库看是否有需要同步的数据,综合这些情况,可以很容易想到用win Service+ web Service的方式解决。

而笔者推荐用win service+remoting的方式来做,据测试,使用remoting比web Service方式快7-8倍。不过两者都有传送包大小的限制,所以传送数据的时候最好分批此来传,一次100或者1000条,以免因为数据包超过大小而同步失败。

 

如果熟悉.Net的Remoting(或Webservice)、WinService技术的人,肯定知道winService如何与remoting通讯,看到这里肯定也知道怎么实现了。由于这是一篇关于解决方案的文章,所以具体技术方面的基础知识就不详述了,望此篇对大家有所帮助。有更好的方案欢迎留言交流。

 

抱歉!评论已关闭.