当前位置: 首页 > 知识库问答 >
问题:

Mongo db java驱动程序-客户端资源管理

裴令秋
2023-03-14

出身背景

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

这是我第一次尝试这样的项目,虽然我精通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秒)。我还设置了驱动程序等待服务器对所有类型请求(查询、写入、命令、身份验证等)的响应的毫秒数。最后,我将threadsAlloweToBlockForConnectionMultiplier设置为5(500)连接,一个FIFO堆栈,等待他们打开数据库。

服务器区

Zone从客户端获取游戏请求,并接收测验类型的元数据字符串。在本例中为“第三集”。分区为用户创建房间,或允许用户将房间与该属性合并。

服务器机房

然后,Room为测验类型建立与mongo collection的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);
}

共有1个答案

谷德本
2023-03-14

我这样做的方式是使用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连接时没有遇到过这样的性能问题。

 类似资料:
  • 我的目标是使用聚合框架创建一个管道来对我的数据进行分组,然后将这个管道与java驱动程序一起使用。MongoDB v4.0.3 我使用MongoDB Compass创建了以下管道(减少到重要部分): 这导致以下(生成的)Java代码: 集合中$组阶段之前的数据如下所示: $组阶段应返回以下数据结构: 问题所在 Mongo Compass按预期预览了阶段的结果,但使用java驱动程序的阶段的结果非常

  • 使用带有PostgreSQL JDBC驱动程序的PostgreSQL数据库,我遇到了一个有趣的挑战。似乎最新版本的驱动程序9.2在执行日期/时间匹配时使用客户端时区。 null

  • 我正在尝试使用tomcat jdbc连接池,并在我的应用程序context.xml文件中定义了它。 类<code>net.sf.log4jdbc。DriverSpy是在<code>log4jdbc4-1.2.jar Tomcat使用它的类加载驱动程序: 为null,并且正在尝试通过加载驱动程序类。据我所知,在这种情况下,驱动程序类正在加载与相同的类加载器实例。这是,如果我的jar在tomcat库中

  • 我试图了解MySQL JDBC驱动程序中的客户端仿真准备语句是如何工作的。 第1部分我在网上读到,对于准备好的语句,关系数据库处理JDBC/SQL查询时涉及四个步骤,它们如下: 分析传入的SQL查询 编译SQL查询 规划/优化数据采集路径 执行优化的查询/获取并返回数据 如果客户端仿真准备好的语句没有往返数据库,那么它如何执行步骤3?还是客户端仿真准备语句的工作方式不同? 第二部分我还做了两个实验

  • 我在MongoTemplate中使用了allowDiskUse选项: 并且仍然收到此错误: 超出$group的内存限制,但不允许外部排序。请传递allowDiskUse:true以选择加入。 是不是被窃听了? 请注意,我使用的是mongo java客户端3.11和mongo atlas M2(v4.2.9) 我还尝试了batch大小和use Couror,但它不起作用

  • 背景资料: 我有一个PHP脚本,它解析文本文件并使用它将数据插入mongo数据库。我不再使用旧的Mongo PHP驱动程序,而是使用MongoDB\driver类(http://php.net/manual/en/book.mongodb.php) 问题 有一段代码,我试图用新类重写,但我似乎无法让它工作——也就是它没有向数据库写入数据...我也不知道如何找到错误。 旧代码: 这是旧代码: 新代码