之前写过一篇文章:binlog还能这么用之Canal篇,在内里先容了一些增量数据迁徙的一些方式,然则对于整体的数据的迁徙先容得不是很深,这里想对迁徙数据整体做一个先容,希望能辅助到人人。

靠山

在星爷的《大话西游》中有一句异常着名的台词:“曾经有一份真挚的情绪摆在我的眼前我没有珍惜,等我失去的时刻才追悔莫及,人世最痛苦的事莫过于此,若是上天能给我一次再来一次的机遇,我会对哪个女孩说三个字:我爱你,若是非要在这份爱上加一个限期,我希望是一万年!”在我们开发人员的眼中,这个情绪就和我们数据库中的数据一样,我们多希望他一万年都不改变,然则往往事与愿违,随着公司的不停生长,营业的不停调换,我们对数据的要求也在不停的转变,也许有下面的几种情形:

  • 分库分表:营业生长越来越快,导致单机数据库蒙受的压力越来越大,数据量也越来越多,这个时刻通常会使用分库的方式去解决这个问题,将数据库的流量均分到差别的机械上。从单机数据库到分库这个历程,我们就需要完整的迁徙我们的数据,我们才气乐成的分库的方式上使用我们的数据。

  • 替换存储介质:上面先容的分库,一样平常来说我们迁徙完之后,存储介质依然是同样的,好比说之前使用的是单机Mysql,分库之后就酿成了多台机械的Mysql,我们的数据库表的字段都没有发生转变,迁徙来说相对对照简朴。有时刻我们分库分表并不能解决所有的问题,若是我们需要许多庞大的查询,这个时刻使用Mysql可能就不是一个靠谱的方案,那么我们就需要替换查询的存储介质,好比使用elasticsearch,这种的迁徙就会稍微要庞大一些,涉及到差别存储介质的数据转换。

  • 切换新系统:一样平常公司在高速生长中,一定会泛起许多为了速度快然后重复建设的项目,当公司再一准时间段的时刻,往往这部门项目会被合并,酿成一个平台或者中台,好比我们一些会员系统,电商系统等等。这个时刻往往就会面临一个问题,将老的系统中的数据需要迁徙到新的系统中,这个时刻就加倍庞大了,有可能不仅是存储介质有更改,有可能项目语言也差别,从更上层的角度来看,部门有可能也差别,以是这种数据迁徙的难度是对照高,风险也加倍的大。

在现实营业开发中,我们会凭据差别的情形来做出差别的迁徙方案,接下来我们来讨论一下到底应该怎么迁徙数据。

数据迁徙

数据迁徙实在不是一蹴而就的,每一次数据迁徙都需要一段漫长的时间,有可能是一周,有可能是几个月,通常来说我们迁徙数据的历程基本都和下图差不多:

首先我们需要将我们数据库已经存在的数据举行批量的迁徙,然后需要处置新增的这部门数据,需要实时的把这部门数据在写完原本的数据库之后然后写到我们的新的存储,在这一历程中我们需要不停的举行数据校验。当我们校验基本问题不大的时刻,然后举行切流操作,直到完全切流之后,我们就可以不用再举行数据校验和增量数据迁徙。

存量数据迁徙

首先我们来说一下存量数据迁徙应该怎么做,存量数据迁徙在开源社区中搜索了一圈发现没有太好用的工具,现在来说阿里云的DTS提供了存量数据迁徙,DTS支持同构和异构差别数据源之间的迁徙,基本支持业界常见的数据库好比Mysql,Orcale,SQL Server等等。DTS对照适合我们之前说的前两个场景,一个是分库的场景,若是使用的是阿里云的DRDS那么就可以直接将数据通过DTS迁徙到DRDS,另外一个是数据异构的场景,无论是Redis照样ES,DTS都支持直接举行迁徙。

那么DTS的存量迁徙怎么做的呢?实在对照简朴也许就是下面几个步骤:

  1. 当存量迁徙义务启动的时刻,我们获取当前需要迁徙的最大的id和最小id
  2. 设置一个分段,好比1万,从最小id最先每次查询1万的数据给DTS服务器,交给DTS处置。sql如下:
select * from table_name where id > curId and id < curId + 10000;

3.当id大于maxId之后,存量数据迁徙义务竣事

固然我们在现实的迁徙历程中可能不会去使用阿里云,或者说在我们的第三个场景下,我们的数据库字段之间需要做许多转换,DTS不支持,那么我们就可以模拟DTS的做法,通过分段批量读取数据的方式来迁徙数据,这里需要注重的是我们批量迁徙数据的时刻需要控制分段的巨细,以及频率,防止影响我们线上的正常运行。

增量数据迁徙

存量数据的迁徙方案对照有限,然则增量的数据迁徙方式就是百花齐放了,一样平常来说我们有下面的几种方式:

  • DTS: 阿里云的DTS算是一条龙服务了,在提供存量数据迁徙的同时也提供了增量数据迁徙,只不过需要按量收费。
  • 服务双写:对照适合于系统没有切换的迁徙,也就是只换了存储然则系统照样同一个,好比说分库分表,redis数据同步等,这个的做法对照简朴直接在代码内里同步的去写入需要迁徙的数据,然则由于不是同一个数据库就不能保证事务,有可能导致迁徙数据的时刻会泛起数据丢失,这个历程通过后续的数据校验会举行解决。
  • MQ异步写入:这个可以适用于所有的场景,当有数据修改的时刻发送一个MQ新闻,消费者收到这个新闻之后再举行数据更新。这个和上面的双写有点类似,然则他把数据库的操作酿成了MQ异步了出问题的概率就会小许多
  • 监听binlog: 我们可以使用之前说过的canal或者其他的一些开源的如databus去举行binlog监听,监听binlog的方式 就和上面的新闻MQ方式一样,只是发送新闻的这一步被我们省略了。这个方式的一个开发量来说基本是最小的。

这么多种方式我们应该使用哪种呢?我小我私家来说是对照推荐监听binlog的做法的,监听binlog削减开发成本,我们只需要实现consumer逻辑即可,数据能保证一致性,由于是监听的binlog这里不需要忧郁之前双写的时刻不是一个事务的问题。

,

以太坊高度

www.326681.com采用以太坊区块链高度哈希值作为统计数据,联博以太坊统计数据开源、公平、无任何作弊可能性。联博统计免费提供API接口,支持多语言接入。

,

数据校验

前面所说的所有方案,虽然有许多是成熟的云服务(dts)或者中间件(canal),然则他们都有可能泛起一些数据丢失,泛起数据丢失的情形整体来说照样对照少,然则异常难排查,有可能是dts或者canal不小心抖了一下,又或者是吸收数据的时刻不小心导致的丢失。既然我们没有办法制止我们的数据在迁徙的历程中丢失,那么我们应该通过其他手段来举行校正。

通常来说我们迁徙数据的时刻都市有数据校验这一个步骤,然则在差别团队可能会选取差别的数据校验方案:

  • 之前在美团的时刻,我们会做一个双读,也就是我们所有的读取都市重新的内里读取一份,然则返回的照样老的,这个时刻我们需要做这部门数据的校验,若是有问题可以发出报警人工修复或者自动修复。通过这种方式,我们常用的数据就能很快的举行一个修复,固然也会不准时的去跑一个全量的数据check,只是这种check出来修复数据的时间就对照滞后。
  • 现在在猿指点之后,我们没有接纳之前的那种方式,由于双读check虽然能很快发现数据的纰谬,然则我们并没有对这部门数据有那么高的一个实时性校验而且双读的一个代码开发量照样稍微对照大的,然则又不能依赖不准时全量check去保证,这样就会导致我们的数据校验时间会异常的延伸。我们采取了一个折中的方式,我们借鉴了对账内里的T+1的一个思绪,我们天天破晓获取老数据库中昨天更新的数据,然后和我们新数据库中的数据做逐一比对,若是有数据不一样或者数据缺失,我们都可以立马举行一个修复。

固然在现实开发历程中我们也需要注重下面几点:

  • 数据校验义务的一个正确性若何保证,校验义务原本就是去校正其他数据的,然则若是他自身泛起了问题,就失去了校验的意义,这里现在来说只能靠review代码这种方式去保证校验义务的正确性。
  • 校验义务的时刻需要注重日志的打印,有时刻泛起问题可能是直接所有数据泛起问题,那么校验义务就有可能会打出大量的错误日志,然后举行报警,有可能会将系统打挂,或者说影响其他人的服务。这里若是要简朴一点搞,可以将一些非人工处置的报警搞成warn,庞大一点搞得话,可以封装一个工具,某个error打印再某个时间段跨越一定量然后就不用再打印了。

  • 校验义务注重不要影响线上运行的服务,通常校验义务会写许多批查询的语句,会泛起批量扫表的情形,若是代码没有写好很容易导致数据库挂掉。

切流

当我们数据校验基本没有报错了之后,说明我们的迁徙程序是对照稳定的了,那么我们就可以直接使用我们新的数据了吗?固然是不可以的,若是我们一把切换了,顺遂的话固然是很好的,若是泛起问题了,那么就会影响所有的用户。

以是我们接下来就需要举行灰度,也就是切流。对于差别的营业切流的的维度会不一样,对于用户维度的切流,我们通常会以userId的取模的方式去举行切流,对于租户或者商家维度的营业,就需要根据租户id取模的方式去切流。这个切流需要制订好一个切流设计,在什么时间段,放出若干的流量,而且切流的时刻一定要选择流量对照少的时刻举行切流,每一次切流都需要对日志做详细的考察,泛起问题尽早修复,流量的一个放出历程是一个由慢到快的历程,好比最最先是以1%的量去不停叠加的,到后面的时刻我们直接以10%,20%的量去快速放量。由于若是泛起问题的话往往在小流量的时刻就会发现,若是小流量没有问题那么后续就可以快速放量。

注重主键ID

在迁徙数据的历程中稀奇要注重的是主键ID,在上面双写的方案中也提到过主键ID需要双写的时刻手动的去指定,防止ID天生顺序错误。

若是我们是由于分库分表而举行迁徙,就需要思量我们以后的主键Id就不能是自增id,需要使用分布式id,这里对照推荐的是美团开源的leaf,他支持两种模式一种是雪花算法趋势递增,然则所有的id都是Long型,适合于一些支持Long为id的应用。另有一种是号段模式,这种会凭据你设置的一个基础id,从这个上面不停的增添。而且基本都走的是内存天生,性能也是异常的快。

固然我们另有种情形是我们需要迁徙系统,之前系统的主键id在新系统中已经有了,那么我们的id就需要做一些映射。若是我们在迁徙系统的时刻已经知道未来也许有哪些系统会迁徙进来,我们就可以接纳预留的方式,好比A系统现在的数据是1到1亿,B系统的数据也是1到1亿,我们现在需要将A,B两个系统合并成新系统,那么我们可以稍微预估一些Buffer,好比给A系统留1到1.5亿,这样A就不需要举行映射,B系统是1.5亿到3亿,那么我们转换成老系统Id的时刻就需要减去1.5亿,最后我们新系统的新的Id就从3亿最先递增。
然则若是系统中没有做计划的预留段怎么办呢?可以通过下面两种方式:

  • 需要新增一个表,将老系统的id和新系统的id做一个映射纪录,这个工作量照样对照大的,由于我们一样平常迁徙都市涉及几十上百张表,纪录的成本照样异常的高。
  • 若是id是Long型的话,我们可以好好行使long是64位这个因素,我们可以制订一个规则,我们新系统的id都是从一个对照大的数最先,好比从大于Int的数最先,将小Int的那部门数都可以留给我们的老系统做Id迁徙,好比我们上面的1.5亿的数据量,实在只用了28位,我们的Int是32位,那么另有4位可以使用,这个4位可以代表16个系统做迁徙,固然若是计划中有更多的系统做迁徙,可以将新系统的id起始点设置得更大一点。如下图所示:

    总结

最后简朴来总结下这个套路,实在就是四个步骤,一个注重:存量,增量,校验,切流,最后再注重一下id。不管是多大量级的数据,基本上根据这个套路来迁徙就不会泛起大的问题。希望能在人人的后续迁徙数据工作中,这篇文章能辅助到你。