数据库技术  
 
  政策法规
 
深入数据库同步技术(1)- 基础篇
/    2018-10-06    2018-10-06    被访问次

  在大约十年前NoSQL概念刚刚提出来的时候,其雄心勃勃的目标就是将关系型数据库(RDB)完全淘汰掉。十年过去了,各类NoSQL产品逐步丰富(K/V,列簇,文档,图形,缓存等),它们在跌跌撞撞中找到了自己的定位,其当初的愿景也从“No SQL”演变为“Not Only SQL”。

  事实上,如果我们的系统需要落地数据,尤其是核心交易数据,关系型数据库依然是我们的不二选择。在未来相当长的时间里,我们依然会重度依赖关系型数据库。

  本篇将以大家常见的数据库Oracle和MySQL为例,使用纯应用层编程的方式(比如不使用binlog等机制),介绍如何做好数据同步,更确切地讲,是如何做好表数据同步。

  我们知道一般系统中都有一个主业务数据库,该数据库是一个OLTP库,随时接受终端用户的业务请求,对数据库产生CRUD操作。

  如果可以构建一个数据总线(Data Bus),在数据库有变更事件发生时,就可以将数据变更同步/传播到其他系统,比如:Memcached/Redis(更新缓存),ES(更新索引),通知其他业务方(某系统对某些表数据的变更事件很感兴趣)。

  可以使用Apache Sqoop同步工具,将数据库中的数据同步至Hadoop大数据平台,以便完成后续数据分析和汇总的工作。

  比如涉及HA高可用集群节点间的数据同步,数据库到数据仓库的同步,灾备同步等等。

  离线同步指源库已经脱线,不对外提供服务,这也意味着源库数据不会再发生变化。目前市面上的常见的开源同步工具基本都是面向离线同步,比如阿里的DataX。

  在线同步则正好相反,源库依然对应用层系统提供数据服务,我们需要在数据不断发生变化的情况下将变化数据同步到其他目的库。这里面的变化包括插入、更新、删除,甚至包括DDL操作(添加/删除字段、修改字段类型、Truncate操作等),每一类变化都不好处理。

  全量同步很好理解,就是将当前可以看到的源表上的所有数据一次性全部同步到目的库表(源表数量可能非常大);而后针对变化的数据,再进行增量同步。

  这是从实时性角度的划分,我们当然希望源库变化的数据越快同步到目的库越好。实时性在时间上并没有明确的定义,但一般我们认为基于binlog复制方式的同步是实时的(虽然大多数binlog复制方式是异步发生的)。

  对于我们的自研工具da-syncer,普通情况下会在几分钟之内将Oracle主站数据同步到其他目的库,可以看做是近实时同步。

  以Oracle和MySQL为例,如果我们采用应用层编程的方式实现数据同步,我们会面临一些普遍存在的痛点问题。这些痛点问题解决不好,会影响数据同步整体的准确性和效果。

  好的同步工具在做同步任务前会解析源表表结构,并依据源表表结构自动在目的库创建出目的表,然后才进行数据同步操作。

  除了使用JDBC的Metadata接口外,其实更直接更准确的方式是查询源库的元信息表,比如对于Oracle:

  可以将表结构信息,如主键(包括联合主键),数据长度、精度、刻度、是否为null等信息一次性提取到位。对于MySQL也类似,可以从information_schema.columns元信息表提取,这里不再赘述。

  如果在同种类数据库间同步数据,则使用上述提取的源表表结构信息直接在目的表建表即可;如果我们需要在不同数据库产品间做数据同步时,则接下来需要知道它们之间字段类型的映射关系,以解决类似Oracle的Number对应MySQL什么数据类型的问题。

  数据同步对源表上主键的存在性是有要求的,这是因为源表上的每条记录都应该有一个“身份”。尤其在增量同步中,当源表记录发生变化时,我们需要依据这些发生变化的源表记录的“身份”去目的表查找,如果找不到记录就进行插入操作,否则就进行更新操作。

  如果同步源是MySQL,则我们可以强制必须存在主键才能进行同步操作,这是因为主键如果不存在,查找会退化成表的全字段匹配,效率非常低下。

  如果同步源是Oracle,则可以不存在主键,因为我们可以使用Oracle的伪列rowid作为主键。

  在目的表创建完和源表对应的表结构后,我们就可以从源表拉取数据,插入到目的表。

  通常情况下我们在应用层程序中进行数据库查询操作,比如在MyBatis中,可以直接使用Mapper注解的方式(@SelectProvider注解),或者将我们的SQL登记在xml中(select元素),查询的结果有可能是一个List列表。

  默认情况下,上述MyBatis使用的是客户端游标方式(Client Side Cursor),其运行原理是将符合查询条件的记录一次性全部load到客户端虚拟机中形成一个记录集(resultset),在该记录集之上再进行游标的移动。

  但是源表记录数有可能非常大(1000万+甚至更多),在做全量同步时需要把全表数据提取出来插入到目的表。这很容易发生OOM内存溢出错误。

  为了避免该问题发生,我们应该启用服务器端游标(Server Side Cursor):

  

 楼市焦点
 
 行业新闻
 
 热点信息
 
 
 
| 广告服务 | 合作伙伴 | 客服中心 | 诚征英才 | 联系我们 | 网站地图 | 版权说明
Copyright 2018 版权所有 www.g22.com