(몽고DB 완벽 가이드) Chapter 8. 트랜잭션

이재문·2023년 11월 27일

트랜잭션은 논리적 처리 그룹

각 그룹과 트랜잭션은 여러 도큐먼트의 읽기, 쓰기 같은 작업을 하나 이상 포함

몽고DB는 컬렉션, 데이터베이스, 도큐먼트 및 샤드에서 ACID 트랜잭션을 지원한다.

8.1 트랜잭션 소개

  • 애플리케이션에서 논리적 처리 단위의 일부로 여러 도큐먼트에 대한 읽기와 쓰기를 요구하는 상황이 생길 수 있다.
  • 성공하든 실패하든 부분적으로 완료되지 않는다는 점

8.1.1 ACID의 정의

  • 트랜잭션이 되려면 ACID 속성을 충족해야 한다.

  • ACID

    • 원자성 (Atomicity)
      • 트랜잭션 내 모든 작업이 적용되거나 아무 작업이 되지 않도록 한다.
      • 부분적으로 적용될 수 없다.
    • 일관성 (Consistency)
      • 트랜잭션에 성공하면 DB가 일관성 있는 상태에서 다음 일관성 있는 상태로 이동해야 한다.
    • 고립성 (Isolation)
      • 여러 트랜잭션이 DB에서 동시에 실행되도록 허용
      • 트랜잭션이 다른 트랜잭션의 부분 결과를 보지 않도록 해야함
      • 병렬 트랜잭션이 각 트랜잭션을 순차적으로 실행할 때와 동일한 결과를 얻는다.
    • 영속성 (Durability)
      • 트랜잭션이 커밋될 때 시스템오류가 발생하더라도 모든 데이터가 유지되어야 한다.
  • mongoDB는 복제 셋과 샤드 전체에 ACID호환 트랜잭션이 있는 분산 데이터베이스이다.

8.2 트랜잭션 사용법

  • 트랜잭션을 사용하기 위한 API를 두가지 제공
  • 코어 API (Core API)
    • 관계형DB와 유사한 (start_transaction, commit_transaction)

    • 대부분의 오류에서 재시도 로직을 제공하지 X

    • 트랜잭션을 시작하고, 커밋하려면 명시적인 호출이 필요하다.
      - 개발자가 작업에 대한 로직, 트랜잭션 커밋 함수, 필요한 재시도 및 오류 로직을 모두 작성

      # 1. 트랜잭션 내에서 작업과 순서를 정의
      def update_orders_and_inventory(my_session):
      	
      	with session.start_transaction(
      			read_concern=ReadConcern("abc"),
      			write_concern=WriteConcern("abc")
      			read_perference=ReadPreference.PRIMARY):
      
      			order.insert_one
      			inventory.update_one
      			
      commit_with_retry()
      
      # 2. 재시도 논리를 사용하여 트랜잭션 실행 및 커밋을 시도
      def commit_with_retry(session):
      	while True:
      		try:
      			session.commit_transaction()
      			break
      
      		except :
      			# 트랜잭션 재시도
      
      # 3. 재시도 로직을 사용하여 트랜잭션 함수 txn_func 실행
      def run_transaction_tieh_ertry(txn_func, session):
      	while True:
      		try:
      			txn_func(session)
      			break
      
      		except :
      			# 전체 transaction 재시도
      
      # 4. 세션 시작
      with client.start_session() as my_session:
      	try:
      		# 5. 4번 함수를 호출하여 1번 함수를 호출, 이 트랜잭션과 세션 2번 함수를 연결
      		run_transaction_tieh_ertry(update_orders_and_inventory, my_session)
      
      	except Exception:
      		raise
      
  • 콜백 API (Callback API)
    • 몽고DB 4.2 이후로 사용 가능

    • 지정된 논리 세션과 관련된 트랜잭션 시작, 콜백 함수로 제공된 함수 실행

    • 트랜잭션 커밋을 포함해 코어 API에 비해 많은 기능을 래핑하는 단일 함수를 제공

    • 커밋 오류를 처리하는 재시도 로직

    1. 트랜잭션 내부에서 수행할 작업 순서를 지정하는 콜백을 정의
      def callback(my_session):
      orders = my_session.client.webshop.orders
      inventory = my_session.client.webshop.inventory

      orders.insert_one()
      inventory.insert_one()
    2. 클라이언트 세션 시작
      with client.start_session() as session:

    3. with_transaction을 사용하여 트랜잭션 시작, 콜백 실행, 오류 발생 시 커밋 또는 중단
      session.with_transaction(callback,
      read_concern=ReadConcern(),
      write_concern=my_write_concern_majority,
      read_perference=ReadPreference.PRIMARY):

8.3 애플리케이션을 위한 트랜잭션 제한 조정

8.3.1 타이밍과 Oplog 크기 제한

시간 제한

  • 트랜잭션 최대 실행 시간 - default : 1min

  • transactionLifetimeLimitSeconds로 컨트롤 가능

  • 샤드 클러스터의 경우 모든 샤드 복제 셋 멤버에 매개변수 설정

    • 이 시간이 만료되면 트랜잭션이 만료됐다고 간주, 정리 프로세스에 의해 중단
    • 정리 프로세스는 60초 or transactionLifetimeLimitSeconds / 2 중 더 낮은 값을 주기로 실행
  • 트랜잭션 제한시간을 commitTransactionmaxTimeMS지정하는게 좋다.

    • 설정하지 않으면 transactionLifetimeLimitSeconds 사용
    • maxTimeMS를 설정했지만 transactionLifetimeLimitSeconds 를 초과하는 경우 transactionLifetimeLimitSeconds 사용
  • 트랜잭션 락을 얻기 위해 트랜잭션이 대기하는 최대 시간은 5ms

    • maxTransactionLockRequestTimeoutMillis 에 의해 제어
    • 0, -1, 0^로 설정 가능
    • 0으로 설정한 경우 필요한 모든 락을 즉시 얻을 수 없으면 트랜잭션 중단
    • -1 설정시 maxTimeMS 에 지정된 대로 사용된다.

epilog 크기 제한

  • 몽고DB는 쓰기 작업에 필요한 만큼 oplog gkdahr todtjd
    • BSON 도큐먼트 크기 제한인 16메가바이트 이하
  • 유연성 있는 모델과 스키마 설계 패턴과 같은 사례를 사용하면 트랜잭션을 사용하지 않아도 된다.
  • 트랜잭션을 애플리케이션에서 자주 사용하지 않는 것이 좋다.
profile
이제부터 백엔드 개발자

0개의 댓글