문서 메뉴

문서 홈애플리케이션 개발MongoDB 매뉴얼

프로덕션 고려 사항

이 페이지의 내용

  • 가용성
  • 기능 호환성
  • 런타임 제한
  • Oplog 크기 제한
  • 와이어드타이거 캐시
  • 트랜잭션 및 보안
  • 샤드 구성 제한
  • 샤드 클러스터 및 중재자
  • 잠금 획득
  • 보류 중인 DDL 작업 및 트랜잭션
  • 진행 중인 트랜잭션 및 쓰기 충돌
  • 진행 중인 트랜잭션 및 오래된 읽기
  • 진행 중인 트랜잭션 및 청크 마이그레이션
  • 커밋 중 외부 읽기
  • 오류
  • 추가 정보

다음 페이지에서는 트랜잭션을 실행하기 위한 몇 가지 프로덕션 고려 사항을 소개합니다. 이는 트랜잭션을 복제본 세트 또는 샤드 클러스터에서 실행하든 상관없이 적용됩니다. 샤드 클러스터에서 트랜잭션을 실행하는 경우, 샤드 클러스터와 관련된 추가 고려 사항은 프로덕션 고려 사항(샤드 클러스터)을 참조하세요.

  • 버전 4.0에서 MongoDB는 복제본 세트에서 다중 문서 트랜잭션을 지원합니다.

  • 버전 4.2에서 MongoDB는 분된 트랜잭션을 도입하여 샤드 클러스터에서 다중 문서 트랜잭션에 대한 지원을 추가하고 복제본 세트에서 다중 문서 트랜잭션에 대한 기존 지원을 통합합니다.

    MongoDB 4.2 배포서버(복제본 세트 및 샤드 클러스터)에서 트랜잭션을 사용하려면 클라이언트는 MongoDB 4.2용으로 업데이트된 몽고DB 드라이버를 사용해야 합니다.

참고

분산 트랜잭션 및 다중 문서 트랜잭션

MongoDB 4.2부터는 이 두 용어가 동의어로 사용됩니다. 분산 트랜잭션은 샤딩된 클러스터 및 복제본 세트의 다중 문서 트랜잭션을 나타냅니다. 다중 문서 트랜잭션 (샤딩된 클러스터에서든 또는 복제본 세트에서든 관계 없이)은 MongoDB 4.2부터 분산 트랜잭션이라고 불립니다.

트랜잭션을 사용하려면 디플로이먼트의 모든 멤버에 대한 FeatureCompatibilityVersion이 최소한 다음과 같아야 합니다.

배포
최소 featureCompatibilityVersion
복제본 세트
4.0
샤딩된 클러스터
4.2

멤버의 fCV를 확인하려면 해당 멤버에 연결하고 다음 명령을 실행하세요.

db.adminCommand( { getParameter: 1, featureCompatibilityVersion: 1 } )

자세한 내용은 setFeatureCompatibilityVersion 도움말 페이지를 참조하세요.

기본적으로 트랜잭션의 런타임은 1분 미만이어야 합니다. mongod 인스턴스에 대해 transactionLifetimeLimitSeconds 을(를) 사용하여 이 제한을 수정할 수 있습니다. 샤딩된 클러스터의 경우 모든 샤드 복제본 세트 멤버에 대해 매개변수를 수정해야 합니다. 이 한도를 초과하는 거래는 만료된 것으로 간주되며 주기적인 정리 프로세스에 의해 중단됩니다.

샤드 클러스터의 경우 commitTransactionmaxTimeMS 제한을 지정할 수도 있습니다. 자세한 내용은 샤드 클러스터 트랜잭션 시간 제한을 참조하세요.

버전 4.2부터
MongoDB는 트랜잭션의 모든 쓰기 작업에 대해 단일 항목을 생성하는 대신, 트랜잭션의 모든 쓰기 작업을 캡슐화하는 데 필요한 만큼의 oplog 항목을 생성합니다. 이렇게 하면 모든 쓰기 작업에 대해 단일 oplog 항목에 의해 부과되는 트랜잭션의 총 16MB 크기 제한이 적용되지 않습니다. 총 크기 제한이 제거되어도 각 oplog 항목은 여전히 BSON 문서 크기 제한인 16MB 내에 있어야 합니다.
버전 4.0부터는
트랜잭션에 쓰기 작업이 포함된 경우, MongoDB는 커밋 시 단일 oplog(작업 로그) 항목을 생성합니다. 즉, 트랜잭션의 개별 작업에는 해당 oplog 항목이 없습니다. 대신 단일 oplog 항목에는 트랜잭션 내의 모든 쓰기 작업이 포함됩니다. 트랜잭션에 대한 oplog 항목은 BSON 문서 크기 제한인 16MB 이하여야 합니다.

스토리지 캐시 압력이 성능에 부정적인 영향을 미치는 것을 방지하려면 다음을 수행합니다.

  • 트랜잭션을 포기하려면 중단하십시오.

  • 트랜잭션의 개별 작업 중에 오류가 발생하면 트랜잭션을 중단하고 다시 시도하세요.

또한 transactionLifetimeLimitSeconds는 만료된 트랜잭션이 주기적으로 중단되도록 하여 저장소 캐시 압력을 완화합니다.

참고

커밋되지 않은 트랜잭션이 있어 WiredTiger 캐시에 과도한 부하가 생기는 경우 트랜잭션이 중단되고 쓰기 충돌 오류가 반환됩니다.

트랜잭션이 너무 커서 WiredTiger 캐시에 맞지 않으면 트랜잭션이 중단되고 TransactionTooLargeForCache 오류가 반환됩니다.

  • 액세스 제어를 사용하여 실행하는 경우 트랜잭션의 작업에 대한 권한이 있어야 합니다.

  • 감사와 함께 실행하는 경우 중단된 트랜잭션의 작업은 계속 감사됩니다. 그러나 트랜잭션이 중단되었음을 나타내는 감사 이벤트는 없습니다.

writeConcernMajorityJournalDefaultfalse로 설정된 샤드가 있는 샤딩된 클러스터에서는 트랜잭션을 실행할 수 없습니다. (예: 인메모리 스토리지 엔진을 사용하는 투표 멤버가 있는 샤드)

쓰기 작업이 여러 샤드에 걸쳐 있는 트랜잭션은 트랜잭션 작업 중 어떤 것이든 중재자가 포함된 샤드에서 읽거나 쓰는 경우 오류를 발생시키고 중단됩니다.

기본적으로 트랜잭션은 트랜잭션 작업에 필요한 잠금을 획득하기 위해 최대 5밀리초까지 대기합니다. 트랜잭션이 5밀리초 내에 필요한 잠금을 획득하지 못하면 트랜잭션이 중단됩니다.

트랜잭션은 중단 또는 커밋 시 모든 잠금을 해제합니다.

트랜잭션을 시작하기 직전에 컬렉션을 만들거나 삭제할 때 트랜잭션 내에서 컬렉션에 액세스하는 경우 쓰기 고려 "majority"가 있는 만들기 또는 삭제 작업을 실행하여 트랜잭션이 필요한 잠금을 획득할 수 있도록 하세요.

maxTransactionLockRequestTimeoutMillis 매개변수를 사용하여 트랜잭션이 잠금을 획득하기 위해 대기하는 시간을 조정할 수 있습니다. maxTransactionLockRequestTimeoutMillis늘리면 트랜잭션의 작업이 필요한 잠금을 획득하기 위해 지정된 시간 동안 대기할 수 있습니다. 이를 통해 빠르게 실행되는 메타데이터 작업과 같이 일시적인 동시 잠금 획득 시 트랜잭션이 중단되는 것을 방지할 수 있습니다. 그러나 이렇게 하면 교착 상태에 빠진 트랜잭션 작업의 중단이 지연될 수 있습니다.

maxTransactionLockRequestTimeoutMillis을(를) -1으로 설정하여 작업별 시간 제한을 사용할 수도 있습니다.

다중 문서 트랜잭션이 진행 중인 경우 동일한 데이터베이스 또는 컬렉션에 영향을 주는 새 DDL 작업이 트랜잭션 뒤에서 대기합니다. 이러한 보류 중인 DDL 작업이 있는 동안 보류 중인 DDL 작업과 동일한 데이터베이스 또는 컬렉션에 액세스하는 새 트랜잭션은 필요한 잠금을 얻을 수 없으며 maxTransactionLockRequestTimeoutMillis 대기 후 중단됩니다. 또한 동일한 데이터베이스 또는 컬렉션에 액세스하는 새로운 비트랜잭션 작업은 maxTimeMS 제한에 도달할 때까지 차단됩니다.

다음 시나리오를 고려하세요.

컬렉션 잠금이 필요한 DDL 작업

진행 중인 트랜잭션이 hr 데이터베이스의 employees 컬렉션에 대해 다양한 CRUD 작업을 수행하는 동안 관리자가 employees 컬렉션 에 대해db.collection.createIndex()DDL 작업을 실행합니다. createIndex() 컬렉션에 대한 배타적 컬렉션 잠금이 필요합니다.

진행 중인 트랜잭션이 완료될 때까지는 createIndex() 작업을 기다려야 잠금을 획득할 수 있습니다. employees collection에 영향을 미치고 createIndex()가 보류 중인 동안 시작되는 신규 트랜잭션의 경우, createIndex()가 완료될 때까지 기다려야 합니다.

보류 중인 createIndex() DDL 작업은 hr 데이터베이스의 다른 컬렉션에 대한 트랜잭션에 영향을 주지 않습니다. 예를 들어, hr 데이터베이스의 contractors 컬렉션에 대한 새 트랜잭션은 정상적으로 시작되고 완료될 수 있습니다.

데이터베이스 잠금이 필요한 DDL 작업

진행 중인 트랜잭션이 hr 데이터베이스의 employees 컬렉션에 대해 다양한 CRUD 작업을 수행하는 동안 관리자가 동일한 데이터베이스의 contractors 컬렉션에 대해 collMod DDL 작업을 실행합니다. collMod에는 상위 hr 데이터베이스의 데이터베이스 잠금이 필요합니다.

진행 중인 트랜잭션이 완료될 때까지 collMod 작업은 잠금을 얻기 위해 기다려야 합니다. hr 데이터베이스 또는 해당 컬렉션에 영향을 미치고 collMod 이(가) 보류 중인 동안 시작되는 모든 새 트랜잭션은 collMod이(가) 완료될 때까지 기다려야 합니다.

어느 시나리오에서든 DDL 작업이 maxTransactionLockRequestTimeoutMillis 이상 보류 상태로 남아 있으면 해당 작업 뒤에 대기 중인 트랜잭션이 중단됩니다. 즉, maxTransactionLockRequestTimeoutMillis 값은 최소한 진행 중인 트랜잭션과 보류 중인 DDL 작업을 완료하는 데 필요한 시간을 포함해야 합니다.

다음도 참조하세요.

  • 진행 중인 트랜잭션 및 쓰기 충돌

  • 진행 중인 트랜잭션 및 오래된 읽기

  • 데이터베이스를 잠그는 관리 명령어는 무엇인가요?

  • 컬렉션을 잠그는 관리 명령어는 무엇인가요?

트랜잭션이 진행 중이고 트랜잭션 외부의 쓰기가 나중에 트랜잭션의 작업이 수정하려고 하는 문서를 수정하는 경우, 쓰기 충돌로 인해 트랜잭션이 중단됩니다.

트랜잭션이 진행 중이고 문서 수정을 잠긴 경우 트랜잭션 외부에서 쓰기가 동일한 문서를 수정하려고 하면 트랜잭션이 종료될 때까지 쓰기가 대기합니다.

트랜잭션 내부의 읽기 작업은 오래된 데이터를 반환할 수 있으며, 이를 부실 읽기 라고 합니다. 트랜잭션 내부의 읽기 작업은 다른 커밋된 트랜잭션이나 비트랜잭션 쓰기에 의해 수행된 쓰기를 확인하는 것이 보장되지 않습니다. 예를 들어 다음 시퀀스를 가정해 보겠습니다.

  1. 트랜잭션이 진행 중입니다.

  2. 트랜잭션 외부에서 쓰기는 문서를 삭제합니다.

  3. 트랜잭션 내부의 읽기 작업은 쓰기 작업 이전의 스냅샷을 사용하므로 지금 삭제된 문서를 읽을 수 있습니다.

단일 문서에 대한 트랜잭션 내부의 오래된 읽기를 방지하려면 db.collection.findOneAndUpdate() 메서드를 사용할 수 있습니다. 다음 mongosh 예제에서는 db.collection.findOneAndUpdate() 를 사용하여 쓰기 잠금 을 설정하고 읽기를 최신 상태로 유지하는 방법을 보여 줍니다.

1
db.getSiblingDB("hr").employees.insertOne(
{ _id: 1, status: "Active" }
)
2
session = db.getMongo().startSession( { readPreference: { mode: "primary" } } )
3
session.startTransaction( { readConcern: { level: "snapshot" }, writeConcern: { w: "majority" } } )
employeesCollection = session.getDatabase("hr").employees
4
employeeDoc = employeesCollection.findOneAndUpdate(
{ _id: 1, status: "Active" },
{ $set: { lockId: ObjectId() } },
{ returnNewDocument: true }
)

트랜잭션 내에서 findOneAndUpdate 작업은 새 lockId 필드를 설정합니다. lockId 필드가 문서를 수정하는 한 원하는 값으로 설정할 수 있습니다. 문서를 업데이트하면 트랜잭션이 잠금을 획득합니다.

트랜잭션을 커밋하기 전에 트랜잭션 외부의 작업이 문서를 수정하려고 시도하면 MongoDB는 외부 작업에 쓰기 충돌 오류를 반환합니다.

5
session.commitTransaction()

트랜잭션을 커밋하면 MongoDB가 잠금을 해제합니다.

참고

트랜잭션의 작업이 실패하면 트랜잭션이 중단되고 트랜잭션의 모든 데이터 변경 사항이 컬렉션에 표시되지 않은 채 삭제됩니다.

청크 마이그레이션은 특정 단계에서 배타 (Exclusive) 컬렉션 락을 획득합니다.

진행 중인 트랜잭션에 컬렉션에 대한 락이 있고 해당 컬렉션을 포함하는 청크 마이그레이션이 시작되면 이러한 마이그레이션 단계는 트랜잭션이 컬렉션에 락을 해제할 때까지 기다려야 하므로 청크 마이그레이션 성능에 영향을 미칩니다.

청크 마이그레이션이 트랜잭션과 중첩되는 경우 (예를 들어 청크 마이그레이션이 이미 진행 중인 동안 트랜잭션이 시작되고, 컬렉션에 대한 락을 트랜잭션이 실행하기 전에 마이그레이션이 완료되는 경우), 트랜잭션은 커밋 시 오류가 발생하고 중단됩니다.

두 작업이 어떻게 교차하는지에 따라 샘플 오류에는 다음과 같습니다. (오류 메시지는 축약됨).

  • an error from cluster data placement change ... migration commit in progress for <namespace>

  • Cannot find shardId the chunk belonged to at cluster time ...

트랜잭션을 커밋하는 동안 외부 읽기 작업은 트랜잭션에 의해 수정될 동일한 문서를 읽으려고 할 수 있습니다. 트랜잭션이 여러 샤드에 쓰는 경우 샤드 전체에 걸쳐 커밋을 시도하는 동안 다음이 수행됩니다.

  • "snapshot" 또는 "linearizable" 읽기 우려 (read concern)를 사용하는 외부 읽기는 트랜잭션의 모든 쓰기가 표시될 때까지 기다립니다.

  • 인과적으로 일관적인 세션의 일부인 외부 읽기 (AfterClusterTime 포함하는 세션)는 트랜잭션의 모든 쓰기가 표시될 때까지 대기합니다.

  • 다른 읽기 고려 (read concern)를 사용하는 외부 읽기는 트랜잭션의 모든 쓰기가 표시될 때까지 기다리지 않고 대신 문서의 트랜잭션 이전 버전을 읽습니다.

MongoDB 4.2 배포서버(복제본 세트 및 샤드 클러스터)에서 트랜잭션을 사용하려면 클라이언트는 반드시 MongoDB 4.2용으로 업데이트된 MongoDB 드라이버를 사용해야 합니다

2} 인스턴스가 여러 개 있는 mongos 샤드 클러스터에서 MongoDB 4.2가 아닌 4.0용으로 업데이트된 드라이버로 트랜잭션을 수행하면 실패하고 다음과 같은 오류가 발생할 수 있습니다.

참고

드라이버에서 다른 오류를 반환할 수 있습니다. 자세한 내용은 드라이버 문서를 참조하세요.

오류 코드
오류 메시지
251
cannot continue txnId -1 for session ... with txnId 1
50940
cannot commit with no participants
← 드라이버 API