이 글은 Martin Kleppmann의 데이터 중심 애플리케이션 설계를 읽고 기억하고자 적는 게시글입니다.
3. 저장소와 검색
이번에 알아 볼 내용은 트랜잭션입니다.
1. OLTP와 OLAP
데이터베이스를 공부하면서 최근에 관심을 갖게 된 두 용어에 대한 내용이 나와 설렜습니다.
OLTP ( OnLine Transaction Prossess )
OLTP는 우리가 생각하는 트랜잭션 처리와 동일합니다. 수 많은 데이터에서 색인을 이용해 일부 키에 대한 적은 수의 레코드를 찾고, 사용자의 입력에 의해 삽입되거나 갱신되는 상태입니다.
예를 들면 사용자가 회원 가입을 하거나, 업체 별 물품 발주, 커머스 앱의 사용자 별 판매 물품 등록 등이 이에 해당합니다. 어떠한 서비스를 위해 데이터를 삽입,수정 및 조회하는 서비스이죠.
OLAP ( OnLine Analytics Processing )
OLAP는 데이터 분석에 가까운 트랜잭션과 접근 방식입니다. 사용자에게 레코드 자체를 보여주는게 아닌 특정 조건에 맞는 레코드들을 읽어 집계 함수등을 통해 원하는 리포트 등을 보여주는 방식입니다.
두 방식의 차이점은 다음과 같습니다.
여기서 새로운 개념인 데이터 웨어하우스에 대해서 알아보겠습니다.
데이터 웨어하우스란
데이터 웨어하우스는 OLAP를 위한 데이터 저장 공간입니다. 기존에는 OLTP와 OLAP 모두 RDB와 같은 데이터베이스 내에서 처리했지만, 점점 데이터 분석만을 위한 새로운 저장 공간을 찾기 시작했습니다. 그러한 공간이 바로 데이터 웨어하우스입니다.
OLTP는 일반적으로 사용자와 가까이에 있는 경우가 많습니다. 로그인을 위한 유저 DB 접근의 경우와 같이 사용자에게 가깝기 때문에 분석가가 3년 동안 A 서비스에 50$ 이상을 사용한 유저의 ID와 같은 분석 쿼리를 동작시켜버리면 실서비스에서도 문제가 발생 할 수 있죠. 그래서 OLTP 관련 개발자들은 분석가들의 쿼리를 싫어한다고 합니다.
그러면 데이터를 데이터 웨어하우스에 넣어야 합니다. OLTP 방식으로 사용중인 데이터베이스에서 분석에 용이한 정보를 하나의(일반적으로) 데이터 웨어하우스로 옮기는 작업을 ETL 프로세스 중 하나라고 볼 수 있습니다.
특정 DB에서 데이터를 추출(Extract) 한 후 저장 형태에 맞게 변환 (Transform)하고 마지막으로 웨어하우스에 저장(Load)합니다. 그로인해 분석가들은 다른 데이터베이스에서 분석을 할 수 있죠.
데이터 웨어하우스와 OLTP 데이터베이스는 둘 다 SQL쿼리를 지원하는 경우가 많지만, 기존의 트랜잭션 위주의 OLTP 데이터베이스와는 달리 트랜잭션 처리와 분석 작업부하 중 한 가지에 초점을 맞추는 경우가 많습니다.
데이터 웨어하우스의 분석용 스키마
일반적으로 많은 데이터 웨어하우스의 스키마는 별 모양 스키마 또는 차원 모델링이라고 불리는 모델을 사용한다고 합니다.
깔끔한 설명이 책에 있어서 첨부합니다. 여기서 가장 큰 부분은 차원의 경우 데이터가 많지 않을 가능성이 높다는 점입니다. 실제가 제가 업무를 하고 있는 회사에서도 데이터 웨어하우스를 사용하지만, 모두 실제 데이터를 담고 있습니다. 어떤 속성값은 Varchar(255)로 되어 있을 것이고, 수 많은 데이터가 저장되어 있기 때문에 용량의 낭비도 있을 것 같습니다.
만약 컬럼을 위와 같이 나눈다면 효율적이지 않을까 생각됩니다.
컬럼 지향 저장소
또 다시 궁금했던 컬럼 지향 데이터베이스에 대해 공부하게 되어 기분이 좋습니다.
OLAP의 측면에서 데이터 분석가분들이 사용하는 쿼리를 본다면 대부분 필요한 컬럼만을 가져오는 것을 볼 수 있습니다. 예를들면 특정 카테고리의 물건들의 가격의 평균을 가져온다면 [카테고리, 물건 고유 번호, 가격]만 가져오면 끝입니다.
하지만 로우 기반 데이터베이스에서는 해당하는 모든 로우의 데이터를 가져와서 색인을 이용하여 데이터를 검색합니다. 여기에는 메모리적인 낭비도 포함되죠.
그래서 천재들은 “컬럼으로 읽으면 되지 않을까?” 라는 생각을 하게 됩니다. 그렇게 컬럼 기반 데이터베이스가 등장하게됩니다. 데이터를 저장하는 순간부터 로우가 아닌 컬럼별로 데이터를 저장하는 방법으로 동작시키고, 어떠한 값을 찾을 때는 찾고자 하는 컬럼만을 읽어서 범위를 찾으면 메모리를 효율적으로 사용하고 빠른 시간안에 찾을 수 있습니다.
예를 들면 로우 기반 데이터베이스로 저장한다면 다음과 같습니다.
A 유저, A’ 물건, 100원 B 유저, B’ 물건, 120원 C 유저, C’ 물건, 150원
하지만 컬럼 기반 데이터베이스로 저장한다면 다음과 같이 저장되죠.
A 유저, B 유저, C 유저 A’ 물건, B’ 물건, C’ 물건 100,120,150
만약 A 유저가 구매한 물건을 찾는다면, 0번째에 존재하는 데이터를 그대로 읽으면 됩니다. 여기서는 [ A 유저, A’ 물건, 100 ]으로 읽히겠네요.
컬럼 압축
컬럼 기반 데이터베이스는 압축에서도 좋은 효율을 보입니다. 일반적으로 데이터베이스의 후보키가 아닌 이상 중복 된 데이터가 많은 것을 알고 있습니다.
예를 들면 국가 코드의 경우에는 모든 사용자 데이터에 포함되어있지만, 전체의 종류가 1000개도 채 되지 않은 것을 알고 있죠. 그러면 이러한 특성을 이용해서 데이터를 줄일 수 있지 않을까요?
2의 10 제곱, 즉 10개의 비트라면 모든 국가를 전부 표현 할 수 있습니다. 그래서 우리가 사용 할 수 있는 압축 방법으로 비트맵 부호화를 알 수 있죠. 그리고 그 결과를 런렝스 부호화를 통해 한층 더 압축 할 수 있습니다.
여기서 런렝스 부호화는 비트의 집합을 0과 1의 갯수로 표현하는 방법입니다.
컬럼스토어의 경우 열로 데이터를 저장하기 때문에 디스크가 순차 접근으로 특정 컬럼의 모든 데이터를 탐색할 수 있기 때문에 주요 병목의 원인이 디스크 대역폭(얼마나 많이)이므로 이러한 데이터 자체를 압축하는 방식이 한번에 처리하는 데이터 처리량을 높일 수 있으므로 필요한 방법이라고 합니다.
컬럼 기반 데이터베이스에서의 쓰기
컬럼 기반 데이터베이스의 압축과 정렬은 물론 읽기 질의에 대해서 매우 효과적이지만 쓰기에는 불리한 점을 가지고 있습니다. 또한 일반적으로 압축된 컬럼에서 데이터를 갱신하는 것은 어렵습니다.
그래서 저자는 LSM을 이용하는 것을 추천합니다. 쓰기 전용 로그를 이용하기 때문에 컬럼의 값 범위를 이용하는 B-tree 대신 사용 할 수 있고, 별도의 SS테이블을 남기고 질의를 사용 할 때 디스크와 메모리의 LSM트리를 함께 확인하여 데이터를 제공 할 수 있습니다.
물론 이러한 방식은 쓰기 자체가 순차적으로 이루어 져야 하겠지만, 좋은 것 같습니다.
데이터 큐브와 구체화 뷰
다음 주 출근해서 사용해 볼 데이터 큐브와 구체화 뷰에 대한 내용이였습니다. 대부분 특정 데이터를 처리하는 것을 Dag로 지정하고 Airflow에서 별도로 작업을 했었는데, 이러한 방식을 사용하면 report는 쉽게 작성 할 수 있곘네요.
어려운 이야기는 아닙니다. 그냥 실제 값을 저장한 뷰인 구체화 뷰로 자주 사용되는 데이터들을 큐브 형태로 미리 저장하는 방안입니다.