'MongoDB'에 해당되는 글 12건

  1. 2015.11.20 :: mongodb mapreduce(2)
  2. 2015.11.20 :: mongodb mapreduce(1)
  3. 2015.11.20 :: mongodb sharding 작업 및 확인
  4. 2015.11.19 :: mongodb cluster(4)
  5. 2015.11.19 :: mongo cluster(3)
  6. 2015.11.19 :: mongo cluster(2)
  7. 2015.11.19 :: mongoDB cluster (1)
  8. 2015.11.17 :: mongdb sort, paging, plan
  9. 2015.11.17 :: mongodb crud(2)
  10. 2015.11.17 :: mongoDB crud(1)
개발관련/MongoDB 2015. 11. 20. 16:40

먼저 collections를 확인해보자. 

1
2
3
4
5
6
7
show collections
 
//result
testReduce
users
 
 
cs

show collections를 하면 결과가 나온다. 앞서 만든 mapreduce에 사용한 testReduce와 데이타를 저장한 users가 존재한다. 


그럼 system.js를 만들어보자. 앞서 만들어놓은 함수들을 어딘가 복사해놓자. 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
 
db.system.js.insert(
    [
        {
            _id: "map",
            value : function () {
             
              var key = {};
              key.eyeColor = this.eyeColor;
              key.gender = this.gender;
              
              var value = {};
              value.age = this.age;
              value.count = 1;
              emit(key, value);
            }
        },
        {
            _id: "reduce",
            value : function (key, values){
                var returnVal = {};
                var totalAge =0;
                var totalCount = 0;
                for( index in values){
                    totalAge += values[index].age;
                    totalCount += values[index].count;
                }
               
                return {"age":totalAge , "count" : totalCount};
                
            }
        },
        {
            _id : "finalize",
            value : function(key, values){
                return {
                    "age" : values.age,
                    "count" : values.count,
                    "avg" :  values.age/values.count
                };
            }
        }
    ]
);
 
 
 
cs

위 형태로 system.js 라는 collections에 저장하자. 이때 앞의 함수와 틀린점은 "_id"가 존재하며 여기에 앞서 사용한 변수명이 들어간다. value부분에 함수가 들어간다. 

여기까지 했으면 다시 collections를 확인해보자. 
1
2
3
4
5
6
 
system.indexes
system.js
testReduce
users
 
cs

system.js 라는 collections과 indexes라는넘이 추가되었다. 


이제 mapReduce를 하기전에 마지막으로 위에 값들을 load 를 해야한다. 


1
2
 
db.loadServerScripts();
cs


위에 구문을 쓰면 몽고 디비의 서버에 맵리듀스 함수가 로드 된것이다. 

그럼 map,reduce, finalize 라는 _id의 값은 어떻게 되있는지 확인하자 

map; reduce; finalize; 라는 명령으로 확인하면 다음과 같은 결과를 확인 할 수 있다. 

아래는 map; 의 함수를 보여주고있다. 

1
2
3
4
5
6
7
8
9
10
function __cf__13__f__anonymous_function() {
    var key = {};
    key.eyeColor = this.eyeColor;
    key.gender = this.gender;
    var value = {};
    value.age = this.age;
    value.count = 1;
    emit(key, value);
}
 
cs



이제 다시한번 mapreduce를 하는데 이번엔 out의 옵션을 좀 추가해보자. 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
 
db.users.mapReduce(
    map,reduce, 
    {
        
       
        out : {
            reduce : "testReduce"
            
        },
        //map들어갈 collection 필터링 할때 
        query : {
            "index" : {
                $gte : 1000
            }
        },
        //가령 추천수가 가장 많은 사람을 쓸때 오름 차순으로 하면 제일 먼저 나오는 사람이 젤위이므로 이 사람을 빨리 가져올때 사용.
        //sort : {},
        //reduce 를 한 결과를 가공을 할때 사용. 
        finalize : finalize,
        //scope는 map, reduce, finalize 함수의 전역 변수로 사용된다. 
        //사용시는 $변수명으로 사용하면된다. 
        //scope: { "temp" : 1},
        //몽고디비는 bson 타입으로 저장을한다. 이때 속도가 좀 걸리는데 json 형태로 할것인지를 선택하는 옵션이다. 
        //그러나 json의 경우 속도는 빠르나 collection document의 제한이 걸린다. 그래서 안쓰는게 상책.
        //jsMode: <boolean>,
        //verbose: <boolean>
    }
);
 
 
cs


out의 옵션에 reduce를 주고 "testReduce" collection명을 주었다. 실행하면 결과는 testReduce로 저장될 것이다. 이제 


db.testReduce.find()로 값을 확인하자. 


아까 값에 reduce 된 값이 보일것이다. 


후 여기까지..... 

posted by 제스트
:
개발관련/MongoDB 2015. 11. 20. 16:18

mapreduce는 map 과 reduce의 합성어 이다. 

map은 특정 collection의 특정 key 와 value를 map으로 하며, map의 key는 중복이 안되며, value는 list에 쌓이는 형태로 된다. 


reduce는 map의 데이터를 감소 시키는 역활을 한다. reduce를 통해 특정 값을 뽑아낸다.이를 통계치 데이터로 사용하게 된다. 


1
2
3
use dbname
 
db.users.find();
cs
먼저 데이터를 확인한다. 앞서 사용한 collections을 사용할 것이다. 


1
2
3
4
5
6
7
8
9
10
11
{
    "_id" : "564c3240e5aa2a5f7c7bd7f5",
    "index" : 0,
    "isActive" : false,
    "age" : 30,
    "eyeColor" : "green",
    "name" : "Rodgers Grant",
    "gender" : "male",
    "company" : "VERTON",
    "email" : "rodgersgrant@verton.com"
}
cs

자 map을 설계 해보자. 필자는 "각 eyeColor 별로  성별를 구분하고, 전체 나이와 인원을 구하고 싶다" 이 기준으로 먼저 map을 만들어 보자. 
1
2
3
4
5
6
7
8
9
10
11
12
13
//make map 
var map = function () {
  //맵은 단순 key value로 선언을 하며 , 이 값들은 emit을 통해 reduce로 전달을 한다. 
  //this는 현재 collection에 document가 저장된다. 
  var key = {};
  key.eyeColor = this.eyeColor;
  key.gender = this.gender;
  
  var value = {};
  value.age = this.age;
  value.count = 1;
  emit(key, value);
};
cs

어라 js랑 똑같다. 걍 js 함수다 . map이라는 함수에 key에는 eyeColor와 gender를 저장하고, value에는 age와 count를 저장한다. 여기서 눈여겨 볼 껀 this라는 넘이다. 이 this는 현재 사용하고 있는 collection을 뜻하며, 이 collection의 filed명을 쓰면 그 값들이 전달된다.  자 위에 map을 선언 하면 다음과 같은 비슷한 결과 형태로 될것이다. (머 내부적으로 어떻게 저장하는지는 몰라서 ... 추측하건데...=_=;)

1
green.male : [{ 30,1},{36,1}............]
cs

위에 작업이 끝나면 map; 를 실행해보자. 위에 코드가 나올것이다. 
여기에 보면 emit이라는 넘이 있다. 저 emit은 reduce로 값을 전달하며 map의 결과를 reduce 매개변수로 전달하게 된다. 그럼 reduce를 해보자. 

1
2
3
4
5
6
7
8
9
10
11
12
var reduce = function (key, values){
    var returnVal = {};
    var totalAge =0;
    var totalCount = 0;
    for( index in values){
        totalAge += values[index].age;
        totalCount += values[index].count;
    }
    //return type은 map의 기준의 value로 결정되므로 reduce의 return type의 value랑 똑같은 형태로 맞춰줘야한다.!!
    return {"age":totalAge , "count" : totalCount};
    
}
cs

이것도 js함수다. key, values에는 emit으로 전달한 파라미터들이 있다. values에는 배열로 값이 들어있으므로, 위에 예시 처럼 loop문을 돌려주면서 totalage와 totalcount에 전체 나이 전체 인원을 계산한다. reduce의 중요한 사실은 return 값에 있다. 이 리턴은 map에서 이미 정해야 한다. 위의 map의 value를 보자. map의 value는 age와 count이다. 이 value 형태로 return이 되야만한다. 

다시 mapreduce에 대해 정리하자. 
1. map은 key, value를 정의하며 emit으로 전달한다. 이때 value는 reduce의 return값과 동일하다. 
2. reduce는 value에 대해 값을 재정의 할수 있으며, return은 map의 value와 동일해야한다.

여기에는 한계가 있다. reduce의 return이 map의 value와 같으므로 값을 정형화 하지 못한다. 이때 쓰는 함수가 finalize이다. 


1
2
3
4
5
6
7
8
9
 
var finalize = function(key, values){
    return {
        "age" : values.age,
        "count" : values.count,
        "avg" :  values.age/values.count
    };
}
 
cs

finalize는 reduce의 마지막 나온 결과를 건네주게 된다. 여기서 마지막이란 trycatch의 finaliy 정도 생각 하면 되겠다. finalize는 결과를 마음 대로 수정해도 된다. 


자 이제 mapreduce 함수를 호출 해보자. 


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
 
db.users.mapReduce(
    map,reduce, 
    {
        //없으면 현재 db에  만든다.
        /**
        *
        out: { <action>: <collectionName>
        [, db: <dbName>]
        [, sharded: <boolean> ]
        [, nonAtomic: <boolean> ] }
        <action>
         replace - 기존의 있는 콜렉션을 없애고 mapreduce결과를 집어 넣는다.
         merge - 이미 있는 콜렉션을 넣는데 현재 키가 존재할경우 오버라이트 한다. 
         reduce - 같이 키로 결과가 있으면 그 결과들 끼리 reduce를 한다. 
         db 
         - output collection 을 쓸 db이름을 정의 default db는 mapreduce collection과 같은 db이다. 
         
         sharded 
         - 맵리듀스 결과 collection을 바로 샤딩하고 싶을때 true로 변경. 
         nonAtomic
         - mapreduce 사용시 true로 사용하면 lock이 걸리지 않는다. (상황에 따라 써야겠구만.)
        **/
        out : "testReduce",
        //map들어갈 collection 필터링 할때 
        query : {
            "index" : {
                $gte : 1000
            }
        },
        //가령 추천수가 가장 많은 사람을 쓸때 오름 차순으로 하면 제일 먼저 나오는 사람이 젤위이므로 이 사람을 빨리 가져올때 사용.
        //sort : {},
        //reduce 를 한 결과를 가공을 할때 사용. 
        finalize : finalize,
        //scope는 map, reduce, finalize 함수의 전역 변수로 사용된다. 
        //사용시는 $변수명으로 사용하면된다. 
        //scope: { "temp" : 1},
        //몽고디비는 bson 타입으로 저장을한다. 이때 속도가 좀 걸리는데 json 형태로 할것인지를 선택하는 옵션이다. 
        //그러나 json의 경우 속도는 빠르나 collection document의 제한이 걸린다. 그래서 안쓰는게 상책.
        //jsMode: <boolean>,
        //verbose: <boolean>
    }
);
 
cs


 파라미터는 총 3개다. map, reduce, 3번째는 object이다. 중요한것은 이 3번째 파라미터...

먼저 out 이라는 넘이 나온다. 단순히 값을 쓰면, 지정한 값으로 collection을 만들고 그 collection에 mapreduce 값을 쓴다. 이때 위에 주석으로 써놓았듯이 옵션에는 총 3가지가 있다. replace, merge, reduce 이 3개가 있는데 default는 replace 로 쓴다. 


query라는 넘은 mapreduce를 할 collection의 값을 특정 결과로 만들고 난 후 mapreduce로 전달한다. 위에 예제는 users collection에 index가 1000 이상인 사람들에 대해 mapreduce를 한다는 예시이다. 


finalize 는 위에 선언해놓은 finalize 함수의 변수를 쓰면 된다. 나머지 옵션은 주석으로 써놓았으니 살펴 보면된다. 


이 mapreduce는 cursor라는 곳에 저장을 한다. 이 cursor는 휘발성이므로  계속적으로 사용 할때는 위와 같이 사용 해서는 안된다. 다음에는 이를 막고자 할때 사용하는 system.js 에 대해 알아본다. 



posted by 제스트
:
개발관련/MongoDB 2015. 11. 20. 13:20

저번 글까지는  단순히 cluster 환경 구성을 하는 것이었다.. 이제 데이터를 넣어보자. 


먼저 필자는 다음과 같은 json 구조로 데이터를 10000건을 만들었다. 


1
2
3
4
5
6
7
8
9
10
11
{
    "_id" : "564c3240e5aa2a5f7c7bd7f5",
    "index" : 0,
    "isActive" : false,
    "age" : 30,
    "eyeColor" : "green",
    "name" : "Rodgers Grant",
    "gender" : "male",
    "company" : "VERTON",
    "email" : "rodgersgrant@verton.com"
}
cs


linux 커널에서 다음과 같은 명령으로 데이터를 넣는다. 

1
2
 ./bin/mongoimport -h 192.168.0.105:45005 -d dbname -c collectionName --file ${path}/users.json
 
cs



그런후... 샤드의 상태를 확인해보자. 

1
2
 
sh.status();
cs

아마도, 1개의 샤드에만 들어있을 것이다. 


분명히 2개의 샤드에 분리 되야 하는데.... =_=; 

그럼 chunk의 size를 확인한다. 


1
2
3
4
5
6
7
8
9
10
11
12
13
14
use config
db.settings.find();
 
//result
{
    "_id" : "chunksize",
    "value" : 64.0000000000000000
}
 
/* 2 */
{
    "_id" : "balancer",
    "stopped" : false
}
cs

use config  이 넘은 cluster server의 내부 db 이다. cluster만 존재하며, 설정 정보들이 들어있다. 

db.settings.fing()를 하면 위의 결과 처럼 나올 것이다. 기본 mongodb의 chunk size는 64M 인것이다. 10000건의 데이터는 3M도 안된다. =_=; 그러므로 샤딩은 당연히 안될것이다. 그럼 한번 줄여보자. 

1
db.settings.save( { _id:"chunksize", value: 1 } );
cs

다시 find로 검색해보면 1M로 바뀌어 있을 것이다. 그럼 sh.status()로 확인해보자.
여전히 샤딩은 안될 것이다. 흠.... 왜 샤딩이 안되지... 자 10000건을 다시 한번 넣어보자. 전체 data양은 20000만건... !!!! 

확인 ... sh.status();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
--- Sharding Status --- 
  sharding version: {
    "_id" : 1,
    "minCompatibleVersion" : 5,
    "currentVersion" : 6,
    "clusterId" : ObjectId("564aff51f77bed76dca6ba70")
}
  shards:
    {  "_id" : "elastic",  "host" : "elastic/192.168.0.105:45001,192.168.0.105:45002,192.168.0.105:45003" }
    {  "_id" : "shard0000",  "host" : "192.168.0.105:55001" }
  databases:
    {  "_id" : "admin",  "partitioned" : false,  "primary" : "config" }
    {  "_id" : "latis",  "partitioned" : true,  "primary" : "elastic" }
        latis.users
            shard key: { "index" : 1 }
            chunks:
                shard0000    4
                elastic    5
            { "index" : { $minKey : 1 } } -->> { "index" : 1 } on : shard0000 Timestamp(50001
            { "index" : 1 } -->> { "index" : 4369 } on : shard0000 Timestamp(30000
            { "index" : 4369 } -->> { "index" : 6554 } on : elastic Timestamp(40001
            { "index" : 6554 } -->> { "index" : 8739 } on : elastic Timestamp(10004
            { "index" : 8739 } -->> { "index" : 10923 } on : elastic Timestamp(30002
            { "index" : 10923 } -->> { "index" : 14000 } on : elastic Timestamp(30003
            { "index" : 14000 } -->> { "index" : 16184 } on : shard0000 Timestamp(40002
            { "index" : 16184 } -->> { "index" : 19000 } on : shard0000 Timestamp(40003
            { "index" : 19000 } -->> { "index" : { $maxKey : 1 } } on : elastic Timestamp(50000
    {  "_id" : "users",  "partitioned" : true,  "primary" : "elastic" }
    {  "_id" : "db",  "partitioned" : false,  "primary" : "elastic" }
    {  "_id" : "test",  "partitioned" : false,  "primary" : "elastic" }
 
 
cs


오오오오... 잘된다. 다음은 aggregation 및 mapreduce로.... 

posted by 제스트
:
개발관련/MongoDB 2015. 11. 19. 18:55

mongodb의 cluster의 최종편.... 후 힘드네.... 


mongos 이름하여 mongo cluster server 라 한다. 거두 절미 하고 셋팅 파일 부터 보자.. 

머 기존꺼랑 비슷하다. 


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#yml 파일이 존재 하지 않으면 /var/local/mongdb/data 에 data를 저장. (경로도 마찬가지로 없으면 default 경로에 저장.)
#log역시 설정 정보가  없으면 /var/local/mongdb/logs/log.log에 저장.  
#net - network 설정
#하위 구조로 bindIp와 port를 설정한다. 
#bindIP는 mongoDB 자신의 ip를 설정. 
#port는 mongDB 의 port를 설정. 
net:
 bindIp: "192.168.0.105"
 port: 45005
#processManagement - 실행 옵션. 
#fork 는 백그라운드 옵션. 
processManagement:
 fork: true
#storage - data 저장 경로를 설정. 
#dbpath - data를 저장할 실제 경로. 
#journal - data를 쓰기 전 , data write query를 파일에 저장하는 옵션. (일종의 검증, 복구를 위한 작업인듯...) 
# enabled - journal 을 쓸지 말지의 설정.
#storage:
# dbPath: /home/solrslave/src/mongodb-linux-x86_64-rhel62-3.0.4/cluster
# journal:
#   enabled: true
 
#destination: file, syslog 2가지 옵션 사용 가능
#file로 선언하면 path 옵션을 필수로 넣어서 경로를 직접 설정
#syslog로 선언하면 경로 설정 없이 디폴트 로그파일에 저장
#
#verbosity: 로그 기록 레벨
default : 0
0 ~ 5 숫자 값으로 레벨 구분
0 : all
1 : debug,
2: information
3: warning
4: errorm
5: fatal
systemLog:
 verbosity: 1
 destination: file
 logAppend: true
 path: /home/solrslave/src/mongodb-linux-x86_64-rhel62-3.0.4/cluster_logs/cluster_log.log
 
 
sharding:
  configDB: "192.168.0.105:45004"
  chunkSize: "64"
 
cs


이것도 마지막 부분만 틀리다 sharding 이라는 설정 값이 추가 됬다 . 일단 옵션은 보통 한개면 될듯 보인다. configDB라는 옵션만..... 

configDB는 앞서 설명한 config server의 아이피와 포트가 온다. 필자는 한개만 썻지만 여러개 썻다면 "xxx.xxx.xxx.xxx:12345, xxx.xxx.xxx.xxx:23456" 요렇게 하면된다. 그리고 두번째 chunkSize라는 넘이 있다. default는 64이다. mongodb의 chunk 는 데이터의 크기의 묶음(?) 정도가 되겠다. 

이 말은 위에 구성은 여러개의 shard는 대략 저 크기로 데이터를 나눈다. 64M 이하인 data는 특정 shard 한군데를 정해서 데이터를 쌓을 것이다. 


실행은 mongd가 아닌 mongos로 실행한다. 실행후 process를 확인해보자. 

1
2
3
4
 
 
500      17431     1  0 Nov19 ?        00:01:45 ./bin/mongos -f cluster.yml
 
cs


자 이제 모든 환경 셋팅은 끝났다.  근데 이상한게 보일 것이다. replicaset과 연동은????


이제 mongos 인 cluster server에 접속하자. 접속은 기존과 동일하게 ip와 port만 cluster server로 하면된다. 


1
2
3
4
5
6
7
 
 
sh.enableSharding("testDB");//없으면 만든다.
 
sh.addShard("192.168.0.105:45001");  
 
sh.status(); 
cs


접속후 sharding과 관련된 명령어인 sh 로 먼저 어떤 db를 sharding을 할지 설정한다. 


addShard 명령어로 셋팅을 한다. 재미난 점은 위 예시는 primary 로 잡혀있는 서버를 했지만 secondary로 해도 된다. 


그럼 제대로 shard를 하기 위해서 독립서버 55001을 한개 띄우고 

sh.addShard("192.168.0.105:55001");


추가한다. 마지막으로 sh.status()로 상태 정보  를 확인해보자 


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
--- Sharding Status --- 
  sharding version: {
    "_id" : 1,
    "minCompatibleVersion" : 5,
    "currentVersion" : 6,
    "clusterId" : ObjectId("564aff51f77bed76dca6ba70")
}
  shards:
    {  "_id" : "elastic",  "host" : "elastic/192.168.0.105:45001,192.168.0.105:45002,192.168.0.105:45003" }
    {  "_id" : "shard0000",  "host" : "192.168.0.105:55001" }
  databases:
    {  "_id" : "admin",  "partitioned" : false,  "primary" : "config" }
    {  "_id" : "latis",  "partitioned" : true,  "primary" : "elastic" }
        latis.users
            shard key: { "index" : 1 }
            chunks:
                shard0000    4
                elastic    5
            { "index" : { $minKey : 1 } } -->> { "index" : 1 } on : shard0000 Timestamp(50001
            { "index" : 1 } -->> { "index" : 4369 } on : shard0000 Timestamp(30000
            { "index" : 4369 } -->> { "index" : 6554 } on : elastic Timestamp(40001
            { "index" : 6554 } -->> { "index" : 8739 } on : elastic Timestamp(10004
            { "index" : 8739 } -->> { "index" : 10923 } on : elastic Timestamp(30002
            { "index" : 10923 } -->> { "index" : 14000 } on : elastic Timestamp(30003
            { "index" : 14000 } -->> { "index" : 16184 } on : shard0000 Timestamp(40002
            { "index" : 16184 } -->> { "index" : 19000 } on : shard0000 Timestamp(40003
            { "index" : 19000 } -->> { "index" : { $maxKey : 1 } } on : elastic Timestamp(50000
    {  "_id" : "users",  "partitioned" : true,  "primary" : "elastic" }
    {  "_id" : "db",  "partitioned" : false,  "primary" : "elastic" }
    {  "_id" : "test",  "partitioned" : false,  "primary" : "elastic" }
 
 
 
cs


필자는 현재 data를 넣어봐서 위와 같은 그림이 보인다. 


shards:
    {  "_id" : "elastic",  "host" : "elastic/192.168.0.105:45001,192.168.0.105:45002,192.168.0.105:45003" }
    {  "_id" : "shard0000",  "host" : "192.168.0.105:55001" }


중요한 것은 위에 shards이다. 추가한 아이피와 포트가 다 생성 되있다... 

이상으로 cluster는 완성 되었다. 


다음은 cloud의 꽃(?)이라 불리는 aggregation과 mapreduce를 ...... 

posted by 제스트
:
개발관련/MongoDB 2015. 11. 19. 18:26

앞서 보여준 그림을 보시면 오른쪽 위가 config server 되있을 것이다. 이는 shard에 대한 모든 쿼리(?) 들을 저장하며, 이를 가지고 백업 등에 사용 하게 된다.  그림의 가운데 위 mongos 라 써있는 서버 보다 먼저 셋팅 해야하는 이유는 mongos 에 config server의 설정을 써야 하므로 config server 를 먼저 셋팅 해야한다. 


설정 정보는 기존 yml 파일과 거의 비슷하다. 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#yml 파일이 존재 하지 않으면 /var/local/mongdb/data 에 data를 저장. (경로도 마찬가지로 없으면 default 경로에 저장.)
#log역시 설정 정보가  없으면 /var/local/mongdb/logs/log.log에 저장.  
#net - network 설정
#하위 구조로 bindIp와 port를 설정한다. 
#bindIP는 mongoDB 자신의 ip를 설정. 
#port는 mongDB 의 port를 설정. 
net:
 bindIp: "192.168.0.105"
 port: 45004
#processManagement - 실행 옵션. 
#fork 는 백그라운드 옵션. 
processManagement:
 fork: true
#storage - data 저장 경로를 설정. 
#dbpath - data를 저장할 실제 경로. 
#journal - data를 쓰기 전 , data write query를 파일에 저장하는 옵션. (일종의 검증, 복구를 위한 작업인듯...) 
# enabled - journal 을 쓸지 말지의 설정.
storage:
 dbPath: /home/solrslave/src/mongodb-linux-x86_64-rhel62-3.0.4/shard
 journal:
   enabled: true
 
#destination: file, syslog 2가지 옵션 사용 가능
#file로 선언하면 path 옵션을 필수로 넣어서 경로를 직접 설정
#syslog로 선언하면 경로 설정 없이 디폴트 로그파일에 저장
#
#verbosity: 로그 기록 레벨
# default : 0
# 0 ~ 5 숫자 값으로 레벨 구분
# 0 : all
# 1 : debug,
# 2: information
# 3: warning
# 4: errorm
# 5: fatal
systemLog:
 verbosity: 1
 destination: file
 logAppend: true
 path: /home/solrslave/src/mongodb-linux-x86_64-rhel62-3.0.4/shard_logs/log.log
 
 
#replication:
# replSetName: elastic
sharding:
  clusterRole: configsvr
 
 
 
cs


기존 replica set 과 다른점은 replication을 안쓰고 sharding이라는 설정이 추가 됐다. 그리고 clusterRole이라는 항목에 configsvr 이라는 configserver의 약자를 써주면 된다. 


공식 사이트에선 이 서버를 여러대 설치 하라고 권장한다. 이유는 다른 정책 서버가 장애가 났을 시 다른 서버에서 값을 가져올 수 있으므로 권장한다. 머 다른이유는 없는거 같다. 


서버는 replicaset 과 동일하게 실행하면 된다. 

실행 후 process는 다음과 같은 형태가 될 것이다. 

1
2
3
4
5
 
500      12235     1  0 Nov17 ?        00:07:42 ./bin/mongod -f startup2.yml
500      12251     1  0 Nov17 ?        00:07:05 ./bin/mongod -f startup3.yml
500      12267     1  0 Nov17 ?        00:07:03 ./bin/mongod -f startup4.yml
500      12298     1  0 Nov17 ?        00:10:28 ./bin/mongod -f shard_config.yml
cs


아래 shard_config.yml이 정책 서버가 된다. 그럼 다음에는 mongos에 대해 알아본다. 


posted by 제스트
:
개발관련/MongoDB 2015. 11. 19. 18:15

이번에는 replicaset에 대해 설정해보자. 먼저 단일 서버를 셋팅한 yml 파일을 복사후 replication name을 셋팅하면 된다. 


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#yml 파일이 존재 하지 않으면 /var/local/mongdb/data 에 data를 저장. (경로도 마찬가지로 없으면 default 경로에 저장.)
#log역시 설정 정보가  없으면 /var/local/mongdb/logs/log.log에 저장.  
#net - network 설정
#하위 구조로 bindIp와 port를 설정한다. 
#bindIP는 mongoDB 자신의 ip를 설정. 
#port는 mongDB 의 port를 설정. 
net:
 bindIp: "192.168.0.105"
 port: 45001
#processManagement - 실행 옵션. 
#fork 는 백그라운드 옵션. 
processManagement:
 fork: true
#storage - data 저장 경로를 설정. 
#dbpath - data를 저장할 실제 경로. 
#journal - data를 쓰기 전 , data write query를 파일에 저장하는 옵션. (일종의 검증, 복구를 위한 작업인듯...) 
# enabled - journal 을 쓸지 말지의 설정.
storage:
 dbPath: /home/solrslave/src/mongodb-linux-x86_64-rhel62-3.0.4/data2
 journal:
   enabled: true
 
#destination: file, syslog 2가지 옵션 사용 가능
#file로 선언하면 path 옵션을 필수로 넣어서 경로를 직접 설정
#syslog로 선언하면 경로 설정 없이 디폴트 로그파일에 저장
#
#verbosity: 로그 기록 레벨
# default : 0
# 0 ~ 5 숫자 값으로 레벨 구분
# 0 : all
# 1 : debug,
# 2: information
# 3: warning
# 4: errorm
# 5: fatal
systemLog:
 verbosity: 1
 destination: file
 logAppend: true
 path: /home/solrslave/src/mongodb-linux-x86_64-rhel62-3.0.4/logs2/repl_log1.log
 
 
replication:
 replSetName: elastic
cs


replication 이름을 추가할 replica에 동일하게 써준다. 이휴 bindIp와 port를 각 서버에 맞게 셋팅한다. 필자는 centos 환경에 3개의 서버를 먼저 띄었다. 

설치된 경로에 mongod -f 설정파일.yml 을 하면 된다. 
이후 ps -ef | grep mongod 를 하면 아래와 같은 결과를 볼수 있다.

1
2
3
500      12235     1  0 Nov17 ?        00:07:42 ./bin/mongod -f startup2.yml
500      12251     1  0 Nov17 ?        00:07:05 ./bin/mongod -f startup3.yml
500      12267     1  0 Nov17 ?        00:07:03 ./bin/mongod -f startup4.yml
cs

그럼 위에 서버들이 replicaset으로 제대로 셋팅이 되었는지 확인해보자. 

아무 몽고 서버에 먼저 접속을 한다. (robomngo tool 추천 또는 ./bin/mongo 아이피:포트 로 접속 하면된다.)


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
use dbaname //사용할 db로 이동.
show dbs //모든 db의 이름 확인
show collections //모든 collection 이름 정보 확인
 
 
 
rs.status();
/* 1 */
{
    "set" : "elastic",
    "date" : ISODate("2015-11-20T09:44:41.517Z"),
    "myState" : 1,
    "members" : [ 
        {
            "_id" : 1,
            "name" : "192.168.0.105:45001",
            "health" : 1.0000000000000000,
            "state" : 1,
            "stateStr" : "PRIMARY",
            "uptime" : 258290,
            "optime" : Timestamp(144800611422),
            "optimeDate" : ISODate("2015-11-20T07:55:14.000Z"),
            "electionTime" : Timestamp(14479202171),
            "electionDate" : ISODate("2015-11-19T08:03:37.000Z"),
            "configVersion" : 1,
            "self" : true
        }, 
        {
            "_id" : 2,
            "name" : "192.168.0.105:45002",
            "health" : 1.0000000000000000,
            "state" : 2,
            "stateStr" : "SECONDARY",
            "uptime" : 92465,
            "optime" : Timestamp(144800611422),
            "optimeDate" : ISODate("2015-11-20T07:55:14.000Z"),
            "lastHeartbeat" : ISODate("2015-11-20T09:44:40.779Z"),
            "lastHeartbeatRecv" : ISODate("2015-11-20T09:44:40.805Z"),
            "pingMs" : 0,
            "syncingTo" : "192.168.0.105:45001",
            "configVersion" : 1
        }, 
        {
            "_id" : 3,
            "name" : "192.168.0.105:45003",
            "health" : 1.0000000000000000,
            "state" : 2,
            "stateStr" : "SECONDARY",
            "uptime" : 92465,
            "optime" : Timestamp(144800611422),
            "optimeDate" : ISODate("2015-11-20T07:55:14.000Z"),
            "lastHeartbeat" : ISODate("2015-11-20T09:44:40.808Z"),
            "lastHeartbeatRecv" : ISODate("2015-11-20T09:44:40.783Z"),
            "pingMs" : 0,
            "syncingTo" : "192.168.0.105:45001",
            "configVersion" : 1
        }
    ],
    "ok" : 1.0000000000000000,
    "$gleStats" : {
        "lastOpTime" : Timestamp(00),
        "electionId" : ObjectId("564d825928cf905edab537fb")
    }
}
cs


mongodb의 replication 정보는 rs 명령어로 한다. rs.status() 함수를 하면 위 정보와 같이 나온다. 여기서  누가 primary이고 secondary인지 알 수있다. 기본적으로 모든 cloud는 대장(?)을 선출하는데 mongodb는 primary라 칭한다. 설정 정보를 보고싶으면, rs.config() 를 하면된다. 


다음은 shard config server에대해 알아보겠다. 


posted by 제스트
:
개발관련/MongoDB 2015. 11. 19. 11:27

몽고 db는 아래 그림과 같은 모양으로 구성된다. 

 


(출처는 http://mobicon.tistory.com/307 이분 블로그는 볼게 많아요.) 


설명을 하자면 아마도 클라우드 환경을 지원하는 대부분의 것들이 mongodb와 유사할 것이다. (solr와 es를 좀 틀리다... =-=;;;) 

먼저 cloud는 두가지 말들이 많이 나온다. shard(파편)와 replica(복제) 이 두말이 가장 먼저 나온다. 몽고 db의 shard는 위에 그림과 같이 몽고db의 물리적 서버를 여러개 합쳐놓은 논리적 단위이다. 그럼 전체 데이터를 봤을때 샤드라고 하는 논리적 단위는 일부 만을 가지게 되고 이들이 합쳐져서 전체 데이타를 이룬다. 


 물리적 서버는 다시 노드 또는 데이터 서버 라고 칭하며, 저 노드들간의 여러개를 replicaset 이라는 이름으로 다시 집합을 이룬다. 결론은 replicaset은 흔히 말하는 replica가 된다.  replica는 들어온 데이타들을 상호간에 복제를 하게 된다. 


그럼 mongos라는 넘을 무얼까? 이넘은 클러스터 서버라는 넘이다. 유저가 쿼리를 전송을 하면 클러스터 서버는 데이터를 저장하지 않고 일종의 queue역활을 해준다. 어느 데이터를 누구한테 전할지 이러한 역활을 한다. 오른쪽 위에 보면 config servers 라는 넘이 있는데 이넘은 모든 쿼리를 저장하며 백업등을 관리한다. 이 역시 장애가 발생할 수 있으므로 여러개를 권장한다. 




posted by 제스트
:
개발관련/MongoDB 2015. 11. 17. 11:51
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
//sort 
//asc     
db.crudtest.find(
    {
        
    }
    
).sort(
    {
        "name" : 1
    }
);      
    
//desc     
db.crudtest.find(
    {
        
    }
    
).sort(
    {
        "name" : -1
    }
);          
 
cs

sort는 sort라는 내부함수로 쓰며 1, -1로 오름 차순과 내림차순을 정한다. 


다음은 다량의 데이터를 넣는 bulk 또는 fetch 또는 batch 다. (용어는 =_=; 쓰기나름. )


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
 
db.users.insert(
    [
  {
    "_id""56497019adbf20c07138d982",
    "index"0,
    "isActive"false,
    "age"24,
    "eyeColor""blue",
    "name""Moon Robles",
    "gender""male",
    "company""MANTRIX",
    "email""moonrobles@mantrix.com"
  },
  {
    "_id""56497019be3cc168feb7b889",
    "index"1,
    "isActive"true,
    "age"32,
    "eyeColor""blue",
    "name""Annabelle Bass",
    "gender""female",
    "company""FOSSIEL",
    "email""annabellebass@fossiel.com"
  },
////////////////////생략/////////////////////////////////
{
    "_id""564970199f18e80dce7f2fed",
    "index"99,
    "isActive"false,
    "age"32,
    "eyeColor""brown",
    "name""Richardson Hansen",
    "gender""male",
    "company""AQUASURE",
    "email""richardsonhansen@aquasure.com"
  }
]
);
cs

insert문에 array형태로 넣으면 된다. 현재 robomongo tool에 의해 작업하므로 file load는 커널에서만 가능 하다. 


다음은 paging 기법.

1
2
3
/////////////////////paging//////////////////////////////
db.users.find().limit(10);
db.users.find().skip(10).limit(10);
cs

몇개의 결과를 가져올지에 대한 함수는 limit(count) 이며, 몇개를 skip할지에 대한 함수는 skip함수를 쓰면된다. 

다음은 색인 작업. 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//////////////////////index//////////////////////////////////
db.users.ensureIndex( 
  {
      "index" : 1
  }
 ); 
db.users.ensureIndex( 
  {
      "email" : 1
  }
 ); 
//compound  
db.users.ensureIndex( 
  {
      "email" : 1,
      "index" : 1
  }
 );  
cs

복합(?) 인덱스의 경우 위의 예제처럼 사용 하면 된다. 

다음은 plan 또는 explain ...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
///////////////////plan////////////////////////  
db.users.find(
  {
      "index":{
          $lte : 50
      }
  }
).explain();  
  
  
db.users.find(
  {
      $and :[
          {
          "index" : 
              { $lte :50
            }
           },
        {
            "name""Joseph Ferguson"
        },
        {
            "email" : "josephferguson@exiand.com"
        }
      ]
  }
).explain();    
cs
위 두개의 plan을 해본 쿼리 문이다. 이것의 결과는 상당히 만족 스럽게 나온다. (plan까지 지원하다니 ....) 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
/* 1 */
{
    "queryPlanner" : {
        "plannerVersion" : 1,
        "namespace" : "test2.users"//어느 db의 어느 collection 인지. 
        "indexFilterSet" : false
        "parsedQuery" : { //실행된 쿼리
            "index" : {
                "$lte" : 50.0000000000000000
            }
        },
        "winningPlan" : {
            "stage" : "FETCH",
            "inputStage" : { //index를 탔을때 쿼리가 실행되는 단계를 나타냄. 
                "stage" : "IXSCAN"//인덱스를 통해서 검색. 
                /**
                *
                COLLSCAN for a collection scan
                                IXSCAN for scanning index keys
                                FETCH for retrieving documents
                                SHARD_MERGE for merging results from shards
                */
                "keyPattern" : { 
                    "index" : 1.0000000000000000
                },
                "indexName" : "index_1",
                "isMultiKey" : false//compound 키 사용 여부. 
                "direction" : "forward",
                "indexBounds" : {
                    "index" : [ 
                        "[-inf.0, 50.0]"
                    ]
                }
            }
        },
        "rejectedPlans" : []//인텍스가 여러개일 경우 색인하지 않을 인덱스 값의 이름이 들어있다. 
    },
    "executionStats" : {
        "executionSuccess" : true,
        "nReturned" : 51,//document 개수
        "executionTimeMillis" : 0,//실행 시간
        "totalKeysExamined" : 51//검색에 사용한 index를 통해서  개수. 
        "totalDocsExamined" : 51//collection에서 검색한 개수. 
        "executionStages" : { 
            "stage" : "FETCH",
            "nReturned" : 51// return 된 document 수. 
            "executionTimeMillisEstimate" : 0,
            "works" : 52
            "advanced" : 51
            "needTime" : 0,
            "needFetch" : 0,
            "saveState" : 0,
            "restoreState" : 0,
            "isEOF" : 1,
            "invalidates" : 0,
            "docsExamined" : 51,
            "alreadyHasObj" : 0,
            "inputStage" : {
                "stage" : "IXSCAN",
                "nReturned" : 51,
                "executionTimeMillisEstimate" : 0,
                "works" : 52,
                "advanced" : 51,
                "needTime" : 0,
                "needFetch" : 0,
                "saveState" : 0,
                "restoreState" : 0,
                "isEOF" : 1,
                "invalidates" : 0,
                "keyPattern" : {
                    "index" : 1.0000000000000000
                },
                "indexName" : "index_1",
                "isMultiKey" : false,
                "direction" : "forward",
                "indexBounds" : {
                    "index" : [ 
                        "[-inf.0, 50.0]"
                    ]
                },
                "keysExamined" : 51,
                "dupsTested" : 0,
                "dupsDropped" : 0,
                "seenInvalidated" : 0,
                "matchTested" : 0
            }
        },
        "allPlansExecution" : []
    },
    "serverInfo" : {
        "host" : "localhost",
        "port" : 35001,
        "version" : "3.0.4",
        "gitVersion" : "0481c958daeb2969800511e7475dc66986fa9ed5"
    }
}
cs


위 결과는 첫번째 예제를 실행 할때 나오는 결과 인데.. 중요한 key들이 몇개 보인다. 


state 경우 값이 COLLSCAN 인경우는 index를 타지 않았을 경우 값이 찍히고, 탔을 경우 IXSCAN 요런 값이 찍히게 된다. 


또 위 두번째 예제를 실행하면 rejectedPlans 에 key에 단일 색인 키들이 들어 갈것이다. 위 주석을 보고 참고 하면 된다. 





posted by 제스트
:
개발관련/MongoDB 2015. 11. 17. 11:12
1
2
db.crudtest.find();
 
cs

특정 collections의 데이터를 전체 가져올때 find()함수로 호출한다. 



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
db.crudtest.find(
    {
        $and: [{
            "name":"hwang"
        },{
            
             "id":"wargen"
        }]
    }
 );
 
db.crudtest.find(
    {
        $or: [{
            "id":"wargen"
        },{
            
            "idx":2
        }]
    }
 )    
cs

 

and, or 검색은 위와 같이 $and, $or 의 명령어로 array 를 선언후 object 형태로 찾고자 하는 field를 선언한다. 


특정 배열의 값을 찾고자 할때는 다음과 같이 선언한다. 


1
2
3
4
5
6
7
8
9
10
11
12
13
db.crudtest.find(
    {
        "language.0""java"
    }
);
    
db.crudtest.find(
    {
        "language" : {
            $all : ["js","java"]
            }
    }
 )     
cs


$all의 경우 array의 값이 있는 것들을 전체 다 찾아준다. 


다음은 mongodb의 꽃(?)이라 할수있는 변수 저장 이다. 

1
2
3
4
5
6
7
8
9
10
11
12
var temp = db.crudtest.find(
    {
       "type": {
           $ne : null
       }
    },
    {
        "type":1
    }
 );      
temp;
 
cs
위의 예제는 type이라는 필드에 값이 널이 아니고 type 필드에 값이 있는 document를 찾는 예제이다. 그런데 저 쿼리(?)를 temp라는 변수에 저장 후 temp;를 실행하면 결과가 화면에 나올것이다. 


이때 다시한번 temp; 를 하면 값이 나오지 않을 것이다. 이를 커서라 한다. 커서에 저장된 값 리턴될 값을 저장하는것이 아니고 실행될  쿼리를 저장한다. 그러므로 변수를 호출하면 쿼리가 호출되므로 커서의 값은 사라진다.


위의 예제의 값을 저장하고 싶다면 다음과 같이 생성해야한다. 


1
2
3
4
5
6
7
8
9
10
11
12
13
 
var returnVal = function (){
    while(temp.hasNext()){
    var currentData = temp.next();
        for(var key in currentData.type){
            print(key);
        }
    }
};
 
    
    
returnVal();    
cs

js랑 똑같다. =_=; 



mongodb도 <, >, <=, >= 이런것들을 지원을 한다. 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
db.crudtest.find(
    {
        "idx" : {
            $lt : 2
        }
    }
);
    
db.crudtest.find(
    {
        "idx" : {
            $lte : 2
        }
    }
);    
    
db.crudtest.find(
    {
        "idx" : {
            $gte : 2
        }
    }
);        
 
db.crudtest.find(
    {
        "idx" : {
            $gt : 2
        }
    }
);        
cs


이상 find는 끝....

posted by 제스트
:
개발관련/MongoDB 2015. 11. 17. 10:50

1
2
3
4
5
6
7
8
9
10
11
12
13
use test
db.crudtest.insert(
    {
        "idx" : 1,
        "name" : "aaa",
        "id" : "aaa",
        "type" : {
            "test1" :"test1",
            "test2" :"test2"
        }
        
    }
);
cs


몽고 db는 내부에 js로 동작(?)하는 듯한 느낌이다. 


먼저 rdb 처럼 어떤 db를 사용할지를 선택한다.  rdb처럼 먼저 스키마를 생성하고 이런짓은 안하고 없으면 만들고 있으면 그냥 가져다 쓴다. 머 여타 nosql도 마찬가지지만. 


use test를 하면 (여기서 ; 세미콜론을 붙으면 안되더라구요 =_=;) db라는 객체에 저장이 되는듯하다. 

이후 db.(콜렉션이름).insert 후 저장할 값을 json형태로 저장하면 된다. 


콜렉션은 document 기반의 table을 뜻한다. 머 elasticsearch나 solr, lucene등 document기반이다. 


insert형식은 자유롭다. object 를 기본으로 하며, 각 키값(field) : value 여기서 value는 다시 object또는 array가 올수 있다. 


1
2
3
4
5
6
7
8
9
db.crudtest.insert(
    {
        "idx" : 3,
        "name" : "gno",
        "id" : "gno"
        
    }
)    
 
cs



다음은 update문이다. 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//update
db.crudtest.update(
    //where
    {
        "name" :"ryu"
    },
    
    {
        //set 
        $set:{"name":"gun-ho"}
        ,
        //add
        $set: {
            "language": ["java","js","angular"]
        },
        //field delete
        $unset : {
            "id" : 1
        }
    }
)
 
cs

update는 크게 두개의 object가 존재하며, 첫번째는 where절을 뜻한다. 두번째는 rdb로 보면 set의 개념을 저장한다. 
만약 필드의 값을 바꾸고 싶고 또는 추가 하고 싶다면  $set을 하면된다. 또, 특정 필드를 삭제하고 싶다면 $unset을 하면 된다. RDB와는 다르게 모든 Field(column)이 동일하지 않아도 된다. 

또, 위에 예제를 보면 language라는 필드에 array 값을 추가 하였다. 이때 값을 또 추가 싶다면 그때는 $push라는 명령어를 쓰면된다. 느낌이 jquery또는 js 내장 함수와 매우 흡사하다. 여러개의 값을 push해서 하고 싶다면 $eash라는 명령어를 사용하면 된다. 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
db.crudtest.update(
    
        {
        "name" :"gun-ho"
        },
        {
        $push : {
                "language" : "c++"
            }       
        }
    
);
    
 
db.crudtest.update(
    
        {
        "name" :"gun-ho"
        },
        {
        $push : {
                "language" : {
                    $each : ["c","python"]
                }
            }       
        }
    
);
 
cs

삭제는 다음과 같이 하면된다. 
1
2
 
db.crudtest.remove() 
cs

다음에는 find에 대해 알아보겠다. 


posted by 제스트
: