背景:
我有一个远程托管的服务器,正在运行Java虚拟机,并使用自定义服务器代码进行多人实时问答游戏。 该服务器处理匹配、房间、大厅等。 我还在同一空间中使用Mongo db,其中保存了移动电话问答游戏的所有问题。
这是我第一次尝试这样的项目,尽管我在Java方面很有能力,但我的mongo技能最多只能算是初学者水平。
客户单例:
我的服务器包含mongo客户端的静态单例:
我有一个远程托管的服务器,正在运行Java虚拟机,并使用自定义服务器代码进行多人实时问答游戏。 该服务器处理匹配、房间、大厅等。 我还在同一空间中使用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数据库的性能。此外,为数据库创建新连接是昂贵的,我应该尝试重用现有的连接。如果连接由于某些原因挂起,我没有将socket超时和连接超时留在默认值(例如无限制),我认为它将永远卡住!
我设置了驱动程序将在连接尝试被中止之前等待的毫秒数,对于通过平台即服务(PaaS)进行的连接(服务器托管),建议具有更高的超时时间(例如25秒)。我还设置了驱动程序将等待服务器响应所有类型请求(查询、写入、命令、身份验证等)的毫秒数。最后,我将threadsAllowedToBlockForConnectionMultiplier设置为5(500)连接入栈,按照FIFO(先进先出)原则等待其在数据库上的轮次。
服务器区域
Zone从客户端得到游戏请求,并接收包含测验类型元数据字符串:“Episode 3”。然后,Zone为用户创建房间或允许用户以该属性加入房间。
服务器房间
然后,房间建立与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);
}