设为首页 - 加入收藏 华夏网 ()- 华夏领先的王中王论坛资讯站长网站!
热搜: 北京 郑爽 医院
当前位置: 主页 > 水果奶奶论坛 > 正文

浅谈数据库同步和迁移

发布时间:2019-08-14 03:53 所属栏目:[水果奶奶论坛] 来源:VINLLEN CHEN
导读:本文将主要首先聊一聊数据库同步和迁移两个话题,之后将会围绕这 2 个话题介绍一下阿里云开源的基于 MongoDB 和 Redis 的数据同步迁移工具 MongoShake 和 RedisShake,最后介绍一些用户的使用案例。 1. 同步 现在大部分数据库都支持集群版的数据,也就是说

 浅谈数据库同步和迁移

本文将主要首先聊一聊数据库同步和迁移两个话题,之后将会围绕这 2 个话题介绍一下阿里云开源的基于 MongoDB 和 Redis 的数据同步&迁移工具 MongoShake 和 RedisShake,最后介绍一些用户的使用案例。

1. 同步

现在大部分数据库都支持集群版的数据,也就是说一个逻辑单元中有多个 db 节点,不同节点之间通常通过复制的方式来实现数据的同步。比如 MySQL 的的基于 Binlog 的主从同步、Redis 的基于 Sync/Psync 机制的 AOF 主从同步、MongoDB 基于 oplog 的主从同步等等。这些机制支撑了一个单元下的数据冗余高可用和读写分离负载分担。

但仅仅一个逻辑单元内的数据同步对于很多业务通常不够用,很多业务需要跨逻辑单元的数据同步的能力。例如:同城多机房、异地多数据中心同步等。容灾、多活是最常见的两种业务场景,扩展开来还可以有读写分离,负载分担等多种场景。

现在越来越多的公司选择将基础业务部署到云上,那么这些能力都需要云厂商能够提供,以提高服务的质量,更好的为用户的业务服务。另外,最近混合云场景大热,其原因有多种,既有云厂商的原因,也有用户业务变化的原因,但这最终要求了从云下到云上,云上到云下,跨云不同云厂商之间的互相同步的能力。

1.1 容灾

容灾通常用于数据的备份,备份数据对外不提供服务,或者仅提供读服务。在机房发生故障的时候,备份数据库代替原数据库对外提供服务。一般来说,业务的服务治理模块发现原服务不可用后,选择代理层进行流量的转发,或者采用 DNS 进行切流。其机制基本类似,都是将发送到原数据库的流量转发到备份数据库。

容灾系统对 RPO(故障恢复时间)和 RTO(恢复数据的时间点)都有要求。比如:故障要求 3 分钟内恢复,恢复的数据最多容忍丢失 1s,这些都需要数据同步和服务治理发现配合完成。如果 RPO 和 RTO 的要求很高,那么全量备份通常不可取。因为全量备份通常是定期的,比如一天一次,假如故障的时间恰好发生在全量备份之前,这意味着这接近一天的数据丢失了。数据只能恢复到一天之前。所以这就要求了具有一个实时增量的热备份能力。

因为数据的全量和增量不断同步,例如:Redis 的 RDB 文件和 AOF 文件,如果 Redis 发生不可服务,这些 RDB + AOF 文件可以恢复成一个数据库继续提供服务。再譬如:MongoDB 的全量 Snapshot + Oplog 增量,也可以恢复成一个完整的数据库。

另外,备份还可以分为逻辑备份和物理备份。逻辑备份通常指的是数据库的逻辑层面通过全量文件 + Binlog 文件来实现,而物理备份通常指引擎层面来进行备份。

以上提到了关于备份,有很多划分种类。比如:冷热备份、冷热恢复、物理、逻辑备份、全量、增量备份等等,关于这些概念如果不清晰可以自行搜索一下。此外,我们在本小节的开头提到,备份还可以提供一个读服务,那对于这种场景来说,备份数据不能单单是一些文件,例如:RDB 文件,AOF 文件等,而需要是一个完整可服务的数据库,所以这种场景下,通常也需要是一个实时增量的热备份。

1.2 多活

多活对于数据库层面来说,指的是跨逻辑单元的多个数据库同时对外提供服务,这些不同单元的数据库具有部分相同或者全部相同的数据。这通常用于解决因地域网络传输层面带来的问题,也就是异地多活。比如:业务层面在北京机房写入一条数据,要求在上海机房也能读到这条数据;同样反过来也可以,在上海机房写入的数据,在北京也能读到。

多活的模式看起来很好,能解决很多业务层面的问题,但同时有很多问题和挑战:

如何解决双向复制的问题?

两个数据库互相同步数据,那难免数据会成环导致风暴。

举个例子:假如 A 数据库和 B 数据库互相同步,我在 A 数据库插入一条数据:insert x。那么这条数据通过同步链路会被同步到 B 数据库,这时候 B 数据库也插入了这条数据:insert x。又由于反向同步链路的存在,这条数据又会被同步回 A 数据库: insert x。长此往复,数据就成环了。

该怎么办呢?答案就是,这种双向复制如果仅依赖通道层面来解决基本不可行。通常需要配合数据库内核或者业务层面来解决,比如:数据库内核增加全局唯一字段,标识数据产生地,而通道在拉取数据时,只拉取数据的产生地 id=当前数据库 id 的数据,打破成环。亦或者在链路层面增加过滤,比如从源库只拉取 db=a,b 的数据,从目的库只拉取 db=c 的数据。

这样数据保证不会成环,而源和目的两个库都有全套的db=a, b, c 三个数据库的数据。然后通过业务层面配合,将 db=a, b 库的写数据分发到源库,db=c 库的写数据分发到目的库来实现。对于开源数据库模式下,第二种模式也是最常见的模式,在后面介绍 MongoShake 和 RedisShake 我们会详细介绍这种模式。

如何解决数据双写的问题?

也就是说,如何保证在两个数据库同时对一条数据进行操作,而结果是正确的。

同样举个例子,假设在源数据库 A 和目的数据库 B 有一条数据 x=1,我先在 A 库操作了 set x=2,而后在B库操作了 set x=3,那么能保证最后2个库的结果都是 3 吗?

答案是否定的,因为数据同步是最终一致性,而最终一致性势必是有时间窗口的。在 B 库操作 set x=3 的时候,可能 A 库之前的 set x=2 语句还没有完成同步,那么先 set x=3,后同步 set x=2,结果目的端就变成了 2,而源端同步了set x=3 结果变成了3,这样数据就变成了不一致。

当然我这里只是随便举个例子,还有很多不一致的情况。那么解决这种问题同样也需要两种手段,其一就是内核层面,其二就是业务配合。内核层面解决的比如 CRDT,其基于一个向量时钟来处理消息的分发,那么向量时钟也会带来冲突,对于冲突的处理需要借助一些手段,比如 last write win、客户端解决等等。而很多数据库本身对 CRDT 的支持很不够,所以这种方案有比较大的局限性。其二就是类似我在如何解决双向复制的问题里面讲到的,对业务流量进行分流解决,由业务保证不会在同步通道的两侧同时对一条数据进行操作。

现在数据库层面的多活,大部分都是一种伪多活,通常都需要业务层面配合分流来解决。下面我在 MongoShake 和 RedisShake 章节,会对这种业务配合的方式进行展开讨论。

2. 迁移

【免责声明】本站内容转载自互联网,其相关言论仅代表作者个人观点绝非权威,不代表本站立场。如您发现内容存在版权问题,请提交相关链接至邮箱:bqsm@foxmail.com,我们将及时予以处理。

网友评论
推荐文章