DB 쿼리 서버

3권에서 새로 도입된 네트웍 및 멀티플레이어 프로그로그래밍 섹션을 위한 게시판입니다.

Moderator: 류광

Locked
imays
Posts: 1044
Joined: 2003-02-18 10:29
Contact:

DB 쿼리 서버

Post by imays »

일부 온라인 게임 프로젝트에서 DB 서버와 게임 서버 사이에 쿼리 서버를 자체 제작해서 배치해 둔다는 얘기를 들었습니다.

제 경험상 쿼리 서버의 필요성을 느끼지 못했는데요... 쿼리 서버의 효과는 무엇인가요?
온라인 게임 서버 엔진 ProudNet
http://www.nettention.com
Guest

Post by Guest »

게임서버에서 디비에 쿼리를 내리고 대기하는 시간동안(디비가 바쁘다거나 쿼리자체가 시간을 요한다거나..등등)

게임서버(또는 작업스레드)가 아무짓도 못하게되서 다른 유저들의 메세지처리가 늦어지는데..

중간에 쿼리서버(저희는..db에이전트라고 부릅니다..)를 둠으써 게임서버 입장에서는 이런 대기시간이 없어지게 됩니다.

쿼리하나당으로 보자면..시간이 조금은 더 들수도 있지만 전체유저를 대상으로 보자면 특정메세지처리로 인한

순간적인 락(?)이 없어지므로 전체적으로 좀더 유연하게 서버가 돌아갑니다.
ke7789
Posts: 224
Joined: 2003-03-26 21:21

저희도 쓰고 있습니다.

Post by ke7789 »

저희는 MemoryDB, DB Broker라고 합니다.

게임서버의 응답시간을 높이기 위해서 DB에 직접 갱신하지 않고..

MemoryDB에 한번 쓰고, DB Broker가 시간을 주기로 돌면서 실제 DB에 갱신시켜 줍니다.

자체적으로 HP가 리젠되거나, 아이템관련 정보, 위치정보등이 매우 자주 업데이트되는데..

그런 부분에 있어서는 응답속도가 빨라 매우좋습니다. 하지만

OverlapJOB형태로 에러처리를 다 해주어야 하기 때문에. 약간은 불편하지만..

(물론 비동기로 DB를 만드는거라 당연히 OverlapJob이 필요하져..)

사실 솔직히 좀 후달립니다. T_T.
myevan
Posts: 1314
Joined: 2003-03-04 10:21
Contact:

Post by myevan »

A라는 사용자가 '가' 서버에 있다가
'나' 서버로 이동했는데..
'가' 서버쪽에 부하가 걸려서 저장이 안되고 있었는데
'나' 서버로 이미 이동해 버려서 기존 데이터르 읽어버렸다! 허억 =ㅁ=);;

같은 암울한 상황을 손쉽게 해결할수 있는 타개책이 되기도 하고...
윗분이 적어주신 것처럼 메모리 DB를 사용하면 부하를 어느정도 완충을 해줄수가 있죠.
빗자루네 http://www.myevan.net >_<b
imays
Posts: 1044
Joined: 2003-02-18 10:29
Contact:

Post by imays »

답변 감사합니다.

그런데, DB 처리에서 응답 시간 대기 지연은 그냥 게임서버에서
1. (스레드풀링 + critical section unlock) 또는
2. 비동기 DB 쿼리 또는
3. 스레드 풀링 + DB 쿼리 + 이벤트 트리거

중 하나를 구현하면 게임 서버에서 DB 억세스 중 노는 시간은 거의 zero로 만들 수 있죠. 제가 측정해 본 바로는, 쿼리 디스패치가 차지하는 퍼포먼스는 게임 서버 퍼포먼스에 비해서 매우 적은데, 이것 때문에 굳이 쿼리 서버를 별도로 만들 필요는 없다고 봅니다.

그리고 여러개의 서버에서의 로딩/저장 순서가 겹치지 않게 하기 위해서는 쿼리 명령어에서 해결할 수 있는데요... ISOLATION LEVEL, TRANSACTION 등등 동원해서요... 이 구문들을 활용한다면 역시 쿼리 서버를 별도로 만들 필요가 없다고 생각합니다. 다만, 분산 트랜잭션에 대한 이해를 요구한다는게 까다로운 점이지만요.

글쎼요, 제가 쿼리 서버의 역할에 대해서 더 찾아보지 않았지만, 굳이 쿼리 서버를 만들지 않더라도 DB 처리에서 응답 시간 대기 지연과 억세스가 겹치는 문제는 해결할 수 있었습니다.
온라인 게임 서버 엔진 ProudNet
http://www.nettention.com
zupet
Posts: 2764
Joined: 2003-05-13 03:34
Location: NCSOFT LE팀

비동기 DB 쿼리로 시간은 줄일 수 있지만..

Post by zupet »

안녕하세요. 매크로 없는 메비~랍니다.

비동기 DB 처리로 쿼리 시간에서 손해보는 CPU 시간을 효율적으로 사용할 수 있는 것은 맞습니다. 그렇지만 DB 에이전트(저는 또 이런 용어를 쓰는군요. 다들 용어가 다르죠..? ^_^)를 사용하게되면 내부적으로 캐쉬기능을 갖고 있을 수 있고 그에 따라서 쿼리 횟수를 줄일 수 있습니다.

또한 단일 DB 서버에 외부로부터 너무 많은 컨넥션(어디 올라온글중에 'DB 컨넥션을 한개만 쓰는 것은 바보짓이다.' 라는 말을 읽은적이 있군요. ^_^ )이 맺어지고 각자 다른 쿼리가 동시에 들어올 경우 DB 서버는 순간적으로 부하가 몰리는 상태가 될 수도 있습니다. 상용 서비스를 하게되면 최소 하루에 1회이상 풀 백업을 하는 경우가 많고 중간중간 트랜젝션 백업(MS-SQL 에서~)을 걸어주게 되는데 이런 순간 게임에 화~악 하고 DB 접근 속도가 느려질 수 있습니다.

물론 데이터 무결성은 트랜젝션을 통해서.. 접속이 너무 많아지면 클러스터링으로~~ 라고 말은 쉽게 하지만 그렇게 장비에 의존하기 보다는 프로그래머의 능력으로 부하를 줄이는 것도 개발에서 중요한 부분이라 생각됩니다. SP 최적화 만으로도 충분히 효율이 좋아! 라고 말하는 분들도 있지만 저는 DB 에이전트를 통한 캐쉬 작업을 지지하고 있습니다. 일단.. DB 서버가 아무리 빨라도 배열에서 데이터 꺼내서 TCP 로 쏴주는것보단 빠를 것 같지 않습니다.

p.s.가령.. 클러스터링을 멋지게 하기 위해서는 SQL Ent. 버젼이나 오라클을 써야하는데 장비값/소프트웨어 가격에 대해서 생각해보신 서버 개발자분들이 얼마나 계실지 궁금합니다. 직접 서비스를 하고 눈앞에서 견적서가 날라다니는걸 보면서 '저거 두어달 고생하면 1/10로 떨어질텐데~' 란 생각이 드시는 분!!! 당신이야 말로 개발자입니다. ^__^

p.s.2.예전에 아노?님과 대화중에 제가 제안했던 방법중에 DB 에이전트가 캐쉬하는 데이터를 MM File 로 구현해서 DB 에이전트가 죽을때나 다시 살아날때 사용하던 데이터를 다시 복구하는 방법을 제안한적이 있습니다. DB 에이전트는 안정성이 문제라 꺼리는 분들이 많은데 이런 부분들로 어느정도 해결이 되리라 생각합니다.
perpet

이런방법은 어떨까요?

Post by perpet »

저도 imays 님 처럼 하는게 기능추가시 작업량?이나 디버깅시 더유리할듯한데.(개인적소견..)
문제는디비서버를 따로 두면 캐시기능을 하지만.imays처럼 하면 캐쉬기능이 없으니
성능은 떨어질수도 있겠죠...
하지만 디비서버를 따로 두어도 디비서버 한대가 부하가 걸리기 시작하면
또한대 두어야할수도 있을텐데..그때도 캐시기능을 할수있나요?
하여튼 저는 디비서버를 포함한 서버구조는 아직 자세히 생각해보지 못했고...
imays 가 같은 방식을 생각했는데...
거기서 좀더 효율을 높이는 방식으로 디비성능을 어떻게 높일까했는데....
mysql 에 보면 replication 기능이 있습니다...
제가 알기론 이기능이 미러링같은 기능으로.. 한쪽이 변하면 다른쪽도 똑같이 변경된다고 알고있는데..
그럼 게임서버한대당 한대씩 붙여서 따로 디비서버에 접근하는건 어떨까요?
replication 기능을 자세히 모르지만 하여튼 그런개념으로...어차피 게임서버에서 자신의 디비정보만
읽어오고 업데이트 되기 때문에 그렇게 문제가 안될것 같지만....
아직 구체적으로는 작업을 안해봐서..그냥 아이디어를 씁니다...
replication 기능이 마스터와 슬레이브 개념이고 마스터만 업데이트 할수있다면..
모든 게임서버가 업데이트 할때만 마스터로 접근하고 나머지는 각자의 슬레이브에 접근하고...
그리고 이런식으로 되면...백업이나 데이타 손실도 어느정도 카바 되고..
하여튼 아이디어입니다..^^
구현은 안해봤음..
해키스트

Post by 해키스트 »

저도 DB Agent 사용에 찬성하는 편입니다.

근데 그건 디비 테이블 설계가 어떻게 되었는가에 따라서도 달라진다고 봅니다.
테이블 설계를 퍼포먼스 위주로 했다면.. (예를들면 인벤토리 데이터를 바이트 스트림으로 잡는다든가 하는 방법이죠)
검색은 좀 힘들겠지만 퍼포먼스면에서는 월등하기 때문에 충분히 쿼리만으로도 처리할 수 있지만..
컬럼수가 많고 크기가 방대한 데이터 테이블일 경우에는 실시간 쿼리전송으로는 역시 후달리겠죠..

디비 에이전트 같은 경우에는 예외 처리를 고려해야 하는 부분이 있기때문에
게임의 성격과 테이블 구조에 맞는 적절한 방법을 사용하면 된다고 생각됩니다 :lol:

p.s 물론 초보의 생각이니 잘못된 부분이 있다면 태클걸어주시면 감사하겠습니다.^^
ke7789
Posts: 224
Joined: 2003-03-26 21:21

없는것 보단 시스템화 해서 만들어 놓는것도 나쁘지 않을것 같습

Post by ke7789 »

저희가 쓰고 있는게, 약간은 조악하고, 시스템화되어 있지 않아서, 매우 불편하지만..

만약에 어느정도 모듈화되고 시스템화 되어 있다면 괜찮을것 같습니다.

무슨얘기냐 하면..

Stocking되는 데이터를 저장하는 공통된 인터페이스를 제공하구여..

해당 Job에대해서 직접 DB에 억세스 할지.. 아니면 Cache를 사용할 지를 세팅 할 수 있게 해서.

좀더 유연하게 대처할 수 있는 시스테을 갖추어 놓으면 좋을것 같습니다.
nomoreid

특정상황에선 DB에이전트를 쓰는것이 좋더군요.

Post by nomoreid »

전에 구현 했던 모 MMORPG경우는 Item정보를 DB에 실시간으로 저장했었습니다.
DB는 Mysql이었구요.
초반에 트랜잭션이 안들어갔을때는 Mysql이 버텨주었는데
프로젝트 도중에 트랜잭션을 걸어주니까 Mysql이 상당히 버벅이더군요.
(뭐 지금 버전에선 어떤지는 모르겠습니다. 혹시 Mysql로 프로젝트 하시는 분은 테스트 해보세요.)
실시간으로 저장했다가 부하가 너무 커져서 주기적으로 저장하는 것으로 바꾸었구요.
그것도 모자라서 우선순위를 두어서 DB Thread가 처리하게 하고
돈을 아이템이아니라 필드 타입으로 바꾸는등의 최적화를 해서 좀 나아졌던 기억이 나네요.
이렇듯 아이템 실시간 처리처럼 디비작업을 많이 하는 구조가 필요한 경우에는 디비 부하에 대한
고려를 하셔서 설계를 하셔야 합니다. (그 반대로 초기에만 읽고 로그아웃때만 저장하는 구조라면
아이템 복사와 서버가 죽었을때 아이템 복구등을 다른 방법으로 구현해야 합니다.)

지금은 새로 하는 프로젝트는 위에서 말씀하신데로
메모리 DB + DB Agent 방법을 고려하고 있습니다.
이유는 일종의 캐쉬 디비를 구현하기 위해선데요.

구현 방법으로 따지자면 아래의 세가지가 있을 수 있는데요.

1 게임서버 <-> 메인디비
2 게임서버 <-> 디비에이전트 <-> 메인디비
3 게임서버 <-> 디비에이전트 <-> 캐쉬디비 <-> 디비에이전트 <-> 메인디비

캐쉬디비라는 의미는 게임서버에 유저가 접속했을때 한번만 주요 데이터를 메인디비에서 읽어서
캐쉬디비에 넣어주고 해당 유저의 플레이시는 캐쉬디비에만 실시간으로 아이템 위치 정보등을 저장해서
플레이를 합니다. (실제 이런일은 게임서버에서 하는게 아니라 디비에이전트의 임무입니다.)
게임 서버 한대에 캐쉬디비 한대가 귀속되는 것이죠. 그러므로 캐쉬디비는 적어도
한서버의 최대 동시접속 유저가 발생시키는 쿼리에 견딜 수 있어야 합니다.
그렇게 플래이시는 캐쉬디비에 저장하고 로그아웃시 메인디비에 캐쉬디비의 내용을 저장 합니다.
(이 작업도 디비에이전트의 몫입니다.)
서버가 죽는다면 디비에이전트는 캐쉬디비의 내용을 메인디비에 넣어주어서 사용자 아이템이
사라지거나 하는 것을 막아줍니다.

이게 기본 시나리오 입니다.

이 시나리오의 기본 가정은 DB서버가 실시간으로 아이템 정보를 저장하지 못할정도의 성능이 나오지 않는다는
겁니다.
모사처럼 cpu 64개짜리 메인프레임급의 DB서버를 메인으로 사용하는 경우라면 상당히
선택의 폭이 다양해지는데
그렇지 못한 경우라면 프로그래머가 알아서 기어야 합니다.

참. 캐쉬DB로 간단한 파일기반 DB를 (access같은) 사용하지 마십시요. (Mysql은 간단하지 않죠.)
부하에 못견뎌 죽으면 파일깨지고 처리하던것 다 날라갑니다.

^^;
Testors
Posts: 557
Joined: 2003-07-26 00:34
Location: (주)nFlavor
Contact:

Post by Testors »

근데 그건 디비 테이블 설계가 어떻게 되었는가에 따라서도 달라진다고 봅니다.
테이블 설계를 퍼포먼스 위주로 했다면.. (예를들면 인벤토리 데이터를 바이트 스트림으로 잡는다든가 하는 방법이죠)
검색은 좀 힘들겠지만 퍼포먼스면에서는 월등하기 때문에 충분히 쿼리만으로도 처리할 수 있지만..
컬럼수가 많고 크기가 방대한 데이터 테이블일 경우에는 실시간 쿼리전송으로는 역시 후달리겠죠..
의외이기는 하겠지만 ;
해당 레코드가 바이트 스트림이든, 혹은 필드의 조합이든.. 성능차이는 그리 크지 않습니다.
자료량이 적은경우는 이런 데이터 타입에 따른 성능차가 많이 날수 있겠지만,
규모가 커질수록 DB 부하의 대부분은 인덱스를 찾고, 그리고 해당 레코드를 물리적으로 디스크에 쓰거나 읽어내는데에 걸립니다. 이것은 DB 규모가 커질수록 더욱 드러나지요...
결국 실제 서비스를 해서 DB 규모가 수십기가 단위 이상으로 커지고 트랜잭션수가 충분히 많아지게 되면 일단 한 레코드에 접근하는데 드는 비용이 매우 크기 때문에, 레코드에 락을 건 이후에는 거기다 무슨짓을 하든 비용차이가 그리 크지 않습니다.

이를테면 실제 서비스 해서 규모가 충분히 커지면..
update xxx set x1=1;

update xxx set x1=1 , x2=2 , x3=3, ... x256=256;

update xxx set xarray = "ef08f8abc3f............"
과의 차이가 그리 크지 않다는 얘기. :wink:

(이쯤되면 무리해서 바이트로 쓰느니 관리가 편하게 좀더 직관적으로 필드를 구성하는편이 낫지요. 사실 상용 서비스의 병목은 "개발" "성능" 보다는 "관리" "유지보수" 인 경우가 태반이니까요)

참고로 DB의 병목은 CPU 가 아니라 HDD 입니다. CPU 64개짜리 기계에 HDD 1개 달린거보다 CPU 4개에 RAID 1+0 이 실제 서비스 해보면 성능이 훨씬 낫다는...
Testors
Posts: 557
Joined: 2003-07-26 00:34
Location: (주)nFlavor
Contact:

Post by Testors »

답변 감사합니다.

그런데, DB 처리에서 응답 시간 대기 지연은 그냥 게임서버에서
1. (스레드풀링 + critical section unlock) 또는
2. 비동기 DB 쿼리 또는
3. 스레드 풀링 + DB 쿼리 + 이벤트 트리거

중 하나를 구현하면 게임 서버에서 DB 억세스 중 노는 시간은 거의 zero로 만들 수 있죠. 제가 측정해 본 바로는, 쿼리 디스패치가 차지하는 퍼포먼스는 게임 서버 퍼포먼스에 비해서 매우 적은데, 이것 때문에 굳이 쿼리 서버를 별도로 만들 필요는 없다고 봅니다.
위의 분들이 잘 설명해 주셨지만 ;

DB 에이전트, 혹은 DB 브로커, 혹은 어떤 회사에서는 cached ;) ..
이것들이 목표하는바는 게임서버의 부하를 줄이는게 아니라 DB 서버의 부하를 줄이는 것에 있습니다.

이것은 비용 면에서 충분히 의미가 있는 것인데요,
예를들자면 - MMORPG 기준으로 - DB 기계 하나에서 1개 월드를 돌릴수 있어서 서비스 운영에 문제가 없다 하더라도..
만약 DB cache 를 써서 쿼리를 2/1 로 줄여 기계 하나에서 2개의 DB 인스턴스를 돌릴수 있다면..
이것으로 정신없이 비싼 MS-SQL Server 라이센스를 절반만 구입해도 됩니다. -_-;
아마 MS-SQL Server 라이센스 두어개 사려면 왠만한 개발자 1년치 연봉을 들여야 할텐데,
그 '월드' 란것이 수십개 단위로 늘어나게 되면....
사람 한명 써서 cached 만들게 되면.. 몇배로 남는 장사가 되겠지요..
nomoreid

또 참고로 말씀 드리자면.

Post by nomoreid »

역시 결론은 강기현씨가 -_-;;;;

특정 상황에 대한 처리 방법이 DB마다 다르기때문에 예상치 못하게 퍼포먼스가
안나오는 경우가 생길 수 있습니다.
제가 써본게 MySQL하고 M$SQL 서버 정도 밖에 없어서 충분히 말씀은 드리지 못하겠지만.

예를 들어 어떤 DB에서는 트랜잭션이 기대 이하로 느리게 작동 될 수도 있고 (MySQL의 경우)
데이터가 특정 싸이즈 이상 되었을때 정도의 차이는 있지만 무지 느려질 수 있습니다.

DB공통적으로는
싸이즈가 큰 필드를 update 할때 비교적 느려진다.
싸이즈가 가변형인 필드를 update할때 비교적 느리다.
Table에 들어 있는 데이터가 많아 질때 비교적 느려진다. (insert시의 index생성등을 위해)
Table안에 필드 수가 많은 경우 느려진다.

이런 여러가지 성능상의 문제가 있는데요. 느려지는 정도는 DB마다 상당히 차이가 있습니다.
Data양이 작을때는 안생기다가 DB싸이즈가 커지면 불쑥 생길 수도 있습니다. -_-;;;;;
개발시 이걸 충분히 고려해서 테이블을 설계하거나 그렇게 했다 하더라도 정확한 데이터는
사용하는 DB종류와 머신의 하드웨어 상황에 따라 달라질 수 있습니다. -_-;;;

좋은 방법은 해당 DB에 정통한 DBA와 상담하는 것도 괜찮은 방법이고 웹에서 자료를 찾아보는 경우도 좋겠구요.
사용할 DB와 머신이 정해진 상황에선 DB에 쓰레기 데이터를 넣고 테스트 해보는 것이 확실한 방법 입니다.

저 같은 경우는 전에 좀 당해서 쿼리양을 줄일수 있는 구조로 진행하는거죠 T_T

잡담으로.
일본쪽의 경우 좀 이상한게 상용 DB서버투자에 대해 좀 보수적이더군요.
이정도 규모면 상용DB를 사용하는 것이 어떠할까요? 라고 했는데 화들짝 놀라더군요.
라이센스비가 얼만데요! 라고 -_-; 그만큼 online게임 시장이 활성화 되지 않은 상태에서
설비나 장비 소스트웨어에 대한 투자를 안하려고 하더군요.

아 그리고 cpu 64개짜리 메인프레임급 DB서버라면 당연히 하드나 여러가지 장비들도 빠방 하겠죠. 냉장고 -_-;
그 서버를 직접 사용 하는 후배한테 그 DB서버 하나 죽거나 랜카드 고장나거나 하면 어떻게 하냐?
라고 했더니 그정도 대책은 이미 하드웨어적으로 되어 있죠. 돈이 얼만데. 라고 면박만 받았다는 -_-;
하지만 부럽다는 -_-;;;;
Testors
Posts: 557
Joined: 2003-07-26 00:34
Location: (주)nFlavor
Contact:

Post by Testors »

이런 여러가지 성능상의 문제가 있는데요. 느려지는 정도는 DB마다 상당히 차이가 있습니다.
Data양이 작을때는 안생기다가 DB싸이즈가 커지면 불쑥 생길 수도 있습니다. -_-;;;;;
개발시 이걸 충분히 고려해서 테이블을 설계하거나 그렇게 했다 하더라도 정확한 데이터는
사용하는 DB종류와 머신의 하드웨어 상황에 따라 달라질 수 있습니다. -_-;;;
그렇군요. 성능 관련 정얘기를 올리면서 환경에 대한 정보가 부족했네요.
제가 위에 올린 경우 -쿼리종류에 따른 성능문제- 는 MS-SQL Server 의 경우였습니다. ^^

저도 초창기에 My-SQL 을 사용했었는데 뭔가 이해하지 못하는 경우에서 성능이 느려진다던가
인덱스가 아무 이유없이 깨진다던가 - 공식적인 답변은 "DB 를 내린다음 xxxx 커맨드를 수행하시면 복구됩니다" 였다는 ; -
여튼 몇가지 문제를 겪고난 이후로 바꿨었어요. >.<

(MySQL 이전에는 file-base DB 를 썼었죠..! 최악의 단점은 역시 DB 비정상 종료시 운나쁘게 인덱스 기록중이었다면 데이터 전체가 작살난다는 -_-+)

성능 관련해서 다른 DB 의 특성도 아시는분 계시면 올려주시면 재밌을것 같네요. 이거 주제를 분리해야 하나..? ;)
imays
Posts: 1044
Joined: 2003-02-18 10:29
Contact:

쿼리 횟수 줄이기라...

Post by imays »

실제 쿼리 횟수를 줄이고자 쿼리 서버를 따로 두는 것이라면... 그런 기능이라면, 어차피 이미 내용을 RAM에 올려놓고 바로 억세스하고 있는 게임 서버 프로세스 내에서 쿼리 횟수를 줄이는걸로 충분하지 않을까요?

그러나, 1분 정도간의 백섭도 문제가 심각하게 나타나는 대박 온라인 게임의 경우까지도 고려할 것이라면, 로딩된 게임 데이터만을 갖고 있는 별도의 서버(아마 같은 컴퓨터 내의 별도 프로세스겠죠)를 두어서 게임 서버는 그 별도 서버와 통신하는 방식을 고려해볼 수도 있겠군요. 성능이 어떨지는 장담 못하지만요...
온라인 게임 서버 엔진 ProudNet
http://www.nettention.com
imays
Posts: 1044
Joined: 2003-02-18 10:29
Contact:

저의 DB 경험담...

Post by imays »

갑자기 얘기가 DB 자체의 성능으로 가는 것 같네요.

저는 MSSQL Standard를 썼습니다. DB 억세스를 할 때 DB 요청을 거는 게임 서버쪽에서는 게임 서버 전체 퍼포먼스에 비해서 거의 zero에 가까운 부하만을 먹을 뿐입니다. 그래서 DB 요청 관련을 별도 서버로 둘 필요를 못찾았습니다. 그러나, DB 억세스 요청을 받은 DB 서버 자체에서 먹는 퍼포먼스가 99% 차지했습니다. 한두개 레코드라면 별 차이 못느끼지만, 예컨대 레코드가 백만개 정도 되면 속도 저하가 슬슬 눈에 띄기 시작합니다.

가장 애먹었던 쪽은 아이템 테이블이었습니다. 레코드 백만개는 금방 채워지더군요. 처음에는 아주 느려서 애먹다가, DBA 전문가가 옆에 붙어줘서 한두주동안 뺑이치면서 최적화를 한 끝에 성능을 약 백배~천배정도 향상시켰습니다. (백배...의 근거는 처리 하나 하는데 2초 걸리던게 0.02~0.001초로 단축되었으니까요.) 처음에는 그냥 검색 대상이다 싶은거만 인덱스 달아두면 다 되는건줄 알았었는데, 그게 아니더군요... 쿼리의 흐름에 따라가는 인덱스 재구성이 중요한거였죠. ID번호 생성 및 관리에 대한 알고리즘 변경, 테이블 분산화 등이었습니다. MSSQL Ent는 테이블 분산 기능이 잘 되어 있지만, 서버 한두개도 아닌지라 가격이 폭등하더군요. 그래서 MSSQL Std만 갖고 분산 처리를 자체 제작해서 커버했습니다.
온라인 게임 서버 엔진 ProudNet
http://www.nettention.com
perpet

db 쪽애기해서 하는애기인데..

Post by perpet »

db서버를 분산하는방법중...
유저아이디를 기준으로
ㄱ~ㅁ 으로 시작하는 아이디들은 A디비서버에
ㅂ~ㅎ 으로 시작하는 아이디는 B디비서버에 저장해서
게임서버가 모든디비서버에 접속하고 필요할때 해당 디비에 접근하는건 어떤가요?
여기서 디비서버끼리 join할일이 없어야 하는거 말고..
좋은 방법아닌가요?
해보신분?
imays
Posts: 1044
Joined: 2003-02-18 10:29
Contact:

DB쪽 분산처리

Post by imays »

분산 테이블은 perpet님이 말씀하신 컨셉대로 분산하는 것입니다.
단, ㄱ~ㅎ 식 구분은 고른 분포가 되지 않는다는 문제가 있습니다. (김씨가 매우 많다는게 그 예이죠.) 어떠한 상황에서도 고른 분포가 될 수 있어야 합니다. 제 앞 글에서도 ID 생성 알고리즘 운운했던 것도 이 때문입니다. 나열한 데이터를 인덱싱한 결과가 각 서버에 고루 분포될 수 있게(INTERLEAVE) 인덱스 값을 생성하는 알고리즘이 필요합니다. HASHING과 좀 비슷하겠죠.
그리고 분산 트랜잭션에서 서로 다른 서버간의 JOIN이 들어가면 성능이 급격히 떨어집니다. 최대한 join 단위는 같은 서버에서 일어날 수 있도록 설계해야 합니다.
온라인 게임 서버 엔진 ProudNet
http://www.nettention.com
Guest

Re: db 쪽애기해서 하는애기인데..

Post by Guest »

perpet wrote:db서버를 분산하는방법중...
유저아이디를 기준으로
ㄱ~ㅁ 으로 시작하는 아이디들은 A디비서버에
ㅂ~ㅎ 으로 시작하는 아이디는 B디비서버에 저장해서
게임서버가 모든디비서버에 접속하고 필요할때 해당 디비에 접근하는건 어떤가요?
여기서 디비서버끼리 join할일이 없어야 하는거 말고..
좋은 방법아닌가요?
해보신분?
전에 게임에선 DB서버를 나누진 않았고 태이블을 저런식으로 나누었었는데요.
나눌때 기준으로 숫자 userid를 이용하는 것도 좋은 방법 입니다.
게임마다 유저에게 인덱스 아이디를 부여하자나요.
인덱스 아이디는 일률적으로 부여되기 때문에 한쪽으로 편중되는 일이 없기때문이죠.
그걸 기준으로 나누는 것도 간단하게 나눌 수 있는 방법 입니다.

저희 같은 경우 id % 10 으로 태이블을 나누고 자주 업데이트되는 태이블과
가끔업데이트 되는 태이블을 나누었지요. (0~9까지 10개로 나눈거죠.)

예)
user_info_fu_1 : 끝자리수가 1로 끝나는 자주 업데이트되는 유저정보 테이블
user_info_ou_0 : 끝자리수가 0으로 끝나는 가끔 업데이트되는 유저정보 테이블

fu에는 마지막 로긴 시간 , 마지막으로 선택한 캐릭터 아이디 처럼 로긴시마다 업데이트되고 불려지는 정보를 넣어두고.
ou에는 전화번호 주민번호, 아이디 거의 업데이트 될일이 없는 정보들을 넣어 두었습니다.

f는 frequently , o는 occasionally 입니다.

마찬가지로 아이템쪽도 나눌 수 있겠죠.

태이블별로 나누어도 효과가 있을 수 있는 이유는 DB가 MySQL일 경우 MySQL은 태이블별로 파일이 생성되는 구조이기 때문입니다.
또 여타 DB에서도 태이블별로 락을 걸어 처리하는 경우가 많기 때문에 태이블을 쪼개놓는 것이 성능 향상에 도움이 될 수 있겠죠. 물론 join등을 자주 하는 경우가 아니어야 겠지요.
왠지 DB성능관련 주제가 된듯한.. -_-;;;
Guest

Re: 쿼리 횟수 줄이기라...

Post by Guest »

imays wrote:실제 쿼리 횟수를 줄이고자 쿼리 서버를 따로 두는 것이라면... 그런 기능이라면, 어차피 이미 내용을 RAM에 올려놓고 바로 억세스하고 있는 게임 서버 프로세스 내에서 쿼리 횟수를 줄이는걸로 충분하지 않을까요?
위의 상황은 주기적으로 아이템등의 바뀐 사항을 모아서 DB에 쿼리하는 방법이겠군요.
게임에 따라 쿼리양이 적은 경우 유용하다고 생각 합니다. 실제적으로 전에 작업했던 게임도
유사한 방법을 써서 해결하긴 했었지요.

하지만 1분단위로 쿼리하는 것과 유저의 로그온 로그아웃시에 쿼리 하는 것과의
양차이는 상당할 것이기 때문에 캐쉬디비는 나름대로 의미가 있다고 생각 합니다. ^^;
Locked