MVCC 아키텍처의 두 가지 흐름
상태바
MVCC 아키텍처의 두 가지 흐름
  • 데이터넷
  • 승인 2017.11.07 08:31
  • 댓글 0
이 기사를 공유합니다

다중 세대 아키텍처와 롤백 세그먼트로 DBMS 동시성 향상…RDBMS 혁신, 오라클이 주도

MVCC는 다중 버전 병행 수행 제어(MultiVersion Concurrency Control)의 약자로 DBMS에서는 쓰기(Write) 세션이 읽기(Read) 세션을 블로킹(blocking)하지 않고, 읽기 세션이 쓰기 세션을 블로킹하지 않게 서로 다른 세션이 동일 데이터에 접근했을 때 각 세션마다 스냅샷 이미지를 보장해주는 메커니즘이다. 이는 RDBMS에서 동시성을 높이기 위해 등장한 기술로, 소수의 전산실 운영자들이 서버 컴퓨터를 사용하던 시절에는 MVCC가 선택사항이었지만 인터넷이 보편화되고 온라인으로 업무를 처리하는 시대에서는 DBMS를 선택하는데 있어 MVCC가 가장 중요한 요소가 됐다. <편집자>

▲ (왼쪽부터) 엑셈 연구콘텐츠팀 권건우 상무, 이근오 부장, 김숙진 연구원, 이대덕 연구원

MVCC는 역사적으로 코드(E. F. Codd) 박사가 RDBMS를 처음 제안했을 때부터 존재했던 개념이 아니라 RDBMS가 구현되고 실용적으로 사용되면서 필요성이 생겨났고, 몇 사람의 천재들에 의해서 발전돼 왔다.

코드 박사는 1981년 튜링상을 수상하는 기념 강연에서 자신의 기념비적인 1970년 RDBMS 논문을 쓴 목적으로 ‘데이터의 독립성’, ‘구조적인 간결함’, 그리고 SQL 같은 ‘고급언어를 통한 집합 처리’의 세 가지를 말한 바 있다.

RDBMS의 시작

1974년 IBM은 이 논문에서 제시된 RDBMS를 구현하기 위해 파일럿 성격의 시스템 R(System R) 프로젝트를 시작했다. 이 프로젝트에서 레이몬드 보이스(Raymond F. Boyce)와 도널드 체임벌린(Donald D. Chamberlin)이 오늘날 RDBMS에서의 표준으로 자리 잡은 SQL의 초기 버전인 시퀄(SEQUEL: Structured English Query Language)을 만들었고, 후일 ‘Transaction Processing: Concepts and Techniques’의 저자이자 DBMS의 트랜잭션 이론을 완성한 짐 그레이(Jim Gray)가 이 프로젝트에서 ‘ACID’, ‘로킹(Locking)’, ‘리커버리(Recovery)’ 메커니즘 같은 트랜잭션 처리에 관한 다양한 이론을 정립하는 등 오늘날 RDBMS의 골격을 이루는 기초적인 연구가 이뤄졌다.

비슷한 시기에 IBM 산호세 연구소와 인접한 UC 버클리 대학에서는 마이클 스톤브레이커(Michael Stonebraker)와 그의 동료 및 제자들에 의해서 잉그레스(Ingres: Interactive Graphics and Retrieval System) 프로젝트가 시작돼 대학에서의 RDBMS 연구를 본격화했다.

1976년 암펙스(Ampex)에서 CIA 관련 프로젝트를 하고 있었던 밥 마이너(Bob Miner)와 에드 오츠(Ed Oates), 그리고 래리 엘리슨(Lally Ellison)은 코드 박사의 논문을 접한 후 직감적으로 RDBMS의 기술적인 혁신성과 상업적 성공을 확신하게 된다. 이후 이들은 SDL이라는 스타트업을 창업했고 오라클(Oracle) DBMS를 발표해 IBM과 사이베이스(Sybase)를 제치고 엄청난 성공을 거두게 된다.

동시 실행 제어 문제 발생 해결

그런데 코드 박사의 논문에 기반해 본격적인 RDBMS가 구현됨에 따라서 필연적으로 동시 실행 제어(Concurrency Control)의 문제가 발생하게 됐다. 코드 박사의 논문 제목처럼 RDBMS는 공유 데이터(Shared Data)를 다루기 때문에 동시에 다수 유저들이 동일한 데이터에 접근하는 상황이 발생하고, 이 문제를 효과적으로 컨트롤해야 되는 문제가 발생하게 된다. 기존에는 로킹(Locking)을 통한 상호배제를 통해 이 문제를 해결해 왔는데, 이는 필연적으로 대기현상이 발생할 수밖에 없어서 DBMS의 동시성을 낮추는 결과를 초래했다.

1970년대 후반 MIT에서 박사학위를 하고 있었던 데이비드 리드(David P. Reed)는 이러한 상호배제를 통한 낮은 동시성 문제를 해결하기 위해 그의 박사논문에서 새로운 제안을 했다. 어떤 데이터에 여러 차례 수정이 가해졌다고 가정할 때 수정이 가해진 각 시점의 개별 버전을 모두 저장하고, 데이터 객체는 이러한 개별 버전들의 연속체로서 정의함으로써 읽기와 쓰기 간의 경합을 최소화할 수 있다는 아이디어를 제시한 것이다.

1981년 필립 번스타인(Philip A. Bernstein)과 네이선 굿맨(Nathan Goodman)은 리드의 박사학위 논문을 인용해 다중 버전 병행 수행 제어(MVCC)라는 용어를 처음 사용했고, 이 개념을 더욱 명확히 했다. 또한 1984년 DEC의 짐 스타키(Jim Starkey)는 Rdb/ELN을 개발하면서 처음으로 MVCC 개념을 구현했고, 자신의 회사를 창업해 인터베이스(Interbase) DB를 개발하면서 상용 DBMS에서 처음으로 MVCC를 성공적으로 구현했다.

이후 오라클을 비롯해서 포스트그레SQL(PostgreSQL), 파이어버드(Firebird) 등 MVCC를 지원하는 DBMS가 등장했고, 2002년에는 ‘Pessimistic Lock’을 사용하는 IBM DB2 UDB V7.2와 언두 세그먼트(Undo segment)를 사용해 MVCC를 구현하는 오라클 9i 간에 MVCC의 기술적 효용성에 대한 논쟁이 있었지만, 지금은 대부분의 상용 DBMS가 MVCC를 지원하고 있다. 이번 글에서는 이처럼 DBMS의 가장 중요한 기능으로 자리 잡은 MVCC의 흐름을 정리해보고자 한다.

첫 번째 흐름 ‘MGA’

1980년 초에 DEC의 짐 스타키는 Rdb/ELN 이라는 제품에 처음으로 MVCC 아키텍처를 도입한다. 이후 짐 스타키는 자신의 회사를 설립해 인터베이스 DB를 개발했으며, 이에서 발전시킨 MVCC 메커니즘을 다중 세대 아키텍처(MGA: Multi Generation Architecture)라 한다.

1999년 바딤(Vadim)은 MGA 아키텍처를 채택해 포스트그레SQL 6.5에 MVCC를 처음 도입했다. 2000년에는 인터베이스 6.0이 오픈소스로 공개됐고, 소스포지(SourceForge) 커뮤니티에서 오픈소스 DBMS 프로젝트로 인터베이스 DB 기반의 파이어버드 DB를 만들었다.

이처럼 짐 스타키가 인터베이스에 구현한 다중 세대 병행 제어(Multi Generation Concurrency Control)는 이후 많은 DBMS에 영향을 줬고, MVCC의 큰 흐름을 이뤘다. 2016년 짐 스타키는 언론 인터뷰에서 자신의 기술 커리어 중 가장 크게 기여한 것은 MGA를 만들어서 DBMS의 동시성을 높인 것이라고 말한 바 있다.

MGA에서는 튜플(Tuple)을 업데이트 할 때 새로운 값으로 변경(Replace)하는 것이 아니라 동일한 데이터 페이지 내에서 새로운 튜플을 추가하고, 이전 튜플은 유효 범위를 마킹해 처리한다.

예를 들어 포스트그레SQL의 MGA를 간략히 살펴보자. <그림 1>의 왼쪽 표에서 보는 것처럼 XMIN에 XID 10이 세팅돼 있고, XMAX에는 아직 세팅된 값이 없을 때 튜플1, 튜플2, 튜플3은 XID 10부터 현재 XID까지 유효한 액티브 튜플이다.

XID가 30일때 업데이트문을 실행하면 오른쪽 표와 같이 나타난다. 기존 튜플2의 XMAX에 XID 30을 세팅해 튜플2의 이전 버전임을 표시하고, 새로운 튜플2를 추가해 XMIN 값을 세팅한다. 튜플2의 이전 버전은 XMIN 10, XMAX 30에 의해서 XID 10부터 XID 30 사이의 범위에서 가시적인 값이고, 새로운 튜플2는 XID 30부터 현재까지 가시적인 액티브 튜플이다.

▲ 포스트그레SQL의 MVC

이러한 MGA가 페이지 내부에서 구체적으로 어떻게 동작하며 서로 다른 세션끼리 어떻게 스냅샷 이미지(snapshot image)를 선택(SELECT)하는지 <그림 2>의 처리 과정을 통해 알아보자. 먼저 T0 시점은 XID 10, T1 시점은 XID 20, T2 시점은 XID 30, T3 시점은 XID 40이라고 가정하자.

▲ 포스트그레SQL 데이터 페이지의 스테이지1

<그림 2>은 T1 시점일 때, 세션 1에서 셀렉트(SELECT)문을 실행하면 XID가 20 이전인 튜플1, 튜플2, 튜플3이 읽히는 것을 보여준다.

▲ 포스트그레SQL 데이터 페이지의 스테이지2

<그림 3>은 T2 시점일 때, 튜플2를 업데이트하면 데이터 페이지에서 값을 변경하는 것이 아니라 새로운 튜플을 추가하고 오래된 튜플은 XMAX에 유효한 XID 범위 값을 세팅한다는 것을 알 수 있다.

▲ 포스트그레SQL 데이터 페이지의 스테이지3

<그림 4>는 T1 시점일 때, 오픈된 세션1에서 선택하면 튜플1, 이전 튜플2, 튜플3이 반환되고, T3 시점일 때, 오픈된 세션3에서 선택하면 튜플1, 새로운 튜플2, 튜플3이 반환되는 것을 볼 수 있다.

두 번째 흐름 ‘롤벡 세그먼트’

1980년대 후반 오라클의 밥 마이너는 롤백 세그먼트를 도입해 MVCC를 구현했는데, 이는 당시 획기적인 방법이었다. 롤백 세그먼트 메커니즘에서는 업데이트문이 실행되면 기존 데이터 블록 내의 데이터 레코드를 새로운 버전(New Version)으로 변경하고, 이전 버전(Old Version)을 별도의 저장소인 롤백 세그먼트에 보관한다.

이후 셀렉트문이 실행될 때, 셀렉트 SCN과 데이터 블록의 SCN을 비교해 읽기 일관성(Consistent Read)이 필요하다고 판단되면 롤백 세그먼트의 이전 버전을 읽어서 버퍼 캐시에 CR블록을 생성한다. 셀렉트 쿼리의 스냅샷 읽기를 보장해주는 이 방법은 유명한 ‘ORA-1555(Snapshot too old)’ 에러라는 한계를 제외하고는 동시성을 극대화시키는 최고의 방법이었다.

오라클은 롤백 세그먼트를 통해 Read Committed 격리 수준(Isolation Level)에서 거의 완벽한 MVCC를 구현함으로써 90년대 이후에 벌어지는 DBMS 경쟁에서 선두를 점하게 된다. 특히 많은 사용자들이 동시에 접속하는 온라인 시스템과 인터넷 서비스 환경에서 강력한 경쟁력을 보유하게 된다.

오라클의 MVCC 아키텍처는 2000년대 초반에 ‘Pessimistic Lock’을 이용해 동시성을 높이는 기술을 가진 IBM DB2 UDB와의 경쟁에서 실질적인 우위를 점함으로써 이후에는 RDBMS가 구현해야 하는 중요한 핵심 아키텍처로 자리 잡게 됐다.

▲ 오라클의 롤백 세그먼트 개요

<그림 5>를 통해 오라클의 롤백 세그먼트 동작원리를 알 수 있다. 데이터 블록에 있는 현재 버전인 A를 B로 업데이트하게 되면 이전 버전인 A를 별도의 롤백 블록에 저장하고, 데이터 블록에는 새로운 버전인 B로 변경하게 된다. 첫 번째 아키텍처인 MGA 아키텍처와는 달리 이전 버전을 별도의 저장 공간인 롤백 세그먼트에 저장하고 데이터 블록에는 오직 현재 버전만 존재하는 것이다.

▲ 오라클의 MVCC 개요

롤백 세그먼트를 사용하는 아키텍처는 <그림 6>처럼 셀렉트 시점에 SCN을 비교해서 읽기 일관성을 위해서 롤백 세그먼트에 존재하는 해당 이전 버전을 찾아서 버퍼 캐시에 CR 블록을 생성한다. 이렇게 CR 블록을 생성함으로써 셀렉트 시점의 스냅샷 이미지를 읽을 수 있다.

1990년대 중반 핀란드의 헤이키 튜리(Heikki Tuuri)에 의해서 개발된 이노(Inno)DB는 별도의 롤백 세그먼트에 이전 버전을 저장하므로 두 번째 흐름에 속한다고 볼 수 있다. 하지만 트랜잭션을 처리하는 ID나 리드뷰(Readview) 등은 오히려 첫 번째 흐름과 유사성을 띤다.



댓글삭제
삭제한 댓글은 다시 복구할 수 없습니다.
그래도 삭제하시겠습니까?
댓글 0
댓글쓰기
계정을 선택하시면 로그인·계정인증을 통해
댓글을 남기실 수 있습니다.