Java Mongo连接在RESTful API中多次创建,从未发布

Java Mongo连接在RESTful API中多次创建,从未发布,java,mongodb,rest,jersey,morphia,Java,Mongodb,Rest,Jersey,Morphia,我已经使用ApacheJersey编写了一个RESTful API。我使用MongoDB作为后端。我使用Morphia(v.1.3.4)将POJO映射并持久化到数据库。我试着在我的API中按照大家推荐的“1应用程序1连接”,但我不确定我是否成功。我在Tomcat8中运行API。我还运行了Mongostat以查看详细信息和连接开始时,Mongostat显示了1个到MongoDB服务器的连接。我使用Postman测试了我的API,它工作正常。然后,我在SoapUI中创建了一个负载测试,模拟每秒100

我已经使用ApacheJersey编写了一个RESTful API。我使用MongoDB作为后端。我使用Morphia(v.1.3.4)将POJO映射并持久化到数据库。我试着在我的API中按照大家推荐的“1应用程序1连接”,但我不确定我是否成功。我在Tomcat8中运行API。我还运行了Mongostat以查看详细信息和连接开始时,Mongostat显示了1个到MongoDB服务器的连接。我使用Postman测试了我的API,它工作正常。然后,我在SoapUI中创建了一个负载测试,模拟每秒100个用户。我在Mongostat上看到了更新我看到有103个连接。这是显示这种行为的gif

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

我的代码看起来像这样

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;
    }
}
@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);
        }
    }
public class PourDao extends BasicDAO<Pour, String>{

    public PourDao(Class<Pour> entityClass, Datastore ds) {
        super(entityClass, ds);
    }
}
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;
        }
    } 
 }

当我使用Mongo+Morphia时,我使用数据存储而不是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 with
org.glassfish.HK2.api.factory
),以及单例绑定,那么这可以更好地实现


此外,您可以查看
mongoclientations
的builder方法的文档,也许您可以在那里找到更好的连接控件。

您的观察没有什么特别令人惊讶或令人担忧的。您正在生成100个线程,这些线程又与数据库建立了100个连接。您是如何验证未发布的部分的?连接数是否达到稳定状态(即~100)?MongoDB Java驱动程序的默认连接池大小为100。试着用不同的颜色来改变这个。我怀疑这100个连接包括默认的连接池,以及您正在运行的
mongo
shell和
mongostat
命令的一些连接。@helmy 1 user=1 mongo连接不是正确的方法。这是不可扩展的。我没有说过,你的测试也不能证明这一点。再次尝试您的测试并模拟200个用户,您很可能会看到类似的结果,例如约100个连接。我的数据存储映射为具体类“Pour”和不同文件中的许多其他类。因此,我在MongoClient级别创建了单例模式。根据文档,MongoClient正在管理应用程序的连接,每个应用程序应该只有一个MongoClient实例。