View
3.616
Download
8
Category
Preview:
DESCRIPTION
임베디드 DB 인 버클리DB 를 이용하여 게임서버를 만들어보았다.
Citation preview
버클리 DB 를 이용한 게임 서버 제작
공봉식kongbong23@gmail.com
버클리 DB 란 ?
오라클에서 만든 임베디드 DB 오픈소스 라이브러리
특징
라이브러리 형태의 DB 이다
별도로 존재하는 게 아니라 응용프로그램에 이식되어서 동작하는 임베디드 형태의 DB 이다 .
응용프로그램에 종속적이다 .
단일 key/ 단일 data 구조
DB 가 하나의 key 와 하나의 data 로 구성되어 있다 .
key 와 data 모두 바이너리 형태
매우 심플한 구조
SQL 문을 지원하지 않는다
관계형 DB 가 아니기 때문에 SQL 문을 지원하지 않는다 . Get, Put, Erase 같은 단순한 API 로 데이터에 접근한다 .
* Join 지원하지 않는다 .
뛰어난 성능
임베디드되고 , SQL 문을 지원하지 않기 때문에 성능이 뛰어나다 .또한 멀티코어를 지원하여 scalability 가 뛰어나다 .
ACID 를 보장하는 트랜잭션
ACID 를 보장하는 트랜잭션 기능을 지원한다 .데드락 디텍션 기능을 제공한다 .RMW 기능을 제공하여 데드락을 회피한다 .
파일 / 메모리 양쪽 모두 사용 가능
파일 DB 로 쓸 수 있고 순수한 메모리 DB 형태로도 사용 가능하다 .파일 DB 를 쓸 경우 트랜잭션 로그를 통해 복원 기능을 제공한다 .메모리 DB 로 사용하면 FILE I/O 로 인한 오버헤드를 없앨 수 있다 .
사용이 간단하다
env.BeginTxn(&txn);db.Get(&txn, &key, &data, flag);db.Put(&txn, &key, &data, flag);db.Erase(&txn, &key, flag);txn.Commit();
이런 형태로 매우 간단한 API 를 제공한다 .
다양한 언어를 지원한다
버클리 DB 는 C 언어로 제작되었으나C, C++, JAVA, Python, C#, Ruby 등 다양한 언어를 지원하고 있다 .또한 모바일 기기 부터 대용량 서버까지 활용 범위가 넓다 .
오픈소스 라이센싱
오픈소스 프로젝트는 무료로 사용할 수 있으나 그렇지 않을 경우에는 별도로 구입해야 한다 .
단점
외부에서 데이터를 볼 수 없다
데이터가 바이너리 형태로 들어가 있어서 별도의 툴을 통하지 않고는 외부에서 볼 수 없다 .
최신 버전에서는 SQLite 를 지원하여 SQL 문과 도구를 지원하고 있기는 하다 .
백업 , 미러링 등의 고급 기능이 없다 .
상용 관계형 DB 에서 제공하는 고급 기능이 많이 빠져있다 .꼭 필요한 기능만 제공하는 편 .
통계용으로 사용하기 힘들다
SQL 문을 지원하지 않기 때문에 실행 계획도 세우지 않고 , 인덱스도 Key 하나만 제공한다 .
따라서 통계용으로 사용하기는 힘들다 .통계용 관계형 DB 를 따로 둬야 한다 .
게임 서버와 버클리 DB
시작은 다크스타 .
다크스타는 Sun 에서 추진했던 JAVA 로 만든 오픈소스 게임서버 엔진이다 .Sun 이 오라클에 인수된 뒤 현재는 공식적인 지원이 끊기고 RedDwarf 란 이름으로 명맥이 유지되고 있는 상태 .
다크스타는 버클리 DB 를 이용하여 게임서버를 제작했다 .
서버의 태스크 분할 형태로 변화
공짜 점심이 끝나고 서버의 코어수가 늘어나면서 멀티 코어를 최대한 활용하기 위해서 태스크 분할 형태로 서버가 변화하고 있다 .
태스크 분할 형태로 갈 경우 가장 큰 문제는 데이터 락킹이다 .
HitTask(){
BeginTransaction();
A = GetForRead();B = GetForUpdate();
B.Hp -= A.Att;
Commit();}
* 태스크의 예 트랜잭션을 시작한다 .
A 에 대해 읽기 락을 건다 .이제 A 에 대해서 쓰기락을 걸 수 없다 .
B 에 대해 쓰기 락을 건다 .이제 B 에 대해서 읽기 /쓰기 락을 걸 수 없다 .
실제 B 데이터를 수정한다 .
트랜잭션을 커밋한다 .B 의 변경점을 적용하고 A 와 B 의 락킹을 푼다 .
하지만 이런 시스템을 구축하는 건 쉽지 않다 .
STM 구축하는 건 쉽지 않고 , 안정성과 성능을 모두 잡기가 힘들다 .특히 , 데드락과 레이스 컨디션 같은 문제를 잡기가 힘들다 .
버클리 DB 는 이 모든 요구조건을 충족한다 .
상용 소프트웨어에서는 별도로 구입해야 한다는 조건을 제외하면 STM 구축에 있어서 가장 빠르고 좋은 해결책이라고 생각된다 .
데모 서버엔진
목적 : 버클리 DB 를 이용하여 태스크 분할 서버엔진을 구현해 본다 .
제작 기간 : 2010 년 4 월 5 일 ~ 2010 년 4 월 12 일 (7 일 )(1 일 평균 5 시간 작업 )
구현 언어 : C++
사용 라이브러리 : BerkeleyDB, TBB, google.test, STL 등
데이터를 관리한다 .내부에는 버클리 DB 를 사용하고 있다 .트랜잭션 , 데이터 체크아웃 , 체크인 기능을 제공한다 .
응용프로그램 동작을 정의한다 .단순한 광부 AI 를 제작하여 동작하도록 구현하였다 . (*Programming game AI by example 2 장 )
네트워크를 담당한다 .데모버전에서는 실제 네트워크를 구현하지 않고 mock 객체로 구현하였다 .
TBB 를 사용하여 태스크 스케쥴러를 작성하였다 .딜레이 태스크 , 반복 태스크등을 지원한다 .
네트워크패킷
태스크 매니져
BeginTransacton
세션 핸들러 OnRecv()
Commit
1. 클라이언트로부터 메시지를 수신
2. 태스크 매니져에 메시지 처리 태스크를 추가한다 .
3. 태스크 시작에 트랜잭션을 시작한다 .
4. 실제 메시지를 처리한다 .이 과정에서 객체 상태가 변화한다 .
5. 태스크 마지막에커밋하여 변경점을 적용한다 .
사용예
// 광부를 만든다 .ServerMiner miner;m_minerRef = g_DataManager::Instance().CreateReference(&miner);
광부 객체를 DataManager 를 통해서 메모리 DB 에 쓰고 그 참조객체를 반환한다 .앞으로 생성한 광부를 객체를 접근하기 위해서 참조객체를 사용하게 된다 .
Task() {
ServerMiner* pMiner = m_minerRef.GetForUpdate();if (pMiner != NULL){
pMiner->receivedMessage(_msg);}
}
광부를 쓰기 권한을 읽는다 .
메시지를 처리함으로써 광부 상태가 변경된다 .
태스크 종료시 변경점이 자동으로 Commit 된다 .또한 데드락 발생시 RollBack 된 뒤 태스크가 일정 횟수까지 재실행 된다 .
특징
Application 에서는 싱글쓰레드Application 에서는 마치 싱글 쓰레드 처럼 프로그래밍 할 수 있다 .실제로는 멀티 쓰레드로 돌고 있지만 태스크 양단을 트랜잭션으로 보호하기 때문에 쓰기 객체에 접근하는 쓰레드는 하나이다 .
멤버 변수로 포인터를 사용할 수 없다 .
데이터매니져에 저장되는 객체의 멤버 변수로 포인터를 사용할 수 없다 .멀티쓰레드 상황이기 때문에 포인터가 삭제되었을 수있고 쓰레드세이프 하지 않기 때문이다 .
대신 가져오고자 하는 객체에 대한 참조객체를 멤버 변수를 가지는 것은 가능하다 .
최소 의존 컴포넌트 구현
멀티 코어를 최대한 활용하기 위해서 각 객체의 사이즈를 최소로 하고 의존관계를 최소화 할 필요가 있다 .
각 객체는 단일 목적 / 단일 객체 라는 원칙으로 최소 의존 컴포넌트를 구성한다 .
반복자나 무거운 작업은 별도 태스크로 분리
많은 객체를 순환하거나 시간이 오래 걸리는 작업은 여러 태스크로 분리하는게 좋다 .
많은 객체를 순환할 필요가 있을 경우 분할 병렬 처리하고 , 외부 DB 작업 등 시간이 오래 걸리는 작업은 요청과 응답 처리를 별도 태스크로 분리하여 동작하도록 하는게 좋다 .
Recommended