com.mongodb.MongoCursorNotFoundException解决方案

本文介绍了一种解决MongoDB中游标超时的方法,通过设置查询选项以避免因游标超时而导致的数据查询中断问题,并强调了使用完成后关闭游标的必要性。

Exception in thread "main" com.mongodb.MongoCursorNotFoundException: 

 Query failed with error code -5 and error message 'Cursor 85789014536 not found on server ****:*' on server *:*

解决方案: DBCursor cursor = mongoTemplate.getCollection("people")

                    .find(new BasicDBObject(), keys)

                    .addOption(Bytes.QUERYOPTION_NOTIMEOUT);

   这样的话在返回的cursor中可以将其转成people对象,然后只有name和age这两个字段有值,

   其他的一些信息比如说weight,sex等就都为null。使用起来是不是很方便。
注意了!!!

       最后的 .addOption(Bytes.QUERYOPTION_NOTIMEOUT) 是为了让这个游标不超时,

       如果你的数据集比较大你处理的时间比较长时就需要指定这个,否则会中途就突然断掉,

       因为超时被回收了,使用这个就一定要注意使用的最后一定要调用close()函数进行关闭,

      否则将一直占用系统资源。


<think>我们面对的是MongoDB游标超时导致查询失败的问题,具体错误为`com.mongodb.MongoCursorNotFoundException: Query failed with error code -5`,错误信息提示游标在服务器上找不到。根据引用内容,结合MongoDB的特性,以下是针对该问题的分析和解决方案。 ### 问题原因分析 1. **游标生命周期问题**:MongoDB的游标默认有10分钟的超时时间。如果查询结果集很大,处理时间超过10分钟,游标会被服务器自动回收,导致后续获取数据时游标不存在[^1]。 2. **网络或性能问题**:如引用所述,网络波动或读取速度受限(如线上业务库有流量控制)可能导致数据传输缓慢,使得游标在未完成数据传输前就已超时。 3. **服务器负载过高**:如果MongoDB服务器负载过高,处理查询请求的速度变慢,同样可能引起游标超时。 4. **客户端处理延迟**:客户端处理每条数据耗时过长,导致两次获取批次数据的时间间隔超过游标超时时间。 ### 解决方案 根据引用提供的思路和MongoDB最佳实践,建议采用以下方法: 1. **设置无超时游标(noCursorTimeout)** 在创建游标时设置`noCursorTimeout`选项,防止服务器自动回收游标。但要注意:这可能导致服务器资源长期占用,需谨慎使用。 ```java // Java驱动示例 MongoCursor<Document> cursor = collection.find().noCursorTimeout(true).iterator(); ``` 2. **分批获取数据并定期重置游标** 即使设置了`noCursorTimeout`,网络中断仍可能导致游标丢失。更安全的做法是: - 使用较小的批处理大小(如每次1000条) - 定期执行`getMore`操作(自动处理) - 显式重置游标超时时间(通过执行`killCursors`后再重新获取) 3. **优化查询性能** - **添加索引**:确保查询条件涉及的字段有合适索引。 - **减少返回字段**:通过投影仅返回必要字段。 - **避免全表扫描**:使用`explain()`分析查询计划。 4. **调整MongoDB服务器配置** 增加游标超时时间(需权衡资源消耗): ```mongodb // 修改全局超时时间(单位:毫秒) // 注意:生产环境修改需谨慎,可能影响其他查询 db.adminCommand({setParameter: 1, cursorTimeoutMillis: 1800000}) // 30分钟 ``` 5. **客户端重试机制** 捕获`MongoCursorNotFoundException`并实现重试逻辑: ```java int retryCount = 0; while (retryCount < MAX_RETRY) { try { // 执行查询并处理数据 break; } catch (MongoCursorNotFoundException e) { retryCount++; // 重新初始化游标(可能需要记录已处理位置) Thread.sleep(1000 * retryCount); } } ``` ### 针对DataX任务的特别建议 引用中提到的DataX任务场景(亿级数据量导出): 1. **调整MongoReader配置** 在自定义的MongoDBReader插件中: - 设置`noCursorTimeout=true` - 增加`batchSize`(如5000)减少请求次数 ```json "reader": { "name": "mongodbreader", "parameter": { "noCursorTimeout": true, "batchSize": 5000 } } ``` 2. **分片键优化** 如果集合已分片,确保查询包含分片键以避免广播操作。 3. **增加客户端资源** 提升DataX任务所在机器的网络带宽和CPU资源,加速数据处理。 > **警告**:长期持有游标可能对MongoDB集群造成压力,建议在业务低峰期执行大数据量操作。 ### 总结流程图 ```mermaid graph TD A[遇到游标超时错误 -5] --> B{原因分析} B --> C1[游标默认10分钟超时] B --> C2[网络/性能问题] B --> C3[服务器负载高] B --> C4[客户端处理慢] C1 --> D1[设置noCursorTimeout] C2 --> D2[优化网络/分批获取] C3 --> D3[降低负载或提升配置] C4 --> D4[优化客户端代码] D1 --> E[实施解决方案] D2 --> E D3 --> E D4 --> E E --> F[问题解决] ``` §§相关问题§§ 1. 如何在MongoDB中监控游标使用情况? 2. DataX读取MongoDB时如何实现断点续传? 3. 除了游标超时,还有哪些常见的MongoDB查询错误? </think> ### 解决`com.mongodb.MongoCursorNotFoundException`错误(错误代码 -5)的方法 该错误通常发生在处理 **大数据量查询** 时,MongoDB服务器上的游标因超时被自动回收,导致客户端无法继续获取数据。以下是针对性的解决方案--- ### 一、核心解决方案(按优先级排序) 1. **设置游标永不超时(推荐)** 在查询时显式添加 `noCursorTimeout` 选项: ```java // Java 驱动示例 MongoCursor<Document> cursor = collection.find() .noCursorTimeout(true) // 关键参数 .batchSize(1000) // 减小批处理量 .iterator(); ``` - **优点**:彻底避免游标被服务器回收 - **注意**:需手动关闭游标(`cursor.close()`),否则可能引发内存泄漏 2. **优化查询性能** - **添加索引**:确保查询条件涉及字段已建立索引 ```mongodb db.yourCollection.createIndex({ yourQueryField: 1 }) ``` - **减少返回字段**:使用投影过滤非必要数据 ```java .projection(Projections.include("field1", "field2")) ``` - **限制结果集**:添加时间范围等过滤条件 3. **调整批处理大小** 减小`batchSize`值(如1000),避免单次数据传输过大: ```java .batchSize(1000) // 默认101,建议设为500-5000 ``` 4. **客户端重试机制** 捕获异常后重建游标(需记录已处理位置): ```java try { // 游标操作 } catch (MongoCursorNotFoundException e) { // 从断点重建查询(如基于_id排序后继续) Bson lastId = ...; // 记录最后处理的文档ID collection.find(gt("_id", lastId)).noCursorTimeout(true); } ``` --- ### 二、服务器端优化 1. **增加游标超时时间** 修改MongoDB服务器配置(需重启): ```yaml # mongod.conf setParameter: cursorTimeoutMillis: 1800000 # 30分钟(默认600000=10分钟) ``` 2. **提升硬件/网络资源** - 检查服务器负载(`mongostat`) - 优化网络带宽(尤其跨机房访问) - 升级MongoDB分片集群 3. **监控游标状态** 实时查看活跃游标: ```mongodb db.currentOp({ "active": true, "ns": "yourDB.yourCollection", "op": "getmore" }) ``` --- ### 三、DataX专项优化(针对亿级数据导出) 1. **修改MongoReader配置** 在`job.json`中添加: ```json "reader": { "name": "mongodbreader", "parameter": { "noCursorTimeout": true, // 关键参数 "batchSize": 2000, // 调整批大小 "query": "{\"createTime\": {\"$gt\": {ISODate(\"2023-01-01\")}}}" // 分段查询 } } ``` 2. **启用分片导出** 按分片键并行读取: ```json "splitPk": "_id", // 指定分片字段 "channel": 8 // 并行度 ``` 3. **网络容错机制** 在DataX任务中添加重试策略: ```json "setting": { "errorLimit": { "record": 1000 // 允许容错记录数 }, "speed": { "channel": 4, "byte": 1048576 // 限速1MB/s避免压垮线上库 } } ``` --- ### 四、根本原因说明 ```mermaid graph LR A[客户端发起查询] --> B[服务器创建游标ID] B --> C{10分钟超时计时} C -->|网络延迟/数据量大| D[游标被服务器回收] D --> E[客户端请求下一页数据] E --> F[抛出Cursor not found错误] ``` **关键点**: - MongoDB默认游标存活时间为 **10分钟**(无活动后自动销毁) - 大数据量导出时,网络波动或处理延迟易触发此机制 > **操作建议**:生产环境优先使用 `noCursorTimeout + 分批处理` 方案,并在业务低峰期执行任务。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值