Skip to content

5장 시스템 구성 요소의 설계 및 구현: 데이베이스와 스토리지 #1582

Description

@jongfeel

5장 시스템 구성 요소의 설계 및 구현: 데이터베이스와 스토리지

5.1 데이터베이스

필요한 이유

  • 데이터 구성
  • 데이터 검색
  • 데이터 무결성
  • 데이터 보안
  • 데이터 일관성
  • 확장성
  • 다중화, 백업 및 복구
  • 복잡한 쿼리
  • 데이터 관계
  • 데이터 이력
  • 데이터 분석
  • 데이터 공유

5.1.1 데이터베이스 유형

데이터베이스는 크게 관계형 데이터베이스와 NoSQL(비관계형) 데이터베이스로 분류할 수 있습니다.

5.1.2 관계형 데이터베이스

관계형 모델 원칙을 기반으로 한 이 모델은 1970년대 에드거 F. 커드(Edgar F. Codd)가 만들었습니다.

관계형 모델은 데이터 요소 간 관계를 정의하여 효율적으로 데이터 저장과 검색을 가능하게 합니다.

관계형 데이터베이스의 주요 특성과 개념은 다음과 같습니다.

  • 테이블(tables)
  • 행(rows)
  • 열(columns)
  • 키(keys)
  • 정규화(normalization)
  • SQL
  • ACID 특성
  • 트랜잭션

관계형 데이터베이스는 금융 시스템, 재고 관리, 고객 관계 관리(Customer Relationship Management, CRM) 등 데이터의 일관성, 구조, 신뢰성이 중요한 다양한 애플리케이션과 산업 분야에서 주로 사용합니다.

5.1.3 비관계형 데이터베이스

NoSQL 데이터베이스라고 하는 이 시스템은 일반적인 관계형 데이터베이스 모델에서 벗어난 데이터베이스 관리 시스템입니다.
비관계형 데이터베이스는 데이터 저장과 검색에서 더 유연한 방식을 사용하며, 비정형 또는 반정형 데이터를 처리하도록 설계되어 다양한 애플리케이션과 용도에 적합합니다.

비관계형 데이터베이스의 특징

  • 키-값 저장소: 레디스, 아마존 DynamoDB, Riak
  • 문서 지향 데이터베이스: MongoDB, CouchDB, RavenDB
  • 컬럼 패밀리 데이터베이스: 아파치 카산드라, HBase, ScyllaDB
  • 그래프 기반 데이터베이스: Neo4j, 아마존 Neptune, OrientDB

5.1.4 관계형 데이터베이스와 비관계형 데이터베이스의 장단점

관계형 데이터베이스 장점

  • 데이터 중복 처리
  • 강력한 보안 기능
  • ACID 트랜잭션

관계형 데이터베이스의 단점

  • 성능
  • 메모리 소모량
  • 복잡성
  • 수평적 확장의 어려움

비관계형 데이터베이스 장점

  • 유연한 데이터 모델
  • 스키마 업데이트
  • 수평적 확장

비관계형 데이터베이스 단점

  • 아직은 부족한 표준화
  • ACID 트랜잭션 미지원

5.2 키-값 저장소

5.2.1 키-값 저장소란

키-값 저장소 또는 키-값 데이터베이스는 각 고유한 키가 특정 값과 연결되는 간단한 데이터 저장 방식입니다.
대규모 분산 딕셔너리나 분산 해시 테이블(Distributed Hash Table, DHT)을 떠올리면 이해하기 쉬운데요.
키를 사용하여 데이터를 저장·검색·업데이트할 수 있습니다.
이 키-값 쌍이 기본적인 데이터 저장 단위를 이루며, 이런 단순한 구조 덕분에 읽기와 쓰기 작업의 효율성이 높습니다.

5.2.2 분산

  • 확장성
  • 성능
  • 유연성
  • 장애 허용성

5.2.3 키-값 저장소 설계

기능적 요구 사항

  • Put(key, value)
  • Get(key)
  • Delete(key)

비기능적 요구 사항

  • 확장성
  • 성능
  • 내구성
  • 일관성
  • 가용성
  • 파티션 허용성

5.3 확장성과 데이터 복제의 최적화

5.3.1 확장성 강화

키-값 데이터를 여러 저장 노드에 나누어 저장하며, 수요에 따라 저장 노드를 추가하거나 줄여야 할 때가 있습니다.
이를 위해 데이터와 부하를 시스템 내 모든 노드에 균형 있게 분배할 수 있어야 합니다.

5.3.2 일관된 해싱 사용

일관된 해싱은 노드 집합에 부하를 효과적으로 분산하는 방식입니다.
이 방식에서는 0부터 n-1까지 해시 값을 가진 가상의 해시 링을 사용하며, 여기에서 n은 가능한 전체 해시 값의 수를 의미합니다.
각 노드의 ID를 해싱하여 링의 특정 위치에 배치합니다.
요청이 들어오면 그 키의 해시 값을 구해서 링 위의 위치에 매핑하고, 그 지점에서 시계 방향으로 가장 가까운 노드가 요청을 처리합니다.

image

Figure 5.2: Consistent hashing of key-value pairs in requests

새로운 노드를 링에 추가해도 바로 다음 노드만 영향을 받아 이 노드는 새로 추가된 노드와 데이터를 공유합니다.
다른 노드들은 영향을 받지 않습니다. 이 방식 덕분에 노드 간 변경을 최소화하면서 쉽게 확장할 수 있고, 전체 키 중 일부만 이동하면 됩니다.
해시 값이 무작위로 분포되므로 요청 부하도 평균적으로 링 전체에 고르게 퍼집니다.

분산 시스템 내에서 서버가 대용량 데이터를 처리하면 해당 서버가 병목 지점이 되어 전체 시스템 성능을 저하시킬 수 있습니다.
이런 현상을 핫스팟이라고 합니다.

5.3.3 가상 노드 사용

노드 간 부하를 보다 고르게 분산하고자 가상 노드를 사용할 수 있습니다.
단일 해시 함수를 적용하는 대신 동일한 키에 여러 해시 함수를 적용하는 방식입니다.

가상 노드 장점

  • 노드에 장애가 발생하거나 서비스 점검을 진행하더라도 작업 부하가 다른 노드에 고르게 분산됩니다. 새로운 노드를 추가하거나 가용하지 않았던 노드가 다시 사용 가능한 상태로 돌아오면 비슷한 수준으로 다른 노드로도 부하가 분산됩니다.
  • 각 노드는 물리적 장비의 성능 차이를 고려하여 담당할 가상 노드 개수를 조정할 수 있습니다.

5.3.4 데이터 복제 전략

주종 모델

이 모델에서는 하나의 저장소를 주 저장소로 설정하고 나머지는 종 저장소 역할을 하도록 구성합니다.
주 저장소는 쓰기 요청을 처리하며, 종 저장소는 주 저장소의 데이터를 복제하고 읽기 요청을 담당합니다.
그러나 쓰기 작업 이후에 복제가 되므로 복제 지연이 발생할 수 있습니다.
또 주 저장소에 장애가 발생하면 시스템의 쓰기 기능이 중단되어 단일 장애점(Single POint of Failure, SPOF) 문제가 생길 수 있습니다.

image

Figure 5.3: A primary-secondary data replication model

동등 모델

동등 모델에서는 모든 저장소가 주 저장소로 설정됩니다.
각 저장소는 읽기와 쓰기 요청을 모두 처리할 수 있으며, 서로 데이터를 복제하여 최신 상태를 유지합니다.
그러나 모든 노드에 데이터를 복제하는 것은 비효율적이고 비용이 많이 듭니다.
이를 해결하려고 보통 노드를 세 개 내지 다섯 개만 선택해서 데이터를 복제하는 방법을 사용합니다.

image

Figure 5.4: A peer-to-peer data replication model

데이터 복제 방식으로 동등 모델을 사용하길 추천합니다.
지연 시간과 가용성 측면에서 유리하기 때문입니다.
주종 모델에서는 주 저장소에 장애가 발생하면 단일 장애점 문제가 생길 수 있지만, 동등 모델을 사용하면 이를 완전히 방지할 수 있습니다.
동등 모델은 여러 호스트(host)에 데이터를 분산하여 저장함으로써 내구성과 높은 가용성을 확보하는 데 효과적입니다.

5.4 get 및 put 함수 구현

5.4.1 get 및 put 함수 구현

시스템에서는 모든 노드가 get(읽기) 및 put(쓰기) 연산을 수행할 수 있습니다.
이런 연산을 담당하는 노드를 코디네이터라고 합니다.
이는 보통 우선 목록에서 상위 n개의 노드 중 첫 번째에 해당합니다.

클라이언트는 두 가지 방식으로 노드를 선택할 수 있습니다.

  • 요청을 일반 로드 밸런서로 라우팅하는 방식
  • 분할 인식 클라이언트 라이브러리5를 사용하여 요청을 해당 코디네이터 노드로 직접 전달하는 방식

첫 번째 방식은 클라이언트가 코드에 종속되지 않도록 하며,
두 번째 방식은 클라이언트가 특정 서버에 직접 접근할 수 있어 홉 수가 줄어들어 지연 시간을 낮출 수 있습니다.

5.4.2 r과 w 사용

r은 읽기 작업이 성공하는 데 필요한 최소 노드 개수를 의미하며,
w는 쓰기 작업이 성공하는 데 필요한 최소 노드 개수를 나타냅니다.
예를 들어 r = 2고 데이터가 노드 세 개에 저장되어 있다면, 시스템은 노드 두 개에서 데이터를 읽어 옵니다.
r과 w의 값을 설정할 때는 읽기와 쓰기 작업이 최소 하나의 노드에서 공통으로 교차되도록 해야 합니다.
이것으로 읽기 작업이 항상 최신 쓰기 데이터를 접근할 수 있게 보장할 수 있습니다.
이를 위해서는 r + w > n이라는 조건을 만족해야 합니다.

n r w Description
3 2 1 Violates constraint – r + w > n
3 2 2 Fulfills constraint
3 3 1 Slow reads and fast writes
3 1 3 Slow writes and fast reads

Table 5.1: The impact of selecting different numbers of read and write successful requests on our system

클라이언트에서 들어오는 읽기 요청이 성공하려면 더 많은 노드가 요청에 응답하도록 설계해야 합니다.
이런 설계 때문에 읽기와 쓰기 요청에서 속도가 느려집니다.

읽기와 쓰기 성능을 저해하지 않으면서도 임의의 노드 장애를 견딜 수 있을 만큼 충분한 중복성을 확보하려면 읽기와 쓰기의 균형을 맞춘 쿼럼 설정이 필요합니다.

5.5 키-값 저장소의 장애 허용성과 장애 식별

5.5.1 일시적 장애 관리

분산 시스템에서 장애를 처리하는 일반적인 방법 중 하나는 쿼럼 기반 시스템을 사용하는 것입니다.
쿼럼은 분산 트랜잭션이 작업을 수행하는 데 필요한 최소 투표수를 의미합니다.

처음에는 쓰기 요청이 노드 A로 전달되지만, 노드 A가 일시적으로 접근할 수 없는 상태가 되면 요청이 노드 D로 넘어갑니다.
노드 D는 요청을 처리하는 동시에 이 요청이 원래 노드 A로 가야 했던 정보임을 함께 저장합니다.
이후 노드 A가 복구되면 노드 D는 노드 A를 대신해서 처리했던 모든 요청을 노드 A로 전달하고, 임시로 저장했던 데이터를 삭제하여 내부 저장소를 초기 상태로 정리합니다.
이것은 힌트 전달 방식(hinted handoff)이라고도 하며, 일시적인 노드 장애가 발생하더라도 읽기와 쓰기 작업을 문제없이 처리하도록 합니다.

image

Figure 5.5: A hinted handoff

5.5.2 영구적 장애 관리

노드에 영구적인 장애가 발생했을 때 시스템 내구성을 강화하려면 레플리카를 동기화 상태로 유지하는 것이 중요합니다.
핵심 목표는 레플리카 간의 불일치를 빠르게 감지하고 데이터 전송을 최소화하는 것입니다.
머클 트리(merkle tree)를 사용하면 이 문제를 해결할 수 있습니다.

머클 트리는 각 키-값 쌍을 해싱하여 트리의 리프 노드(leaf node)로 사용합니다.
트리의 상위 부모 노드는 자식 노드의 해시 값을 저장하여 데이터 간 관계를 나타내는 계층적 구조를 만듭니다.
머클 트리의 특징은 각 가지(branch)를 개별적으로 확인할 수 있어 전체 트리나 데이터셋을 모두 비교하지 않고도 데이터 불일치를 효과적으로 검증할 수 있다는 점입니다.
이 방식은 레플리카 간 데이터 불일치를 확인할 때 전송해야 하는 데이터양을 크게 줄여 줍니다.

머클 트리의 장점은 전체 트리나 데이터셋을 불러오지 않고도 각 가지를 개별적으로 검증할 수 있다는 점입니다.
동기화 과정에서 교환해야 할 데이터양은 줄어들고 안티 엔트로피 과정에서 필요한 저장소 접근 횟수도 감소합니다.

하지만 시스템에 새로운 노드를 추가하거나 기존 노드를 삭제하면 각 노드가 담당하는 키 범위가 바뀌면서 여러 키 범위에 영향을 주는데, 이에 따라 트리 해시를 다시 계산해야 하는 것은 단점입니다.

5.5.3 해시 링의 노드 구성과 장애 감지

대부분의 장애는 일시적이며 영구적인 문제가 아닌 경우가 많습니다.
따라서 해시 링에서 노드를 추가하거나 제거하는 작업은 신중히 결정해야 합니다.

노드를 추가하거나 삭제하면 해시 링에서 데이터를 관리하는 노드 구성이 달라집니다.
이런 변경 사항은 각 노드에 저장되고, 가십 프로토콜을 통해 다른 노드와 동기화됩니다.
이 프로토콜은 시스템 구성 정보를 모든 노드가 결국 같은 상태로 공유할 수 있도록 합니다.
두 노드가 무작위로 서로를 선택해서 통신하면 각자 저장하고 있는 구성 정보를 비교하고 필요한 부분을 동기화하여 일치시킵니다.
이렇게 하면 모든 노드가 같은 정보를 가집니다.

5.6 시스템 설계 인터뷰: 키-값 저장소 설계 관련 질문과 전략

  • 문제를 명확히 정의할 것
  • 확장성과 성능에 중점을 둘 것
  • 레플리카와 일관성을 설명할 것
  • 장애 발생 가능성을 염두에 둘 것
  • 시스템의 발전 가능성을 고려할 것

5.7 DynamoDB

DynamoDB는 AWS(Amazon Web Services)에서 제공하는 완전 관리형, 서버리스 비관계형 데이터베이스 서비스입니다.
DynamoDB는 SSD 스토리지를 사용하며, 지리적으로 분리된 데이터 센터 세 곳에서 데이터를 분산 저장하는 키-값 및 문서형 데이터베이스입니다.
여러 독립적인 데이터 센터에 데이터를 복제하여 높은 가용성을 유지할 수 있습니다.

5.7.1 고정된 스키마가 없다

DynamoDB는 고정된 스키마를 사용하지 않도록 설계했습니다.
덕분에 애플리케이션의 여러 요구 사항을 유연하게 처리할 수 있습니다.

비관계형 데이터베이스의 장점

  • 유연성: 비관계형 데이터베이스는 비정형 데이터나 반정형 데이터를 저장할 수 있어 RDBMS에서 여러 테이블로 나누어 관리하던 데이터를 하나의 문서로 통합할 수 있습니다.
  • 확장성: 비관계형 데이터베이스는 데이터를 테이블이 아닌 문서 형식으로 저장하기 때문에 데이터 확장이 비교적 간단합니다.
  • 성능
  • 가용성: 비관계형 데이터베이스는 노드를 교체할 때도 서비스에 영향을 최소화하며, 데이터 파티셔닝을 쉽게 구성할 수 있어 높은 가용성을 유지합니다.

5.7.2 DynamoDB API 함수

  • PutItem
  • UpdateItem
  • DeleteItem
  • GetItem

5.7.3 DynamoDB의 데이터 분할

DynamoDB는 스키마 없이 동작하며 방대한 양의 행(row)을 처리해야 하기에 수평적 분할이 더 적합합니다.
각 테이블은 작은 데이터 단위로 쪼개지고, 이 데이터는 SSD 스토리지에 저장해서 빠르게 처리됩니다.

image

Figure 5.6: Vertical and horizontal data partitioning in DynamoDB

기본 키 유형

  • 분할 키: 단일 속성을 이용하여 항목을 고유하게 식별합니다.
  • 분할 키에 정렬 키를 결합한 복합 키: 두 속성을 결합하여 항목을 고유하게 식별합니다. 이 방식은 동일한 분할 키를 가진 여러 항목을 정렬 키를 기준으로 구분할 수 있습니다.

다음 그림에서는 분할 키에 해시를 적용한 후 정렬 키와 함께 데이터가 저장될 서버 위치를 결정합니다.

image

Figure 5.7: Partition keys, sort keys, and composite keys in DynamoDB

보조 인덱스

DynamoDB는 기본 키 외에도 다른 쿼리 키를 사용할 수 있어 쿼리를 더 유연하게 실행할 수 있습니다.

5.7.4 DynamoDB에서 처리율 최적화

처리율 할당

DynamoDB에서는 테이블에 사용할 읽기 처리 용량(RCUs)과 쓰기 처리 용량(WCUs)의 상한선을 설정할 수 있습니다.

버스팅: 단기 오퍼 프로비저닝

실제 환경에서는 특정 키에 요청이 몰리면서 파티션 간 요청 분포가 고르지 않을 때가 자주 발생합니다.
버스팅은 이런 순간적인 트래픽 증가를 처리하려고 다른 파티션에서 남아 있는 여유 처리 용량을 잠시 활용하는 전략입니다.

image

Figure 5.8: Comparing the reads/sec served without bursting and with bursting support in DynamoDB

토큰 버킷 시스템

토큰 버킷 시스템은 노드에서 데이터 처리 속도를 조절하고 일시적으로 처리량을 높이는 데 사용합니다.
이 시스템은 버킷을 두 개 활용합니다.
하나는 기본적으로 처리할 수 있는 데이터양을 관리하는 ‘기본 처리량 버킷’이고, 다른 하나는 추가적으로 데이터를 처리할 수 있는 여유분을 관리하는 ‘버스트 처리량 버킷’입니다.

적응형 용량 관리: 장기적 관점의 방향

버스팅이 단기적으로 급증하는 요청에 대응하는 방식이라면, 적응형 용량 관리(adaptive capacity)는 장기적인 사용 패턴에 따라 처리량을 변경하는 방식입니다.

적응형 용량 관리가 동작하는 방식

DynamoDB는 내부적으로 알고리즘을 활용하여 시간에 따라 데이터를 읽거나 쓰는 패턴을 분석합니다.
이렇게 해서 자주 접근하는 핫 파티션(hot partitions)과 덜 접근하는 콜드 파티션(cold partitions)을 찾아냅니다.
이후 시스템 내에서 읽기 처리 단위와 쓰기 처리 단위를 효율적으로 나누어 읽기와 쓰기 작업을 더 균형 있게 처리합니다.
그러면 과도한 작업이 몰리는 파티션에서 처리량 제한(throttling)이 발생할 가능성은 줄어듭니다.

글로벌 접근 제어: 파티션 간 관리

글로벌 접근 제어는 모든 파티션의 처리량을 효율적으로 관리하는 기법입니다.

사용량에 맞춘 분할: 선제적 파티션 관리

작업 부하가 크게 변한다고 예상했다면 이를 대비해서 파티션을 미리 나누거나 합치는 방식을 고려할 수 있습니다.
이를 사용량에 맞춘 분할(splitting for consumption)이라고 합니다.

5.7.5 DynamoDB의 높은 가용성

쓰기 가용성

DynamoDB의 아키텍처는 테이블을 여러 파티션으로 나누고, 각 파티션을 복제하는 구조로 설계했습니다.
동일한 파티션의 레플리카는 복제 그룹(replication group)이라고 하며, 이 그룹 내에서 리더 레플리카는 멀티-팩소스를 기반으로 선출됩니다.
리더 레플리카는 쓰기 요청을 처리하며, 요청을 우선 WAL(Write-Ahead Log)(쓰기 전 로그)에 기록하고 메모리에 색인화합니다.
이후 리더 레플리카는 해당 로그와 색인 데이터를 복제 그룹 내 다른 레플리카로 전파합니다.

읽기 가용성

DynamoDB의 읽기 가능 여부는 읽기 요청을 할 때 최신 데이터를 반환할 수 있는지에 따라 결정됩니다.
DynamoDB의 복제 시스템은 데이터를 여러 레플리카에 분산하여 저장하지만, 모든 레플리카가 최신 데이터를 동시에 반영하지는 않기 때문에 기본적으로 최종 일관성을 따릅니다.

DynamoDB에서 리더 레플리카의 안정성은 시스템 전체의 신뢰성과 성능에 중요한 영향을 미칩니다.
리더에 장애가 발생하면 이전 리더의 임기가 만료될 때까지 새로운 리더를 선출할 수 없습니다.
이런 상황에서는 레플리카 간 통신 프로토콜을 설정하여 리더 레플리카의 상태를 먼저 확인한 후 리더 선출을 진행하는 방식이 해결책이 될 수 있습니다.

5.8 컬럼 패밀리 데이터베이스

컬럼 패밀리 데이터베이스는 대규모 데이터를 처리하도록 설계된 비관계형 데이터베이스의 한 유형으로, 높은 성능과 확장성을 제공합니다.

컬럼 패밀리 데이터베이스는 다음 특징이 있습니다.

  • 데이터 구성: 컬럼 패밀리 그룹 관리, 컬럼 동적으로 추가
  • 컬럼(column): 컬럼을 사전에 정의할 필요가 없으며, 필요에 따라 컬럼을 추가할 수 있습니다.
  • 행(row)
  • 와이드 컬럼 스토어(wide-column store): 각 행에 대해 데이터를 효율적으로 담을 수 있는 구조를 갖추고 있습니다.
  • 확장성: 컬럼 패밀리 데이터베이스는 수평적 확장을 위해 설계되었습니다.
  • 높은 읽기 및 쓰기 처리량
  • 데이터 분산(data distribution): 컬럼 패밀리 데이터베이스에서는 데이터를 클러스터 내 여러 노드에 분산 저장합니다. 또 장애 허용성과 데이터 가용성을 보장하려고 복제 방식을 활용할 때가 많습니다.

아파치 카산드라는 오픈 소스 컬럼 패밀리 데이터베이스로 잘 알려져 있습니다.

5.9 HBase

아파치의 HBase는 오픈 소스 기반의 분산형 확장 가능한 비관계형 데이터베이스 관리 시스템으로, 대량의 데이터를 높은 읽기 및 쓰기 속도로 처리할 수 있도록 설계했습니다.
HDFS(Hadoop Distributed FileSystem)(하둡 분산 파일 시스템)를 기반으로 만들었으며, 구글의 빅테이블(Bigtable)에서 영감을 받아 개발했습니다.

HBase에서는 데이터가 다음 방식으로 구성됩니다.

  • 테이블은 여러 행으로 구성됩니다.
  • 행은 여러 컬럼 패밀리를 포함합니다.
  • 컬럼 패밀리는 여러 컬럼으로 구성됩니다.
  • 컬럼은 키-값 쌍의 모음입니다.

HBase의 특징

  • 분산 처리 및 확장성
  • 컬럼 패밀리 데이터 모델
  • 일관성 모델
  • 데이터 버전 관리
  • 확장성과 부하 분산
  • 높은 읽기 및 쓰기 처리량
  • 하둡을 이용한 통합 기능
  • 블룸 필터와 블록 캐시
  • 데이터 압축
  • 사용 사례: 대규모 데이터셋에서 무작위로 데이터에 접근이 필요한 애플리케이션에서 주로 활용합니다.
  • 활발한 커뮤니티와 생태계

5.9.1 HBase 자세히 살펴보기

HBase의 개념과 아키텍처

image

Figure 5.9: A diagram showing the different components of HBase architecture, namely the RegionServer co-located with the DataNode, the NameNode, the ZooKeeper, and the HBase Master nodes.

리전 서버

리전 서버는 읽기와 쓰기 작업에서 데이터를 처리하는 핵심적인 역할을 담당합니다. 데이터 요청은 HBase 리전 서버와 직접 연결되어 처리되며, 리전 서버가 관리하는 데이터는 하둡 데이터 노드(DataNode)에 저장됩니다.

image

Figure 5.10: A diagram showing the internals of the RegionServer, with the multiple regions it’s responsible for

HBase 마스터

HBase 마스터 프로세스는 리전 할당과 데이터 정의 언어(DDL) 작업(테이블 생성, 수정, 삭제 등)을 관리합니다.
이름 노드는 파일을 구성하는 모든 물리적 데이터 블록의 메타데이터 정보를 유지하고 관리하는 역할을 합니다.

HBase 마스터의 역할을 정리하면 다음과 같습니다.

  • 리전 서버를 관리하고 조율하는 작업
  • 시작할 때 리전을 할당하거나 복구 및 부하 분산 상황에서 리전을 다시 배치하는 작업
  • 클러스터 내 모든 리전 서버를 모니터링하며, 주키퍼에서 상태 변경 알림을 수신
  • 테이블 생성, 삭제, 업데이트 등 주요 테이블 작업을 처리하는 인터페이스 제공

image

Figure 5.11: A diagram showing the role of HBase Master in the HBase architecture

주키퍼

주키퍼는 클러스터의 실시간 상태를 관리하는 분산형 조율 서비스로, HBase에서 클러스터 내 서버들의 최신 상태를 유지하는 데 사용됩니다.

image

Figure 5.12: Shows the role of the ZooKeeper in HBase architecture

META 테이블과 .META. 서버

HBase의 META 테이블(그림 5-13 참고)은 HBase 카탈로그 테이블(HBase Catalog Table)이라고도 하며, 클러스터 내 리전의 위치 정보를 저장합니다.
주키퍼가 관리하는 .META. 서버가 이 테이블을 관리합니다.
META 테이블은 HBase 테이블처럼 작동하며, 시스템 내 모든 리전의 전체 목록을 관리합니다.

.META. 테이블의 구조는 다음과 같습니다.

  • 키(Keys): 리전의 시작 키와 고유한 리전 ID로 구성됩니다.
  • 값(Values): 해당 리전이 속한 리전 서버를 나타냅니다.

image

Figure 5.13: This diagram shows the META table and .META. server

리전 서버 구성 요소

리전 서버는 HDFS의 데이터 노드에서 동작하며, 다음은 구성 요소로 되어 있습니다(그림 5-14 참고).

image

Figure 5.14: Shows the several components inside the RegionServer – namely, BlockCache, WAL, MemsStore, and HFiles

  • WAL: WAL은 분산 파일 시스템에 저장된 파일로, 아직 영구적으로 저장되지 않은 새로운 데이터를 보관합니다. WAL의 주요 목적은 장애가 발생할 때 데이터를 복구할 수 있도록 지원하는 것입니다.
  • 블록 캐시: 자주 읽는 데이터를 메모리에 저장해서 읽기 속도를 높이는 역할을 합니다. 캐시가 꽉 차면 가장 오래 사용하지 않은 데이터(Least Recently Used, LRU)를 삭제하여 공간을 확보합니다.
  • MemStore(메모리 저장소): 데이터를 디스크에 기록하기 전 임시로 저장하는 쓰기 캐시 역할을 합니다.
  • HFile: HFile은 디스크에 데이터를 정렬된 키-값 형태로 저장합니다.

HBase의 작업 실행 과정

  1. 클라이언트는 주키퍼와 통신을 시작하여 META 테이블을 관리하는 .META. 서버(보통 리전 서버로 구현) 정보를 요청합니다.
  2. 이후 클라이언트는 .META. 서버에 쿼리를 보내 원하는 행의 키와 연결된 리전 서버 정보를 가져옵니다.
  3. 클라이언트는 이렇게 얻은 META 테이블 위치 정보를 포함한 데이터를 캐싱합니다.
  4. 캐싱된 정보를 바탕으로 클라이언트는 해당 리전 서버에서 원하는 행 데이터를 가져옵니다.

image

Figure 5.15: This diagram shows the first HBase read or write access

HBase 쓰기 작업

클라이언트가 Put 요청을 보내면 가장 먼저 데이터를 WAL에 기록합니다(그림 5-16 참고).

  1. 변경된 데이터는 WAL 파일의 끝부분에 추가되며, 이 파일은 디스크에 저장됩니다. WAL은 서버가 다운되었을 때 아직 영구적으로 저장되지 않은 데이터를 복구하는 데 사용됩니다. 이 파일은 리전 서버가 아닌 HDFS나 다른 파일 시스템에 속합니다.
  2. 데이터가 WAL에 기록되면 MemStore에 저장합니다. 이후 요청 처리가 완료되었다는 응답을 클라이언트에 보냅니다.

image

Figure 5.16: HBase writes are first written to WAL and then to Memstore, and then they are sent back to the user

HBase 리전 플러시

  • MemStore에 데이터가 충분히 쌓이면 전체 데이터셋을 정렬한 후 HFile을 새로 만들어 기록합니다.
  • HBase는 컬럼 패밀리마다 HFile을 여러 개 생성하며 이 파일에는 실제 데이터 셀(KeyValue 인스턴스)이 저장됩니다. MemStore에서 데이터를 정렬한 후 디스크로 플러시하며, KeyValue 변경 내용을 새로운 HFile에 추가합니다.
  • HBase는 마지막으로 기록된 시퀀스 번호를 저장하여 사용자가 지금까지 영구 저장된 데이터 범위를 확인할 수 있도록 합니다. 가장 높은 시퀀스 번호는 각 HFile의 메타 필드에 기록하여 데이터가 어디까지 저장되었는지와 이후 저장 작업이 어디에서 시작되어야 하는지 알 수 있습니다.
  • 리전이 시작되면 시스템이 해당 시퀀스 번호를 불러오고, 가장 높은 번호를 새로운 수정 작업의 시퀀스 번호로 사용합니다.

HBase 읽기 작업

데이터를 읽으려면 블록 캐시, MemStore, HFile에 있는 키-값 데이터를 차례대로 조회한 후 이를 합쳐야 합니다.

  1. 먼저 스캐너가 블록 캐시에서 행 데이터를 검색합니다. 최근에 사용한 키-값 데이터가 여기에 저장되며, 메모리가 부족하면 가장 오래 사용하지 않은 데이터부터 삭제합니다.
  2. 다음으로 스캐너가 MemStore 안을 찾아봅니다. MemStore 저장소는 가장 최근에 저장한 데이터를 담고 있는 쓰기 캐시입니다.
  3. 다만 스캐너가 MemStore와 블록 캐시에서 모든 행 셀을 찾지 못하면, HBase는 다음으로 블록 캐시에 저장된 인덱스와 블룸 필터를 활용합니다. 그럼으로써 필요한 데이터가 들어 있을 가능성이 있는 HFile을 메모리로 불러오고, 스캐너는 거기에서 다시 목표 행 셀을 검색합니다. 이런 방식 덕분에 데이터 조회 과정이 더 빠르고 효율적입니다.

image

Figure 5.17: This diagram shows the flow of an HBase read – reading data from the BlockCache, MemStore, and the HFiles and then consolidating them before returning to the client

5.10 그래프 기반 데이터베이스

그래프 기반 데이터베이스는 복잡한 데이터 관계를 저장하고 관리하는 데 최적화된 비관계형 데이터베이스입니다.

그래프 기반 비관계형 데이터베이스의 주요 특징과 개념

  • 그래프 구조: 데이터는 노드(node)와 에지(edge)로 구성된 그래프 형태로 저장됩니다.
  • 노드: 노드는 그래프의 기본 데이터 단위로, 각각의 노드는 해당 개체에 대한 속성(키-값 쌍)을 포함할 수 있습니다.
  • 에지: 에지는 노드 간 연결을 나타내며, 두 대상 간 연관성을 표현합니다.
  • 레이블 및 관계 유형: 노드와 에지에 레이블을 추가하여 이를 특정 카테고리나 유형으로 분류할 수 있습니다.
  • 탐색 기능: 그래프 기반 데이터베이스는 노드 관계를 탐색하는 작업에 최적화되어 있습니다.
  • 사이퍼 쿼리 언어: 그래프 기반 데이터베이스에서는 주로 사이퍼(Cypher)라는 쿼리 언어를 사용합니다.
  • 인덱싱
  • 확장성
  • 활용 사례: 소셜 네트워크, 추천 엔진, 사기 탐지, 네트워크 및 인프라 관리, 지식 그래프(knowledge graph) 같은 분야에서 활용합니다.
  • 패턴 매칭: 그래프 데이터베이스는 패턴 매칭에서 뛰어난 성능을 발휘하며, 그래프 내 특정 구조나 연결을 식별하는 데 최적화되어 있습니다.

5.11 Neo4j 그래프 데이터베이스

Neo4j는 복잡하게 얽힌 데이터 관계를 효율적으로 저장하고 관리하며 이를 빠르게 탐색할 수 있는 그래프 데이터베이스 관리 시스템(DBMS)입니다.

Neo4j의 특징

  • 그래프 데이터 모델
  • 노드
  • 관계
  • 레이블과 관계 유형: Neo4j에서는 노드와 관계에 레이블을 부여하여 이를 카테고리나 유형으로 묶을 수 있습니다.
  • 사이퍼 쿼리 언어
  • 인덱싱과 쿼리 최적화
  • 확장성
  • ACID 특성
  • 데이터 버전 관리
  • 활용 사례: Neo4j는 소셜 네트워크, 추천 시스템, 사기 탐지, 실시간 분석, 네트워크 및 인프라 관리, 지식 그래프 등 다양한 애플리케이션에서 사용할 수 있습니다.
  • 활발한 커뮤니티와 생태계

5.11.1 Neo4j 자세히 살펴보기

그림 5-18은 사람 사이의 관계를 그래프로 표현한 모습입니다.
예를 들어 세 사람을 각각 노드(노드 1·2·3) 세 개로 나타낼 수 있습니다.
노드 1은 노드 2와 노드 3을 팔로우하고, 노드2는 노드 3을 팔로우합니다.

image

Figure 5.18: The relationship between three nodes

5.12 관계형 모델링과 그래프 모델링

관계형 모델링 방식으로 데이터를 저장하는 방법은 두 가지로 나눌 수 있습니다.

  • 관계를 단방향으로 저장: 그림 5-19(a)에서 관계(에지)의 시작점과 도착점을 하나의 행으로 저장합니다.
  • 관계를 양방향으로 저장: 그림 5-19(b)에서 관계의 출발점과 도착점을 한 번씩 번갈아 가면서 저장하고, 방향을 나타내는 추가 열을 더 보탭니다.

image

Figure 5.19: A diagram showing the options to store graph data using a relational model

5.12.1 그래프 모델링

그림 5-20처럼 데이터를 이중 연결 리스트 그래프와 두 테이블(노드와 관계 테이블)로 표현할 수 있습니다

image

Figure 5.20: A diagram showing a representation of graph data using graph modeling

  • 그림 5-20(a)는 노드와 그 관계를 이중 연결 리스트로 표현한 것입니다.
  • 그림 5-20(b)는 노드가 실제로 저장되는 방식을 표현한 것입니다. 각 레코드에는 해당 노드의 첫 번째 관계의 ID(first_rid)가 저장됩니다. 예를 들어 노드 1과 노드 2의 첫 번째 관계는 모두 A입니다.
  • 그림 5-20(c)는 관계가 실제로 저장되는 방식을 의미합니다. 각 레코드에는 관계의 출발점(src)과 도착점(dst)이 저장됩니다. 이외에도 출발 노드와 도착 노드 각각에서 이전 관계와 다음 관계 ID(src_prev_rid, src_next_rid, dst_prev_rid, dst_next_rid)도 저장됩니다.

5.12.2 기존 그래프에 새로운 노드 추가

노드 4를 그래프에 추가하려 한다고 가정합시다(그림 5-21(a) 참고). 여기에서 노드 2가 노드 4를 팔로우하는 관계를 추가하려면 다음 그림과 같이 이중 연결 리스트와 두 테이블을 수정해야 합니다.

image

Figure 5.21: A diagram showing the process of adding a new node and relationship to an existing graph

노드 테이블에는 nid = 4와 first_rid = D가 들어 있는 새로운 행을 추가했습니다.

관계 테이블에 새로운 관계 D를 추가하면서 각 열(rid, src, dst, src_prev_rid, src_next_rid, dst_prev_rid, dst_next_rid)에 필요한 값을 입력하고, 기존 데이터도 수정되었습니다.

노드와 관계가 저장되는 방식

노드 저장소

노드 레코드는 15바이트 크기입니다.

  • 첫 번째 바이트: 사용 중인지 나타냄(inInUse)
  • 다음 4바이트: 노드 ID
  • 그다음 1바이트: 첫 번째 관계 ID
  • 그다음 1바이트: 첫 번째 속성 ID
  • 다음 5바이트: 레이블 저장소
  • 남은 1바이트: 향후 사용 공간

관계 저장소

관계 정보 레코드는 34바이트로 구성되며, 구조는 다음과 같습니다.

  • 출발 노드 ID: 관계 시작점을 나타냄
  • 도착 노드 ID: 관계 끝점을 나타냄
  • 관계 유형 포인터: 관계의 유형 정보를 가리킴
  • 각 출발 노드와 도착 노드에 대한 이전 및 다음 관계 레코드 포인터: 연결된 관계 레코드 간 탐색을 지원

Metadata

Metadata

Assignees

Projects

Status
Done

Relationships

None yet

Development

No branches or pull requests

Issue actions