【问题标题】:Mongo db java driver - resource management with clientMongodb java驱动 - 与客户端的资源管理
【发布时间】:2015-08-06 11:04:20
【问题描述】:

背景

我有一个远程托管服务器,它运行 java vm,带有用于多人实时问答游戏的自定义服务器代码。服务器处理配对、房间、大厅等。我还在同一空间使用 Mongo 数据库,其中包含手机问答游戏的所有问题。

这是我第一次尝试这样的项目,虽然我精通 Java,但我的 mongo 技能充其量只是新手。

客户端单例

我的服务器包含 mongo 客户端的静态单例:

     public class ClientSingleton 
  {

  private static ClientSingleton uniqueInstance;
  // The MongoClient class is designed to be thread safe and shared among threads. 
  // We create only 1 instance for our given database cluster and use it across
  // our application.
  private MongoClient mongoClient;
  private MongoClientOptions options;
  private MongoCredential credential;

  private final String password = "xxxxxxxxxxxxxx";
  private final String host = "xx.xx.xx.xx";
  private final int port = 38180;

  /**
    * 
  */
  private ClientSingleton() 
{
    // Setup client credentials for DB connection (user, db name & password)
    credential =  MongoCredential.createCredential("XXXXXX", "DBName", password.toCharArray());
    options = MongoClientOptions.builder()
            .connectTimeout(25000)
            .socketTimeout(60000)
            .connectionsPerHost(100)
            .threadsAllowedToBlockForConnectionMultiplier(5)
            .build();
    try 
    {
        // Create client (server address(host,port), credential, options)
        mongoClient = new MongoClient(new ServerAddress(host, port), 
                Collections.singletonList(credential),
                options);
    } 
    catch (UnknownHostException e) 
    {
        e.printStackTrace();
    }
}

  /**
   * Double checked dispatch method to initialise our client singleton class
   * 
   */
  public static ClientSingleton getInstance()
  {
    if(uniqueInstance == null)
    {
        synchronized (ClientSingleton.class)
        {
            if(uniqueInstance == null)
            {
                uniqueInstance = new ClientSingleton();
            }
        }
    }
    return uniqueInstance;
  }

  /**
   * @return our mongo client
   */
  public MongoClient getClient() {
    return mongoClient;
  }
 }

注意事项:

Mongo 客户端对我来说是新的,我知道未能正确利用连接池是一个主要的“问题”,它极大地影响了 Mongo 数据库的性能。与数据库创建新连接也很昂贵,我应该尝试重新使用现有连接。 如果连接由于某种原因挂起,我没有离开套接字超时和默认连接超时(例如无限),我认为它会永远卡住! 我设置了在连接尝试中止之前驱动程序将等待的毫秒数,对于通过平台即服务(服务器托管的地方)建立的连接,建议设置更高的超时时间(例如 25 秒)。我还设置了驱动程序等待服务器响应所有类型请求(查询、写入、命令、身份验证等)的毫秒数。最后我将threadsAllowedToBlockForConnectionMultiplier设置为5(500)个连接,一个FIFO堆栈,等待他们打开数据库。

服务器区

Zone 从客户端获取游戏请求并接收测验类型的元数据字符串。在这种情况下,“第 3 集”。 Zone 为用户创建房间或允许用户使用该属性加入房间。

服务器机房

Room 然后为测验类型建立到 mongo 集合的 db 连接:

// Get client & collection
mongoDatabase = ClientSingleton.getInstance().getClient().getDB("DBName");
mongoColl = mongoDatabase.getCollection("GOT");

// Query mongo db with meta data string request
queryMetaTags("Episode 3");

注意事项:

在游戏之后,或者我应该说在房间空闲时间之后房间被摧毁 - 这个空闲时间当前设置为 60 分钟。我相信,如果每个主机的连接数设置为 100,那么当这个房间空闲时,它将使用宝贵的连接资源。

问题

这是管理我的客户端连接的好方法吗? 如果我有数百个同时连接的游戏,并且每个游戏都访问数据库以提取问题,那么可能按照该请求释放客户端连接以供其他房间使用?这应该怎么做?我担心这里可能存在瓶颈!

Mongo 查询仅供参考

    // Query our collection documents metaTag elements for a matching string
// @SuppressWarnings("deprecation")
public void queryMetaTags(String query)
{
    // Query to search all documents in current collection
    List<String> continentList = Arrays.asList(new String[]{query});
    DBObject matchFields = new 
       BasicDBObject("season.questions.questionEntry.metaTags", 
      new BasicDBObject("$in", continentList));
    DBObject groupFields = new BasicDBObject( "_id", "$_id").append("questions", 
       new BasicDBObject("$push","$season.questions"));
    //DBObject unwindshow = new BasicDBObject("$unwind","$show");
    DBObject unwindsea = new BasicDBObject("$unwind", "$season");
    DBObject unwindepi = new BasicDBObject("$unwind", "$season.questions");
    DBObject match = new BasicDBObject("$match", matchFields);
    DBObject group = new BasicDBObject("$group", groupFields); 
    @SuppressWarnings("deprecation")
    AggregationOutput output = 
    mongoColl.aggregate(unwindsea,unwindepi,match,group);

    String jsonString = null;
    JSONObject jsonObject = null;
    JSONArray jsonArray = null;
    ArrayList<JSONObject> ourResultsArray = new ArrayList<JSONObject>();

    // Loop for each document in our collection
    for (DBObject result : output.results()) 
    {       
        try 
        {
            // Parse our results so we can add them to an ArrayList
            jsonString = JSON.serialize(result);             
            jsonObject = new JSONObject(jsonString);
            jsonArray = jsonObject.getJSONArray("questions");

            for (int i = 0; i < jsonArray.length(); i++)
            {
                // Put each of our returned questionEntry elements into an ArrayList
                ourResultsArray.add(jsonArray.getJSONObject(i));
            }                
        } 
        catch (JSONException e1) 
        {
            e1.printStackTrace();
        }
    }   
    pullOut10Questions(ourResultsArray);
}

【问题讨论】:

    标签: mongodb java


    【解决方案1】:

    我这样做的方式是使用 Spring 创建一个 MongoClient Bean。然后你可以在任何需要的地方自动装配这个 bean。

    例如:

    MongoConfig.java

    import com.mongodb.MongoClient;
    import com.mongodb.MongoClientURI;
    import com.tescobank.insurance.telematics.data.connector.config.DatabaseProperties;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    import java.net.UnknownHostException;
    
    @Configuration
    public class MongoConfig {
    
        private @Autowired DatabaseProperties properties;
    
        @Bean
        public MongoClient fooClient() throws UnknownHostException {
            return mongo(properties.getFooDatabaseURI());
        }
    
    }
    

    需要连接MongoDB的类:

    @Component
    public class DatabaseUser {
    
        private MongoClient mongoClient;
    
        ....
    
        @Autowired
        public DatabaseUser(MongoClient mongoClient) {
             this.mongoClient = mongoClient;
        }
    }
    

    然后,Spring 将创建连接并在需要的地方进行接线。您所做的似乎非常复杂,并且可能试图通过使用诸如 Spring 之类的久经考验的框架来重新创建您将免费获得的功能。如果可以避免的话,我通常也会尽量避免使用单例。我在使用这样的 Mongodb 连接时没有遇到任何性能问题。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多