MongoDB 트랜잭션 성능
Source: Dev.to

많은 사람들은 MongoDB 트랜잭션이 느리다고 믿지만, 이 오해는 종종 낙관적 잠금을 오해해서 생깁니다 — 충돌이 발생하면 차단하는 대신 트랜잭션이 재시도하는 방식입니다. 따라서 느리게 느껴지는 것은 본질적인 오버헤드가 아니라 경쟁의 결과이며, 이는 내재된 지연이 아니라 **경합(contention)**에 따른 것입니다 (이전 글을 참고하세요).
MongoDB에서는 모든 데이터‑조작 작업이 스토리지‑엔진 수준에서 트랜잭션으로 처리됩니다. 단일‑문서 작업(삽입, 업데이트, 삭제)은 내부 스토리지 트랜잭션을 사용하며, 이는 WriteUnitOfWork와 RecoveryUnit 인터페이스를 통해 이루어지고, 각 문서 변경 및 해당 인덱스 항목에 대해 ACID 특성을 보장합니다.
MongoDB에서 트랜잭션이라는 용어는 특히 세션을 통해 여러 문서와 컬렉션에 걸쳐 원자성을 제공하는 다중‑문서 트랜잭션을 의미합니다. 이들의 성능은 단일‑문서 작업과 다르지만, 무조건 더 빠르거나 느리다고 말할 수는 없습니다.
ACID 특성
원자성
다중 문서 트랜잭션은 커밋되지 않은 변경 사항을 추적하고 작업 전반에 걸쳐 트랜잭션 상태를 유지하기 위해 추가 메모리를 사용합니다.
일관성
단일 문서와 다중 문서 작업 모두 쓰기 시점에 인덱스 업데이트와 스키마 검증을 강제합니다.
격리성
다중 문서 트랜잭션은 낙관적 동시성 제어를 사용한 스냅샷 격리 기능을 제공하며, 이로 인해 쓰기 충돌이 발생할 수 있습니다. 충돌이 발생하면 MongoDB는 TransientTransactionError를 반환합니다; 클라이언트는 이전 게시물에서 설명한 대로 재시도 로직과 지수 백오프를 사용해 이를 처리해야 합니다.
지속성
다중 문서 트랜잭션은 변경 사항을 더 적은 oplog 엔트리로 배치하여, 여러 단일 문서 작업을 개별적으로 실행하는 경우에 비해 지연 시간을 줄일 수 있습니다.
예시: 백만 개 문서 삽입
트랜잭션 없이
db.test.drop();
const start = new Date();
// Insert a million documents
const res = db.test.insertMany(
Array.from({ length: 1e6 }, (_, i) => ({
name: `user_${i}`,
value: Math.random(),
}))
);
// Show timing
const elapsed = new Date() - start;
print(`Elapsed: ${elapsed} ms`);
무료 MongoDB Atlas 클러스터에서 이 작업은 ≈ 53 025 ms가 소요됩니다. 단일 insertMany 호출이지만 ACID 속성은 문서별로 적용됩니다—각 문서는 자체 일관성 단위이므로 다른 세션이 작업이 완료되기 전에 일부 삽입된 문서를 볼 수 있습니다.
트랜잭션과 함께
db.test.drop();
// Start a transaction in a session
const se = db.getMongo().startSession();
const sessionDb = se.getDatabase(db.getName());
const start = new Date();
se.startTransaction();
// Insert a million documents
const res = sessionDb.test.insertMany(
Array.from({ length: 1e6 }, (_, i) => ({
name: `user_${i}`,
value: Math.random(),
}))
);
// Commit and show timing
se.commitTransaction();
const elapsed = new Date() - start;
print(`Elapsed: ${elapsed} ms`);
se.endSession();
같은 작업을 트랜잭션 안에서 실행하면 무료 Atlas 클러스터에서 ≈ 49 047 ms가 소요되어 약간 더 빠릅니다. 이는 기본 transactionLifetimeLimitSeconds인 60초에 근접합니다; 더 큰 작업이나 느린 클러스터에서는 이 제한에 걸리지 않도록 해당 파라미터를 조정해야 합니다. MongoDB는 짧은 트랜잭션을 사용하는 OLTP에 최적화되어 있어, 예측할 수 없는 시간 동안 기다리기보다 빠르게 실패하는 것을 선호합니다.
요점
- MongoDB는 여러 삽입을 하나의
applyOpsoplog 항목에 piggyback 할 수 있으며, WiredTiger는 로그 플러시를 배치하여 여러 트랜잭션이 하나의 디스크 동기화 를 공유할 수 있습니다. j: true및w: majority(기본값)와 함께 쓰기 시, MongoDB는 종종 복제 확인에 의존하여 내구성을 보장하면서 대기 없이 저널 플러시를 트리거합니다.- 트랜잭션 자체가 본질적으로 느린 것은 아니며, 성능은 경쟁, 샤드 배치, 트랜잭션 크기와 같은 요인에 따라 달라집니다. 원자성, 일관성, 격리성 및 내구성 요구 사항에 따라 트랜잭션을 사용하십시오.