개요 : 트랜잭션(Transaction)이란?

트랜잭션이란 개념은 게임 프로그래머들에게는 그다지 익숙하지 않을 수도 있겠지만,

DB 나 웹 프로그래밍을 하는 사람이라면 많이 들어보거나 사용해보았을 개념이다.

트랜잭션은 중요한 대상을 다루는 프로그램에서는 없어서는 안될 중요한 개념이다.

이 글에서는 트랜잭션이 무엇을 의미하는지 알아보고, 우리가 만드는 프로그램과 어떤

연관이 있을 수 있는지 알아보도록 한다.



사례 : 마약 거래

영화에 보면 흔히 나오는 장면중 하나가 어둠의 조직이 마약과 현금을 교환하는 장면

이다. 주로 두 진영이 접선하는 장소는 외부로부터의 방해를 받지 않을 수 있는 외딴

창고나 공장 같은 곳이 되어 있고, 두 진영은 거래가 안전하게 성사되도록 서로 스나

이퍼를 매복시켜놓거나 해서 감시하고 있으며, 교환하는 방식도 최대한 서로를 의심

의 눈초리를 늦추지 않은 채 살벌한 분위기에서 이루어진다. 물론 대부분의 영화 스토

리 상에서는 주인공이나 경찰, 또는 한진영의 변심등에 의해서 총부림 난장판으로 변해

버리는 경우가 많지만.

이런 식의 거래가 완벽하게 이루어지려면 다음과 같은 조건을 만족해야 한다.

1. All or nothing - 마약뭉치와 돈가방을 교환하는 거래라면 전부와 전부가 교환되어야

한다. 일부와 전부가 교환되거나, 일부와 일부가 교환되거나 한쪽만 받고 한쪽은 못 받는

경우가 되어서는 안된다. 마약은 넘겨줬는데 돈은 못 받거나, 반대로 돈은 넘겨줬는데

마약은 못 받거나 하는 일이 생겨서는 안된다는 점이다.

2. Isolation - 각각의 거래는 다른 거래와 완벽히 구분된 것이어야 한다. 예를 들어서

마약을 A 조직에도 팔고, B 조직에도 팔겠다고 해서 둘 다 약속장소로 불러낸다던가 하면

정상적인 거래가 이루어질 수 없을 것이다.

3. Durability - 각각의 상품은 지속적으로 안정성을 유지해야 한다. 예를 들어서 정상

적인 마약인 줄 알고 거래를 했는데, 24 시간이 지나자 마약이 스르륵 녹아버린다던가

하는 식이 되면 공평한 거래를 했다고 할 수 없을 것이다.


사례 : 은행 인출기

좀 더 트랜잭션 실제 적용의 개념에 가까운 사례를 생각해보자. 우리 대부분은 은행에

계좌를 갖고 있고, 언제 어디서나 예금을 인출할 수 있는 현금카드나 신용카드를 소유

하고 있다. 이 인출기를 사용하면서 혹시 이런 생각을 해본 적은 없는가?

- 만약 이걸 사용하는 도중에 인출기가 정전이 되서 꺼지면 혹시 돈을 따블로 뺄 수는

   없을까? 반대로 내 돈이 중간에 공중으로 붕 떠서 날아가버리는 수는 없을까?
  
- 은행 서비스 시간이 마감될 직전에 인출기를 이용해서 돈을 인출하면 위와 같이 돈은

   빠지면서 잔고는 그대로 남거나, 그 반대의 경우는 생기지 않을까?

- 한 계좌에 대해 카드 두개를 만들어서 인출기 두군데를 이용해서 동시에 돈을 양쪽으로

   인출을 하면 혹시 양쪽 다 돈이 나올 수 있을까? (예:통장 잔고에 10만원만 남겨놓고
  
   양쪽에서 10만원씩 인출요청을 한다)
  
- 제일은행에서 국민은행으로 계좌를 이체하는데, 제일은행에서만 돈이 빠져나가고 국민

   은행에서는 '난 모르는 일이요' 하고 씹어버리는 경우는 혹시 생길리 없을까?
  
필자의 경우 시도해보지 않아서 모르지만, 100% 안될 것으로 장담할 수 있다. 왜냐하면

이런 사건이 벌어지면 파장이 엄청나기 때문이다. 이런 일이 일어나지 않는 이유는 무엇

일까?


사례 : 온라인 게임

온라인 게임의 개발 초기단계에는 다양한 버그들이 존재한다. 그러한 여러가지 버그들 중

에서도 특정 계층의 가장 큰 관심을 끄는 것은 역시 돈 복사나 아이템 복사에 관련된 버그

들이다. 지금까지 많이 알려졌던 (그리고 안정된 게임에서는 거의 막혀버린) 복사 기법들

중 몇가지의 예를 들어보자.

- 더블로그인

   계정하나를 가지고 컴퓨터 2 대를 이용해서 거의 동시에 로그인을 시도한다. 로그인이
  
   된 경우 같은 플레이어 2 명이 동시에 게임 안에 등장하게 된다. 이때 순서를 잘 맞춰서
  
   아이템을 땅바닥에 버리고, 다른쪽에서 줍고, 로그 아웃을 하고 하면 데이터베이스 상에
  
   서는 아이템을 가지고 있는 상태로 저장이 되면서 동시에 땅바닥에 아이템이 남아있는
  
   상태를 만들 수 있다. 물론 순서를 잘 못하면 반대로 아이템만 날릴 수도 있다.

- 서버 점검 타임

   서버가 꺼질 즈음에 아이템을 막 버리고 줍고 하다보면 위와 비슷하게 아이템은 갖고
  
   있는데, 땅바닥에 아이템이 또 남겨진 경우가 생길 수 있다

- 서버 어택

   특정 행동을 하면 게임 서버가 다운되는 상황을 알아내서 역시 땅바닥이나 교환창으로
  
   막 아이템이 오고가게 만드는 중간에 서버를 다운시킨다.

- 창고와 교환창

   창고와 교환창 두개를 열어놓고 아이템을 동시에 넣으려고 하다보면 창고에는 아이템이
  
   안 빠지면서 아이템이 다른 캐릭터에게 가게 되는 경우가 간혹 있다

- 퀘스트 스크립트와 교환창

   퀘스트를 깨고나서, 퀘스트 아이템 A 를 보상물 B 와 바꾸려는 순간에 교환창을 이용해서
  
   퀘스트 아이템 A 를 다른 캐릭에게 주거나 땅바닥에 버리면, A 는 npc 에게 가지 않으면서
  
   보상물 B 만 받게 될 수 있다. 이 방법을 반복해서 계속 보상물 B 를 받아먹을 수 있다
  
- 기타 등등 (여러분도 알고 계신 방법들이 있으면 제보 바랍니다)


자, 이제 필자의 의도를 아마 알게되었을 것이다. 트랜잭션이란 개념은 온라인 게임서버의

안정성에는 핵심이라고 할 수 있을 정도로 중요한 개념이기 때문에 개발자들이 꼭 숙지해두지

않으면 안된다. 위에 소개된 복사 기법의 사례들을 보면 여러가지 방식으로 트랜잭션의 조건

(Isolation, All or nothing 등) 이 지켜지지 않는 헛점을 노린 것임을 알 수 있다.

트랜잭션이 그렇게 중요한 것이라면 그냥 트랜잭션을 도입하면 되지, 왜 도입하지 않아서

저런 위험성을 노출시킨 것일까? 필자가 생각하기엔, 그리고 필자가 직접 체험한 입장에서는

두가지 원인이 있었다.

첫째로, 트랜잭션의 개념에 대해서 잘 알지 못했기 때문이다. 당하기 전에는 모르는 것이

이런 복사버그들이다. 이런 개념들은 위에 소개한 전자상거래나 금융권 프로그래밍에서는

일반적인 개념이었지만, 패키지 게임만 만들어 오던 게임개발자들에게는 그다지 와닿지도 않고

무슨 관련이 있는지 모르는 생소한 개념이었다가, 온라인 게임의 개발을 하게 되면서 알게

된 것들이다.

두번째로, 현실적인 제약때문에 트랜잭션에 맞는 데이타베이스의 처리를 하지 않았기 때문이다.

온라인 게임 초반에는 서버의 사양이 그다지 높지가 않았었기 때문에, 게임상에서의 중요한

조작을 할 때마다, 일일이 DB 에 읽고 쓰고 하는 것은 현실적으로 생각하기 어려웠었다. 혹은

그런 고성능 장비를 도입하기에는 서비스 예산이 넉넉하지 않았기 때문에, 그 대안으로 중요한

조작을 할 때마다 일일이 DB 의 트랜잭션으로 처리하는 것이 아니라, 일단 컴퓨터의 메인 메모

리에 저장을 해 놓고, 나중에 주기적으로 그 결과들을 저장시키는 방식을 택했다. 위의 복사

기법중 상당수가 실제 행동이 일어나는 타이밍과 그것이 DB 에 저장되는 타이밍의 차이를 노린

것이다.


그렇다면 이제는 어떻게 해야 할까? 개발자들에게 해주고 싶은 조언은 다음과 같다

1. 트랜잭션의 개념에 대해 배우고 적용할 것

ACID 개념을 이해하는 것이 가장 우선이 될 것이다. 그 다음에는 사용하는 DB 의 SQL 에서 지원

하는 트랜잭션의 문법을 익히도록 하자. 만약 지금 만드는 게임이 제대로 된 상용 DB 를 사용하지

않고 있다면, 상용 DB (MS-Sql 이나 Oracle) 의 사용을 검토하기 바란다. MySQL 의 경우 스토어드

프로시져를 현시점의 정식버전에서 지원하지 않기 때문에 불편하긴 하지만 트랜잭션 자체는 지원

하는 것으로 알고 있다. 빠른 시일 내에 버전 5 가 정식으로 발표되길 희망한다.

2. 게임 서버 내에도 트랜잭션에 알맞은 구조로 바꾼다

DB 처리를 트랜잭션에 맞게 한다고 하더라도, 그 전이나 후의 처리가 트랜잭션상의 헛점이 있다면

헛수고가 될 것이다. 헛점이 10 개 있다면 10 개를 다 막아야지 9 개만 막은 것은 안 막은 것에

비해 크게 나은 점이 없다. 또한 최대한 트랜잭션에 맞게 게임내의 데이타를 관리할 필요가 있다.

하지만 현실적으로 모든 처리를 트랜잭션화 할 수는 없는 법이므로, 메인 메모리에서 캐슁해도

괜찮은 정보와, 캐슁하지 말고 곧바로 트랜잭션처리를 해야 하는 정보를 구분해야 할 필요가 있다.

3. npc 스크립트도 트랜잭션 구조로 바꾼다

역시 마찬가지로 2 번 이야기의 연장선이라 할 수 있다. 위에 복사기법의 사례로 나온 스크립트

의 예에서도 마찬가지로 여러가지 예외에 대한 처리와 방어가 필요하다. 하지만 스크립트는 프로

그래머가 아니라 기획자에 의해 씌여지는 경우가 많기 때문에 실수가 일어날 가능성이 더 높은

관계로, 아예 처음부터 규칙과 문법을 정해서 일관성있는 처리가 일어나도록 해야 할 것이다.


-- 보너스 --

Q. 트랜잭션은 쓸 수록 몸에 좋은 만병통치약인가?

A. 아니. 그렇지 않다. 때에 따라서는 사람을 환장하게 만들 수도 있다.

가장 대표적인 예 중 하나가 파일 다운로드의 경우이다. 파일을 주고 받는 행위도 트랜잭션

이라고 생각할 수 있다. 그래서 윈도우가 파일을 다운로드 할 때에는 All or nothing 개념으로

처리한다. 파일을 받는 도중에는 임시 temp 폴더로 받았다가 완전히 다 받고 난 다음에야

원래 받으려던 곳으로 보여주는 식. 헌데 거의 다 받아가는데 접속이 끊겼다면? 결과는 all

or nothing 에서의 nothing 쪽이 되어버린다.

근래에는 이러한 점을 보완하기 위해서 중간에 다시 받기를 지원하고 있다. 하지만 초창기

에는 이어받기가 잘 안되었었다. 특히나 한번에 여러개의 파일을 다운 받고 있을 때에는...

imcgames 의 김학규입니다