SpringBoot使用MongoDB异常问题

一 环境介绍

  • SpringBoot1.5.13.RELEASE(本地)
  • Spring Data MongoDB
  • Java 8
  • MongoDB(青云)

二 问题描述

  • 使用 Studio3T 或者 Compass 等 MongoDB 的 GUI 工具连接 MongoDB 不操作一段时间, 就会掉线。但重连速度很快。
  • 使用 Java 的 Mongo 连接驱动, 也是一段时间不操作, 再去操作会出现异常(SocketTimeout, 能发不能收; 连接没有断),同样也是重连速度很快。
# java 日志太长,省略一部分
14:03:47.629 [http-nio-8081-exec-5] ERROR c.d.o.c.TestController - Timeout while receiving message; nested exception is com.mongodb.MongoSocketReadTimeoutException: Timeout while receiving message
org.springframework.data.mongodb.UncategorizedMongoDbException: Timeout while receiving message; nested exception is com.mongodb.MongoSocketReadTimeoutException: Timeout while receiving message
......
Caused by: com.mongodb.MongoSocketReadTimeoutException: Timeout while receiving 
message
......
Caused by: java.net.SocketTimeoutException: Read timed out

三 搜索原因

连接被对方丢弃

  • MongoDB 始终是部署操作系统上,而对于大型公司提供 MongoDB 的服务会经过层层防火墙、代理服务和负载均衡器。它们把 Java 保持的连接踢掉了 ( 状态变成CLOSE_WAIT,只能发数据但无法再收到 )。
  • 于是提了工单问青云情况,他们反馈就是如果从外网连接需要通过 VPN 才不会掉线,经过测试将应用部署在青云服务器上的确没有问题。
  • 如果是自己的服务器搭建 mongdb 可以参考:https://stackoverflow.com/questions/35597930/sockettimeout-with-opened-connection-in-mongodb 该链接解决。(设置:sudo sysctl -w net.ipv4.tcp_keepalive_time= )

参考:https://segmentfault.com/q/1010000009595664/a-1020000009596082

参考:https://blogs.msdn.microsoft.com/avkashchauhan/2011/11/12/windows-azure-load-balancer-timeout-details/

  • 同样的情况也出现在了微软的 Azure Load Balancer。

参考:https://blogs.msdn.microsoft.com/avkashchauhan/2011/11/12/windows-azure-load-balancer-timeout-details/

四 解决方案

(1)Studio 3T 的掉线问题

  • 设置 Max connection idle time(连接池中某个连接的空闲时间超过该值,将丢弃该连接并重新新建立一个连接)

参考:https://studio3t.com/knowledge-base/articles/prevent-mongodb-connection-timeout/

(2)SpringBoot 中如何设置?

  • 方案 1:
@Configuration
public class MongoDbSettings {
<span class="hljs-meta">@Bean</span>
<span class="hljs-keyword">public</span> MongoClientOptions <span class="hljs-title function_">mongoOptions</span><span class="hljs-params">()</span> {
    <span class="hljs-keyword">return</span> MongoClientOptions
        .builder()
        .maxConnectionIdleTime(<span class="hljs-number">60000</span>)
        .build();
}

}

  • 方案 2:程序员 DD 的 spring-boot-starter-mongodb-plus

参考:http://blog.didispace.com/springbootmongodb-plus/

(3)应用放到防火墙里面

五 Spring Data Mongo 与 mongodb-driver 的关系

  • SpringBoot 启动日志中的一句(由 SimpleServerCluster 打印的)
14:36:55.672 [restartedMain] INFO  org.mongodb.driver.cluster - Cluster created with settings {hosts=[mongodb的IP地址:27017], mode=SINGLE, requiredClusterType=UNKNOWN, serverSelectionTimeout='30000 ms', maxWaitQueueSize=500}
# 这句日志只能显示简短的启动信息,不能作为你修改了配置后是否生效的判断依据。

  • mongodb-driver 相关的类
    • MongoClientOptions:MongoDB 连接的配置类
    • MongoClient(继承 Mongo):带有连接池的 Mongo 客户端
    • Mongo:带有连接池的数据库连接
    • DefaultClusterFactory:集群实现的默认工厂
    • SimpleServerCluster:真正创建的集群 Server 连接
    • DB:MongoDB 集群中逻辑数据库的线程安全客户端视图,用于实际操作 MongoDB 的类。
  • Spring Data Mongo 相关的类
    • MongoOperations:指定一组基本 MongoDB 操作的接口。(Spring Data Mongo)
    • MongoTemplate(实现 MongoOperations):MongoOperations 的首要实现类(Spring Data Mongo)
    • SimpleMongoDbFactory:一个从 Mongo 实例创建 DB 实例的工厂类。(Spring Data Mongo)

注意:篇幅有限,加上比较复杂,以后再详细研究一下。