KMongo协程查询环境性能差异问题排查求助
KMongo协程查询在开发环境耗时过长的问题分析与建议
问题概述
使用KMongo的CoroutineCollection查询数据库时,本地环境耗时小于0.5秒,但在开发环境中耗时长达10-25秒,性能差异显著。
运行环境与调用栈
应用基于Spring Boot Netty(支持Reactor协程)运行,通过DGS框架搭建GraphQL端点,简化调用栈如下:
DGSQuery suspend fun -> suspend fun | | -> suspend fun KMongo first CoroutineCollection.find() | -> suspend fun KMongo second CoroutineCollection.find()
关键发现与怀疑点
- KMongo默认
batchSize为2,导致底层会执行多次查询拉取数据,增加网络交互开销 - 怀疑代码在单线程上运行且该线程被整个应用共享,开发环境因客户端请求和定时任务更多,更容易出现线程拥堵,进而拉长耗时
日志分析
从日志可以看到:
[ctor-http-nio-1][][] c.x.d.a.wellreport.***Resolver : wellReports run [ctor-http-nio-1][][] c.x.d.d.wellreport.***Service : all***Provider.invoke() start [ctor-http-nio-1][][] d.m.w.Mongo***Repository : fetchAll started [tter-2-thread-1][][] org.mongodb.driver.protocol.command : Sending command '{"find": "***", "filter": {}, "batchSize": 100, "$db": "***", "lsid": {"id": {"$binary": {"base64": "hdGYjs3YSX6K5y2YJzUJkw==", "subType": "04"}}}}' with request id 56 to database *** on connection [connectionId{localValue:22, serverValue:1902}] to server localhost:27017 [ntLoopGroup-3-6][][] org.mongodb.driver.protocol.command : Execution of command with request id 56 completed successfully in 13.32 ms on connection [connectionId{localValue:22, serverValue:1902}] to server localhost:27017 [ntLoopGroup-3-6][][] org.mongodb.driver.operation : Received batch of 54 documents with cursorId 0 from server localhost:27017 [ntLoopGroup-3-6][][] d.m.w.Mongo***Repository : fetchAll finished [ntLoopGroup-3-6][][] c.x.d.d.wellreport.***Service : all***Provider.invoke() finished [ntLoopGroup-3-6][][] c.x.d.d.wellreport.***Service : positive***Provider.invoke() start [ntLoopGroup-3-6][][] w.Mongo***Repository : fetchAllPositive start [tter-2-thread-1][][] org.mongodb.driver.protocol.command : Sending command '{"find": "***", "filter": {"score": {"$gt": 0.0}}, "batchSize": 2, "$db": "***", "lsid": {"id": {"$binary": {"base64": "hdGYjs3YSX6K5y2YJzUJkw==", "subType": "04"}}}}' with request id 57 to database *** on connection [connectionId{localValue:22, serverValue:1902}] to server localhost:27017 [ntLoopGroup-3-6][][] org.mongodb.driver.protocol.command : Execution of command with request id 57 completed successfully in 5.26 ms on connection [connectionId{localValue:22, serverValue:1902}] to server localhost:27017 [ntLoopGroup-3-6][][] org.mongodb.driver.operation : Received batch of 2 documents with cursorId 6831622277590159417 from server localhost:27017
- 首次调用KMongo的
find()后,线程从ctor-http-nio-1切换到ntLoopGroup-3-6,后续所有操作都在该线程上执行 - 第二次查询的
batchSize为2,仅拉取到2条数据,且返回了非0的cursorId,说明还需要多次请求拉取剩余数据,这会显著增加总耗时
相关代码片段
Repository实现类代码:
class MongoXXXScoreRepository(private val collection: CoroutineCollection<MongoXXXScore>) : XXXScoreRepository { private val logger by logger() override suspend fun fetchAllPositive(): List<XXXScore> { logger.info("fetchAllPositive start") val result = collection.find(MongoXXXScore::score gt 0.0).toList().map { it.toXXXScore() } logger.info("fetchAllPositive start") // 注:此处日志重复,建议改为finished return result } }
优化建议
- 调整batchSize:显式设置更大的
batchSize(如100或根据实际数据量调整),减少网络请求次数,例如:collection.find(MongoXXXScore::score gt 0.0).batchSize(100).toList() - 协程调度器优化:确保KMongo使用合适的协程调度器(如
Dispatchers.IO)执行IO操作,避免阻塞Netty的事件循环线程。可通过配置KMongo的客户端参数指定调度器,或在调用时用withContext(Dispatchers.IO)包裹查询逻辑 - 并行查询优化:如果两个
find查询无依赖关系,可使用async/await并行发起,减少总耗时:val allData = async { firstCollection.find().toList() } val positiveData = async { secondCollection.find(MongoXXXScore::score gt 0.0).batchSize(100).toList() } val result = allData.await() + positiveData.await() - 数据库连接池配置:检查MongoDB连接池的最大连接数设置,确保开发环境有足够的连接资源,避免请求等待连接
- 索引优化:为
score字段创建索引,提升查询过滤效率:collection.createIndex(Indexes.ascending(MongoXXXScore::score.name)) - 线程调度监控:使用协程监控工具(如Kotlinx Coroutines Debug Agent)追踪线程调度情况,确认是否存在线程阻塞或资源竞争问题
内容的提问来源于stack exchange,提问作者bemol
相关产品推荐
相关产品推荐

