개발

검색어 추천 서비스 V4(Sharding)

개발자_티모 2024. 8. 13. 17:54
반응형

이전의 V3는 정말 모든 것을 만족했지만, 데이터가 지속적으로 확장된다면 결국 디비와 레디스의 용량은 한계에 도달하게 된다. 따라서 우리는 scalue-out 방법인 샤딩을 도입해서 이러한 문제를 방지해야 합니다.
 
검색어 추천 서비스의 경우에는 두 개의 저장소를 사용하고 있기 때문에 두 개의 저장소(Redis, Mongo)에 샤딩을 진행해야 합니다. 먼저 샤딩을 어떤 방식의 샤딩이 있는지 알아보고, 그에 맞는 적적한 샤딩 키 설계를 진행해야 합니다. 샤딩 키 설계가 잘못되면 한 서버로 데이터가 몰리게 되면서 샤딩 효과를 볼 수 없게 됩니다.
 
샤딩 방식에는 크게 모듈러 샤딩과 레인지 샤딩이 있습니다. 이제부터 각각의 장단점을 한번 살펴보겠습니다.
 
먼저 모듈러 방식은 아래 그림과 같습니다. 모듈러 방식으로 진행되기 때문에 데이터가 매우 균등하게 분산된다는 장점이 있습니다. 

 
하지만 치명적인 약점이 존제하는데 서버가 추가되거나, 삭제되면 모든 샤드키가 변경되게 됩니다. 이는 데이터의 조회 시 다른 샤드를 참조할 수 있기 때문에 서버가 추가되거나 삭제되면 샤드에 맞게 데이터를 재정렬하는 상황이 생기게 됩니다.

레인지 샤딩의 방식은 데이터를 키를 기준으로 저장소를 나누는 것입니다. 이 방식의 장점은 저장소가 추가되도 데이터의 재정렬이 발생하지 않습니다. 하지만 최악의 경우 특정 데이터베이스로만 값이 몰리게 되면서 샤딩 효과를 얻지 못한다는 단점이 생기게 됩니다. 이를 바로 Hot Spot 현상이라고 부릅니다.

 
따라서 어떤 방식의 샤딩이 나의 서비스에 알맞을까를 고민한 결과 레인지 샤딩의 방식을 채택하기로 결정했습니다. 그 이유를 알기 위해선 다음과 같은 결정 배경지식이 필요하게 됩니다.
 
샤딩을 진행하는 이유는 하나의 몽고디비 저장소가 가득 찼기 때문에 scale-out을 진행하는 것입니다. 하나의 프리티어 EC2를 기준으로 하여 몽고 디비만 올라가게 되면 저장할 수 있는 용량은 20~25G가 됩니다. 우리의 한 칼럼의 용량이 600Byte임으로 44,739,242건의 데이터를 저장할 수 있게 됩니다.
 
따라서 이정도의 표본이면 몽고 디비의 쿼리 질의를 통해서 레인지 샤딩을 구성하면 충분히 Hot Spot효과를 예방할 수 있다고 판단했습니다. 또한 Trie를 저장하는 것이기 때문에 A로 시작하는 데이터는 항상 DB1에 있어야 합니다. AB로 질의가 들어왔을 때 DB2로 가게 되면 사용자에게는 잘못된 결과 값을 돌려주게 됩니다. 따라서 저는 레인지 샤딩을 구성하게 됐습니다. 
 
몽고 디비에서는 다음과 같은 명령어를 통해서 키워드들의 빈도수를 추출할 수 있습니다. 저는 트라이 구조를 지키기 위해서 keyword의 첫 문자만 추출하는 형식으로 진행했습니다.

더보기
db.Trie.aggregate([
    {
        $project: {
            firstChar: { $substr: ["$keyword", 0, 1] }
        }
    },
    {
        $group: {
            _id: "$firstChar",
            count: { $sum: 1 }
        }
    },
    {
        $sort: { count: -1 }
    }
])

 

이후 결과를 확인해 보면 아래와 같이 추출된 빈도수를 확인할 수 있게 됩니다. 따라서 이를 기반으로 레인지 샤딩을 구성하면 됩니다. 따라서 아래의 그림처럼 샤딩이 나뉘게 됩니다.

 
몽고에서는 샤딩된 클러스터 아키텍처를 제공하지만, 이는 샤딩키 설계를 하지 못했을 때 사용하면 좋은 것으로 판단됩니다. 따라서 저는 직접 몽고 서버를 여러 개 가동하여 분산시키는 방식으로 결정하게 됐습니다. 레디스를 나중에 설명한 이유는 레디스의 샤딩도 몽고의 샤딩과 다르지 않습니다. 따라서 레디스 역시 똑같이 적용해면 됩니다

레디스 샤딩 후

 

참고로 특정 문자가 너무 많아질 경우에는 2단계 깊이의 샤딩이 필요하게 됩니다. 하지만 2단계 샤딩 방법도 이미 적용한 샤딩 방법과 다르지 않음으로 넘어가겠습니다.

 

프로젝트의 막이 내렸는데 이렇게 함으로써 우리는 적절한 응답속도인 100ms를 지킬 수 있었습니다. 또한 DAU기준으로 매일매일 약 36.53MB의 데이터가 추가되는 것도 문제없이 해결했습니다.

반응형