<?xml version="1.0" encoding="utf-8"?><?xml-stylesheet type="text/xsl" href="atom.xsl"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <id>https://chsy0823.github.io/blog</id>
    <title>Elon Choi Blog</title>
    <updated>2021-01-26T00:00:00.000Z</updated>
    <generator>https://github.com/jpmonette/feed</generator>
    <link rel="alternate" href="https://chsy0823.github.io/blog"/>
    <subtitle>Elon Choi Blog</subtitle>
    <icon>https://chsy0823.github.io/img/favicon.ico</icon>
    <entry>
        <title type="html"><![CDATA[Bigtable 분석 Part 2]]></title>
        <id>https://chsy0823.github.io/blog/bigtable2</id>
        <link href="https://chsy0823.github.io/blog/bigtable2"/>
        <updated>2021-01-26T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[이전 Part 에서는 Bigtable 의 개요와 Bigtable 의 Data model 에 대해 분석해 보았다.]]></summary>
        <content type="html"><![CDATA[<p><a href="https://chsy0823.github.io/blog/bigtable1">이전 Part</a> 에서는 Bigtable 의 개요와 Bigtable 의 Data model 에 대해 분석해 보았다.
이번 Part 에서는 Bigtable 을 구성하는 핵심 요소들 (building blocks) 에 대해 정리를 해보겠다.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="bigtable-의-building-block">Bigtable 의 Building Block<a href="https://chsy0823.github.io/blog/bigtable2#bigtable-%EC%9D%98-building-block" class="hash-link" aria-label="Direct link to Bigtable 의 Building Block" title="Direct link to Bigtable 의 Building Block">​</a></h2>
<p>Bigtable 은 다음과 같은 building block 으로 구성되어 있다.</p>
<ul>
<li>distributed <strong>GFS(Google File System)</strong></li>
<li><strong>Cluster Management System</strong></li>
<li><strong>SSTable</strong></li>
<li><strong>Chubby</strong></li>
</ul>
<p>하나씩 살펴보자.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="1-gfs">1. GFS<a href="https://chsy0823.github.io/blog/bigtable2#1-gfs" class="hash-link" aria-label="Direct link to 1. GFS" title="Direct link to 1. GFS">​</a></h3>
<p>GFS 는 구글에서 만든 분산 파일 시스템이다. GFS 는 Bigtable 에서 <strong>로그 파일과 데이터 파일을 저장하기 위한 데이터 저장소로 사용</strong>된다. GFS 는 다음과 같은 특징을 가지고 있다.</p>
<ul>
<li><code>High Scalability, Availability</code>: 메타데이터를 관리하는 Master 서버, 실제 chunk 데이터가 저장되는 다수의 Chunk 서버의 역할 분리로, <strong>분산된 파일 시스템을 구현</strong></li>
<li><code>Fault Tolerance</code>: 각 청크 (chunk) 는 64MB 크기로 고정되어 있으며, <strong>여러 청크 서버에 중복 저장</strong></li>
<li><code>High Throughput</code>: 클라이언트가 직접 청크 서버와 상호작용 하는 방식으로, <strong>마스터 서버 병목을 줄임</strong>. 또한 <strong>손쉽게 서버를 확장</strong>가능한 구조</li>
<li><code>Optimization on Data structure</code>: 큰 청크 단위 읽기로 <strong>Disk I/O 효율화</strong>, <strong>블록 인덱스를 통한 빠른 검색</strong>, 메타데이터 <strong>캐싱</strong></li>
</ul>
<p>| ⁉️잠깐 CS 지식: <strong>왜 큰 chunk 단위로 읽으면 Disk I/O 가 좋아지는가?</strong></p>
<ul>
<li>디스크는 물리적으로 데이터를 읽어오는 장치이므로, <strong>디스크의 물리적 위치에 따라 읽기 속도가 달라진다</strong>.</li>
<li>HDD, SDD 등 디스크에서 데이터에 접근할 때, 일정한 초기 <strong>오버헤드(seek time 등)가 발생</strong>한다.</li>
<li>따라서 작은 chunk 단위로 읽으면, <strong>매번 디스크의 물리적 위치를 이동해야 하므로 오버헤드가 커지는 반면, 큰 Chunk 단위로 읽으면 줄어든다</strong>.</li>
<li>큰 chunk 단위로 읽어오면, <strong>캐시 히트율이 높아져서</strong>, 디스크 I/O 가 줄어들게 된다.</li>
<li>큰 chunk 단위로 읽어오면, <strong>Sequential I/O 의 장점이 극대화</strong> 되는 반면, <strong>작은 chunk 는 Random I/O 의 단점이 부각</strong> 된다. (<a href="https://velog.io/@kko0369/DB-%EC%88%9C%EC%B0%A8%EC%A0%81-IO%EC%99%80-%EB%9E%9C%EB%8D%A4-IO" target="_blank" rel="noopener noreferrer">Sequential I/O vs Random I/O</a>)</li>
</ul>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="2-cluster-management-system">2. Cluster Management System<a href="https://chsy0823.github.io/blog/bigtable2#2-cluster-management-system" class="hash-link" aria-label="Direct link to 2. Cluster Management System" title="Direct link to 2. Cluster Management System">​</a></h3>
<ul>
<li>Bigtable cluster 는 여러 종류의 분산 어플리케이션이 실행되는 <strong>Shared Machine Pool</strong> 이다.</li>
<li>이 cluster management system 은 <strong>task scheduling, resource allocation, machine monitoring, fault detection, recovery 등을 기능을 수행</strong>한다.</li>
</ul>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="3-sstable">3. SSTable<a href="https://chsy0823.github.io/blog/bigtable2#3-sstable" class="hash-link" aria-label="Direct link to 3. SSTable" title="Direct link to 3. SSTable">​</a></h3>
<p><strong>SSTable(Sorted String Table)</strong> 은 Bigtable 에서 <strong>데이터를 저장할 때 사용</strong>되는 자료 구조이다. 간단히 말하면 key/value string pair 인데, key 를 기준으로 정렬된 table 이라 할 수 있다.
SSTable 은 다음과 같은 특징을 가지고 있다.</p>
<ul>
<li>key 는 <strong>중복을 허용하지 않으며 immutable 하다</strong>.</li>
<li><strong>64KB 단위로 chunking</strong> 되어 block 으로 저장된다.</li>
<li>각 블록을 indexing 하는 <strong>Block index</strong> 가 각 SSTable에 저장되며, SST 가 open 될 때 <strong>메모리에 load된다</strong>.</li>
</ul>
<p>기본 구조는 심플한데 정리하자면, SST 는 <strong>"key/value pair 형태의 구조이며, 64kb 단위로 chunk 가 만들어서져서 블록단위 indexing이 되겠구나"</strong> 라고 이해해볼 수 있겠다.</p>
<p>예시를 보자면, 다음과 같이 이름:값 쌍으로 이루어진 key/value pair 가 있고,</p>
<p style="text-align:center"><img src="https://chsy0823.github.io/assets/images/sst1-74fff6ea4e9ea3f01abf3345e6ea517f.png" alt="sst1" style="max-width:1000px;width:100%;height:auto"><em>출처: <a href="https://velog.io/@yunhongmin/SSTable-data-storage">SSTable를 이용한 데이터 저장</a></em></p>
<p><code>Amelia</code>, <code>Lily</code>, <code>Neil</code> 로 시작되는 각 Block으로 chunking 된다고 했을 때, index 는 아래와 같이 저장된다.</p>
<p style="text-align:center"><img src="https://chsy0823.github.io/assets/images/sst2-beb612f3c78f3509626b531a6b04b22a.png" alt="sst1" style="max-width:1000px;width:100%;height:auto"><em>출처: <a href="https://velog.io/@yunhongmin/SSTable-data-storage">SSTable를 이용한 데이터 저장</a></em></p>
<p>메모리에 load 된 block index 는 각 블록이 다루는 key 로 정렬되어있어 binary search 가 가능하다. 이를 통해 찾고자하는 key 가 어떤 block 에 포함되는지 알아내서 single disk seek 으로 해당 블록을 읽어올 수 있다.
한번 block 을 disk 에서 읽어와 메모리로 load 하면, 해당 key 를 찾는 것은 binary search 를 하거나 iterator 를 통해 순차적으로 비교하며 찾을 수 있을 것이다.</p>
<p>여기까지가 기본적인 SSTable 의 구조와 개념이지만, 다른 자료들을 보면 아래와 같이 <code>Filter Block</code>, <code>Meta Index Block</code> 등 으로 구성된 SSTable 을 설명하는 <a href="https://sslab.dankook.ac.kr/1-4-sstable/" target="_blank" rel="noopener noreferrer">글</a>도 찾아볼 수 있다.</p>
<p style="text-align:center"><img src="https://chsy0823.github.io/assets/images/sst3-5d10cf1c05146eefcedcca28d8b87a69.png" alt="sst1" style="max-width:300px;width:100%;height:auto"><em>출처: <a href="https://sslab.dankook.ac.kr/1-4-sstable/">SSTable</a></em></p>
<p>이는 google이 Bigtable 이후에 이를 베이스로 단일 노드 환경에 최적화 되도록 개량한 <code>LevelDB</code>  에서 기존 SST 의 최적화를 위해 개선한 구조로 보여진다.
<code>Bloom filter</code> 등 RocksDB 에서도 자주 보이는 keyword 들이 등장하는데, 추후 LevelDB 를 정리할 때 다시 정리해보겠다.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="4-chubby">4. Chubby<a href="https://chsy0823.github.io/blog/bigtable2#4-chubby" class="hash-link" aria-label="Direct link to 4. Chubby" title="Direct link to 4. Chubby">​</a></h3>
<p>Chubby 는 구글에서 만든 분산 환경에서의 동기화, Lock 관리, 메타데이터 저장 등의 작업을 수행하는 <strong>Distributed Lock Service</strong> 로 분산 코디네이션(coordination) 서비스중 하나이다.
<strong>"어? 이거 Zookeeper 아니야?"</strong> 라고 생각할 수 있는데, 코디네이션의 역할은 같지만, 합의 알고리즘 등 세부적인 내용이 다르다.
또한, Chubby 는 apache 오픈소스인 Zookeeper 보다 먼저 만들어진 서비스이기 때문에 Zookeeper 가 Chubby 의 영향을 받아 만들어졌다고 볼 수 있다.</p>
<p>Chubby 의 구조를 구체적으로 설명하려면, Paxos 알고리즘을 합의 알고리즘을 사용하고 5개의 replica 중 하나가 master 로 선출되며, atomic Read/Write 방식 등.. 다룰 내용이 꽤 많다.
이는 Bigtable 과 마찬가지로 별도의 <a href="https://research.google/pubs/the-chubby-lock-service-for-loosely-coupled-distributed-systems/?ref=pangyoalto.com" target="_blank" rel="noopener noreferrer">논문</a>이 하나 있을 정도로 정리가 필요할 것 같아 추후 따로 정리를 하는 거로 하고,
여기서는 Chubby 가 Bigtable 에서 다음과 같은 목적으로 쓰인다는 것만 이해해두자.</p>
<ul>
<li><strong>Bigtable 의 단일 활성 마스터 보장</strong>: Chubby 의 리더 선출 방식을 통해</li>
<li><strong>메타데이터 및 스키마 저장</strong>: column family, ACL 등 메타데이터를 chubby 에 저정하여, client 에서 참조가능하도록 함</li>
<li><strong>Tablet 서버 탐지 및 관리</strong>: Tablet 서버의 등록, 상태 모니터링, 실패 후 종료 처리등 지원</li>
<li><strong>부트스트랩(bootstrap) 정보 제공</strong>: Bigtable 데이터의 초기 boostrap 위치(데이터 파일의 위치 등)를 Chubby 에 저장, 복구 시에 Chubby 에서 빠르게 정보를 읽어와 복구 가능</li>
</ul>
<p>자, 여기까지가 Bigtable 을 구성하는 핵심 Building Block 들에 대한 간략한 정리이다. 나는 이를 정리하면서 GFS, Chubby, SSTable 등 <strong>이미 구글에서 만든 기술들을 잘 활용하여</strong>, Bigtable 이라는 멋진 아키텍처를 만들었다는 점에서, 구글의 기술력에 감탄하지 않을 수 없었다.
사실상, 구글의 관점에서는 회사 자체의 기술력을 다 zero-base 로 시작한 것이 다름없다. (물론, Chubby 에서는  <a href="https://en.wikipedia.org/wiki/Leslie_Lamport" target="_blank" rel="noopener noreferrer">갓-포트</a> 형님의 Paxos 알고리즘 등 third-party techinq 을 활용하긴 하지만..)</p>
<p>다음으론 Tablet 을 관리하는 방식, 데이터를 압축하는 방식 등에 대한 구현을 집중적으로 분석해보고, 논문을 낼 당시엔 적용이 안됬지만 Future works 로 남겨둔 것으로 보여지는 <code>Refinements</code> (high performance, availability, and reliability 를 얻기위해 refactoring 이 필요한 구조들) 가 어떤 것들이 있는지 정리해보겠다.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="references">References<a href="https://chsy0823.github.io/blog/bigtable2#references" class="hash-link" aria-label="Direct link to References" title="Direct link to References">​</a></h2>
<ul>
<li><a href="https://velog.io/@yunhongmin/SSTable-data-storag" target="_blank" rel="noopener noreferrer">https://velog.io/@yunhongmin/SSTable-data-storag</a></li>
<li><a href="https://sslab.dankook.ac.kr/1-4-sstable" target="_blank" rel="noopener noreferrer">https://sslab.dankook.ac.kr/1-4-sstable</a></li>
<li><a href="https://velog.io/@kko0369/DB-%EC%88%9C%EC%B0%A8%EC%A0%81-IO%EC%99%80-%EB%9E%9C%EB%8D%A4-IO" target="_blank" rel="noopener noreferrer">https://velog.io/@kko0369/DB-%EC%88%9C%EC%B0%A8%EC%A0%81-IO%EC%99%80-%EB%9E%9C%EB%8D%A4-IO</a></li>
<li><a href="https://pangyoalto.com/chubby-zookeeper/" target="_blank" rel="noopener noreferrer">https://pangyoalto.com/chubby-zookeeper/</a></li>
<li><a href="https://gruuuuu.github.io/integration/paxos-raft/" target="_blank" rel="noopener noreferrer">https://gruuuuu.github.io/integration/paxos-raft/</a></li>
</ul>]]></content>
        <author>
            <name>Suyong Choi (Elon)</name>
            <uri>https://github.com/chsy0823</uri>
        </author>
        <category label="Distributed System" term="Distributed System"/>
        <category label="Architecture" term="Architecture"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Bigtable 분석 Part 1]]></title>
        <id>https://chsy0823.github.io/blog/bigtable1</id>
        <link href="https://chsy0823.github.io/blog/bigtable1"/>
        <updated>2021-01-25T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[제프 딘 가라사대, “분산데이터저장소 있으라” 하시매..]]></summary>
        <content type="html"><![CDATA[<h2 class="anchor anchorWithStickyNavbar_LWe7" id="제프-딘-가라사대-분산데이터저장소-있으라-하시매">제프 딘 가라사대, “분산데이터저장소 있으라” 하시매..<a href="https://chsy0823.github.io/blog/bigtable1#%EC%A0%9C%ED%94%84-%EB%94%98-%EA%B0%80%EB%9D%BC%EC%82%AC%EB%8C%80-%EB%B6%84%EC%82%B0%EB%8D%B0%EC%9D%B4%ED%84%B0%EC%A0%80%EC%9E%A5%EC%86%8C-%EC%9E%88%EC%9C%BC%EB%9D%BC-%ED%95%98%EC%8B%9C%EB%A7%A4" class="hash-link" aria-label="Direct link to 제프 딘 가라사대, “분산데이터저장소 있으라” 하시매.." title="Direct link to 제프 딘 가라사대, “분산데이터저장소 있으라” 하시매..">​</a></h2>
<p><a href="https://static.googleusercontent.com/media/research.google.com/ko//archive/bigtable-osdi06.pdf" target="_blank" rel="noopener noreferrer">Bigtable</a> 은 2006년에 구글에서 공개한 분산 데이터 저장소이다. 아마 구글이 처음으로 공개한 분산 데이터 저장소일 것이다. Bigtable 은 구글의 여러 서비스에서 사용되고 있으며, 그 중에서도 구글 검색 엔진과 구글 맵스에서 사용되고 있다.
<a href="https://cloud.google.com/bigtable?hl=ko" target="_blank" rel="noopener noreferrer">현재는 구글 클라우드를 통해 서비스 되고 있는 것을 확인할 수 있다.</a></p>
<p>Bigtable 공개로 부터 15년이 훌쩍 넘은 지금은 분산 시스템을 다루는 모던한 기술들이 많이 있지만, 2006년 당시에는 대단한 기술이었고, 현재의 구글의 핵심 서비스들의 기반이 되는 기술이다.</p>
<p><strong>그럼 이 Bigtable 은 누가 만들었을까?</strong></p>
<p style="text-align:center"><img src="https://chsy0823.github.io/assets/images/jd1-57fec24ef3ef4aa5da84b4911f27c488.png" alt="JeffDeanMeme" style="max-width:400px;width:100%;height:auto"><em>출처: <a href="https://ttimes.co.kr/article/2023050418237753322/">ttimes</a></em></p>
<p>chatgpt 는 물론 stack overflow, 구글링 같은 웹에서 양질의 정보를 찾기 힘든 시절에 이러한 시스템을 만든 사람은, 아직까지도 구글에서 단 2명 뿐인 L11 개발자인 <strong>제프 딘(Jeff Dean)</strong> 이다.
언제나 그렇듯이 구글에서 만든 Fancy 한 기술들의 저자들의 이름에서 Jeff Dean 을 쉽게 찾아 볼 수 있다.</p>
<p>(<a href="https://dev-ahn.tistory.com/136" target="_blank" rel="noopener noreferrer">하지만 제프딘 형님은 인터뷰에서 엔지니어로 살아오면서 저질렀던 가장 큰 실수라고 한다..</a>)</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="근데-왜-15년이나된-고대-기술을--알아야하는가">근데 왜 15년이나된 고대 기술을  알아야하는가?<a href="https://chsy0823.github.io/blog/bigtable1#%EA%B7%BC%EB%8D%B0-%EC%99%9C-15%EB%85%84%EC%9D%B4%EB%82%98%EB%90%9C-%EA%B3%A0%EB%8C%80-%EA%B8%B0%EC%88%A0%EC%9D%84--%EC%95%8C%EC%95%84%EC%95%BC%ED%95%98%EB%8A%94%EA%B0%80" class="hash-link" aria-label="Direct link to 근데 왜 15년이나된 고대 기술을  알아야하는가?" title="Direct link to 근데 왜 15년이나된 고대 기술을  알아야하는가?">​</a></h2>
<p><a href="https://github.com/paust-team/pirius" target="_blank" rel="noopener noreferrer">Pirius</a> 프로젝트를 진행하면서 분산 환경에서의 storage를 구현하는데 핵심이 되는 RocksDB 를 이해하기 전에, LevelDB 와 Bigtable 에 대해 이해가 필요하다고 판단을 했다.</p>
<p>우선 Bigtable은 분산 NoSQL 데이터베이스로(당시엔 NoSQL 이라는 용어가 익숙하지 않았지만..), 내부적으로 <strong>LSM(Log-Structured Merge) 트리 기반의 SSTable 구조</strong> 를 사용한다.
BigTable 논문이 공개된 뒤, 같은 아이디어를 바탕으로 단일 노드용 LSM 엔진인 LevelDB 가 공개되었고, 이후에 페이스북이 <strong>LevelDB</strong> 를 Fork 하여 Performance, Concurrency, Configuration 등을 확장한 버전인 <strong>RocksDB</strong> 를 만들었다.</p>
<p>Bigtable 기술 자체는 15년전에 나온 아이디어지만, 내부에서 Bigtable을 기반으로 다양한 서비스가 운영되면서 계속 개량과 확장을 거쳤고, 그 기술을 클라우드 서비스 형태로 재구성해 외부에 제공한 것이 Google Cloud Bigtable 이다.
따라서 내가 분석할 Bigtable 은 2006년 당시의 논문이므로, 현재 GoogleCloud 의 Bigtable 구조와 기능적인 부분에서 차이가 있을 수 있다.
그래도 LevelDB, RocksDB 의 기반이 되는 SSTable 의 기반 구조는 아직까지 남아있으며, 분산 시스템에서의 여러 mission critical 한 부분들을 어떻게 해결했는지에 대한 인사이트를 얻을 수 있을 것이라 생각한다.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="a-distributed-storage-system-for-structured-data">"A Distributed Storage System for Structured Data"<a href="https://chsy0823.github.io/blog/bigtable1#a-distributed-storage-system-for-structured-data" class="hash-link" aria-label="Direct link to &quot;A Distributed Storage System for Structured Data&quot;" title="Direct link to &quot;A Distributed Storage System for Structured Data&quot;">​</a></h2>
<p>Bigtable 은 논문의 제목 그대로 <strong>Structured Data</strong> 를 위한 분산 저장소이다. 그럼 Structured Data 란 무엇인가?</p>
<ul>
<li><strong>Structured Data</strong>:<!-- -->
<ul>
<li>정형화된 데이터로, 관계형 데이터라 불리며 Strict Schema 를 준수하는 데이터</li>
<li>예를 들어, 테이블 형태로 저장된 데이터, 즉 행(row)과 열(column)로 구성된 데이터</li>
</ul>
</li>
<li><strong>Unstructured Data</strong>:<!-- -->
<ul>
<li>비정형화된 데이터로, 관계형 데이터베이스에서 사용되지 않는 데이터 모델을 따르는 데이터</li>
<li>예를 들어, 이미지, 비디오, 오디오, 텍스트 파일 등</li>
</ul>
</li>
<li><strong>Semi-Structured Data</strong>:<!-- -->
<ul>
<li>반정형화된 데이터로, 관계형 데이터베이스에서 사용되지만, 정형화된 데이터 모델을 따르지 않는 데이터</li>
<li>예를 들어, XML, JSON, YAML 등</li>
</ul>
</li>
</ul>
<p>아래 차차 분석해보겠지만, Bigtable 에서는 <strong>Row/Column/Column Family/Timestamp</strong> 라는 정해진 형태(structured)로 데이터를 저장한다.</p>
<p>논문의 abstract 에 나와있는 내용을 보면, Bigtable 은 다음과 같은 목적을 가지고 있다.</p>
<ol>
<li><strong>대규모 데이터 관리를 위한 분산 스토리지 제공</strong></li>
</ol>
<ul>
<li>페타바이트(PB)급 데이터와 수천 대 규모의 저비용 서버(commodity servers)를 활용해 매우 큰 스케일로 데이터를 저장하고 처리할 수 있도록 설계되어야함</li>
</ul>
<ol start="2">
<li><strong>다양한 구글 서비스에서의 공통 스토리지 요구 사항 충족</strong></li>
</ol>
<ul>
<li>구글 검색 색인(web indexing), 구글 어스, 구글 파이낸스 등 서로 다른 요구 사항을 가진 애플리케이션들이 Bigtable을 사용해야함</li>
<li>데이터의 종류(예: URL, 웹페이지, 위성 이미지 등)와 처리 지연(latency) 요구가 서로 다른 상황에서, 유연하고 고성능인 스토리지로 기능해야함</li>
</ul>
<ol start="3">
<li><strong>단순한 데이터 모델과 동적 제어</strong></li>
</ol>
<ul>
<li>클라이언트가 데이터 구조와 포맷을 동적으로 제어할 수 있도록 함으로써 다양한 사용 시나리오를 지원해야함</li>
</ul>
<ol start="4">
<li><strong>유연성과 고성능을 동시에 제공</strong></li>
</ol>
<ul>
<li>여러 Google 제품들이 요구하는 높은 처리량과 빠른 응답 속도를 모두 만족해야함</li>
</ul>
<p>위와 같은 요구사항들을 충족하기 위해 Bigtable 에선 어떤 해법을 제시했는지 살펴보자.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="bigtable-의-데이터-모델">Bigtable 의 데이터 모델<a href="https://chsy0823.github.io/blog/bigtable1#bigtable-%EC%9D%98-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%AA%A8%EB%8D%B8" class="hash-link" aria-label="Direct link to Bigtable 의 데이터 모델" title="Direct link to Bigtable 의 데이터 모델">​</a></h2>
<blockquote>
<p>A Bigtable is a sparse, distributed, persistent multidimensional <strong>sorted map</strong>. The map is <strong>indexed by a row key, column key, and a timestamp</strong>; each value in the map is an <strong>uninterpreted array of bytes</strong>. (row<!-- -->:string<!-- -->, column<!-- -->:string<!-- -->, time<!-- -->:int64<!-- -->) → string</p>
</blockquote>
<p>Bigtable 의 구현부를 살펴보기전에 Data model 부터 살펴볼 필요가 있다. 위에서 기술한 것 처럼 Bigtable 은 <strong>multi-dimensional sorted map</strong> 이다.
여기서 multi-dimensional sorted map 이라 함은,</p>
<ol>
<li>Row key, Column key, Timestamp 라는 <strong>세 차원(multi-dimensional)</strong> 으로 구성된,</li>
<li>Row key를 기준으로 전체 데이터가 사전순(lexicographical) <strong>정렬(sorted)</strong> 된,</li>
<li><strong>key-value 쌍(map)</strong> 이라는 의미이다.</li>
</ol>
<p>이러한 설계 이점은 Row key 를 기준으로 정렬되어 있기 때문에, 특정 <strong>Row key 를 기준으로 데이터를 빠르게 검색</strong>할 수 있고, <strong>Range Scan</strong> 을 가능하게 한다는 것이다. 이로써 <strong>Data 의 Locality</strong> 를 보장할 수 있다.</p>
<p>논문에서 figure1 으로 설명하고 있는 Webtable 예제를 보면, Bigtable 의 데이터 모델을 이해하는데 도움이 된다.
<img decoding="async" loading="lazy" alt="Figure1" src="https://chsy0823.github.io/assets/images/fig1-915f624fdeb0e869e6f6c000f7961ee3.png" width="1401" height="442" class="img_ev3q"></p>
<p>이를 RDB 의 테이블 관점으로 생각하면 잘 이해가 가지 않는 구조다. Bigtable 이 NoSQL 과 가까운 것을 생각해보면, JSON 구조로 nested 데이터 구조로 표현해 볼 수 있다. (실제로는 json 형태로 저장하지 않지만..)</p>
<div class="language-json codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-json codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token property" style="color:#36acaa">"com.cnn.www"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"anchor"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"cnnsi.com"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token property" style="color:#36acaa">"t9"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"CNN"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"my.look.ca"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token property" style="color:#36acaa">"t8"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"CNN.com"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token property" style="color:#36acaa">"contents"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"t3"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"&lt;html&gt;...&lt;/html&gt;"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"t5"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"&lt;html&gt;...&lt;/html&gt;"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      </span><span class="token property" style="color:#36acaa">"t6"</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"&lt;html&gt;...&lt;/html&gt;"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg viewBox="0 0 24 24" class="copyButtonIcon_y97N"><path fill="currentColor" d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg viewBox="0 0 24 24" class="copyButtonSuccessIcon_LjdS"><path fill="currentColor" d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>
<p>Bigtable 에 저장되는 데이터는 3차원 array 에 접근하는 expression 으로 예를 들자면, <code>array[rowkey][columnkey][timestamp]</code> 형태로 접근할 수 있을 것이다.
<strong>column key</strong> 는 <strong>column family 와 qualifier</strong> 를 조합하여 만들어지며(위에서 column family 는 <code>anchor</code>, <code>contents</code>), <strong>value 는 timestamp 별로 관리</strong>가 되는 형태라 볼 수 있다.  이렇게 timestamp 는 <strong>row 의 각 column 에 대해 버전 관리</strong>가 가능하다.</p>
<p>음.. 여기서 의문이 생길 만한 질문을 몇개 던져보자.</p>
<ul>
<li><strong>Row Key 는 어떻게 정해지는가?</strong>
<ul>
<li>👉 Row Key 는 사용자가 정해줄 수 있다. 예를 들어, URL 을 Row Key 로 사용하면, URL 을 기준으로 정렬된 데이터를 저장할 수 있다.</li>
</ul>
</li>
<li><strong>예제에선 왜 Row Key 를 URL 역순으로 저장했는가?</strong>
<ul>
<li>👉 Row Key 를 역순으로 저장하면, URL 의 접두사(prefix) 검색이 가능하다. 예를 들어, com.cnn 으로 subdomain 을 제외하고 검색할 때, wildcard 검색을 통해 com.cnn 으로 시작하는 모든 URL 을 iterate 할 수 있다. (Locality of data 의 장점으로)</li>
</ul>
</li>
<li><strong>같은 Row Key, Column Family 에 Timestamp 별 버전을 관리한다는 것은, row 를 update 하지 않고 insert 하는 방식인가?</strong>
<ul>
<li>👉 맞다. Bigtable 은 row 를 update 하지 않고 insert 하는 방식이다. 즉, row 를 update 하는 것은 in-place update 로 덮어쓰는 것이 아니라, 새로운 row 를 insert 하는 것이다. 이로 인해, row 의 버전 관리가 가능하다.
이는 LSM 트리 구조로 부터 생기는 특징으로 뒤에서 자세히 설명할 예정이다.</li>
</ul>
</li>
<li><strong>Qualifier 는 필수가 아닌가?</strong>
<ul>
<li>👉 맞다. Qualifier 는 필수가 아니다. 즉, Column Family 만으로도 데이터를 저장할 수 있다. 예를 들어, <code>anchor</code> 라는 Column Family 만으로도 데이터를 저장할 수 있다. 하지만, Qualifier 를 사용하면 더 세부적인 데이터 구조를 만들 수 있다.</li>
</ul>
</li>
</ul>
<p>추가적으로 Qualifier 는 무엇인지, Column 이면 column 이지 Column Family 는 무엇인지 등 궁금증이 생긴다. 위의 예제만을 보고는 아직 Data model 에 대해서 잘 와닿지 않을 수 있다. 그래서 Bigtable 의 Data model 를 구성하는 요소들에 대해 좀 더 자세히 살펴보자.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="rows">Rows<a href="https://chsy0823.github.io/blog/bigtable1#rows" class="hash-link" aria-label="Direct link to Rows" title="Direct link to Rows">​</a></h3>
<ul>
<li>
<p><strong>Row Key 의 특성</strong></p>
<ul>
<li>임의의 문자열을 Row Key로 사용 가능, 최대 64KB까지 지원 (일반적으로 10~100바이트 정도를 사용)</li>
<li>동일 Row Key에 대한 읽기/쓰기는 <strong>Atomic</strong> 하게 처리됨(해당 Row에 있는 여러 컬럼에 대한 연산도 동시에 atomic operation 으로 수행).</li>
</ul>
</li>
<li>
<p><strong>Lexicographic 정렬 및 동적 분할</strong></p>
<ul>
<li>Bigtable은 <strong>Row Key 기준으로 사전순(lexicographic order) 정렬을 유지</strong>함.</li>
<li>테이블은 <strong>Row Key의 범위에 따라 동적으로 분할(파티셔닝)</strong> 되고, 각 범위를 <strong>Tablet</strong>이라 부름.</li>
<li><strong>Tablet 단위로 분산 및 부하 분산</strong>(load balancing)이 이뤄지므로,<!-- -->
<ul>
<li>인접한 Row 범위를 읽을 때는 비교적 적은 수의 서버(node)만 통신하면 되고, Disk I/O에도 효율적. (Locality of data)</li>
</ul>
</li>
</ul>
</li>
<li>
<p><strong>로컬리티(Locality) 를 고려한 RowKey 설계 가능</strong></p>
<ul>
<li>사용자는 <strong>Row Key를 잘 설계하여, 자주 함께 조회되는 데이터가 서로 인접하도록 저장할 수 있음</strong>.<!-- -->
<ul>
<li>예시: 웹 페이지를 저장하는 Webtable은 도메인을 뒤집어서(예: com.google.maps/index.html) Row Key로 사용</li>
</ul>
</li>
<li>이를 통해 동일 도메인(maps.google.com, mail.google.com 등)의 웹 페이지들이 인접한 범위를 이루게 됨.</li>
<li>이러한 접근 방식은 호스트나 도메인 단위의 분석에 유리하고, <strong>연관 데이터 스캔 시 효율이 높아짐</strong>.</li>
</ul>
</li>
<li>
<p><strong>Row key 에 대한 atomic operation 이 가지는 장점</strong></p>
<ul>
<li>여러 column 간의 부분 갱신으로 인한 데이터 불일치 문제를 방지 (일관성 유지)</li>
<li>Row 단위로 lock 이 걸리기 때문에 여러 column 간에 all-or-nothing 의 atomicity 를 보장</li>
<li>쓰기 작업 실패로 인한 부분 column 갱신을 방지 (rollback 등 필요없음)</li>
</ul>
</li>
</ul>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="column-family">Column Family<a href="https://chsy0823.github.io/blog/bigtable1#column-family" class="hash-link" aria-label="Direct link to Column Family" title="Direct link to Column Family">​</a></h3>
<ul>
<li>
<p><strong>Column Family의 기본 개념 및 구성</strong></p>
<ul>
<li>Column Family는 <strong>여러 개의 열(Column)들을 하나의 그룹으로 묶은 것</strong>으로, Bigtable 에서의 기본 접근 제어 단위</li>
<li><strong>데이터 일관성</strong>: 한 Column Family 내에 저장되는 모든 데이터는 보통 같은 유형이며, <strong>같은 유형의 데이터를 함께 압축</strong>하면 높은 압축률을 얻을 수 있음<!-- -->
<ul>
<li>How? =&gt; 압축할때는 데이터 내의 <strong>반복 패턴, 유사한 패턴이 많을 수록 압축률이 높은데</strong>, column family 의 특성상, 같은 종류의 데이터는 반복되는 패턴이나 유사한 구조를 보이기 쉽기 떄문</li>
</ul>
</li>
<li><strong>생성 순서</strong>: Column Family는 <strong>미리 생성</strong>되어 있어야 하며, 생성된 후 그 안에서 어떤 Column key(형식: family<!-- -->:qualifier<!-- -->)도 사용가능</li>
</ul>
</li>
<li>
<p><strong>Column Family 의 제약 조건</strong></p>
<ul>
<li>테이블 내의 <strong>Column Family는 수백 개 정도로 제한</strong>되어 있고(대략 수백 개 이하), <strong>운영 중에는 잘 변하지 않는 것</strong>이 이상적</li>
<li>반면, 개별 <strong>Column key(또는 Qualifier)는 무제한으로 생성</strong>될 수 있음</li>
</ul>
</li>
<li>
<p><strong>Column Family vs. Columns</strong></p>
<ul>
<li>RDB의 Column은 정해진 스키마에 따라 모든 행에 대해 동일하게 존재하는 <strong>고정형 데이터 필드</strong>로, 데이터 타입과 제약이 엄격하게 적용됨</li>
<li>반면, Bigtable의 Column Family는 <strong>미리 정의된 그룹 단위</strong>로, <strong>이 그룹 내에서 동적으로 다양한 Column Qualifier(실제 컬럼)가 추가</strong>될 수 있으며, <strong>이 단위로 압축, 접근 제어, 리소스 관리</strong> 등이 이루어짐</li>
</ul>
</li>
<li>
<p><strong>왜 Column Family는 미리 생성되어있어야하는가?</strong></p>
<ul>
<li>Column Family가 <strong>runtime에 생성되지 않는 것을 가정하에, 읽기/쓰기 작업에서 최적의 성능을 유지</strong>할 수 있도록 설계됨</li>
<li>Column Family 설계는 RDB <strong>Table 의 schema 를 설계하는 것과 유사</strong>하며, 저장되는 <strong>데이터 모델을 쉽게 이해하고 어플리케이션 로직을 구현하는데 도움</strong>을 줌</li>
</ul>
</li>
</ul>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="timestamps">Timestamps<a href="https://chsy0823.github.io/blog/bigtable1#timestamps" class="hash-link" aria-label="Direct link to Timestamps" title="Direct link to Timestamps">​</a></h3>
<ul>
<li>
<p><strong>다중 버전 관리의 목적</strong></p>
<ul>
<li>Bigtable의 각 셀은 동일 데이터의 여러 버전을 저장할 수 있으며, 이들 각각은 Timestamp에 의해 구분</li>
<li>Timestamp는 64비트 정수로 표현되며, 각 버전은 이 숫자를 기반으로 정렬(내림차순) 되므로 가장 최신의 데이터에 빠르게 접근이 가능</li>
</ul>
</li>
<li>
<p><strong>Timestamp의 할당</strong></p>
<ul>
<li><strong>자동할당</strong>: Bigtable이 자동으로 timestamp를 부여하는 경우, ms 단위로 실제 시간을 기록</li>
<li><strong>수동할당</strong>: 사용자가 직접 timestamp를 지정하는 경우, 사용자가 원하는 값을 설정 가능 (중복 되지 않도록 해야함)</li>
</ul>
</li>
<li>
<p><strong>Garbage Collection 매커니즘</strong></p>
<ul>
<li><strong>각 셀에 대해 최대 n 개의 버전만 유지</strong>하도록 설정 가능</li>
<li>또는, 유효 기간이 지난 데이터는 <strong>자동으로 삭제</strong>되도록 설정 가능 (ex. 마지막 7일 이내의 데이터만 유지 등)</li>
</ul>
</li>
</ul>
<p>여기까지, Bigtable 의 개요와 데이터 모델에 대해 정리해보았다. 다음 Part 에서는 Bigtable 을 이루는 Building Block 들과 주요 implementation 에 대해 살펴보겠다.</p>]]></content>
        <author>
            <name>Suyong Choi (Elon)</name>
            <uri>https://github.com/chsy0823</uri>
        </author>
        <category label="Distributed System" term="Distributed System"/>
        <category label="Architecture" term="Architecture"/>
    </entry>
</feed>