• 2007-02-08

    In-game Ads 의 현실

    이미 게임 내 광고의 세계는 거인들의 전쟁터가 되어 버렸다. 개발자들끼리 자조적으로 이야기하는 것처럼 "코묻은 돈을 얼마나 많이 긁어내느냐?"는 고민 대신, 가능한한 많은 무료 사용자를 유치해서 게임내 광고를 거부감을 최소화하는 범위에서 가급적 많이 노출시켜, 사용자가 아닌 광고사로부터 돈을 긁어내는 방법을 연구해야 할 때가 온 것이다. (이미 TV나 라디오가 그런 것처럼...)

  • 2007-01-16

    지금까지 팔린 Microsoft points는 얼마?

    지금 만들고 있는 게임이 국내용이 아닌지라, 해외 특히 미국에서 서비스중인 게임들의 비지니스 모델들을 연구하고 있다. 그런 와중에, 개인적으로 관심있게 지켜보고 있는 XBOX 라이브 마켓플레이스의 2006년 8월의 통계 자료를 찾았다. 그 중에서 괄목할만한 통계들만 뽑아보면...

    • 5천만 회 : 마켓플레이스를 통한 다운로드 회수. 불과 3개월 전에 2천5백만회였음.
    • 2백만 시간 : 매든 07을 판매한 첫 주만에 달성한, 라이브를 통해 이루어진 네트워크 플레이 시간의 총합
    • 20억 시간 : 2002년 11월 이후부터 누적된 네트워크 플레이 시간의 총합
    • 백 삼십만 개 : 매일매일 라이브를 통해 전송되는 텍스트와 보이스 채팅 메시지의 개수
    • 8백만 회 : XBOX360 발매 이후, 라이브 아케이드 게임의 다운로드 횟수
    • 20억 포인트 : 지금까지 팔린 Microsoft Points 의 액수

    여기서 가장 중요한 것은 바로 Microsoft Points 의 판매액인데, wikipedia에 따르면 미화 1달러가 80 포인트이므로, 2천5백만달러어치, 이걸 네이버 환율 계산기로 환전하면 무려 230억원이나 된다는 사실. 마켓플레이스에 올라가 있는 대부분의 아이템들이 테마나 게이머카드라는 점과, 아직 소액 결제가 우리 나라처럼 활성화되어 있지 않다는 점, 그리고 현거래가 필수화되는 MMORPG가 아니라 비교적 폐쇄적인 네트워크-콘솔-게임-환경이라는 점을 감안해보면 실로 엄청난 판매량이라고 봐야 하지 않을까?

    see also:

  • 2007-01-10

    TRAC custom field

    trac.ini 를 아래와 같이 수정해서 티켓에 커스텀 필드를 추가할 수 있다.

    
    [ticket-custom]
    
    WorkTime = text
    WorkTime.label = 예상작업시간
    WorkTime.order = 1
    
    StartDate = text
    StartDate.label = 시작일
    StartDate.order = 2
    
    EndDate = text
    EndDate.label = 완료일
    EndDate.order = 3
    

    그리고 나서 티켓 수정 화면에 가보면 다음과 같이 커스텀 필드가 추가되어 있다.

    trac_custom_field.jpg

  • 2006-12-18

    데드락 추적하기

    SQL 서버에서 데드락이 걸리면 락 매니저는 그 중 하나를 victim 으로 삼아서 죽이게 된다. 문제는 기본 설정 만으로는 어떤 SQL문끼리의 충돌인지를 확인할 수 없다는 점인데, SQL Server 에러 로그를 이용해서 이를 쉽게 알아낼 수 있다.

    normal deadlock

    dbcc traceon(1204,3605,-1) 를 이용하면, 데드락 이벤트(1204)가 발생할 경우 에러 로그에 남길 수 있다. -1 은 세션 설정이 아닌 서버 전역 설정을 의미한다. 가장 좋은 방법은 시스템 시작 파라미터에다가 -T1204 를 넘겨주는 방식. 단 성능에 문제가 있을 수 있으므로, 데드락을 잡고 나서 끄는 것을 잊지 말도록.

    주기적으로 sp_readerrorlog 또는 엔터프라이즈 매니저에서 확인해보다 보면 아래와 같은 로그가 나올 때가 있다.

    
    Deadlock encountered .... Printing deadlock information 0
    2006-12-13 14:31:13.11 spid4    0
    2006-12-13 14:31:13.11 spid4  Wait-for graph    0
    2006-12-13 14:31:13.11 spid4    0
    2006-12-13 14:31:13.11 spid4  Node:1    0
    2006-12-13 14:31:13.11 spid4  RID: 8:1:3534:228  CleanCnt:1 Mode: X Flags: 0x2  0
    2006-12-13 14:31:13.11 spid4  Grant List 2::    0
    2006-12-13 14:31:13.11 spid4  Owner:0x4ae74ca0 Mode: X  Flg:0x0 Ref:0 Life:02000000 SPID:64 ECID:0  0
    2006-12-13 14:31:13.11 spid4  SPID: 64 ECID: 0 Statement Type: UPDATE Line #: 12    0
    2006-12-13 14:31:13.11 spid4  Input Buf: Language Event: insert into take_time_table (type, name, userID, takeTime) values (4, 'PickupServerApp', 50780, 6493)  0
    2006-12-13 14:31:13.11 spid4  Requested By:     0
    2006-12-13 14:31:13.11 spid4  ResType:LockOwner Stype:'OR' Mode: S SPID:58 ECID:0 Ec:(0x778C9508) Value:0x7321ac20 Cost:(0/1BC) 0
    2006-12-13 14:31:13.11 spid4    0
    2006-12-13 14:31:13.11 spid4  Node:2    0
    2006-12-13 14:31:13.11 spid4  RID: 8:1:3535:117  CleanCnt:1 Mode: X Flags: 0x2  0
    2006-12-13 14:31:13.11 spid4  Grant List 1::    0
    2006-12-13 14:31:13.11 spid4  Owner:0x3e54c7c0 Mode: X  Flg:0x0 Ref:0 Life:02000000 SPID:58 ECID:0  0
    2006-12-13 14:31:13.11 spid4  SPID: 58 ECID: 0 Statement Type: CONDITIONAL Line #: 8    0
    2006-12-13 14:31:13.11 spid4  Input Buf: Language Event: insert into take_time_table (type, name, userID, takeTime) values (2, 'GatewayServerApp', 50977, 0)    0
    2006-12-13 14:31:13.11 spid4  Requested By:     0
    2006-12-13 14:31:13.11 spid4  ResType:LockOwner Stype:'OR' Mode: U SPID:64 ECID:0 Ec:(0x611CD508) Value:0x4ae74e20 Cost:(0/134) 0
    2006-12-13 14:31:13.11 spid4  Victim Resource Owner:    0
    2006-12-13 14:31:13.11 spid4  ResType:LockOwner Stype:'OR' Mode: U SPID:64 ECID:0 Ec:(0x611CD508) Value:0x4ae74e20 Cost:(0/134) 0
    
    

    위 로그에 의하면 single insert statement 2개를 동시에 실행할 때 데드락이 걸렸다. 처음에는 legacy 서버에서 스토어드 프로시저 대신 raw SQL을 실행했기 때문에 발생된 것으로 추측했는데, 논리적으로 이 둘이 데드락을 유발시키기는 좀 힘든 상황이었다. 이 경우 dbcc page 명령을 이용하면, 구체적으로 어떤 메모리 페이지에서 락이 걸렸는지를 확인해볼 수 있다. 위 로그에서 RID 부분을 찾아서 넘겨주면 끝. (단 이 명령을 실행하면 역시나 에러 로그에 남기 때문에, 나중에 보고 놀래지 말 것!)

    [sql]
    dbcc page(8,1,3534,3)
    dbcc page(8,1,3535,3)
    [/sql]

    결국 문제는 저 테이블에는 다른 테이블로 또다시 select & insert 하는 무지몽매한 트리거(-_-)가 걸려 있어서 생긴 문제였다. 하아.

    Key deadlock

    이번엔 키 데드락 로그를 살펴보자. 이 경우 RID 대신 KEY 라고 나오는데, SELECT OBJECT_NAME(KeyID) 를 이용해서 어떤 오브젝트에서 락이 걸렸는지를 알아낼 수 있다.

    
    Deadlock encountered .... Printing deadlock information 0
    2006-12-20 20:37:35.73 spid4    0
    2006-12-20 20:37:35.73 spid4  Wait-for graph    0
    2006-12-20 20:37:35.73 spid4    0
    2006-12-20 20:37:35.73 spid4  Node:1    0
    2006-12-20 20:37:35.73 spid4  KEY: 8:612197231:1 (5000dcb808b7) CleanCnt:1 Mode: Range-S-U Flags: 0x0   0
    2006-12-20 20:37:35.73 spid4  Grant List 1::    0
    2006-12-20 20:37:35.73 spid4  Grant List 3::    0
    2006-12-20 20:37:35.73 spid4  Owner:0x25bdf860 Mode: Range-S-S Flg:0x0 Ref:0 Life:02000000 SPID:69 ECID:0   0
    2006-12-20 20:37:35.73 spid4  SPID: 69 ECID: 0 Statement Type: EXECUTE Line #: 0    0
    2006-12-20 20:37:35.73 spid4  Input Buf: RPC Event: sp_cursoropen;1 0
    2006-12-20 20:37:35.73 spid4  Requested By:     0
    2006-12-20 20:37:35.73 spid4  ResType:LockOwner Stype:'OR' Mode: X SPID:57 ECID:0 Ec:(0x39939508) Value:0x5223ee00 Cost:(0/1070)    0
    2006-12-20 20:37:35.73 spid4    0
    2006-12-20 20:37:35.73 spid4  Node:2    0
    2006-12-20 20:37:35.73 spid4  KEY: 8:612197231:1 (d000bebebbe4) CleanCnt:2 Mode: X Flags: 0x0   0
    2006-12-20 20:37:35.73 spid4  Wait List:    0
    2006-12-20 20:37:35.73 spid4  Owner:0x3dc49b20 Mode: S  Flg:0x0 Ref:1 Life:00000000 SPID:65 ECID:0  0
    2006-12-20 20:37:35.73 spid4  SPID: 65 ECID: 0 Statement Type: SELECT Line #: 1 0
    2006-12-20 20:37:35.73 spid4  Input Buf: Language Event: select b.charid from user_table a join char_table b on a.userid=b.userid where b.disable=0 and b.usertype=2 and a.username='throwrocks@me.com' 0
    2006-12-20 20:37:35.73 spid4  Requested By:     0
    2006-12-20 20:37:35.73 spid4  ResType:LockOwner Stype:'OR' Mode: Range-S-S SPID:69 ECID:0 Ec:(0x3A7A1548) Value:0x68dded80 Cost:(0/0)   0
    2006-12-20 20:37:35.73 spid4    0
    2006-12-20 20:37:35.73 spid4  Node:3    0
    2006-12-20 20:37:35.73 spid4  KEY: 8:612197231:1 (d000bebebbe4) CleanCnt:2 Mode: X Flags: 0x0   0
    2006-12-20 20:37:35.73 spid4  Grant List 1::    0
    2006-12-20 20:37:35.73 spid4  Owner:0x4f336b40 Mode: X  Flg:0x0 Ref:0 Life:02000000 SPID:57 ECID:0  0
    2006-12-20 20:37:35.73 spid4  SPID: 57 ECID: 0 Statement Type: UPDATE Line #: 135   0
    2006-12-20 20:37:35.73 spid4  Input Buf: RPC Event: U_CharacterSaveLocker;1 0
    2006-12-20 20:37:35.73 spid4  Requested By:     0
    2006-12-20 20:37:35.73 spid4  ResType:LockOwner Stype:'OR' Mode: S SPID:65 ECID:0 Ec:(0x74FA7548) Value:0x3dc49b20 Cost:(0/0)   0
    2006-12-20 20:37:35.73 spid4  Victim Resource Owner:    0
    2006-12-20 20:37:35.73 spid4  ResType:LockOwner Stype:'OR' Mode: S SPID:65 ECID:0 Ec:(0x74FA7548) Value:0x3dc49b20 Cost:(0/0)   0
    2006-12-20 20:37:40.73 spid4    0
    

    DBCC PSS

    DBCC PSS(uid [, spid]) 를 통해서 특정 pid 의 다양한 속성들을 알 수 있다. uid 는 select * from sysusers 로 체크하고, 프로세스는 sp_who2 로 알아내면 된다. 물론 spid 를 생략하면 해당 유저의 모든 프로세스의 정보가 뜬다.

    
    PSS @0x1B9E71E0
    ---------------
    pspid = 53  m_dwLoginFlags = 0x03e0  plsid = 1827921760
    pbackground = 0
    pbSid
    -----
    81ee3246 10030a4a 8c19c980 f40a127f  ..2F...J........
    sSecFlags = 0x2  pdeadlockpri = 0  poffsets = 0x0
    pss_stats = 0x0  ptickcount = 905625531
    pcputickcount = 2711581261636168  ploginstamp = 313917
    ptimestamp = 2006-12-18 03:18:26.550  plangid = 0
    pdateformat = 1  pdatefirst = 7  Language = us_english
    UserName = ubo_game  poptions = 0x28400020  poptions2 = 0x3f438
    pline = 1  pcurstepno = 0  prowcount = 1
    pstatlist = 0  pcurcmd = 253  pseqstat = 0
    ptextsize = 2147483647  pretstat = 0  CNestLevel = 0
    @@procid = 0  pslastbatchstarttime = 2006-12-21 23:36:14.363
    pmemusage = -2095  hLicense = 0  tpFlags = 0x1
    isolation_level = 0  fips_flag = 0x0  sSaveSecFlags = 0x0
    psavedb = 0  pfetchstat = 0  pcrsrows = 0
    pslastbatchtime = 2006-12-21 23:36:14.363  pubexecdb = 0
    fInReplicatedProcExec = 0 pMsqlXact = 0x6D6AD038  presSemCount = [0]0
    presSemCount = [0]0  pcputot = 5182694  pcputotstart = 5182694
    pcpucmdstart = 5182694  pbufread = 346  pbufreadstart = 346
    plogbufread = 11300361  plogbufreadstart = 11300354
    pbufwrite = 6374  pbufwritestart = 6374  pLockTimeout = 4294967295
    pUtilResultSet = 0x00000000
    

    [sql]
    SET SHOWPLAN_ALL ON
    SET STATISTICS PROFILE ON
    [/sql]
    DB에 문제가 생기면 언제나 무료로 컨설팅해주시는 자칭 초보 DBA 창아군에게 Special Thanks를 보낸다.