背景
我有一个远程托管服务器,运行带有自定义服务器代码的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 db性能。创建与db的新连接也很昂贵,我应该尝试重用现有的连接。 我没有离开套接字超时并且默认情况下连接超时(例如无限)如果由于某种原因连接挂起我认为它会永远卡住! 我设置驱动程序在连接尝试中止之前将等待的毫秒数,对于通过Platform-as-a-Serivce(托管服务器)进行的连接,建议具有更高的超时(例如25秒)。我还设置了驱动程序等待服务器对所有类型的请求(查询,写入,命令,身份验证等)的响应的毫秒数。最后我将threadsAllowedToBlockForConnectionMultiplier设置为5(500)连接,一个FIFO堆栈,等待它们打开db。
服务器区域
区域从客户端获取游戏请求并接收测验类型的元数据字符串。在这种情况下"第3集"。区域为用户创建空间或允许用户与该属性一起加入房间。
服务器室
Room然后为测验类型建立与mongo集合的数据库连接:
// 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查询FYI
// 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);
}
答案 0 :(得分: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这样的试用和测试框架来重新创建免费获得的功能。如果我能避免使用Singletons,我通常会尽量避免使用Singletons。我使用像这样的Mongodb连接没有性能问题。