이 글은 kraken-confdb의 내부 구조를 다룬다. kraken-confdb를 단순히 사용하는데 관심이 있다면 위키의 http://krakenapps.org/wiki/KrakenConfDB 글을 참고하시기 바란다.
1. 서론
2005년부터 보안 솔루션 개발을 해오면서 가장 큰 고민거리는 설정과 정책을 관리할 때 어떤 접근 방식을 취할 것인가 하는 점이었다. 대부분의 경우 설정과 정책을 관리하는 방식은 관계형 데이터베이스 (RDBMS)나 파일 (XML, JSON 등) 둘 중 하나로 양분된다. 나는 이 두 가지 접근 방식이 모두 불만족스러웠다.
RDBMS는 멀티-티어 아키텍처를 구현하는 경우 일반적으로 사용되는 접근 방식이다. RDBMS를 사용하면 트랜잭션을 이용하여 원자성 (Atomicity), 일관성 (Consistency), 고립성 (Isolation), 지속성 (Durability)을 쉽게 구현할 수 있으므로, 다수의 프로세스나 스레드가 접근하더라도 별다른 고민할 필요없이 데이터를 처리할 수 있다. 그러나 RDBMS를 사용하려면 반드시 정규화를 해야 하고, 설정/정책이 복잡한 경우 원래 의도한 것보다 몇 배나 더 많은 엔터티가 발생하게 된다. 가령, 하나의 객체가 다수의 객체를 포함하는 경우 일 대 다 관계로서 일반적으로 2개의 테이블을 생성해야 한다. 데이터베이스가 안전하고 편리하기는 하지만 XML의 유연성에 비하면 모델이나 쿼리가 너무 복잡하다는 생각을 하게 된다. 비즈니스 데이터가 아닌 단순한 설정과 정책을 저장하는데 이렇게까지 하고 싶지는 않다. ORM이 많은 수작업을 대신해주지만 복잡도가 줄어드는 것은 아니다.
파일 접근 방식을 선택하는 경우에는 동시에 파일을 읽고 수정하는데 취약하다는 점을 피할 수 없다. 파일을 수정하고 있는데 전원이 나간다거나, 동시에 다른 프로세스가 접근하여 수정하면 파일이 깨질 확률이 높다. 여러분들이 오피스 문서를 작업할 때 주의깊게 보았다면 파일 손상을 막기 위해 반드시 임시 파일을 쓰고 이름을 바꿔치기 하는 것을 보았을 것이다. 그러나 다수의 동시 접근이 있을 때 이렇게 하기에는 곤란하다. 그렇다고 무조건 파일에 잠금을 걸고 읽고 쓰기엔 동시성이 매우 떨어질 것이다.
한편으로, 오랜 기간 개발하면서 대부분의 관리/운영 담당자가 인프라에서 핵심적인 네트워크 및 서버의 설정 실수를 두려워하며 주기적으로 설정 백업을 수행한다는 사실을 알게 되었다. 만약 우리가 개발할 때 일상적으로 사용하는 버전 컨트롤 시스템을 설정 관리하는데도 사용할 수 있다면 과거 설정 이력을 쉽게 조회할 수 있을 뿐만 아니라 설정을 실수하더라도 장애 발생 원인을 쉽게 파악하고 과거의 특정 시점으로 되돌릴 수 있게 될 것이다. 또한 HA 시스템에서 설정을 동기화 할 때에도 전체 설정을 전송하여 복제하는 대신, 설정 변경사항만을 전달하여 복제할 수 있다.
confdb는 RDBMS와 파일 양쪽 접근 방식의 장점만을 취하고 설정에 형상 관리를 도입함으로써 위에서 언급한 문제들을 해결한다.
2. confdb 파일 포맷
confdb는 mercurial의 설계를 참고하였다. mercurial의 내부에 대하여 궁금하다면 Towards a Better SCM: Revlog and Mercurial 논문을 참고하기 바란다. confdb는 로그 파일과 데이터 파일의 쌍으로 구성된 RevLog를 사용한다. 로그 파일은 오퍼레이션의 유형 (문서 생성, 문서 갱신, 문서 삭제, 컬렉션 생성, 컬렉션 삭제 중 하나)과 리비전, 문서의 ID와 데이터 파일에 기록된 위치 (파일 오프셋), 문서의 길이를 담은 34바이트짜리 레코드의 집합이다.
하나의 로그 레코드 레이아웃은 다음과 같다:
- 리비전 (8바이트)
- 이전 리비전 (8바이트) - 충돌 탐지 및 이후 브랜치 확장 대비
- 오퍼레이션 유형 (1바이트)
- 0 패딩 (1바이트)
- 문서 ID (4바이트)
- 문서 파일 오프셋 (8바이트)
- 문서 길이 (4바이트)
데이터 파일 레이아웃은 다음과 같다:
- 문서 길이 (4바이트)
- 옵션 (4바이트) - 향후 압축, 무결성 검증 등의 확장을 대비한 것
- 문서 본문 (가변 길이)
이렇게 로그 파일과 데이터 파일이 한 쌍으로 RevLog를 구성하는데, 이를 이용하여 컬렉션, 매니페스트, 변경로그를 구성한다. 컬렉션 RevLog는 단일 컬렉션에 다수의 문서들을 보관한다. 매니페스트는 ID, 다수의 CollectionEntry와 다수의 ConfigEntry로 구성되는데, 이를 통해 컬렉션의 메타데이터와 특정한 리비전의 문서에 대한 포인터를 관리한다. 마지막으로 변경로그는 리비전, 커밋 일시, 커미터, 커밋 로그, 매니페스트 ID, 그리고 해당 커밋에서 변경된 모든 컬렉션/문서에 대한 기록을 포함한다.
즉, 변경로그는 매니페스트의 ID를 참조하고, 매니페스트는 각 문서의 리비전을 참조하기 때문에, 특정한 리비전에서의 문서 집합을 바로 얻어낼 수 있다. 또한 전체적으로 RevLog의 자기복제적인 구조를 갖추고 있으므로 짧은 시간 안에 구현할 수 있다.
3. 동시성 제어
설정의 변경은 자주 일어나지 않지만, 읽기는 매우 빈번하게 발생한다. confdb는 파일 끝에만 데이터가 추가되는 append only 모델을 갖추고 있다. 쓰기가 발생할 때 컬렉션 데이터를 먼저 쓰고, 매니페스트, 변경로그 순으로 쓰기가 발생하기 때문에, 읽기 수행 시 별도로 잠금을 걸지 않더라도 불완전한 읽기를 방지할 수 있다. 쓰기를 수행할 때는 쓰기의 시작부터 끝까지 데이터베이스에 전역적인 파일잠금을 건다. 이를 통해 다른 프로세스가 동시에 쓰는 일이 없도록 방지한다.
4. 충돌의 탐지
일반적으로 뷰와 모델의 간극으로 인해 동시에 읽고 쓰기를 수행할 때, 동일한 리비전에 대해 다른 사람이 이미 수정한 데이터를 덮어쓰는 경우가 발생할 수 있다. confdb는 변경을 수행할 때 넘겨받은 이전 Config 개체의 리비전을 탐색하여 충돌이 발생했는지 탐지하고 예외를 발생시킬 수 있다. 이는 낙관적인 잠금 시나리오 구현에 유용하게 사용될 수 있다. 물론 충돌과 관계없이 덮어쓸 수 있도록 충돌 무시 옵션도 제공한다.
5. 트랜잭션의 구현
컬렉션 데이터와 매니페스트를 쓰더라도 마지막 순간에 변경로그를 기록하지 않으면 읽을 방법이 없어지기 때문에 트랜잭션 역시 간편하게 구현된다. 트랜잭션을 커밋하면 변경로그를 쓰고, 도중에 예외가 발생하거나 롤백을 호출하는 경우 변경로그를 쓰지 않는다.
6. 플래시백(회상)과 롤백
특정 시점의 변경로그를 선택하면, 변경로그에 연결된 매니페스트와, 매니페스트에 연결된 문서 리비전들을 통해 과거 시점의 문서 내용들을 들여다 볼 수 있다. 플래시백 모드에서는 수정이 불가능하다. 롤백은 변경로그를 새로 쓰면서 과거의 매니페스트 ID를 쓰는 방법으로 간단히 구현된다. 롤백하면 최신의 리비전이 과거의 매니페스트를 참조하는 것이므로 이후 수정도 가능하다.
7. 문서 인코딩과 리플렉션의 활용
문서는 RevLog 파일에서 바이트 배열로 저장되는데, confdb는 자바 객체 그래프를 크라켄 코덱을 이용하여 직렬화하고 저장한다. 크라켄 코덱은 ASN.1 DER과 유사한 인코딩 규칙으로 구성되어 있어서, 바이트 배열로 직렬화 된 상태에서도 자바 원시 타입을 보존할 수 있고 읽을 때도 원본 자바 객체 그래프를 그대로 추출할 수 있다. 크라켄 코덱은 위키 페이지 http://krakenapps.org/wiki/KrakenCodec를 참고하기 바란다.
크라켄 코덱이 자바 원시 타입과 기본적인 컬렉션 타입 (Map, List, Array 등)만을 지원하지만, confdb는 임의의 사용자 정의 타입 또한 리플렉션을 이용하여 원시 타입과 컬렉션 타입의 조합으로 자동 변환할 수 있는 기능을 갖추고 있다. 따라서 사용자는 confdb를 객체를 쉽게 저장하고 그대로 꺼낼 수 있는 객체 지향 데이터베이스로 사용할 수 있다.
8. 결론
kraken-confdb 라이브러리는 설정 형상 관리(configuration version control)를 지원하는 내장 가능한 경량 객체 지향 데이터베이스 (embeddable leightweight object-oriented database) 이다. 형상 관리는 코드 뿐 아니라 설정을 관리하는데도 유용한 개념이다. 무거운 데이터베이스를 사용하는 대신 confdb를 사용하면 객체 그래프를 쉽게 영속적으로 저장하고 원하는 시점에 따라 조회할 수 있다.
궁금한 점이 있다면 언제든지 메일(xeraph@nchovy.com)로 연락하시기 바란다.





최근 덧글