대규모 데이터베이스 성능 향상을 위한 샤딩 알고리즘

2024. 7. 14. 13:24·Computer Science

 

 

 저는 지금껏 데이터베이스 성능 향상을 위한 방법들에 대해 포스팅을 해왔는데요. 캐싱, 정규화 등의 방법도 중요하지만, 오늘은 특히 더 중요한 대규모적으로 운영하는 환경에서 데이터베이스의 데이터를 분산하고 샤딩하는 방법에 대해 이야기해보려고 합니다.

 

 

 


 

목차

 

1. 데이터베이스 샤딩(Sharding)
2. 샤딩의 종류
3. 컨시스턴트 해싱(Consistent Hashing)
4. 간단한 코드 구현
5. 분석

 

 


 

#1 데이터베이스 샤딩

 

 대규모 데이터베이스를 운영하는 경우, 단일 서버에 데이터를 모두 저장해서 사용하기에는 성능이 좋지 못하고 비효율적입니다. 심지어는 부하를 일으키고 서버에 장애를 유발할 수 있습니다. 이를 방지하기 위해 대규모적으로 운영하는 기업들은 샤딩(Sharding)을 필수적으로 사용하고 있습니다. 실제로, 게임, 금융, SNS 등 다양한 플랫폼에서 샤딩을 사용 중이에요. 샤딩에 대해서 말씀을 드리자면, 여러 개의 데이터베이스 서버를 추가하고, 각각의 서버에 데이터들을 분산시키는 방식을 의미한다고 말할 수 있습니다.

 

 

샤딩의 특징

  • 병렬 작업
  • 부하, 장애 방지
  • 유지 보수 쉬움

 

 데이터베이스 샤딩을 이용하는 경우에는 많은 장점이 존재합니다. 그중 대표적인 것이 바로 병렬 작업이 가능하다는 점입니다. 한 번에 여러 데이터베이스 서버를 접속하여 동시에 업무 처리가 가능해요. 따라서 성능이 굉장히 많이 향상됩니다.   병렬작업을 하기 때문에 부하가 최소화되고 서버에 장애를 일으키는 요소를 줄여줍니다. 혹여나 서버에 장애가 일어난 경우에는 서버가 독립적으로 분리되어 있기 때문에, 다른 데이터베이스 서버에는 영향을 일으키지 않아 유지와 보수가 편리하다는 장점이 존재합니다. 샤딩을 안쓸 이유가 없는 것 같아요!

 

 

정규화랑 차이점?

 

 정규화는 데이터베이스 서버 내에서 테이블을 분할하여 중복을 제거하고 일관성과 유연성을 목적으로 하는 과정이며, 데이터베이스 논리적 모델을 설계할 때 발생합니다!

 

 이와는 달리, 샤딩은 데이터베이스 서버를 분할하여 부하를 최소화하고 성능 향상을 목적으로 하는 과정이며, 외부에서 프로그램을 짤 때 추가하는 방식입니다!

 

 둘 다 무언가를 분할하여 성능을 향상시키는 방식이지만, 서로 다른 방식으로 작동됩니다. 따라서 동시에 정규화랑 샤딩을 처리할 수도 있습니다. :)

 

 

 

 


 

#2 샤딩의 종류

 

 정규화의 방법이 제1 정규화부터 제5 정규화가 있는 것처럼, 샤딩에도 종류가 여러 개가 존재합니다. 그중 가장 많이 쓰이는 방식은 바로 수평 기반 샤딩, 범위 기반 샤딩, 해시 기반 샤딩이에요.

 

<그림 1> 해시 샤딩과 범위 샤딩

 

  • 수평 샤딩 (Horizontal Sharding)

수평 샤딩은 데이터의 키, 즉, 테이블의 인스턴스를 기준으로 분리하는 것을 의미합니다. 예를 들어, 회원 ID가 있다면, 맨 앞 숫자가 A이냐 B이냐에 따라 분리가 될 수 있는 거예요.

 

  • 범위 샤딩 (Ranging Sharding)

범위 샤딩은 데이터 키의 범위를 기준으로 분리합니다. 수평 샤딩과는 다르게 범위가 추가되었는데요. 회원 ID가 A~C이냐, D~F이냐에 따라 분리가 될 수 있습니다.

 

  • 해시 샤딩 (Hasing Sharding)

 해시 샤딩은 데이터의 키를 해싱을 하여 그 결과를 기준으로 분리합니다. A001이라는 회원 ID를 해싱하여 A1B2C3와 같은 값이 나왔을 때, 맨 뒤의 숫자가 몇이냐에 따라 분할해요. 이 해시 샤딩은 보안을 높이기 위해서도 사용이 됩니다.

 

 

 이 외에도 테이블을 기준으로 분할하는 수직 샤딩과 리스트 기준으로 분할하는 리스트 샤딩도 존재합니다. 보안성이 필요한지, 데이터 특성에 따라서 샤딩의 종류를 적절하게 선택하여 사용해야 합니다.

 


 

#3 컨시스턴트 해싱(Consistent Hashing)

 

<그림 2> 컨시스턴트 해싱

 

 

 컨시스턴트 해싱이란 해시 샤딩을 할 때 사용되는 해싱 방법입니다. 대규모 트래픽이 발생하고, 서버를 빈번하게 추가하거나 삭제해야 할 때, 이 컨시스턴트 해싱을 사용합니다. 다른 샤딩 종류에 비해 보안성도 우수하고, 해시 함수를 사용하기 때문에 샤드가 추가되거나 삭제될 때, 재해싱을 해야 하는 상황이 발생하지 않는다는 장점이 있습니다.

 

 위의 <그림 2>는 컨시스턴트 해싱을 그림으로 표현하여 설명하자면, 원형 해시 공간으로, DB 서버 노드와 데이터를 저러한 방식으로 위치시킵니다. 따라서 원에 노드를 추가하거나 제거가 간편하기 때문에 효율적이라고 할 수 있어요.

 

 

그럼 해시함수를 사용해 샤딩할 때 가장 많이 쓰이는 다른 알고리즘은?

 

  • SHA-256 알고리즘

256 비트의 해시 값을 생성하기 때문에, 충돌 가능성이 낮고 보안성이 우수합니다.

  • MurmurHash 알고리즘

비암호화 해시 함수이기 때문에 빠르고, SHA-256 알고리즘에 비해 성능이 뛰어나지만, 보안성이 없습니다.

 

 

그렇다면 컨시스턴트 해싱을 구현한 코드에 대해 살펴보고, 어떻게 작동이 되는지 알아보겠습니다.

 

 

 


 

#4 간단한 코드 구현

 

 

파이썬으로 제작한 샤딩 코드입니다.

class DBshard:
    def __init__(self, port, host, user, password, database):
        self.cursor.execute(f"CREATE DATABASE IF NOT EXISTS {database}") # DB 만들기
        self.host = host 
        self.port = port
        self.user = user
        self.password = password
        self.database = database
        self.conn = mysql.connector.connect(
            host = self.host,
            port = self.port,
            user = self.user,
            password = self.password,
            database = self.database,
            auth_plugin ='mysql_native_password'
        )
        self.cursor = self.conn.cursor()
        self.createTB() # 테이블 만듦
        return self.conn

 

 DBshard라는 객체는 데이터베이스 서버를 만들고 연결합니다.

 

    def createTB(self):
        self.cursor.execute(
            "CREATE TABLE IF NOT EXISTS data (id VARCHAR(255) PRIMARY KEY, name TEXT)"
        ) # ID가 식별자, 이름이 칼럼인 테이블 제작

    def insert(self, id, name):
        query = "INSERT INTO data (id, name) VALUES (%s, %s)" #MySQL에서는 %s가 모든 데이터 타입을 반영
        column = (id, name)  
        self.cursor.execute(query, column) 
        self.conn.commit()

    def search(self, key):
        query = "SELECT name FROM data WHERE id = %s"
        value = (key,)  # SQL 인젝션 방어
        self.cursor.execute(query, value) 
        result = self.cursor.fetchone()  # 첫번째 행 전체 칼럼을 저장

        if result:
            return result[0] # 첫번째 행의 첫번째 칼럼을 반환. 즉, 이름 출력
        else:
            return None

 

 테이블 만들기, 삽입, 검색 함수가 DBshard 클래스 안에 들어가 있습니다. 검색 함수는 회원ID를 넣으면 이름이 출력되는 역할을 수행합니다. SQL인젝션 방어를 위해 파라미터도 처리됩니다.

 

class ConsistentHash:
    def __init__(self, nodes=None):
        self.dict = dict() # 서버 딕셔너리
        self.sorted_nodes = [] # 정렬된 해시된 서버 목록

        if nodes:
            for node in nodes:
                self.add_node(node) #객체 생성시 서버가 있으면 서버목록에 추가

    def __hash__(self, key):
        value = int(hashlib.sha256(key.encode('utf-8')).hexdigest(), 16)
        return value

 

 컨시스턴트해시 객체는 딕셔너리를 이용하여 서버노드를 저장시킵니다. sorted_nodes라는 리스트는 나중에 서버를 분산시킬 때, 데이터를 어느 서버에 저장할지 정하기 위해 사용합니다. 해시함수는 SHA-256 알고리즘을 사용합니다.

 

    def add_node(self, node):
        hashed_node = self.__hash__(node)
        self.dict[hashed_node] = node #해시값이 키이고 DB 서버 이름이 값.
        self.sorted_nodes.append(hashed_node) # 서버 목록에 넣고
        self.sorted_nodes.sort() # 정렬

    def search_node(self, node):
        if not self.dict:
            return None # 서버가 없을 때
        hashed_key = self.__hash__(node) # 해시
        index = bisect_left(self.sorted_nodes, hashed_key) # 왼쪽에서부터 해쉬된 노드의 위치 찾기(이진트리)
        if index == len(self.sorted_nodes):
            return None # 넣을 서버를 찾지 못했을 때
        return self.dict[self.sorted_nodes[index]] # 해당 서버의 이름을 반환

 

 search_node() 함수는 이진트리 방식으로 탐색을 수행하며 서버 이름이 존재하는지를 반환합니다. 서버가 없거나 넣을 서버를 찾지 못했을 때에는 서버를 새로 만들어야 합니다.

 

 이렇게 클래스를 정의하면, 튜플 개수에 따라 서버를 추가하고, 삭제하는 기능이 가능하고, 데이터를 적절하게 분리된 데이터베이스에 삽입이 가능해집니다.

 

 


 

#5 분석

 

 데이터베이스 샤딩은 대규모 서비스뿐만이 아니라, 편리성을 위해서도 사용이 될 수 있는 보편적이고 중요한 기술입니다. 그러나 샤딩에도 알고리즘에 따라 비용(cost)이 발생할 수도 있고 보안성이 낮아질 수 있으므로, 적절한 샤딩 알고리즘을 선택하는 것이 중요합니다.

 

 

 

이미지 출처

https://devopedia.org/database-sharding

https://levelup.gitconnected.com/how-consistent-hashing-can-smooth-out-data-distribution-89282074eead

'Computer Science' 카테고리의 다른 글

데이터 불균형 문제 해소를 위한 SMOTE와 SMOTEENN 샘플링 기법  (0) 2025.08.26
B+트리를 활용하여 DB 인덱싱하기  (0) 2024.07.23
데이터베이스 정규화와 성능 최적화 전략  (0) 2024.07.04
BruteForce 공격 방어를 위한 해싱 알고리즘 #2  (0) 2024.07.03
BruteForce 공격 방어를 위한 해싱 알고리즘 #1  (0) 2024.07.02
'Computer Science' 카테고리의 다른 글
  • 데이터 불균형 문제 해소를 위한 SMOTE와 SMOTEENN 샘플링 기법
  • B+트리를 활용하여 DB 인덱싱하기
  • 데이터베이스 정규화와 성능 최적화 전략
  • BruteForce 공격 방어를 위한 해싱 알고리즘 #2
Cloud9Ops
Cloud9Ops
CloudOps 지망생입니다. 스스로의 공부를 위한, 더 많은 사람들이 양질의 지식을 습득하는 공간입니다.
  • Cloud9Ops
    CloudOps Engineer
    Cloud9Ops
  • 전체
    오늘
    어제
    • 전체 (23)
      • Computer Science (16)
      • Programming (2)
      • Projects (5)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    해시 체이닝
    해시 테이블
    SQL 인젝션
    비동기적 처리
    BruteForce
    B+트리
    컨시스턴트 해싱
    성능 최적화
    해싱
    데이터베이스 인덱싱
    샤딩
    단방향 알고리즘
    정규화
    캐시
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.6
Cloud9Ops
대규모 데이터베이스 성능 향상을 위한 샤딩 알고리즘
상단으로

티스토리툴바