MONGODB01 - Prematurely reached end of stream 错误定位及修复

4,855 阅读2分钟

最近项目在运行过程,当一段时间没有操作mongo,再次访问报错,如下

 org.springframework.data.mongodb.UncategorizedMongoDbException: Prematurely reached end of stream; nested exception is com.mongodb.MongoSocketReadException: Prematurely reached end of stream
	at org.springframework.data.mongodb.core.MongoExceptionTranslator.translateExceptionIfPossible(MongoExceptionTranslator.java:132)
	at org.springframework.data.mongodb.core.MongoTemplate.potentiallyConvertRuntimeException(MongoTemplate.java:2607)
	at org.springframework.data.mongodb.core.MongoTemplate.executeFindMultiInternal(MongoTemplate.java:2474)
	at org.springframework.data.mongodb.core.MongoTemplate.doFind(MongoTemplate.java:2282)
	at org.springframework.data.mongodb.core.ExecutableFindOperationSupport$ExecutableFindSupport.doFind(ExecutableFindOperationSupport.java:213)
	at org.springframework.data.mongodb.core.ExecutableFindOperationSupport$ExecutableFindSupport.all(ExecutableFindOperationSupport.java:169)
	at org.springframework.data.mongodb.repository.query.AbstractMongoQuery.lambda$getExecution$1(AbstractMongoQuery.java:113)
	at org.springframework.data.mongodb.repository.query.AbstractMongoQuery.execute(AbstractMongoQuery.java:97)
	at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:602)
	at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:590)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185)
	at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:59)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185)
	at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185)
	at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:61)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185)

原因

mongo没有配置空闲连接时间,而spring boot 默认的空闲连接时间为0,即永不超时。当连接闲置一段时间,由于防火墙或者负载均衡的原因,导致连接被关闭,而客户端并不知道,当客户端继续使用这个关闭的连接进行读写时就会出错。

解决方式

方式一:写一个配置类设置空闲连接时间

@Configuration
public class MongoCongig {
 
    @Bean
    public MongoClientOptions mongoOptions() {
        //默认空置一个小时重置一次
        return MongoClientOptions.builder().maxConnectionIdleTime(3600000).build();
	}
}

方式二:如果使用mongo 3.x 配置

spring.data.mongodb.uri=mongodb://username:password@xx.mongodb.rds.aliyuncs.com:3717/test?maxIdleTimeMS=3600000

方式三:引入spring-boot-starter-mongodb-plus

POM文件

<dependency>
    <groupId>com.spring4all</groupId>
    <artifactId>mongodb-plus-spring-boot-starter</artifactId>
    <version>1.0.0.RELEASE</version>
</dependency>

配置

spring:
  data:
    mongodb:
      option:
        max-connection-idle-time: 3600000

在启动类加上@EnableMongoPlus注解

@EnableMongoPlus
@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

PS:此包是对官方spring boot starter对mongodb支持的扩展,提供更多配置属性,比如:连接数的配置等,GITHUB地址

支持的配置属性如下:

spring.data.mongodb.option.min-connection-per-host=0
spring.data.mongodb.option.max-connection-per-host=100
spring.data.mongodb.option.threads-allowed-to-block-for-connection-multiplier=5
spring.data.mongodb.option.server-selection-timeout=30000
spring.data.mongodb.option.max-wait-time=120000
spring.data.mongodb.option.max-connection-idle-time=0
spring.data.mongodb.option.max-connection-life-time=0
spring.data.mongodb.option.connect-timeout=10000
spring.data.mongodb.option.socket-timeout=0

spring.data.mongodb.option.socket-keep-alive=false
spring.data.mongodb.option.ssl-enabled=false
spring.data.mongodb.option.ssl-invalid-host-name-allowed=false
spring.data.mongodb.option.always-use-m-beans=false

spring.data.mongodb.option.heartbeat-socket-timeout=20000
spring.data.mongodb.option.heartbeat-connect-timeout=20000
spring.data.mongodb.option.min-heartbeat-frequency=500
spring.data.mongodb.option.heartbeat-frequency=10000
spring.data.mongodb.option.local-threshold=15

以上均为默认配置

补充MongoDB连接Options(3.6.X)

mongo 3.6.x 配置:

  • uri: mongodb://[username:password@]host1[:port1][,hostN[:portN]]][/[database[.collection]][?options]]

  • options属性

常见配置整理如下:

属性说明
authSource数据库名开启认证的database
authMechanismSCRAM-SHA-1
MONGODB-CR (Deprecated in MongoDB 3.6)
MONGODB-X509
GSSAPI (Kerberos)
PLAIN (LDAP SASL)
认证方式
ssltrue或false是否采用ssl
connectTimeoutMS任务毫秒数连接超时时间
maxIdleTimeMS毫秒数,默认0最大空闲时间
maxLifeTimeMS毫秒数,默认0最大存活时间
maxPoolSize数量,默认100最大连接数
minPoolSize数量,默认0最小连接数
waitQueueMultiple数量,默认5每个连接的队列等待数量
waitQueueTimeoutMS毫秒数,默认以驱动为准线程最长等待时间
slaveOktrue或false是否从slave读取数据
readPreferenceprimary (Default)
primaryPreferred
secondary
secondaryPreferred
nearest
读取偏好,会覆盖slaveOK

官方options文档:传送门