Skip to content

常见问题&FAQ

Vinllen Chen edited this page Sep 25, 2020 · 61 revisions

如果你的问题没有出现在下面列表,请提在github issue上面。第一部分是常见问题咨询,第二部分是出错问题处理。 关于如何进行配置,请参考第一次使用,如何进行配置?;关于配置参数的意义,请参考配置参数说明

1. 常见问题

Q: mongoshake是否会同步config, local, admin库?

A: 不会同步。如果用户一定要把admin的库同步到别的,那么可以通过命名转换功能(配置transform.namespace)把admin库同步到别的数据库,同时配置filter.pass.special.db参数:

  1. filter.pass.special.db = admin
  2. transform.namespace = admin.abc:target.abc # 把admin库下面的abc同步到target库的abc

Q: 从MongoDB同步到MongoDB发现全量阶段目的端MongoDB压力过大怎么办?

A: 用户可以降低全量同步配置replayer的相关参数,以降低目的端压力。

Q: 从MongoDB同步到MongoDB发现全量阶段同步时间过久,怎么办?

A: 用户可以定位一下看看目的慢的原因是什么,正常情况下可以提高全量配置replayer的相关参数,以提高全量同步的性能。但也有可能,问题的瓶颈是源端/网络端/通道cpu,内存等压力过高,都是有可能的。

Q: 增量同步效率很低,怎么办?

A: 用户首先要确认是否真的是同步效率低,是否本身源端写入数据量就很少。另外,启用命名空间转换(transform.namespace)将会极大的降低同步性能,谨慎建议开启。

Q: 如何查看监控?如果配置限速?如何查看运行指标?

A: 请查看如何监控和管理MongoShake的运行状态?

Q: 到底什么是checkpoint?

A: checkpoint是记录增量同步的位点情况,mongoshake的启动就是根据这个位点来进行的,比如我们已经同步到10点钟了,那么这个时候挂掉了,如果没有位点,那么只能从头开始拉,位点的意义就是在于断点续传。在mongoshake中,位点信息是以64位时间戳来标记的(ts字段,准确的说是32位时间戳+计数),如果发生挂掉重启,那么会从源库的oplog表中寻找这个位点,并从此开始往后进行同步。
到这里,用户可能会问,那么mongoshake里面位点是存储在哪里的?存储的位置就是取决于用户context的相关配置,以副本集为例,checkpoint是存储于源库的mongoshake库的ckpt_default表,其大概内容长这个样子:

rszz-4.0-2:PRIMARY> use mongoshake
switched to db mongoshake
rszz-4.0-2:PRIMARY> show collections
ckpt_default
rszz-4.0-2:PRIMARY> db.ckpt_default.find()
{ "_id" : ObjectId("3d75e8b872d91278c3be0cc9"), "name" : "rszz-4.0-2", "ckpt" : Timestamp(1566556865, 196096) }

其中ckpt对应的field就是checkpoint。
用户可能还会问,那么mongoshake的checkpoint是怎么存储的,什么时候会存储?答案是,checkpoint是定期存储的,如果有数据同步,那么checkpoint的更新会很频繁(秒级别);如果没有数据同步,比如这个时候用户源端就是没有写入,那么默认是分钟级别更新一次心跳checkpoint。假设mongoshake数据位点记录是10:00:00,但是数据已经同步到10:00:10,这个时候mongoshake挂掉了,下次会从10:00:00重新开始同步,由于DML本身具有幂等性,数据的重复回放是OK的。那么用户可能会问,DDL怎么办?参考下面问题。

Q: checkpoint存在什么地方?对源库需要什么权限?是否可以不存在源库,我的源库是线上库,不能随便写?

A: checkpoint默认存在源库,对于副本集直接存在源端副本集里面;对于集群版,则默认存在源端的config-server的admin库里面。所以副本集来说需要mongoshake的库(默认情况下,用户可以修改库名)的写权限,和local库的读权限;对于集群版,需要config-server的admin库的写权限和mongod的local库的读权限。
如果用户不希望写到源库里面,可以配置checkpoint.storage.url参数为第三方的MongoDB,checkpoint将会写入到这个配置的MongoDB里面,同样这个MongoDB需要有mongoshake库(默认)的写权限。
如果源端是阿里云的集群版,那么cs的写权限没有开放,所以用户同样可以配置checkpoint.storage.url为源端mongos的地址,以便于checkpoint的写入

Q: 如果我想清掉原来的数据,重新进行一次全量+增量同步,怎么做?

A: 删掉目的端的库的数据,并且删掉checkpoint,然后重启shake。

Q: 如何同步DDL?DDL能保证幂等性吗?

A: 设置replayer.dml_only = false(v2.4.0之后是filter.ddl_enable = true)可以同步DDL。DDL不能保证幂等性。在mongoshake里面,如果发现是DDL语句,会卡一个全局的barrier,让当前DDL语句同步,然后再卡一个全局barrier,等当前DDL语句同步完成,再接着并发同步接下来的oplog,barrier的卡锁伴随着checkpoint的强制刷新。但是由于DDL同步和checkpoint的刷新并不是一个院子操作,如果用户恰好在同步DDL完成和checkpoint刷新之间,进程挂掉了,那么没有办法,重启以后肯定会持续报错,用户需要手动运维解决,比如跳过这个DDL,或者目的端近些一个反向操作(原来DDL是建库,需要进行删除库;原来是建索引,需要进行删索引操作)。但是,这个概率很低。

Q: mongoshake碰到同步出错的情况,会跳过这个错误,继续同步吗?

A: 不会,会持续报错,用户需要关注日志的运行情况。

Q: 全量同步是否会同步索引?

A: 2.1以下版本,目前会同步索引,先是全量同步,全量同步完毕后会建前台索引;2.4版本开始提供索引配置项full_sync.create_index:

  • none:表示不创建所以。
  • background:全量同步前创建后台索引。
  • foreground: 全量同步完毕后创建前台索引。

Q: 选择all模式同步,如果挂掉以后重启,是否会重新发起一次全量同步?进入增量阶段,是否要修改为oplog增量模式,然后再重启?

A: 先全量同步,全量同步完毕会写入checkpoint,然后进行增量同步,增量同步阶段会不断更新checkpoint。对于mongoshake来说,是否进行全量同步取决于checkpoint,如果checkpoint存在且合法,那么只会进入增量同步;否则,会先进行全量同步,然后是增量。那么checkpoint怎么知道是存在的,就是checkpoint.storage.url里面的参数的位置决定;那么怎么知道checkpoint是合法的?如果最老的oplog的时间位点小于checkpoint,那么就是合法的,证明增量能接上。

Q: 我的数据量很大,几百G/几个T/几十个T,all模式同步有什么要注意的地方?

A: 最需要注意的就是,全量同步完毕,增量能否接上。mongoshake是根据oplog的位点来决定全量结束是否要进行增量,如果全量花了2天,但是oplog表只能存储1天,那么全量同步完毕以后mongoshake就会报错退出,这是因为增量的位点丢失了。所以如果全量很大,同步时间势必很久,那么就需要放大oplog的表的大小以维持增量oplog。
其他还需要注意的就是压力问题,如何选取适当的参数应对对于源端/目的端的压力,减少对业务的影响。用户也可以决定从一个hidden结点,护着一个独立的secondary结点进行拉取。

Q: 目前mongoshake有校验工具吗?

A: 目前script下面有个comparison.py的全量校验脚本校验数据的一致性。那么如何进行增量的校验呢?目前还没有,敬请期待。

Q: sharding模式同步有啥需要注意的吗?

A: 如果源端是sharding,那么目前需要关闭balancer,v2.4版本开始,我们支持了不关闭balancer:通过change stream对接。但本身change stream的同步效率相比于oplog来说会低不少,另外DDL操作目前也只有有限的几种支持,且MongoDB版本必须大于4.0。那么问题来了,为什么非change stream场景一定要关闭balancer?请看issue65

Q: 我把数据写入到kafka,怎么从kafka中拉取数据,发现直接拉取出现乱码

A: 请参考如何使用kafka tcp rpc file等异步通道进行数据的发送和消费

Q: 我发现mongoshake建立以后对源端性能有所影响,出现了一些慢查询。

A: 目前全量阶段由于是扫表等操作,会对源端产生一些影响。增量阶段,正常情况影响很小,因为目前oplog找对应ts是二分模式。如果用户真的发现还有性能问题,请在github issue上面进行反馈。

Q: 是否可以把一个MongoDB同步到多个MongoDB?

A: 可以,需要启动多个mongoshake。对于不同的mongoshake,可以修改写入不同地方的checkpoint即可(比如表名修改一下),或者直接修改不同的collector.id。此外,需要注意的是,同一个目录下启动多个mongoshake,如果collector.id相同,是无法启动成功的。参考:https://github.com/alibaba/MongoShake/wiki/FAQ#q-how-to-sync-data-from-one-mongodb-to-several-target-mongodb

Q: 开源MongoDB版本是否支持双向同步?

A: 不支持,只有2边都是云上版本才支持,而且必须源端和目的端都是云上版本。阿里云云上版本目前只有3.4-4.0支持双向同步,4.2及以上版本后面会进行开发支持。

Q: 多个mongodb同步到一个mongodb,如果存在冲突,能否覆盖重复Key或者忽略重复的key?

A: 可以,不过需要启动多个mongoshake,如果是一台机器上请注意不要在同一个目录下启动,且设置不同的port以保证端口不冲突:

  • full_sync.http_port
  • incr_sync.http_port
  • system_profile_port

v2.4版本支持full_sync.collection_exist_drop,可以设置false保证全量同步前相同的collection不会被删除(默认情况下,如果目的端如果存在跟源端一样名字的表,将会先进行删除再开启同步)。

Q: 开源版本是否支持双向同步?

A: 不支持,只有阿里云云上MongoDB的副本集,以及关闭balancer的集群版才支持双向同步。

Q: 我想通过filter只关注某个表的变更,这个filter操作是在源端find的时候过滤的,还是shake拉渠道以后过滤的?

A: 是shake全量拉取以后再进行过滤的,所以即使只需要某个表的变更,也会拉取所有表的数据,再过滤。

Q: sharding到sharding同步是否目的端会开启分片?为什么我的版本没有?

A: 是会开启,mongoshake在2.4.0-2.4.3的版本里面,有个Bug会导致目的端没有开启分片,请升级到2.4最新版本可以解决。

Q: 全量是否支持断点续传?

A: 目前还不支持,敬请期间,后面版本可能会考虑支持。

Q: 全量并发切片拉取是否支持_id不是ObjectId的情况?

A:支持,但是需要特别注意的地方:只支持_id主键为同一个类型的情况,比如_id主键又有ObjectId,又有string,分片将会导致丢key。如果启用了并发切片拉取,需要用户自己保证这种情况。

Q: 为什么我的索引/事务/建表/删库语句不同步?

A:这些都属于DDL语句,需要启用DDL同步:filter.ddl_enable = true

Q: 阿里云云上是否支持双活?哪些版本支持?有什么限制?

A:云上目前4.0以下的版本都支持支持双活,4.0的副本集支持双活,集群版暂未支持。集群版的限制跟普通同步一样,不支持开启DDL。只支持两个都是云上的集群之间互相同步,如果一个是云上,一个是云下,则不支持。双活依赖的gid默认不开启,如果需要开启请联系售后同学,拿到gid后根据gid配置到MongoShake里面:MongoShake1负责A->B同步,则A的gid配置到MongoShake1参数里面;MongoShake2负责B->A同步,则B的gid配置到MongoShake2的参数里面。

Q: 通过MongoShake写数据到kafka,MongoShake重启后发现一部分数据重复了,如何解决这个重复数据的问题?

A:本身挂掉重启就是有重复数据的,这个没办法避免。这是因为checkpoint持久化策略不是实时的,不是说同步一条数据就写一个checkpoint,这样明显性能会很挫。而且写数据跟写checkpoint本身也不是原子的,也无法保证写数据成功,写checkpoint前挂掉。所以如果是从kafka读取,需要进行去重判断,比如已经同步到10:00了,下次拉到10:00前的数据就直接丢弃掉,从而去除重复数据。
mongodb到mongodb同步,会自动处理这个幂等关系,所以即使重放也没有关系。kafka场景就依赖消费者自己处理了。

Q: 目前MongoShake支持哪些MongoDB版本?

A:首先,MongoDB版本需要大于等于3.0,3.0以下的版本可能会存在兼容性的问题。其次,源的版本号需要小于等于目的端的版本,例如源端版本是3.4,目的端版本是4.0,这是OK的,但如果源端版本大于目的端版本,可能会存在兼容性的问题,尤其是启用DDL的情况下。再还有,源端和目的端的版本形态可以不一样,比如源端是分片集群,目的端是副本集;或者源端是副本集,目的端是分片集群。

Q: MongoShake是否支持master/slave架构形态和单节点架构形态?

A:不支持增量同步,但支持全量同步。master-slave架构区别于replica架构形态,其oplog的位置有所不同,位于oplog.$main,考虑到这个架构形态的集群版版在3.2的以后被废弃了,主从版吧也在3.6废弃了,所以不再进行支持。单节点本身不具有oplog,所以也不支持增量同步。

Q: 源端是分片集群,MongoShake全量同步完以后索引不一致问题是为什么?

A:在2.4.6以前,全量同步和索引同步都是从mongod上拉取的,这会导致某些情况下,比如源端MongoDB分片集群,不同分片的索引不一致,同步到目的端以后出现部分索引丢失的情况。2.4.6以后改为从MongoS拉取可以规避这个问题。

Q: sync_mode=all,如何判断全量阶段结束,进入了增量?

A: 日志打印:------------------------full sync done!------------------------

Q: 分片集群,我先用的oplog方式,全量+增量了一段时间,然后开了balancer,mongoshake挂了,再改成change stream模式为什么不能拉取?

A: oplog模式下,checkpoint是一个mongod一个,而change_stream模式下,全局就只有一个checkpoint。checkpoint是用于断点续传的,启动后会去拉取这个位点,如果启动发现这个位点不存在,那么就有问题了,而oplog模式的checkpoint跟change_stream模式的checkpoint是不兼容的,所以不能这么使用。正确的使用姿势:all模式启动,change_stream对接即可,无论是全量还是增量,都不需要关闭balancer。

Q: 全量报错以后如何恢复?

A: 用户需要先看下报错的信息,先解决问题,然后清除目的端库(默认full_sync.collection_exist_drop = true,表示会自动清理)以及源端checkpoint表(默认是mongoshake库,可以手动drop),然后再进行重启mongoshake。


2. 报错问题处理

Q: 报错"Oplog Tailer initialize failed"

A: 请查看具体报错细节,如果是关于源端mongodb的,请检测源端mongodb的连通性以及权限控制。如果是关于worker的,请检测tunnel的配置,tunnel地址是否可连通。
另外,密码中间不能包含'@',否则也可能会报错。

Q: 报错"Oplog Tailer initialize failed: no reachable servers"

A: 请先检查mongodb的连通性和权限是否已经给到位;如果源端是单节点配置比如hidden结点,但是mongo_connect_mode是默认的那么也会报错,此时需要改为standalone,我们建议把整个集群都配置上以防止切换情况发生。
另外,密码中间不能包含'@',否则也可能会报错。

Q: 报错"error type[*mgo.QueryError] error[no such cmd: applyOps]"

A: 这表明拉取的oplog里面有applyOps信息,但目前applyOps对于目的是集群版的暂未支持。对于2.4.0-2.4.2的版本,如果源端没有applyOps的oplog,也可能会报这个错,后续我们会进行修复。

Q: 报错"Oplog Tailer initialize failed: no oplog ns in mongo"

A: 通常,这个是权限不够;此外,还需要检查一下oplog是否存在,尤其单节点的情况(单节点没有Oplog所以没办法进行增量同步,只支持增量sync_mode=full);另外,如果是sharding,给的地址需要是shard的地址而不是mongos,连接串格式需要按照如下进行配置:mongodb://user1:passwd1@10.1.1.1:20011,10.1.1.2:20112;mongodb://user2:passwd2@10.1.2.1:20011,10.1.2.2:20112。 此外,如果是单节点,但是同步模式是document全量同步,那么v2.0.6以后的版本不会抛这个错误。

Q: 报错"oplog syncer internal error: current starting point[6672853605600460800] is bigger than the newest"

A: 这表明checkpoint地址比目前mongodb有的最新的oplog还新,这是不允许的。

Q: 报错"duplicate key"

A: 如果是增量期间报错,可以启用replayer.executor.upsertreplayer.executor.insert_on_dup_update。但通常,用户最好先检查一下这个原因,mongoshake同步不会产生这个问题。另外,对于sharding的情况,不建议开启这个参数,将可能会引发错误
如果是全量期间报错,可以启用full_sync.executor.insert_on_dup_updatefull_sync.executor.filter.orphan_document,通常是源端孤儿文档导致(2.4.6版本开始,sharding源端从Mongos拉取,全量期间不会有这个问题),或者目的端对应的key已经存在了(目的端本来不为空,或者全量中间发生过中断)。

Q: 报错"ns {xx yy} to be synced already exists in dest mongodb"

A: 这个错误发生在全量同步阶段,表示表已经在目的库存在了,这个时候用户要么自己删除表,要么启用replayer.collection_drop参数(v2.4以后改名为full_sync.collection_exist_drop = true)进行删除。

Q: 报错"An upsert on a sharded collection must contain the shard key"

A: 请参考duplicate key

Q: 运行对比脚本报错"Reserved characters such as ':' must be escaped according RFC 2396. An IPv6 address literal must be enclosed in '[' and ']' according to RFC 2732."

A: --src--dest需要以mongodb://开头:--src=mongodb://username:password@primaryA,secondaryB,secondaryC

Q: 报错"syncer default-0 load checkpoint queryTs[Timestamp(1582304516, 305)] is less than oldTs[Timestamp(1582304698, 152)], this error means user's oplog collection size is too small or document replication continues too long]"

A: 这个通常发生在全量同步过久以后,增量开始拉取而源端的oplog丢失了。举个例子,比如全量开始的时间是A,全量结束的时间B,那么到B以后,增量的oplog将会从A时间点开始拉取,如果源端A时间点对应的oplog不存在了(用户可以通过rs.printReplication查看源端最老的oplog是否大于A),就会报这个错误。通常的解决方式是,扩大local.oplog.rs表的大小,或者提高全量同步的速度(比如提高并发数)。

Q: log打印"smallest candidates is zero"是什么意思?

A: 这个并不是报错,通常出现在刚启动的时候,并且源端没有数据写入的情况,过一段时间就会消失。如果这个日志长期存在,并且源端的确有写入,那么就有问题了,请在issue上面进行反馈。

Q: 报错“target mongo server connect failed: no reachable servers”

A: 用户需要先检查目的端的连通性,目的端给的连接串必须包含primary角色。
另外,密码中间不能包含'@',否则也可能会报错。

Q: 报错“oplog syncer internal error: current starting point[6672853605600460800] is bigger than the newest”

A: 启动的时间大于源端最新的oplog时间,通常是context.start_position配置出错。

Q: 报错“Conf.Options check failed: XXX”

A: 配置不合法,请查看具体报错原因进行修改。

Q: 报错“oplog syncer internal error: get next oplog failed. release oplogsIterator, invalid cursor”

A: 通常是连接抖动,或者源端主从切换导致,MongoShake本身会进行重试连接,所以不需要太过担心。

Q: 报错“oplog collection capped error, users should fix it manually”

A: 最直观的原因就是同步慢了,导致源端写入速度追不上。这个需要查看一下同步速度慢的原因,正常情况下不会出现,但也有几种情况会导致这个错误发生:

  1. 启用了命名空间转换transform.namespace,这个启用后效率会很低,所以谨慎建议开启。以后版本我们会考虑进行优化。
  2. 源端写入qps很大。
  3. 目的端写入存在瓶颈。
  4. MongoShake所在的机器负载很高,cpu/memory/带宽等存在瓶颈。

这些都需要用户去排查具体原因。 不过假如用户没有指定开始同步的oplog位点,也就是说oplog从最老的开始拉取,这也可能会在刚启动的时候报错capped error(#390),其原因是:mongodb oplog回收的最小单元是stone,一个stone会包括多个oplog,尽管拉取的比写入快,但是最开始的stone比较特殊。举个例子,比如最开始stone的oplog是10:00-11:00,拉取从10:00-10:10都是OK的,15:00的时候写入了一条新的数据,导致整个oplog大小超了,就会删除最老的stone(对比stone最后一条record的ts跟需要Purge的ts来判断整个stone要不要删除),这样就会导致10:00-11:00全被删除了,从而拉取就失败了。

Q: 源端配置change stream拉取,但是报错"Resume of change stream was not possible, as the resume point may no longer be in the oplog"

A: 通常是拉取的位点在oplog里面已经不存在了,用户需要排查:

  1. 如果第一次启动,查看checkpoint.start_position设置是否正确,需要大于所有mongodb上最老的oplog的timestamp(ts字段)。
  2. 如果已经有checkpoint了,可能之前的checkpoint已经失效了,需要删除旧的checkpoint表并重启。

Q:报错:run replication failed: incr sync beginTs[2] is less than current the biggest old timestamp[1589271068], this error usually means illegal start timestamp(checkpoint.start_position) or capped collection error happen

A: 参考"Resume of change stream was not possible, as the resume point may no longer be in the oplog"报错处理。

Q: 报错:move chunk oplog found

A: 源端启用了balancer,发生move chunk导致同步退出了,对于源端是sharding的情况,如果用oplog格式拉取,需要关闭balancer。在2.4开启,支持change stream模式,可以在开启balancer的情况下进行同步,不过效率会低一些。关于change stream的具体实现请参考v2.4版本对接change stream架构设计,如何配置请参考从MongoDB集群版同步到MongoDB集群版

Q: 报错: ddl oplog found when oplog timestamp[xxx] less than fullSyncFinishPosition[xxx]

A: 全量同步期间产生的增量oplog不允许DDL同步,举个例子,1:00开启MongoShake进行同步,2:00完成全量同步进入增量,那么1:00-2:00中间产生的oplog不允许有DDL。

Q: 报错:not authorized on admin to execute command { update: "ckpt_default", writeConcern: { getLastError: 1, w: "majority" }, ordered: true, $db: "admin" }

A: 如果源端是阿里云的集群版,那么cs的写权限没有开放,用户可以配置checkpoint.storage.url为源端mongos的地址,以便于checkpoint的写入。从2.4.6开始,checkpoint默认将会写入源端mongos,而不是checkpoint。

Q: KafkaWriter send [xxx] with type[json] error[kafka server: Message was too large, server rejected it to avoid allocation error.]

A: 这个说明写入kafka的数据过大了,默认kafka和MongoShake的producer的max message size都是1MB,而MongoDB自身的oplog最大可以达到16MB。解决方案:升级MongoShake到2.4.6以后的版本,默认会将producer max message size调大到18MB以满足需求;同时,用户还需要自己调整kafka的该配置项大于16M以满足需求。

Q: 编译报错:“use of vendored package not allowed”

A: 当前版本v2.4.7及之前,MongoShake包管理工具用的是govendor,而不是go.mod,所以会有内部包引用的报错,解决方式是go版本切到1.10并重新编译可以解决(1.12以后添加了该约束)。

Q: 报错:Connect checkpointStorageUrl[] error[]. Please add primary node into 'mongo_urls' if 'context.storage.url' is empty

A:源端是单节点的情况,必须配置mongo_connect_mode=standalone,否则没办法识别其他角色:primary、secondary

Q: 报错:'idIndex' is not allowed with 'autoIndexId'

A: autoIndexId字段跟idIndex无法共存,如果源端创建collection时候携带了{autoIndexId: true},则生成的oplog同时会携带autoIndexId和idIndex。v2.4.10开始,对这个问题进行了修复。具体请参考#400

Q: 报错:EOF如何处理?

A: 如果是写入目的端报错,则一般是目的端MongoDB的问题,或者网络层面的问题,通常是前者,请检查对应时间点MongoDB的日志,包括主从节点的,查看是否有报错;如果是源端报错,则请检查源端MongoDB的日志。