안녕하세요, 독학하면서 웹공부한지 1~2년되는 고등학생입니다,

그냥개발하면서 나름대로 빅데이터를 관리한 노하우가있는데, 딱히올릴때가 없어서 올립니다.

틀린점이나 보안할 부분은 지적해주시면 감사하겠습니다.




우선 상황을 가정해볼게요.

1억개의 유저정보를 관리를해야하는상황이라고 해보죠.

보통 1초에 1,000,000개의 요청을 수행한다고 가정하고, 한테이블에서 1억개의 회원정보를 저장한다면,

로그인기능을 구현한다면 수행속도가 100초가 나옵니다.


학생이라 주로 개인프로젝트를 많이 했지만, 페이스북이나, 네이버 등 관리해야하는 레코드가 수십 수백억개가 넘는다면 나름 뭔가 최적화를 해줘야할것같다는 생각에

테이블분산이라는 방법을 생각했습니다.


테이블 분산은,

개발자가 정한 임의의 레코드 수(TB_OVERCOUNT)를 넘어서면 새로운테이블을 만들고 그 테이블에 값을 저장하는 것입니다.

TABLE_name_[테이블포인터(0이상의 정수)] 이런방식을 취하고 있는데


예로들어

처음엔 TABLE_0 이라는 테이블에다가 데이터를 저장하다가,

1,000,000개의 레코드가 넘어선다면,

TABLE_1 이라는 TABLE_[기존테이블포인터(0)+1] 을한 새로운 테이블을 만들어 새로이 데이터를 축적하는 

이런식으로 말이죠.


아! 하지만 id 즉 autoincrement 는 다시 1로 초기화되는것이아니라 그대로 이어받아 증가합니다.


또 여기서 추가해야할것이,

TABLE_POINTER 이라는 테이블입니다.

TABLE_POINTER 라는 테이블은 테이블분산을 사용하고있는 테이블의 테이블포인트를 저장하는 테이블로 즉,

현재 저장해야할 테이블 포인터를 지정해주는 테이블인데. 이 테이블의 컬럼을 보자면

--------------------------

|   table_name  |   table_pointer  | 

--------------------------

이런식으로 되어있을 것입니다.


그러므로 아까 TABLE_0 에서 TABLE_1로 넘어갈때,

UPDATE `TABLE_POINTER` SET `table_pointer`=`table_pointer`+1 where `table_name`='TABLE' 이라는 쿼리도 함께 수행해주어야겠지요.










그 다음에는 실저 서버사이드에서 쓰일 약간의 함수를 살펴보겠습니다.

간단하게, 회원정보로 봐보죠.


function get_userinfo(user_id,callback){}

function get_usertablePointer(callback){}

function find_user(search_info,callback){}


매우 심플하게 설계했습니다.


우선 가장 기본적인 동작방식이니 살펴보도록하죠.

밑의 소스들은 대충 어떻게 돌아가는지만 간단히 설명하는 것이니 참조만 해주세요.


var TB_OVER_POINTER=1000000; // 한테이블에 저장될 최대 레코드수

function get_userinfo(user_id,callback){

if(typeof user_id !="number"){

callback(0); // 0 = false

return 0;

}

var pointer=parseInt(user_id/TB_OVER_POINTER); //parseInt 는 정수형 변환

get_usertablePointer(function(val){

if(pointer<0 || pointer>val){

callback(0);

return 0;

}

conn.query("select * from `USERS_"+pointer+"` where `id`='"+user_id+"' limit 1;",function(err,data){

if(err){

callback(0);

throw err;

return 0;

callback(data[0]);

});

});

}

function find_user(info,callback){

var i,infoKey=Object.keys(info),where_query="";

for(i in info){

where_query+="`"+infoKey[i]+"`='"+info[infoKey[i]]+"'";

if(i<infoKey.length){

where_query+=" and ";

}

}

get_usertablePointer(function(val){

var pass=0;

for(i=0; i<val; i++){ // 최대 백만개 씩 저장되어있는 각각의 테이블들을 비동기방식으로 동시에 검색하기 때문에 매우시간이 단축될거라고 생각한다.

conn.query("select `id` from `USERS_"+i+"' where "+where_query,function(err,rows){

if(err){

callback(0);

throw err;

return 0;

}

pass++;

if(rows[0]){

callback(rows[0]);

}

if(pass==val){

callback(undefined); // undefined==null

}

});

}

});

}