공부내용공유

MongoDB 샤딩 적용하기 (with spring) 본문

Server/MongoDB

MongoDB 샤딩 적용하기 (with spring)

forfun 2024. 6. 22. 21:47

서론


 

MongoDB는 다양한 장점이 있고 그 중 샤딩과 관련된 유용한 기능들을 제공하는 것도 큰 장점이다.

 

 

오늘은 샤딩과 관련하여 이것 저것 테스트를 하기 위해서 로컬에다가 샤딩 환경을 구성하면서 공부한 샤딩과 관련된 내용을 정리할 예정이다.

 

 

본론


 

이번 글의 목차는 

- sharding cluseter 만들기

- sharding 적용해보기

 

로 구성되어져 있다. (만약 샤딩이 정확히 뭔지 모르는다면 해당글을 참고하자.)

 

sharding cluster 만들기

 

샤딩을 위한 shard cluster는 로컬에서 docker로 간단히 만들었고

  • router 1개
  • config DB 1개 (replica set)
  • shard DB 2개 (replica set)

이렇게 구성하였다.

 

 

config 서버의 경우에는 docker로 작성할 때 --configsvr을 붙여서 작성해야 하고 레플리카 셋이니 --replSet 옵션도
붙여줘야 한다.

docker run -d --network mongo-bridge -v /var/lib/mongo_conf1:/data/db --name mongo_conf1 
mongo --replSet repl_conf --configsvr

 

 

이런식으로 3개의 컨테이너를 띄우고 mongo client로 들어가서 replicaset을 설정해주면된다.

rs.initiate( {
   _id : "repl_conf",
   members: [
      { _id: 0, host: "mongodb0.example.net:27017" },
      { _id: 1, host: "mongodb1.example.net:27017" },
      { _id: 2, host: "mongodb2.example.net:27017" }
   ]
})

출처: 공식문서

 

그 후 rs.status(), rs.conf() 등으로 구성이 잘 됐는지 확인이 가능하다.

 

 

shard db도 동일하게 각각 docker 컨테이너를 띄어주고 client로 들어가서 replication 설정을 해주면된다.

 

 

그렇게 각 서버 준비가 끝났다면 이제 어플리케이션에 연결할 mongo router 서버를 만들고서버에 접속해서 shard로 사용될 아까 생성한 replica set을 연결해주면 된다.

//replica set중 하나만 작성해주면 된다고 한다.
sh.addShard("<replica_set>/<hostname><:port>")   

//물론 여러개를 작성해도 문제는 없다.
sh.addShard("repl_shard1/mongo_shard1:27018,mongo_shard2:27018,mongo_shard3:27018")

 

그렇게 shard cluster가 잘 설정되었는지 확인하려면 sh.status()를 사용하면 된다.

 

 

스키마 샤딩 설정

이게 샤딩 클러스터를 구성하고 mongos 서버를 spring에 연결하였다.

@Document("users")
@Sharded(shardKey = { "country", "userId" }) 
public class User {

    @Id
    Long id;

    @Field("userid")
    String userId;

    String country;
}

출처 : spring docs

 

그리고 위와 비슷하게 코드를 작성하고 두근거리며 db에 insert를 하였는데 샤딩이 전혀 되지 않았다, 왤까?

Spring Data MongoDB does not auto set up sharding for collections nor indexes required for it.
The snippet below shows how to do so using the MongoDB client API.

 

 

그렇다고 한다, 위 코드의 어노테이션은 그냥 명시용이지 sharding을 해준다거나 그런 기능은 없다고 한다. 그래서 나는 mongosh 서버에서 직접 샤딩 관련 설정을 해주었다.

 

(물론 어플리케이션에서도 가능하다.)

MongoDatabase adminDB = template.getMongoDbFactory()
    .getMongoDatabase("admin");                                     

adminDB.runCommand(new Document("enableSharding", "db"));           

Document shardCmd = new Document("shardCollection", "db.users")     
    .append("key", new Document("country", 1).append("userid", 1)); 

출처: spring docs

 

 

샤딩 설정 명령어

use admin
db.runCommand({enablesharding:'dbName'});
db.runCommand({shardcollection:'dbName.collectionName', key:{id:1}});

이렇게 하면 짠 하고 될 줄 알았다, 근데 또 안됐다 ㅋㅋ 왜 안됐을까?

 

 

일단 mongo의 sharding에는 크게 hashed sharding, ranged sharding 이렇게 2가지가 있다, 이름에서 바로 어떤식으로 작동하는지 유추가 될 것이므로 설명은 생략하겠다.

 

 

아까 위의 명령어에서

db.runCommand({shardcollection:'dbName.collectionName', key:{id:1}}); //ranged
db.runCommand({shardcollection:'dbName.collectionName', key:{id:"hashed"}}); //hashed 

이렇게 값을 정해줌에 따라 샤딩 방식을 변경할 수 있다.

 

 

hashed로 했을 땐 곧바로 샤딩이 적용되었고 실제로 어플리케이션에서 넣으면 샤딩도 잘 됐다, 그런데 왜 ranged는 안될까? 이것 저것 찾아보다가 해결 방법을 찾았다.

// 중간 값 50을 기준으로 청크 분할
db.adminCommand({ split: "itemDatabase.itemCollection", middle: { shopNo: 50 } })

// 특정 샤드로 청크 이동 (예: shopNo < 50)
sh.moveChunk("itemDatabase.itemCollection", { shopNo: 50 }, "repl_shard1")

// 특정 샤드로 청크 이동 (예: shopNo >= 50)
sh.moveChunk("itemDatabase.itemCollection", { shopNo: 50 }, "repl_shard2")

 

 

위 코드에서 1번째 명령어를 통해 직접 범위를 지정해주니 정상적으로 샤딩이 되었다, 그 아래는 기존 데이터를 옮기는 명령어이다.

sh.addTagRange( "exampledb.collection",
        { state: "NY", zip: MinKey },
        { state: "NY", zip: MaxKey },
        "NY"
)

위와 같은 명령어로도 범위 지정이 가능하다.

 

잘됐는지 안됐는지는 위에 나온 명령어나 db.post.getShardDistribution() 와 같은 명령어로 확인이 가능하다.

shopNo 5이상만 저장되는 shard

 

shopNo 6이상만 저장되는 shard

 

 

이런식으로 해결은 했지만 이렇게 직접 설정을 해야만 작동이 되는걸까? 아니였다, 데이터 한 10만개 넣어주니까 샤딩이 적용되어서
데이터가 저장됨을 확인했다. (정확히 어느 크기부터 적용이 되는지는 모르겠다.. shardBanlancer 개념이 관련된 것 같은데 추후 필요하면 찾아볼 예정이다) 

 

 

결론


로컬 환경에다 간단한 설정을 하면서 찾아본 내용을 간단히 정리하였다, 더 자세한 내용이나 다른 명령어도 테스트를 하면서
정리할 예정이다.