matsukaz's blog

Agile, node.js, ruby, AWS, cocos2d-xなどなどいろいろやってます

Java Driverのコネクションプールについて調べてみた

コネクションプールの設定について、ちょっと気になることがあったので調べてみた。



MongoDBのJava Driverで、コネクションプールのプール数に関連する設定として、以下のものがあります。

  • connectionsPerHost
    • The number of connections allowed per host (the pool size, per host)
  • threadsAllowedToBlockForConnectionMultiplier
    • multiplier for connectionsPerHost for # of threads that can block if connectionsPerHost is 10, and threadsAllowedToBlockForConnectionMultiplier is 5, then 50 threads can block more than that and an exception will be throw

connectionsPerHostのHostってどこのこと?自分自身?接続先のmongod/mongos?わからなかったので動作確認してみた。

import java.util.ArrayList;
import java.util.List;

import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.mongodb.Mongo;
import com.mongodb.MongoOptions;
import com.mongodb.ServerAddress;
import com.mongodb.WriteConcern;


public class ConnectionTest {
	
	public static void main(String[] args) throws Exception {
		
		MongoOptions options = new MongoOptions();
		options.connectionsPerHost = 3;
		options.threadsAllowedToBlockForConnectionMultiplier = 2;

		List<ServerAddress> addresses = new ArrayList<ServerAddress>();
		addresses.add(new ServerAddress("localhost", 28101));

		Mongo mongo = new Mongo(addresses, options);
		mongo.setWriteConcern(WriteConcern.SAFE);
		final DB db = mongo.getDB("hoge");
		
		for(int i = 0;i < 9;i++){
			Thread thread = new Thread(){
				public void run() {
					long count = db.getCollection("user").count();
					System.out.println(System.currentTimeMillis());
				}
			};
			thread.start();
		}
	}
}

結果は、ミリ秒が正しく表示された。9スレッドならOK。

1303230289466
1303230289470
1303230289477
1303230289476
1303230289474
1303230289473
1303230289472
1303230289488
1303230289494

次に、for文の数値を変更して10スレッド動作するように変更してみた。すると、以下のようにOut of semaphoresのエラーが表示されてしまった。

Exception in thread "Thread-3" com.mongodb.DBPortPool$SemaphoresOut: Out of semaphores to get db connection
        at com.mongodb.DBPortPool.get(DBPortPool.java:166)
        at com.mongodb.DBTCPConnector$MyPort.get(DBTCPConnector.java:325)
        at com.mongodb.DBTCPConnector.call(DBTCPConnector.java:195)
        at com.mongodb.DBApiLayer$MyCollection.__find(DBApiLayer.java:295)
        at com.mongodb.DB.command(DB.java:152)
        at com.mongodb.DBCollection.getCount(DBCollection.java:760)
        at com.mongodb.DBCollection.getCount(DBCollection.java:731)
        at com.mongodb.DBCollection.count(DBCollection.java:686)
        at ConnectionTest$1.run(ConnectionTest.java:33)
1303230406895
1303230406898
1303230406904
1303230406903
1303230406902
1303230406901
1303230406900
1303230406912
1303230406915

この状態で、接続先のmongosをもう一つ追加して実行してみた。

		addresses.add(new ServerAddress("localhost", 28101));
		addresses.add(new ServerAddress("localhost", 28102));

結果は上記と同様にOut of Semaphoresのエラーが出力された。

以上より、MongoDBのJava Driverのコネクションプールは、以下のような仕組みらしい。

  • connectionsPerHostの値だけコネクションが利用可能となる
  • connectionsPerHost × threadsAllowedToBlockForConnectionMultiplierの値だけコネクションを待ち続けることが出来る
  • connectionsPerHost + connectionsPerHost × threadsAllowedToBlockForConnectionMultiplierの値を超えるリクエストが来ると、以降のリクエストはOut of Semaphoreエラーが発生する
  • 接続先のmongod/mongosの数は無関係。connectionsPerHostは、接続先ごとのコネクションプール数ではなく、あくまでアプリケーション内のプール数。

すっきりしたー。