2015. 1. 22. 16:07ㆍAbout IT/유용한 정보.
출처: http://www.comqna.net/bbs/board.php?bo_table=database&wr_id=40&page=1
메 모리 DB의 역사는 불과 3년 정도다. 빠른 시간 동안 급성장해 다양한 분야에서 사용되고 있지만 아직 일반화됐다고 보기는 어렵다. 또 기술 및 기능에 있어서도 기존 디스크 DB에 비해 아직 미흡한 점이 있는 것도 사실이다. 메모리 DB는 적용분야가 구분되고 있으며 역할 또한 기존 디스크 DB와 차별됨으로써 적용사례가 늘어나고 있다. 본 강좌에서는 최근 사용이 늘고 있는 메모리 DB의 기술과 발전방향을 살펴보고자 한다.
메모리 DBMS는 하드웨어인 메모리를 기반으로 데이터를 처리하는 것으로 오해되는 경우가 종종 있다. 메모리 DBMS는 오라클 DBMS나 IBM의 DB2 등과 같은 순수 소프트웨어다. 따라서 메모리 DBMS는 기능 측면에서는 기존의 디스크 기반 DBMS와 동일하다. 단지 구조의 차이로 인해 역할 측면에서 차이가 있을 뿐이다. 이번 호에서는 메모리 DBMS의 구조, 적용 기술, 역할 등에 대해 자세하게 살펴보고 독자들의 이해를 돕고자 한다.
인덱스·테이블 등 메모리에 상주
메모리 DBMS의 구조를 살펴보기에 앞서 디스크 기반 DBMS와의 근본적인 차이를 알아야 할 것이다. 디스크 DBMS의 저장 장소는 디스크인데 반해, 메모리 DB의 저장 장소는 메모리다.
이
는 두 DBMS를 구분 짓는 가장 큰 특징이면서 가장 큰 차이점이라고 할 수 있다. 디스크 기반 DBMS는 테이블과 인덱스 전체가
디스크에 존재한다. 다수쿠 DBMS는 특정 레코드가 필요한 경우 그 레코드가 포함된 데이터 페이지, 인덱스 페이지를 메모리에
올려 처리한다. 반면, 메모리 DBMS는 최초에 구동할 때 디스크에 존재하는 DB 전체를 메모리에 상주시킨다.
모든 레코드의 접근도 메모리에서 바로 이루어진다. 이 때 디스크는 백업 역할을 담당할 수 있으며, 데이터의 안정성을 위해 디스크에 존재하는 DB를 제3의 저장 장치로 백업할 수 있다.
<그림 1> 디스크 기반 DBMS와 메모리 DBMS의 데이터 처리 개념도
메모리 DBMS의 아키텍처는 크게 클라이언트-서버 구조, 응용-내장형 구조로 구분된다. 클라이언트-서버 구조는 DBMS 서버 모듈과 클라이언트 모듈을 분리된다.
클
라이언트 서버가 통신을 통해 데이터 및 처리 정보를 서로 주고 받는다. 이 구조는 클라이언트의 역할에 따라 다시
경량-클라이언트(light-weight client)와 중량-클라이언트(heavy-weight client)로 나눌 수 있다.
경량-클라이언트는 단순히 ODBC(Object Database Connection), JDBC(Java Database Connection) 등과 같은 응용 프로그래밍 인터페이스 라이브러리만을 제공한다.
중
량-클라이언트는 SQL 등의 질의어(query language) 처리 부분 중 파서(Parser) 또는 파서를 포함한 일부 실행
계획(execution plan)까지 포함하는 구조를 말한다. 클라이언트-서버 구조는 모듈의 독립성이 보장되어 유연성이 매우
뛰어나며, 자원을 적게 사용한다는 장점을 갖는다. 반면 응용-내장형 구조에 비해 성능이 떨어진다는 단점이 있다. 응용-내장형
구조는 DBMS의 서버 모듈과 API 모듈 전체가 응용 프로그램에 직접 연계(direct linking) 되는 구조로서 응용
프로그램과 DBMS 간에 통신이 없다. 이 구조는 통신 비용이 들지 않아 성능이 매우 뛰어나지만, 자원 사용이 커 동시 사용자
수가 제한적이다.
<그림 2> 클라이언트-서버 및 응용-내장형 구조 비교
<표 1> 클라이언트-서버 VS 응용-내장형 구조의 차이점
메모리 DBMS는 디스크 기반 DBMS와 마찬가지로 자료저장 관리기, 질의 처리기, 인터페이스, 유틸리티 등의 요소로 구성되어 있으나 제품별로 약간의 차이가 있을 수 있다.
클
라이언트-서버 구조와 응용-내장형 구조에서 각각의 요소들이 어떻게 구성되어 있는지 살펴보면 <그림 3>과 같다.
QPI(Query Processor Interface), MMI(Main Module Interface) 등은 응용-내장형
인터페이스이고, ODBC, JDBC, ESQL(Embedded SQL) 등은 클라이언트-서버용 인터페이스다. 질의 처리(query
processing)는 응용 프로그램으로부터 전달 받은 SQL문을 파싱하고 실행하는 모듈이다. 자료 관리(storage
management)는 메모리에 상주하는 DB를 실제로 관리한다.
세션 관리자(session manager)는 클라이언트의
연결 정보를 관리하는 모듈이며, 이중화 관리자(replication manager)는 DB를 서로 다른 컴퓨터 서버에 복제하기
위한 모듈이다. 이중화 기능에 관해서는 뒷부분에서 상세히 다루도록 한다. 메모리 DB는 DB 전체가 메모리에 상주하고, 성능
향상에 최우선 목표를 두고 있다.
적용 기술 또한 디스크 기반 DBMS의 그것과는 상당한 차이가 있다. 이제 소개하고자
하는 기술들은 메모리 DBMS에 적용된 DBMS 기술 중 일부로, 필자가 메모리 DBMS를 개발하는 과정에서 연구하거나 실제
적용한 기술들이다.
<그림 3> 메모리 DBMS의 구성 요소
메모리 관리 기술
데이터베이스를 메인 메모리에 상주시킨다고 하면 언뜻 메모리를 과다하게 사용할 것이라는 생각이 든다. 물론 메모리 DBMS가 데이터베이스를 위한 대용량의 메모리를 필요로 한다.
그러나 메모리의 효율적인 관리 여하에 따라 현격한 성능의 차이를 보일 수 있다.향상된 성능을 위해서는 메인 메모리에 최적화된 데이터베이스 구조의 설계 및 관리 방법의 적용이 필수다.
데이터베이스와 같은 시스템 소프트웨어는 단순히 메모리를 할당(malloc)하고 값을 지정(memset)하는 연산만으로도 성능에 큰 영향을 미칠 수 있다.
따
라서 메모리 풀을 이용한 메모리 관리 모듈을 자체적으로 설계하고 구현하는 것이 매우 바람직하다. 또한 메인 메모리에 최적화된 저장
단위로 데이터 페이지를 구성하고 각 페이지의 연계성을 극대화함으로써 데이터베이스를 효율적으로 저장하고 관리해야 한다. 질의
처리기는 질의 처리할 때 필요한 임시 공간(temporary storage)을 효율적으로 관리하기 위한 것이다.
실행 중 불필요한 메모리 자원의 할당과 반납에 따른 성능 저하 요소를 최소화할 수 있어야 한다. 실제 메모리 DB를 운영하다 보면 특정 테이블에 필요한 메모리 공간보다 더 많은 양의 메모리를 차지하는 경우가 있다.
이
는 대량의 데이터가 특정 테이블에 삽입된 후 변경 및 삭제가 빈번하게 이루어질 때 주로 발생한다. 해당 테이블에서 필요없는
메모리를 시스템으로 반환할 수 있다면 보다 효율적으로 메모리를 사용할 수 있다. 테이블 압축(table compaction)이라는
이 기술을 적용하면, 테이블 연산에 따른 메모리의 불필요한 메모리 낭비를 방지할 수 있다.
메인 메모리 내의 데이터베이스
공간은 영구 공간(persistent space)과 임시 공간(temporary space)으로 구분된다. 영구 공간은 실제
테이블과 메타 정보에 관한 데이터를 저장하고 있는데, 디스크에 존재하는 백업 데이터베이스 내용을 반영하고 있다. 임시 공간은 색인
데이터와 질의연산 중에 파생되는 임시 테이블들이 놓이는 장소다. 디스크에 위치한 백업 데이터베이스에는 반영되지 않고 DBMS
서버가 종료되면 사라지는 공간이다.
색인 데이터는 백업 데이터베이스에 저장되지 않기 때문에 DBMS 서버가 실행되는 초기에
시스템 카탈로그에서 색인 정보를 구하여 임시공간에 색인을 빠르게 생성한다. 색인을 백업 데이터베이스에 저장하지 않음으로써 서버
수행도중 색인 변경될 때 로깅할 필요가 없다. 그만큼 데이터베이스 성능을 향상시킬 수 있다는 장점을 갖는다.
동시성 제어 기술
동시성 제어 기법은 기존의 "열 단위 잠금(row locking)" 방식의 단점으로 지적돼 왔던 수정된
데이터(updating data)에 대해 장기간 동안 연산이 대기하는 문제점을 해결하는 기술이다. 읽기 연산을 대기하도록 하거나 또
이미 읽힌 데이터에 대한 수정 대기 시간을 줄인 것이다.
필자는 다중버전 기법(MVCC: Multi-Version Concurrency Control)을 이용한 동시성 제어 기법을 적용함으로써 위의 문제점을 해결했다.
더
이상 필요로 하지 않는 오래된 데이터를 즉시 회수함으로써 메모리의 낭비를 방지한다. 다중 버전 기법은 하나의 데이터에 대해 여러
개의 버전을 유지하여 읽기와 쓰기 연산에 대한 충돌을 없애 최대의 성능을 발휘할 수 있도록 한 것이다.
다중 버전 기법은 대량의 사용자가 접근하는 환경에서 최적의 성능을 발휘하도록 한다. 데이터베이스를 종료 하지 않고도 즉시 백업할 수 있는 "핫백업(hot-backup)" 시스템의 가능성도 지원한다.
그
러나 다중 버전 기법에서는 한 데이터에 대해 필요 없는 오래된 데이터가 생성될 수 있다. 따라서 "낭비 공간 수집
쓰레드(garbage collection thread)"를 두어 이러한 데이터에 대해 필요 없게 된 시점에 즉각적으로 메모리
공간을 회수한다. 재사용할 수 있도록 조치하는 것이다. 메모리 사용의 효율성을 극대화하는 기능이 반드시 수반되어야만 한다.
다중 사용자 처리 기술
데이터베이스에 대한 동시사용자 수는 데이터베이스의 특성 및 해당 시스템의 용량과 밀접한 관계를 가진다. 그러나 실제 시스템 용량이 늘어나는 만큼 데이터베이스가 지원하는 동시사용자 수가 정비례로 늘어나지 않는다.
이
는 데이터베이스가 지원하는 서비스 아키텍처가 이러한 시스템 자원에 관련된 문제와 직접적인 연관이 있다. 서비스 당 단일 프로세스를
생성하는 전통적인 구조에 의하면, 사용자 수만큼의 프로세스가 생성된다. 이처럼 자원 낭비가 극심한 상태에서는 대용량 사용자
지원의 해결책을 찾기가 쉽지 않다.
만일 한정된 프로세스로 대량의 사용자를 지원한다고 하더라도 자원을 사용자 간에 시간을 두고 서로 나누어 쓰는 것이기 때문에 근본적인 해결책이 될 수는 없다.
이
로 인해 현재 데이터베이스의 구조는 쓰레드 기반의 아키텍처로 옮겨가고 있는 추세다. 그러나 쓰레드 아키텍처 또한 구현 및 검증의
어려움을 가지고 있다. 특히 다중 프로세스 환경보다 우수한 쓰레드 기반의 시스템 확장성(system scalability)과
서비스 확장성(load scalability)를 보장해야 한다.
자칫 프로세스 구조의 데이터베이스 아키텍처보다 더 나쁜 수행 결과를 초래할 수도 있다.
이
러한 문제를 보완하기 위해서는 쓰레드 아키텍처를 기반으로 서비스 쓰레드 풀(pool) 및 서비스 세션 풀 두 단계의 구조적 기반을
제공하는 방법이 있다. 서비스 세션 풀은 클라이언트의 요청을 직접 담당하고 클라이언트에게 정보를 되돌려 주는 세션을 유지하는
것이다.
서비스 쓰레드 풀은 이러한 클라이언트의 서비스를 실제로 하위 모듈에서 수행(execution)하는 것이다. 서비스
세션 풀과 서비스 쓰레드 풀의 개수는 프로퍼티를 통해 해당 시스템의 부하에 맞게 적절한 값으로 선택할 수 있게 함으로써 필요
이상의 서버자원을 소모하지 않도록 해야 한다.
또한 클라이언트에 대한 빠른 응답을 보장하기 위해 일정 개수는 서버
쓰레드와의 1:1 연결을 통해 최대의 성능을 보장한다. 일정 개수 이상의 클라이언트가 접속될 경우에는 N:N의 연결로 자동
변환하여 서버의 자원을 효율적으로 사용할 수 있도록 해야 한다. 클라이언트-서버간의 혼합 서비스(hybrid
architecture) 방식이 요구되는 것이다.
질의 최적화 기술
사용자의 질의 처리할 때 비용 기반(cost-based)으로 최적화된 데이터 접근 경로를 계산하기 위한 비용은 상대적으로 적다. 또한 질의 변형(query transformation)을 비롯한 질의 최적화(query optimization) 알고리즘은 메모리 주소공간에 최적화된 기법이 적용된다. 이는 질의 최적화 시간을 최소화시키며, 실제 데이터 접근 속도를 향상시킴으로써 월등한 성능 상의 차이를 가져온다.
class="sub1"캐시 고려한 프로그래밍 작성
CPU가 데이터를 처리하기 위해서는 메모리로부터 연산자와 데이터를 읽어들여야 한다. 일반적으로 CPU의 성능은 매우 빠르게
향상하고 있는 반면 메모리의 성능은 더디게 향상되고 있다. 예를 들어 RISC 기반의 CPU는 1GHz인 반면 메모리의 접근
속도는 100MHz 정도이다.
<그림 4> CPU와 메모리의 성능 차이
이
CPU의 경우 이론상으로 1초에 약 10억 개의 연산이 가능하지만, 메모리의 접근으로 인해 10배 정도 CPU 성능이 저하되는
현상이 발생한다. 이러한 문제점 해결을 위해 대부분 CPU는 캐시(cache) 기능을 포함하고 있다.
그러나 이 캐시
조차도 성능을 고려해 L1 캐시, L2 캐시 등과 같이 여러 계층으로 설계하고 있다. 앞에서 예시한 CPU의 경우 L2 캐시를
도입하게 되면 캐시가 없는 경우보다 약 2배 정도의 성능 향상을 가져올 수 있다. 그만큼 메모리 접근 속도의 영향을 벗어나
CPU의 성능을 최대한으로 살릴 수 있게 되는 것이다.
결국 캐시 메모리를 채택한 CPU의 성능은 캐시 메모리의 크기와
캐시 계층을 얼마나 최적화 하느냐에 달려있다. 이는 CPU 종류마다 다르게 채택되고 있다. 이미 언급했던 것처럼, 메모리 DB
도입의 최우선 목표는 성능이다. 따라서 성능 향상을 위한 모든 수단을 도입할 필요가 있다. CPU 캐시를 고려한 프로그래밍도 고려
방법 중의 하나이다.
<그림 5> Cache 구조
여
기서는 캐시를 고려한 프로그램 작성 방법에 관하여 살펴 보도록 한다.한 연구 서적에 의하면, CPU의 사용 시간 50% 이상이
메모리 접근에 따른 대기 시간이라고 한다. 만일 캐시에 최적화된 프로그램을 작성할 수 있다면 20~30%의 성능을 향상시킬 수
있다.
그러나 각종 플랫폼별 고유의 캐시를 지원하고 있고 문맥교환(context switching)이 발생한 이후의 CPU
캐시는 이전의 캐시 패턴과는 무관할 가능성이 크다. 오히려 성능을 저해하는 요인을 제공하는 결과를 초래할 수 있다. 캐시를
고려한 프로그래밍에는 세심한 주의가 요구된다.
캐시를 프로그래밍이란 결국 캐시 미스(Cache Miss)를 줄이는 것이다. 이를 위해 먼저 캐시 시뮬레이터를 통해 통계적으로 대상 프로그램의 캐시 미스 영역을 찾은 후 병목 현상을 해결해야 한다.
시
스템이 최초로 데이터에 접근할 때 반드시 발생하는 필수 손실(Compulsory Miss)은 피하기가 어려우므로 해결 대상에서
제외한다. 또한 접근하려는 데이터가 캐시라인보다 클 경우에 발생하는 캐시 손실은 데이터 구조의 압축으로 해결할 수 있다.
마
지막으로 접근하는 두 개의 데이터가 동시에 동일한 캐시라인으로 수렴될 때, 준비된 캐시 웨이의 수가 부족하면 "충돌
손실(Conflict Miss)"이 발생한다. 충돌 손실은 어드레스를 서로 충돌하지 않게 변경함으로써 문제를 해결할 수 있다.
<그림 6> 메모리 DB 이중화 구성 모델
'About IT > 유용한 정보.' 카테고리의 다른 글
MTU Size (0) | 2016.05.17 |
---|---|
Reliable UDP (0) | 2016.05.16 |
Direct IO / Buffered IO (0) | 2015.06.02 |
퍼옴] 컴파일러 최적화의 장애물: 포인터 (0) | 2015.01.22 |
퍼옴] Lock free Algorithms for Ultimate Performance (0) | 2015.01.22 |