2017-07-04 57 views
2

我已经使用Apache Jersey编写了一个RESTful API。我使用MongoDB作为后端。我使用Morphia(v.1.3.4)来映射POJO并将其保存到数据库中。我尝试在我的API中按照“1应用程序1连接”的方式推荐,但我不确定自己是否成功。我运行我的API在Tomcat 8。我也跑了Mongostat查看细节和连接。 在开始时,Mongostat显示1到MongoDB服务器的连接。我使用Postman测试了我的API,它工作正常。然后,我在SoapUI中创建了一个负载测试,其中我每秒模拟100个用户。我看到了Mongostat的更新。 我看到有103个连接。这是显示此行为的gif。Mongo Connection在RESTful API中多次创建并且从未发布

enter image description here

我不知道为什么有这么多的连接。有趣的事实是,mongo连接的数量与我在SoapUI上创建的用户数成正比。这是为什么?我发现了其他类似的问题,但我认为我已经实施了一些建议。

Mongo connection leak with morphia

Spring data mongodb not closing mongodb connections

我的代码看起来是这样的。

DatabaseConnection.java

// Some imports 
public class DatabaseConnection { 

    private static volatile MongoClient instance; 
    private static String cloudhost="localhost"; 

    private DatabaseConnection() { } 

    public synchronized static MongoClient getMongoClient() { 
     if (instance == null) { 
      synchronized (DatabaseConnection.class) { 
       if (instance == null) { 
        ServerAddress addr = new ServerAddress(cloudhost, 27017); 
        List<MongoCredential> credentialsList = new ArrayList<MongoCredential>(); 
        MongoCredential credentia = MongoCredential.createCredential(
         "test", "test", "test".toCharArray()); 
        credentialsList.add(credentia); 
        instance = new MongoClient(addr, credentialsList); 

       } 
      } 
     } 
     return instance; 
    } 
} 

PourService.java

@Secured 
@Path("pours") 
public class PourService { 

final static Logger logger = Logger.getLogger(Pour.class); 
private static final int POUR_SIZE = 30; 

    @POST 
    @Consumes(MediaType.APPLICATION_JSON) 
    @Produces(MediaType.APPLICATION_JSON) 
    public Response createPour(String request) 
    { 
     WebApiResponse response = new WebApiResponse(); 
     Gson gson = new GsonBuilder().setDateFormat("dd/MM/yyyy HH:mm:ss").create(); 
     String message = "Pour was not created."; 
     HashMap<String, Object> data = null; 
     try 
     { 
      Pour pour = gson.fromJson(request, Pour.class); 

      // Storing the pour to 
      PourRepository pourRepository = new PourRepository();   
      String id = pourRepository.createPour(pour); 

      data = new HashMap<String, Object>(); 
      if ("" != id && null != id) 
      { 
       data.put("id", id); 
       message = "Pour was created successfully."; 
       logger.debug(message); 
       return response.build(true, message, data, 200); 
      } 

      logger.debug(message); 
      return response.build(false, message, data, 500); 
     } 
     catch (Exception e) 
     { 
      message = "Error while creating Pour."; 
      logger.error(message, e); 
      return response.build(false, message, new Object(),500); 
     } 
    } 

PourDao.java

public class PourDao extends BasicDAO<Pour, String>{ 

    public PourDao(Class<Pour> entityClass, Datastore ds) { 
     super(entityClass, ds); 
    } 
} 

PourRepository.java

public class PourRepository { 

    private PourDao pourDao; 

    final static Logger logger = Logger.getLogger(PourRepository.class); 

    public PourRepository() 
    { 
     try 
     { 
      MongoClient mongoClient = DatabaseConnection.getMongoClient(); 
      Datastore ds = new Morphia().map(Pour.class) 
        .createDatastore(mongoClient, "tilt45"); 
      pourDao = new PourDao(Pour.class,ds); 
     } 
     catch (Exception e) 
     { 
      logger.error("Error while creating PourDao", e); 
     } 
    } 

    public String createPour (Pour pour) 
    { 
     try 
     { 
      return pourDao.save(pour).getId().toString(); 
     } 
     catch (Exception e) 
     { 
      logger.error("Error while creating Pour.", e); 
      return null; 
     } 
    } 
} 
+1

没有什么特别令人惊讶或关于您的观察。您正在产生100个线程,而这些线程又将100个连接数据库连接起来。 – helmy

+0

你是如何验证_and never released_ part? – Veeram

+1

连接数量是否达到稳定状态(即〜100)? MongoDB Java驱动程序的默认连接池大小为100.尝试使用['maxPoolSize'选项](http://mongodb.github.io/mongo-java-driver/3.2/driver/reference/connecting/connection -settings /#选项)。我怀疑这100个连接包括默认的连接池以及你正在运行的'mongo' shell和'mongostat'命令的一些连接。 – Stennie

回答

1

当我与蒙戈+吗啡工作,我得到使用的数据存储,而不是为MongoClient工厂模式更好的结果,例如,检查下面的类:

public DatastoreFactory(String dbHost, int dbPort, String dbName) { 
    final Morphia morphia = new Morphia(); 
    MongoClientOptions.Builder options = MongoClientOptions.builder().socketKeepAlive(true); 
    morphia.getMapper().getOptions().setStoreEmpties(true); 
    final Datastore store = morphia.createDatastore(new MongoClient(new ServerAddress(dbHost, dbPort), options.build()), dbName); 
    store.ensureIndexes(); 
    this.datastore = store; 
} 

使用这种方法,每次需要数据存储时,都可以使用工厂提供的数据存储。当然,如果您使用支持工厂模式的框架/库(例如:HK2与org.glassfish.hk2.api.Factory),以及单例绑定,则可以更好地实现。

此外,您可以检查MongoClientOptions的构建器方法的文档,也许您可​​以在那里找到更好的连接控制。

+0

我的数据存储被映射到具体类“倒”和许多其他类在不同的文件。因此我在MongoClient级别创建了单例模式。根据文档MongoClient正在管理应用程序的连接,每个应用程序应该只有一个MongoClient实例。 –