실시간 애플리케이션과 사물인터넷(IoT) 디바이스의 사용은 물론 비정형 데이터 자산의 기하급수적 증가로 인해 조직들이 NoSQL 데이터베이스로 전환하는 추세가 점점 더 확산되고 있습니다. 실제로 NoSQL 시장은 2024년부터 2032년까지 24.9%의 성장률(CAGR)을 보이며 2032년까지 미화 745억 달러에 이를 것으로 예상됩니다(IMARC group, 2024).
대규모의 다양한 데이터 세트와 이와 관련된 빅데이터 분석을 효과적으로 관리할 수 있는 NoSQL 데이터베이스 관리 시스템(DBMS)의 기능을 고려할 때 이러한 성장은 놀라운 일이 아닙니다. 그러나 많은 사람들은 여전히 많은 조직의 핵심 요구 사항인 ACID 트랜잭션 관리 및 컴플라이언스를 NoSQL DBMS가 해결하지 못한다고 생각합니다. 좋은 소식은 일부 NoSQL DBMS는 확실히 가능하다는 것입니다!
이 아티클에서는 ACID 트랜잭션이 무엇인지, ACID 트랜잭션 속성, 이러한 트랜잭션이 중요한 이유, NoSQL DBMS의 ACID 트랜잭션 예시를 다뤄보겠습니다.
목차
가장 기본적인 수준에서 데이터베이스 트랜잭션은 DBMS 정의(예: 정의된 트랜잭션 기준)에 따라 성공적으로 완료된 데이터베이스 읽기 및 쓰기 작업 그룹입니다. 트랜잭션에는 두 가지 주요 유형이 있습니다.
단일 트랜잭션: 단일 트랜잭션은 연속적인 하나 이상의 데이터베이스 작업을 의미하며, 하나의 동작으로 끝나고 성공적으로 완료됩니다. 완료되면 트랜잭션이 수락되어 트랜잭션 로그에서 찾을 수 있습니다. 단일 트랜잭션의 일반적인 예로 ATM에서 돈을 인출하는 경우를 들 수 있습니다.
다중 트랜잭션: 분산 트랜잭션이라고도 하는 다중 트랜잭션은 서로 다른 데이터베이스 및 시스템(예: 분산 시스템)에 분산된 상호 의존적인 여러 트랜잭션으로 구성됩니다. 이러한 트랜잭션의 기록은 트랜잭션 로그에서도 찾을 수 있습니다. 이러한 트랜잭션의 예로는 한 계좌에서 다른 계좌로 돈을 이체하거나 고용주가 신입 직원에게 사진이 있는 보안 배지를 발급하는 경우를 들 수 있습니다.
일부 트랜잭션은 데이터 무결성(예: 데이터가 완전하고 정확함) 및 데이터 일관성(예: 값이 모든 테이블/데이터베이스에서 동일함)에 대한 엄격한 표준을 준수해야 한다는 점에 유의해야 합니다. 이는 수탁자 책임 또는 규정 컴플라이언스가 관련된 경우가 많습니다. 상업 은행, 투자 중개, 법적 합의 등을 예로 들 수 있습니다. 이러한 상황에서는 DBMS 정의에 대한 표준 준수만으로는 충분하지 않으며 ACID 트랜잭션이 필요합니다.
ACID는 원자성(Atomicity), 일관성(Consistency), 격리성(Isolation), 영속성(Durability)을 가리키는 약자입니다. ACID 속성은 예기치 않은 오류가 발생하더라도 일련의 데이터베이스 작업(트랜잭션으로 그룹화됨)이 데이터베이스를 유효한 상태로 유지하도록 보장합니다. 또한 ACID 트랜잭션은 여러 규제 기관에서 요구하는 수준의 트랜잭션 보장을 제공합니다.
다음은 각 ACID 트랜잭션 요소에 대한 일반적인 개요와 NoSQL 문서 데이터베이스가 해당 ACID 요소를 처리하는 방법에 대한 설명입니다. 이 아티클의 목적을 위해 MongoDB Atlas가 사용됩니다.
원자성은 트랜잭션을 구성하는 모든 명령이 하나의 단위로 취급되어 함께 성공하거나 실패하도록 보장합니다. 이는 시스템 장애 또는 정전 시 트랜잭션이 완전히 처리되지 않으면 삭제되어 데이터베이스가 데이터 무결성을 유지한다는 점에서 중요합니다.
MongoDB에서 쓰기 작업은 단일 문서 내에 내장된 여러 문서를 수정하는 경우에도 단일 문서 수준에서 원자적으로 이루어집니다. 여러 문서(단일 컬렉션 또는 여러 컬렉션)에 대한 읽기 및 쓰기의 원자성이 필요한 상황의 경우, MongoDB는 복제본 세트 및 샤딩된 클러스터에서의 트랜잭션을 포함한 분산 트랜잭션을 지원합니다.
일관성은 트랜잭션 내에서 이루어진 변경 사항이 데이터베이스 시스템(예: 노드) 전체에 걸쳐 DBMS 제약 조건에 맞게 채워지도록 보장합니다. 데이터 일관성이 일관되지 않은 상태의 트랜잭션으로 인해 부정적인 영향을 받게 되면 전체 트랜잭션이 실패하게 됩니다.
MongoDB가 일관성을 처리하는 방법:MongoDB는 데이터를 정규화하거나 복제하여 애플리케이션을 최적화할 수 있는 유연성을 제공합니다. 스키마에서 데이터가 복제되는 경우 개발자가 여러 컬렉션에서 복제된 데이터를 일관되게 유지할 방법을 결정해야 합니다. 일부 애플리케이션은 중복된 데이터를 즉시 일관되게 만들어야 하는 반면, 다른 애플리케이션은 오래된 데이터 읽기를 용인할 수 있습니다. 예시는 아래에서 확인할 수 있습니다.
참고: 데이터 일관성] 자세히 알아보기.
각 트랜잭션은 데이터 충돌을 방지하기 위해 다른 트랜잭션과 격리됩니다. 이는 또한 다중 항목 및 다중 레벨 트랜잭션 관리와 관련된 데이터베이스 운영에도 도움이 됩니다. 예를 들어, 두 명의 사용자가 동일한 데이터(또는 동일한 트랜잭션)를 수정하려고 하는 경우 DBMS는 잠금 관리자라는 메커니즘을 사용하여 첫 번째 사용자의 변경 작업이 완료될 때까지 다른 사용자를 일시 중단합니다.
MongoDB는 스냅샷 격리라는 기술을 사용합니다(예: 각 트랜잭션은 트랜잭션 시작 시 생성된 데이터베이스의 개인 스냅샷에서 작동하는 것처럼 보입니다). 트랜잭션은 트랜잭션이 시작될 때 커밋된 데이터의 '스냅샷'에서 데이터를 읽을 수 있으며 충돌하는 업데이트가 발생하면 트랜잭션이 중단됩니다.
또한 MongoDB 트랜잭션은 트랜잭션 수준 읽기 고려(read concern) 트랜잭션 수준 쓰기 고려(write concern)를 지원합니다. 클라이언트는 적절한 수준의 읽기 고려(read concern) 및 쓰기 고려(write concern)를 설정할 수 있는데, 가장 엄격한 수준은 스냅샷 읽기 고려(read concern)와 과반수 쓰기 고려(write concern)를 결합한 것입니다. 과반수 쓰기 고려(write concern)는 쓰기 작업이 데이터 보유 노드의 계산된 과반수에 내구성 있게 커밋되었음을 의미합니다(개발자가 설정할 수 있음).
영속성은 트랜잭션이 완료되고 변경 사항이 데이터베이스에 기록되면 해당 변경 사항이 유지되도록 보장합니다. 이렇게 하면 충돌이나 정전과 같은 시스템 장애가 발생하더라도 시스템 내의 데이터가 유지됩니다. 영속성 개념은 데이터 신뢰성의 핵심 요소입니다.
MongoDB는 각 '쓰기'마다 변경된 디스크 위치와 바이트가 포함된 OpLog를 생성합니다. 트랜잭션 쓰기 중에 예상치 못한 이벤트(예: 정전)가 발생하는 경우 시스템이 다시 시작될 때 OpLog를 사용하여 종료 전에 디스크에 플러시되지 않은 모든 쓰기를 재실행할 수 있습니다. 또한 OpLog에 기록되기 전에 작업이 변경되므로, 작업은 멱등적이며 여러 번 재시도할 수 있습니다. 트랜잭션, 즉 '쓰기'는 기본적으로 약 60초마다 디스크로 플러시됩니다.
ACID 트랜잭션은 데이터 무결성과 신뢰성을 유지하는 동시에 정부 또는 업계 규제의 대상이 되는 중요한 데이터(예: 은행 계좌, 주식 포트폴리오)가 필수 표준을 충족하도록 보장합니다. 또한 분산 데이터베이스 시스템에서 데이터 복제를 구현하고 고가용성을 달성하기 위해서는 ACID compliance가 전제 조건인 경우가 많습니다.
다음은 NoSQL 문서 데이터베이스인 MongoDB Atlas를 사용하여, ACID 다중 문서 트랜잭션이 처리되는 방식과 ACID 트랜잭션이 최소 ACID 속성 표준에 일치함을 보장하는 방법에 대한 예시입니다.
각 계좌가 별도의 기록인 한 은행 계좌에서 다른 계좌로 돈을 이체하는 기능을 만든다고 가정해 보세요. 출처 계정에서 돈이 성공적으로 인출되었지만 대상 계정으로 입금되지 않았다면 심각한 회계 문제가 발생한 것입니다. 반대로 대상 계정에 입금되었으나 출처 계정에서 차감되지 않는다면 또 다른 심각한 회계 문제가 발생합니다.
다이어그램은 ACID 속성이 한 은행 계좌에서 다른 은행 계좌로 자금을 이체하는 흐름에 어떤 영향을 미치는지 보여줍니다.
시스템과 데이터의 일관성을 유지하려면 이 두 가지 쓰기 작업이 모두 발생하거나 둘 다 발생하지 않아야 합니다. 즉, 트랜잭션의 명령이 실패하면 데이터베이스는 트랜잭션 과정에서 기록한 모든 변경 사항을 롤백(예: 실행 취소)해야 합니다.
참고: 자세한 내용은 Node.js 빠른 시작 GitHub 리포지토리를 방문하여 전체 코드 샘플 사본을 받아서 직접 실행해보세요.
분산된 시스템에서 다중 문서 트랜잭션을 처리할 때는 리소스 제약 조건과 성능 목표에 영향을 줄 수 있는 성능 오버헤드 영향이 있다는 점을 기억하세요. 또한 데이터베이스는 동시 쓰기가 서로 간섭하지 않도록 관련 리소스를 '잠금'해야 하기 때문에(예: 트랜잭션 실패), 데이터를 쓰려는 다른 클라이언트는 트랜잭션이 완료될 때까지 기다려야 할 수도 있는데, 이에 따라 애플리케이션 지연 시간과 사용자 경험에 영향을 미칠 수 있습니다.
MongoDB의 문서 모델을 사용하면 관련 데이터를 하나의 문서에 함께 저장할 수 있습니다. 문서 모델은 원자적 문서 업데이트와 결합되어 대부분의 사용 사례에서 트랜잭션이 필요 없게 됩니다. 그럼에도 불구하고, 진정한 다중 문서, 다중 컬렉션 MongoDB 트랜잭션이 가장 좋은 선택인 경우도 있습니다.
MongoDB 트랜잭션은 다른 데이터베이스의 트랜잭션과 유사하게 작동합니다. 트랜잭션을 사용하려면 드라이버를 통해 MongoDB 세션을 시작합니다. 그런 다음 해당 세션을 사용하여 데이터베이스 작업 그룹을 실행합니다. 여러 문서, 컬렉션, 샤드에서 어떤 CRUD(생성, 읽기, 업데이트, 삭제) 작업도 실행할 수 있습니다.
트랜잭션을 구현하는 방법에 대한 구체적인 코드 샘플은 MongoDB 개발자 센터의 빠른 시작을 참조하세요:
MongoDB 드라이버 문서에서 MongoDB에서 공식적으로 지원하는 각 언어에 대한 언어별 가이드를 확인하세요. 트랜잭션 권장사항 및 프로덕션 고려 사항 목록도 확인할 수 있습니다.
트랜잭션이 필요한 애플리케이션에는 일반적으로 서로 다른 당사자 간에 값이 교환되는 사용 사례가 있습니다. 일반적으로 'SoR(System of Record)' 또는 'LoB(Line of Business)' 애플리케이션이 이에 해당합니다.
다중 문서 트랜잭션의 이점을 누릴 수 있는 애플리케이션의 예는 다음과 같습니다.
한 계좌에서 다른 계좌로 자금을 이동하는 시스템(예: 뱅킹 애플리케이션, 결제 처리 시스템, 거래 플랫폼).
상품과 서비스의 소유권이 한 당사자에서 다른 당사자로 이전되는 공급망 및 예약 시스템.
요약 기록뿐만 아니라 상세 기록에도 정보를 저장하는 청구 시스템.
일반적으로 함께 액세스한 데이터가 함께 저장되도록 데이터를 모델링하는 것이 좋습니다. 이러한 방식으로 데이터를 모델링하면 더 나은 성능을 달성할 수 있을 뿐만 아니라 트랜잭션도 필요하지 않습니다.
트랜잭션이 필요한 애플리케이션의 경우 다음 권장사항을 준수하세요.
장기 실행 트랜잭션을 작은 단위로 나눕니다. 그래야 기본 60초 제한 시간을 초과하지 않습니다. (이 시간 제한은 연장될 수 있습니다.) 트랜잭션의 작업이 인덱스를 사용하여 빠르게 실행되도록 합니다.
각 트랜잭션의 문서 수정을 1,000건으로 제한합니다.
적절한 읽기 및 쓰기 고려가 구성되었는지 확인합니다.(MongoDB는 버전 5.0부터 필수 과반수 쓰기 고려(write concern)를 기본값으로 사용합니다).
적절한 오류 처리를 추가하고 일시적인 오류로 인해 실패한 트랜잭션을 다시 시도합니다.
여러 샤드에 영향을 미치는 트랜잭션의 성능 비용에 유념합니다. 이러한 권장사항에 대한 자세한 내용은 MongoDB의 다중 문서 ACID 트랜잭션 백서와 트랜잭션에 대한 MongoDB 문서를 참조하세요.
자세히 알아볼 준비가 되셨나요? MongoDB Atlas는 MongoDB의 완전 관리형 서비스형 데이터베이스이며, MongoDB를 가장 쉽게 사용할 수 있는 방법입니다. 무료 MongoDB Atlas 클러스터를 만들어서 트랜잭션을 시작하세요.