mongodb jdbc 를 이용한 connection pooling을 구현하는 방법에 대하여 알아보도록 하겠습니다.

 

일단 무지 짧고 무지 쉽습니다.

 

code

package co.kr.softcast.MobilePush.db;
import java.net.UnknownHostException;
import java.util.Map;

import co.kr.softcast.MobliePush.util.PropertyUtil;

import com.mongodb.BasicDBObject;
import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.mongodb.DBCursor;
import com.mongodb.DBObject;
import com.mongodb.Mongo;
import com.mongodb.MongoOptions;
public class MongoDB {
 private static MongoDB mongoDB;
 private static Mongo m;
 private static MongoOptions options;
 private static DB db;
 public static MongoDB getInstance() throws Exception{
  if(mongoDB == null){
   options =  new MongoOptions();
   options.connectionsPerHost = 20;
   m = new Mongo( "dev.softcast.co.kr" , options );
   db = m.getDB( "test" );
   
   MongoDB mongoDB = new MongoDB();
   mongoDB.setOptions(options);
   mongoDB.setM(m);
   mongoDB.setDb(db);
  }
  return mongoDB;
 }
 public static Mongo getM() {
  return m;
 }
 public static void setM(Mongo m) {
  MongoDB.m = m;
 }
 public static MongoOptions getOptions() {
  return options;
 }
 public static void setOptions(MongoOptions options) {
  MongoDB.options = options;
 }
 public static DB getDb() {
  return db;
 }
 public static void setDb(DB db) {
  MongoDB.db = db;
 }
 
}

위 빨간 부분이 connection pool을 설정하는 부분입니다. 무지 쉽지 않습니까??

 

그럼 정말 풀링이 되는지 테스트 해보도록 하겠습니다.

step1. MongoDB 조회

일단 Eclipse로 mongoDB 조회를 하는 테스트 프로그램을 짜 돌려보았습니다.

 

 

step 2. Server 와 연결 확인

 20개 connection pool 연결

 

 

 

 TCP 연결을 유지한채 데이터만 전송

 

mongo>db.serverStatus() 명령확인

현재 커넥션 갯수확인 ( 다른연결 2개 제외하면 20개)

 

이상 MongoDB Connection Pool Test를 마치도록 하겠습니다.


출처 - http://rocksea.tistory.com/113


'DB > MongoDB' 카테고리의 다른 글

mongodb - GridFS save/read file 예제  (1) 2013.06.10
mongodb - install mongodb on centos, fedora  (0) 2013.06.04
mongodb - how to use  (0) 2013.05.21
mongodb - mongod.conf(web interface enable)  (0) 2013.05.19
mongo - 보안 및 계정 관리  (0) 2013.04.30
Posted by linuxism
,


PHP의 유용한 함수 모음

<?
///////////////////////////////////////////////////////////////////////
// 프로그램 ID : web-lib.php3
// 프로그램 설명 : WebSite Library 모음
// 작 성 자 : iHelpers
// 작 성 일 : 2001.06.22
//  


///////////////////////////////////////////////////////////////////////
// 함  수  명 : PrintMsg
// 입력 필드
//		$strMessage : 출력될 메시지
// 리  턴  값 : 없음
// 설      명 : 화면에 메시지를 출력
function PrintMsg($strMessage)
{
	?>
	<script language="javascript">
	<!--
		alert("<?echo $strMessage;?>");
	//-->
	</script>
	<?
}


///////////////////////////////////////////////////////////////////////
// 함  수  명 : PrintMsgBack
// 입력 필드
//		$strMessage : 출력될 메시지
// 리  턴  값 : 없음
// 설      명 : 화면에 메시를 출력하고 이전 페이지로 이동
function PrintMsgBack($strMessage) 
{
	?>
	<script language="javascript">
	<!--
		alert("<?echo $strMessage;?>");
		history.back();
	//-->
	</script>
	<?
}


///////////////////////////////////////////////////////////////////////
// 함  수  명 : cuttingStr
// 입력 필드
//		$str : 자를 문자열
//		$divpnt : 문자열 크기
// 리  턴  값 : $substring
// 설      명 : 문자열 길이가 길때 "..."으로 대치
function cuttingStr($str, $divpnt) { 
	$retArray = array(); 
	if ( strlen($str) <= $divpnt ) { 
		return $str; 
	} 
	for ( $i=0, $substring="", $hanStart=false; $i < $divpnt; $i++ ) { 
		$char=substr($str,$i,1); 

		if ( ord($char) > 127 ) { // toggle 
			if ( $hanStart ) $hanStart = false; 
			else $hanStart = true; 
		} 

		if ( $i >= ($divpnt -1) ) { 
			if ( ord($char) <= 127 || !$hanStart ) $substring .= $char; 
			else $substring = substr($substring,0,$i--); 
			break; 
		} 
		$substring .= $char; 
	} 
	return $substring . "...";
} 


///////////////////////////////////////////////////////////////////////
// 함  수  명 : TimeComp
// 입력 필드
//		$temptime : 날짜
// 리  턴  값 : $new
// 설      명 : 
Function TimeComp($temptime) 
{
	/* 인자 형식
	YYYY-MM-DD
	YYYY-MM-DD HH:mm:ss
	*/

	$save = GetTimeStamp($temptime);
	$now = GetTimeStamp(date("Y-m-d H:j:s"));
	$diff = (int)(($now - $save)/60/60);

	if ($diff < 35){
		$new = "TRUE";
	}
	else{
		$new = "FALSE";
	}
	return $new;
}


///////////////////////////////////////////////////////////////////////
// 함  수  명 : GetTimeStamp
// 입력 필드
//		$date : 날짜
// 리  턴  값 : $time
// 설      명 : 
function GetTimeStamp($date) 
{
	/* 인자 형식
	YYYY-MM-DD
	YYYY-MM-DD HH:mm:ss
	*/
	if (strlen($DATE) == 10) {
		$time = mktime(0,0,0,(int)substr($date,5,2),
(int)substr($date,8,2),(int)substr($date,0,4));
	} else {
		$time = mktime((int)substr($date,11,2),(int)substr($date,14,2),
(int)substr($date,17,2),(int)substr($date,5,2),(int)substr($date,8,2),
(int)substr($date,0,4));
	}
	return $time;
}


///////////////////////////////////////////////////////////////////////
// 함  수  명 : DayDiff
// 입력 필드
//		$day : 계산할 날짜
// 리  턴  값 : 날짜의 차이
// 설      명 : 입력한 날짜를 오늘과 비교하여 날짜의 차이를 계산 
function DayDiff($day)
{
	$save = GetTimeStamp($day);
	$now = GetTimeStamp(date("Y-m-d H:j:s"));
	return ($now-$save)/60/60/24;
}


///////////////////////////////////////////////////////////////////////
// 함  수  명 : CheckBrowser
// 입력 필드
//		$num : Explore value
//		$num2 : Netscape value
// 리  턴  값 : 브라우저 value
// 설      명 : 브라우저 종류 체크
function CheckBroswer($num, $num2)
{
	global $HTTP_USER_AGENT;

	if (strpos($HTTP_USER_AGENT, "MSIE")) {
		return $num;
	} else {
		return $num2;
	}
}


///////////////////////////////////////////////////////////////////////
// 함  수  명 : GoUrl
// 입력 필드
//		$strUrl : 이동할 Url
// 리  턴  값 : 없음
// 설      명 : 지정한 url로 이동
function GoUrl($strUrl)
{
	?>
	<script language="javascript">
	<!--
		varUrl = '<?echo $strUrl;?>';
		if (varUrl !="") {
			document.location.replace(varUrl);
		}
	//-->	
	</script>
	<?
}


///////////////////////////////////////////////////////////////////////
// 함  수  명 : RedirectTarget
// 입력 필드
//		$url : 이동할 Url
//		$target : 바뀔 target명
// 리  턴  값 : 없음
// 설      명 : 지정한 url & Target 으로 이동
function RedirectTarget($url,$target,$param="")
{ 
	?>
	<html>
	<body onLoad="document.form1.submit()";>
	<form action="<?echo $url;?>" target="<?echo $target;?>" name=form1 method=post>
	<input type=hidden name=name value=""><?echo $param;?>
	</form>
	</body>
	</html>
	<?
}


///////////////////////////////////////////////////////////////////////
// 함  수  명 : RedirectTarget2
// 입력 필드
//		$url : 이동할 Url
//		$target : 바뀔 target명
//		$param : 전달할 parameter
// 리  턴  값 : 없음
// 설      명 : 지정한 url & Target 으로 Parameter를 전달
function RedirectTarget2($url,$target,$param)
{ 
	?>
	<html>
	<body onLoad="document.form1.submit()";>
	<form action="<?echo $url;?>" target="<?echo $target;?>" name=form1 method=post>
	<?echo $param;?>
	</form>
	</body>
	</html>
	<?
}


///////////////////////////////////////////////////////////////////////
// 함  수  명 : CloseWindow
// 입력 필드
//		$opener : 부모창
// 리  턴  값 : 없음
// 설      명 : 창이 닫힐때 부모창을 reLoad
function CloseWindow($opener)
{ ?>
		<html>
		<head>
		<meta http-equiv="Content-Type" content="text/html; charset=euc-kr">
		<title>저장중</title>
		<SCRIPT LANGUAGE="javascript">
		<!--
		function close_win() {
			<? if ($opener == "opener") echo "opener.document.location.reload();";?>
			self.close();
		}
		//-->
		</SCRIPT>

		</head>
		<body bgcolor=white onload="close_win()">
		</body>
		</html>
	<?
}

///////////////////////////////////////////////////////////////////////
// 함  수  명 : GoBack
// 입력 필드
//		$strUrl : 지정된 url
// 리  턴  값 : 없음
// 설      명 : 지정된 Url로 돌아감
function GoBack($strUrl) 
{
	?>
	<html>
	<head></head>
	<body onLoad="document.form1.submit();">
	<form name=form1 method=post action="<?echo $strUrl;?>">
	<input type=hidden name=name value=>
	</form>
	</html>
	<?
}

///////////////////////////////////////////////////////////////////////
// 함  수  명 : CompStr
// 입력 필드
//		$buffer : 비교할 값
//		$value : 입력된 값
// 리  턴  값 : 없음
// 설      명 : 
function CompStr($buffer, $value) {
	if (strlen($buffer) <= strlen($value)) return false;
	
	if (substr($buffer, 0, strlen($value)) == $value) {
		return true;
	} else {
		return false;
	}
}

///////////////////////////////////////////////////////////////////////
// 함  수  명 : PrintDate
// 입력 필드
//		$date : 날짜
// 리  턴  값 : 없음
// 설      명 :
function PrintDate($date){
	$date = substr($date,0,10);
	return $date;
}


////////////////////////////////////////////////
// HTML 메일 보내기
function SendMail($from_name, $from_email, $to_name, $to_email, $subject, $content) {
	//$bodytext = base64_encode("<html><body><font size=2>$content</font></body></html>"); 
	$bodytext = "<html><body><font size=2>$content</font></body></html>"; 
	$mailheaders = "Return-Path: ".$from_email." 
From: $from_name <$from_email>
MIME-Version: 1.0 
X-Mailer: PHP/".phpversion()." 
Importance: normal 
Content-Type: text/html;  charset=\"ks_c_5601-1987\" 
"; 
	return mail($to_email, $subject, $bodytext, $mailheaders);
}

///////////////////////////////////////////////////////////////////////
// 함  수  명 : NumberPrint
// 입력 필드
//		$num : 숫자
// 리  턴  값 : 콤마 처리 숫자
// 설      명 : 콤마 처리 함수
function NumberPrint($num) 
{
	if( $num == ""){
		return "";
	} else {
		return number_format($num);
	}
}


?>







'Development > PHP' 카테고리의 다른 글

php - array  (0) 2013.06.19
php - foreach 문  (0) 2013.06.19
php - 기본 문법  (0) 2013.05.17
php - iphone, android detect  (0) 2013.05.16
php - syslog  (0) 2013.05.15
Posted by linuxism
,

mongodb - how to use

DB/MongoDB 2013. 5. 21. 11:06


mongoDB 어떻게 사용할 것인가?

September 15, 2011


kth 로컬플랫폼팀 김수보

이호철 님이 작성해주신 “포스퀘어가 MongoDB를 선택한 이유 : Auto-Sharding” 과 윤희 님께서 소개한 “MongoDB 초보자를 위한 보안 관련 Tips” 에 이어, “mongoDB 어떻게 사용할 것인가?” 에 대해 정리해보았습니다. 세 명의 팀원 분들이 고생해주었습니다.

1. mongoDB는 왜 만들어졌을까?

우스갯소리이지만, mongoDB는 몽고에서 만들어진게 아닙니다.
wikipedia 를 보면, 다음과 같이 설명되어 있습니다.

MongoDB (from “humongous : 거대한”) is an open source, high-performance, schema-free, document-oriented database written in the C++ programming language.[1] The database is document-oriented so it manages collections of JSON-like documents.

“대용량”을 지향하면서, “Document” 방식으로 데이터를 관리한다는 걸 알 수 있습니다.
하지만, 오픈 소스이다 보니 사용법이 까다롭습니다.

mongoDB 가 인기있는 NoSQL의 대표주자이다 보니, 아예 러시아에서는 모든 DB의 문제를 해결해주는 솔루션으로 극찬을 받고 있다고 합니다.

하지만, Sergei Tulentsev는 mySQL DB 5억 건을 mongoDB로 옮기려다가 auto-sharding에 성공하지 못하고 cluster를 해체하여 직접 호출하는 방식으로 사용하고 있다고 하는군요.

mongoDB 는 만능이 아닙니다. 그 특징을 잘 분석해서 사용하는 것이 가장 현명한 적용방법이 아닐까 생각합니다.

2. mongoDB 특징

  • No Schema :
  • no schema 가 무슨 뜻일까요? 쉽게 말하자면, schema는 RDBMS 의 relation 을 의미한다고 보면 됩니다. 즉, no schema란 foreign key 개념이 없다는 것입니다. JOIN query 사용하기 힘들다는 뜻입니다.
    mongo db는 “humongous”해지기 위해서 “Relation”을 포기하고, “Performance”와 “Scalability”를 선택했다는 뜻입니다.

    관계형 연산이 필요한 CRM, 데이터마트 구축에는 RDBMS을 사용하세요.

    “즉, code table을 참조하는 방식으로 data modeling 을 해서는 안된다는 뜻입니다.”

  • 문서기반의 데이터 구조
  • 무슨 뜻일까요? 데이터 설계를 “종이문서” 설계하듯이 설계해야 한다는 뜻입니다.

    한 장의 document에 필요한 정보를 모두 담아야 한다는 뜻입니다. one query로 모두 해결이 되게끔 collection model 설계를 해야 합니다.

  • Auto-sharding
  • 자세한 구성방식과 그림은 포스퀘어가 MongoDB를 선택한 이유 : Auto-Sharding을 참고하시면 됩니다.

    auto-sharding은 mongoDB 의 핵심기능입니다.
    이론적으로는 가상의 큰 테이블을 만들고 데이터를 집어넣는 방식이 sharding 입니다. 아무렇게나 랜덤으로 Disk에 집어넣는 거죠.
    중요한 것은 Disk Error 가 뜨면, 그 부분의 데이터 유실이 발생됩니다. 뭘 잃어버렸는지 모르는 거죠. ㅠㅠ
    꼭, 그래서 Replica set 을 구성해야 합니다. sharding 와 replication 은 1 set 으로 구성해야 한다고 보시면 됩니다.

  • Map Reduce
  • Auto-sharding, Replica, Map Reduce 는 하나의 set 입니다. 흩어진 데이터를 어떻게 모아서 읽거나 쓸 것인가에 대해 핵심적인 부분입니다. 쉽게 구성이 되고 쉽게 사용할 수 있습니다.
    다만, 생각보다 detail 하게 만질 수 없습니다.

3. 무엇이 불편한가?

  • config server 에 부하 집중
  • document에는 sharding 관련해서 file index 가 config server 에 구성된다고 써있습니다.
    config server에 병목이 발생되면, 대용량 분산 서버 구성도 말짱 헛일이 될 수 있습니다.

    Auto-sharding을 구성하면서 반드시 config server 부하 테스트를 해보시길 바랍니다.
    병목이 발생된다면, Hadoop 등으로 분산형 스토리지를 구축할 필요가 있을 것 같습니다.

  • 현실적인 Spatial query 는 “Near”, “Box”, “Center” 연산만 지원합니다.
  • Near 연산은 기준점에서 가장 가까운 것부터 출력해줍니다.
    Box 연산은 사각형 내의 poi 를 출력해줍니다.
    Center 연산은 원형의 반경내 poi 를 출력해줍니다.

    polygon 내의 poi 검색은 현재 개발자 버전만 지원한다고 하지만, Indexing 생성이 제대로 되지 않는 등의 문제가 있었습니다.

  • 저장블럭이 2G 단위로 커집니다.
  • 아직까지 조정이 불가능합니다. 큰 불편은 아니지만, 알아두어야 할 것 같습니다.
    64M, 128M, 512M,1G,2G,2G,2G…. 이렇게 블럭이 늘어납니다.

  • 단편화된 저장공간을 모으는 것이 offline mode 에서만 가능합니다.
  • 따라서, 한 개씩 disk를 offline 으로 떨구어 가면서 repair를 해야 합니다.
    불편할 것 같네요. PC환경에서 테스트 시에는 1GB에 20분 정도 걸렸다고 합니다.
    저장블럭은 2G씩 늘어나는데, 삭제가 많은 환경이면 Disk 낭비가 심할 것 같은데요.

    빈번한 delete, insert 가 반복되는 환경에는 권하고 싶지 않습니다.
    프로그래밍 할 때도 delete, insert 형식으로 데이터를 update하지 마세요.

  • 관리툴이 미흡해서 운영이 불편할 것 같네요.
  • 많은 disk 를 repair하다 보면, 많이 헷갈릴 듯.
    손토매틱(반대말 오토매틱)으로 하던지, 별도 개발을 해야 할 것 같습니다.

4. mongoDB 어떤 곳에 써야 하나?

  • 기본적으로 하나의 table(collection)이 무한정 커지는 경우
  • collection 설계하고, shard 에 태우면 됩니다. 쉽죠? 오라클은 partitioning table, archive backup, hot backup/recovery 이런거에 신경써야 하는 반면, mongo db는 disk 하나를 더 끼우고 configuration에 더해주면 끝입니다.

    어떤 경우가 하나의 table 이 무한정 커지는 경우일까요?

    “로그 데이터”에 적용하면 좋겠네요.
    파일로그를 분석 하려면 어차피 DB에 넣어야 하는데, 기가급이 넘어가도 Handling 이 쉽지 않죠.

    “회원정보 테이블”에 좋겠네요.
    물론 회원수가 일정하면 상관없겠지만, Foursquare나 Facebook 같은 글로벌 서비스의 경우는 회원수 관리하기가 만만치 않을 듯.

    “메시징 데이터 테이블”도 좋겠네요.
    하루에도 수억 건씩 쌓이니까요.

  • 쌓아놓기만 하고, 삭제가 적은 경우
  • delete가 많은 거대 데이터라면 주기적으로 repair 를 해야 하는데, 서버 환경이나 운영에 드는 손 씀씀이로 볼 때, 현실적으로 가능할까 싶습니다.

    쌓아놓기만 하고, 삭제가 적은 경우가 어떤 경우일까요?

    “오래된 음원 DB”를 만들 때는 좋겠군요.
    값싼 Disk 에 오랫동안 많이 넣어두면 보관하기 좋고, read/write 성능도 떨어지지 않을 듯.
    CDDB나 bugs 같은 곳은 좋을 듯.

    “poi” 나 “check-in” 데이터를 넣어두기 좋겠네요.
    많은 상점들이 사라졌다 생겼다 하겠지만, foursquare 와 같은 user check-in 데이터들은 거의 삭제할 이유가 없으니(데이터가 재산인 사업환경), 정말 딱 적합하다는 생각이 듭니다.

5. Simple Test

  • mongoDB upload test
  • jdbc를 이용하여 mongoDB에 원격으로 접속하고, poi 400만건에 대한 insert를 수행하였습니다.
    데이터 량 대비 insert 시간이 정비례 하고 있으니 안정적이라고 할 수 있고, mySQL 대비해서는 100배 정도 빠르니 성능은 충분하다고 보여집니다.

  • “Near” Spatial Query
  • insert된 poi를 가지고 mongoDB의 Spatial Query기능을 테스트 해보았습니다.

    Near 연산은 좌표점으로부터 가까운 poi 부터 일정개수를 리턴합니다.
    php 로 호출을 해보았는데요. 적정부하 테스트를 해보아도 안정적으로 순식간에 결과를 리턴해줍니다.
    Foursquare 가 왜 mongoDB를 사용했는지 짐작이 갔습니다.

  • “Box” Spatial Query
  • 두 개의 모서리 좌표점만 주면, Box 를 그리고 그 내부에 있는 poi를 리턴합니다.
    1600개를 리턴하는데 0.3초 걸렸으니, 발군의 실력이라고 할 수 있을 것 같습니다.

  • “Center Spatial Query”
  • 반경 내에 있는 poi를 모두 리턴합니다.
    5,600개를 리턴하는데 0.06초 걸렸으니 놀랍습니다. Oracle spatial 과 비교를 해도 훨씬 가볍다고 볼 수 있습니다.

6. 맺음말
오픈 소스형 패키지들은 불완전한 면이 많습니다.
하지만, 만들어진 취지와 목적에 맞게 사용한다면 더할 나위 없이 좋은 솔루션이 됩니다.

두려워하지 말고 적합한 프로젝트를 골라 mongoDB를 적용해봅시다.



출처 - http://dev.kthcorp.com/2011/09/15/how-to-use-mongo-db/



Posted by linuxism
,