[TIL/17] 트랜잭션과 원자성

안건우·2025년 10월 21일

sparta_til

목록 보기
16/26

오늘 기재할 내용은 어제에 이어 데이터 처리방식에 대한 고민이다.
이 사고가 이어진 부분을 보여주기위해 이번 TextRpg프로젝트에서 발생했던 트러블슈팅을 하나 소개한다.

문제의 발단

아이템관리 기능에 인스턴스상의 아이템의 독립성을 부여하기 위한 아이디가 부여되어있었다.

이렇게 Clone메서드에 자체적으로 Id값을 부여하여 연산을 하여 AutoIncrement를 구현하는 간단한 방식이었다.
사실 프로젝트내에서 Id값 자체가 비즈니스로직으로 활용되는것은 아니었다.
아이템데이터 자체는 Json데이터를 파싱하여 사용하고 있었지만 리소스로딩 또한 Id값이 name값으로 사용되고 있었다.

그렇기때문에 딱히 문제는 되지않을거라 생각했으나... 오산이었다.
기본 Id값의 원본데이터자체가 휘발성을 지닌 단일 어플리케이션 인스턴스상에서만 보장되고 있었던것이다.

그렇기때문에 저장후 게임데이터를 새롭게 로딩하면 인스턴스상의 AutoIncrement Id값이 초기화되었고,
그렇게 생성된 동일한 Id값을 지닌 아이템 인스턴스가 장비 장착시 중복으로 장착되어버리는 버그가 발생한것이었다.

AutoIncrement값의 영속성이 보장되지 않은것이다.

영속성해결, 그러나...

때문에 나는 간단하게 Json을 활용해 AutoIncrement값의 영속성처리를 진행했다.

하지만 그다음 곧바로 추가적인 고민이 생겼다.
바로 원자성확보에 대한 고민이었다.

물론 이 프로젝트는 프로덕션용이 아니며 단일 인스턴스상에서의 실행이 보장되어있다.
즉 멀티 I/O환경이 아니기때문에 프로세스의 고립성과 일관성까지 보장할 필요는 없다.
그렇기에 완벽한 트랜잭션 처리는 명백하게 불필요했다.

하지만 원자성과 영속성은 동시성이 요구되는 환경에서만 필요한 개념이 아니다.
데이터를 다루는 환경에서 데이터가 기초적으로 가져야하는 무결성을 지키기위해 필수적으로 지켜져야 하는 요소인것이다.

사실 단일 C#기반 프로젝트에서 원자성을 확보하는 방법이야 간단하다.
GetLastId가 호출되는곳이 Item클래스 상속자들의 Clone메서드내부이니 그때마다 SaveAIConfig를 호출하면 간단히 확보되는 문제인것이다.

하지만 기본적으로 리소스 사용량이 큰 I/O작업을 수도없이 발생하는 인스턴스 Clone메서드 내에 배치한다...?
이것은 개념을 떠나 개발자의 본능으로서 도저히 내릴수 없는 선택이었다.

결국

때문에 어쩔수 없이 나는 원자성을 일부 희생시키고 SaveAIConfig를 C#의 생명주기에 배치했다.
이는 정상적인 프로그램 종료시에만 실행이 보장된다.
원자성을 포기하는 대신 리소스 효율을 선택하는 Trade Off를 진행한것이다.

물론 이 프로젝트에서 Clone메서드내에 SaveAIConfig를 호출하는것은 성능저하를 일으킬만한 큰 병목을 일으킬 우려가 없다.
그렇기때문에 이 프로젝트 내에서 내가 정답을 선택했느냐라고 묻는다면 나는 당당하게 오답을 선택했다고 이야기할수 있다.
하지만 위에서도 언급했다시피 개념과 이론이 아닌 본능이 그 선택을 막았다.


사실 나에게도 트랜잭션 처리는 데이터베이스가 활용되는 환경에서만 필요한 개념이라는 좁은 식견이 있었다.

하지만 이번 작은 트러블슈팅 경험을 통해 데이터 무결성은 환경과 무관하게 항상 고려되어야 하는 본질적인 요소임을 깨달았다. 특히 원자성(Atomicity)영속성(Durability)은 동시성 환경뿐 아니라, 단일 스레드 환경에서도 데이터의 신뢰성을 보장하기 위해 필수적으로 고려해야 할 개념이었다.

데이터베이스가 없는 환경에서도 트랜잭션과 유사한 안전성을 확보하는 다양한 방식이 존재한다:

  • 즉시 저장(Write-Through) - 매 작업마다 즉시 영속화
  • Atomic File Write - 임시 파일 생성 후 원자적 교체
  • WAL(Write-Ahead Logging) - 변경 로그를 먼저 기록 후 반영
  • 소프트웨어 트랜잭셔널 메모리(STM) - 메모리 상에서 트랜잭션 개념 구현
  • 파일 시스템 저널링 - 파일 시스템 레벨에서 변경사항 기록
  • 메시지 큐 - 비동기 메시지 처리를 통한 안정성 확보

특히 Temp파일을 생성하는 방식은 정말 쉽고, 또 자주 만나볼수 있는 고전적인 방식의 트랜잭션처리 기법이다.
나는 매번 데이터베이스가 아닌 OS단위의 트랜잭션을 마주하면서도 그게 트랜잭션을 위한 방식이라는걸 깨닫지 못학 있었던 것이다.
작은 프로젝트였지만, 데이터를 다루는 모든 환경에서 무결성에 대한 고민이 필요하다는 값진 교훈을 얻었다.

0개의 댓글