NDC 참관기: 덤프 파일을 통한 사후 디버깅 실용 테크닉

슬라이드는 “NDC2012 덤프 파일을 통한 사후 디버깅 실용 테크닉“에서 볼 수 있음.

넥슨 김이선 님의 발표.

내용 요약:

돈을 벌기 전에는 배포 전 디버깅이 중요하다.
라이브 상황에서는 배포 후 디버깅이 더 중요해진다.

덤프 파일

특정 상황 — 특히 안좋은 상황 — 에서 프로세스 상태를 디버깅 용으로 남기는 것.
풀 메모리 덤프를 남기면 좋지만 커서(…) 미니 덤프를 남긴다.
상용 서비스까지 갔다면 미니덤프를 남기고 이를 수집해서 디버깅하는 시스템은 필수.

하지만 미니 덤프 디버깅의 현실은…

  • 덤프 파일을 열었는데 심볼이 없다고 어셈블리 코드가 보이는 경우
  • 여기서 죽으면 안되는데 왜 죽었나 싶은 경우?
  • 콜스택이 깨졌다거나
  • 풀 메모리 덤프를 남겼는데 내가 보려는 객체는 어디에?

덤프 파일과 pdb 파일 연결하기

  • 미니덤프 헤더는 RSDS 헤더, GUID, age, pdb-path 등이 들어감
  • pdb, exe, minidump는 이 GUID로 연결된다
  • 심볼서버는 당연히 써야
  • 보안 솔루션 (더미다 류) 을 사용하면 덤프 파일의 GUID가 바뀐다
  • 하지만 COFF file format의 링크 시간을 기록한 타임 스탬프는 유지
  • 클라이언트 덤프 수집단계에 미니덤프와 해당하는 PDB를 맺어주는 단계를 넣자(클라이언트 버전 정보; 타임 스탬프를 이용해서)

여러 개의 덤프 파일을 분석할 때

일어나지 않을 것 같은 일도 덤프 파일이 많으면 분석할 수 있음[1]

  • 분류 기준으로 EIP, callstack, 게임에 따른 정보(맵, 장비, …)
  • 외부 모듈이나 말이 안되는 곳이면 어떻게하지? 클라는 환경을 통제할 수 없으니 외부 변수를 추적한다
  • EIP와 다른 변인 (OS, CPU, GPU) 등을 보면 예상되는 것과 다른 분포인 경우가 있다 (=환경 편재)
  • OS라면 드라이버 버그, CPU의 문제 (보통은 mainboard), GPU 문제, 외부 모듈 (보안 프로그램이나 해킹 툴)

사례 분석

 

  1. DF의 코드 베이스를 VS 2003에서 VS 2008로 이전함.
  2. 특정 유저 (소수) 에서 채널 선택하는 순간 HeapAlloc/HeapFree 중에 크래시 하는 버그 발견
  3. Heap-corruption이라,
    • 게임 시작에서 채널 선택하는 부분까지의 코드를 리뷰
    • 이 영역에 많은 수의 trap code와 HeapValidate 코드 삽입
    • 하지만 문제는 발견되지 않음
  4. 모듈 목록에 환경 편재가 있음: BFCO0GAF.dll 등의 알파벳/숫자가 섞인 특정 패턴의 모듈 발견
  5. 해당 dll이 악성 프로그램이 삽입한 것; 2003과 2008의 heap 구현이 달라서 생긴 일

콜 스택이 깨지는 경우

  • EBP, ESP 중 하나만 깨져도 콜 스택을 복원할 수 없다
  • 이를 다음 휴리스틱으로 극복
    1. 스택 메모리에서 주소를 추려낸다 (모듈 정보의 주소 영역을 이용해서)
    2. 스택 메모리에서 스택 주소를 추려낸다
    3. 1 + 2를 해서 콜 스택을 추정
  • 프로그래머의 해석이 필수

힙 메모리 문제

  • 메모리 덤프가 있으면 디버깅에 큰 도움이 된다
  • 하지만 모든 메모리 객체에 접근하는 건 쉽지 않음
  • 메모리를 exhaustive하게 검색
  • vfptr 값 이용
  • typeid(T)의 구현 형태를 이용해서 타입 이름을 이용해서 검색

이걸 포함한 오픈소스 툴을 공개

 

 

감상:

이번에 네 개 세션 밖에 못들었는데, 그 중 제일 괜찮은 강연이었다. 다음 세션을 회사 돌아갈 시간이라 못 들은게 아쉬움.

내가 예전에 했던 유사한 시도는 통계적으로 분류하고 / 적당한걸 찾을 수 있게 도와준다 정도였는데 (VS 안띄우게 하는게 목표였으니..) 이렇게 실제 사례를 바탕으로 한 내용을 알고 있었다면 훨씬 좋게 할 수 있었을 듯.
그리고 바이너리가 수정된 경우의 처리는 제대로 못했는데 — ipkn 패치해서 돌아가게 수정 — 이 부분에 대한 정보도 얻게 되어서 좋았다.

게다가 강연자 분이 “이런거 되는걸 모아서 새로 짜서 공유했습니다”라고 말한건 대박(…).
아마 `지식 공유’란 점에서 모델이 될만한 수준.

summerlight 님이 녹화한 영상도 토런트 시딩되고 있을테니 (촬영 가능한 세션이었음) 관심 생기신 분들은 한 번씩 보는걸 추천합니다.

  1. 이건 이전 회사에 있을 때 내가 포스트모텀 디버깅, 그것도 최대한 많은 수를 수집해야 한다고 주장한 이유와 같음 []

NDC 참관기: 실시간 HTTP 양방향 통신에 붙여…

이전 글에 안 써놓은 감상을 여기에.

HTTP 자체가 프로토콜 적으로 한계를 갖기 때문에 여러 가지 보완 방법이 제시되고 있는데, 현재 상태를 다른 수단으로 극복하기 위한 몇 가지 시도에 대해서 논해서 재밌었다.

구현이 궁금했지만 까본 적은 없었던 몇 가지 구현체 — FB 메신저, gmail에 달린 google talk — 를 분석하고 이에 대한 단점 (장점이야 HTTP 한계 극복이니) 을 논한 점은 +.
html5의 web-socket을 좀 더 자세히 다뤄줬으면 좋았겠지만 이건 스코프를 벗어나는 문제인 듯 하니 어쩔 수 없겠지.

 

앞으로 알아봐야 할 것, 생각해 볼 것들을 정리하자면,

  • http가 주 프로토콜인 non-SNG 게임 서비스를 만들 일이 근 미래(3년 내)에 있을까?
  • 그렇다면 html5 + web socket 기술이 충분히 침투한 상태일까?
  • 모바일까지 지원한다면 결국 어느 기술을 골라서 쓰게 될까?
  • 말미에 언급한 미들웨어 서버의 성숙도는 충분할까?

정도인데;

일단 http가 주 프로토콜인 서비스를 만들 일은 머지 않은 미래에 겪게될 것 같다. 지금 하는 일이랑 연관이 없긴 하지만(…).

표준화 속도나 사람들이 적응하는 속도를 따져보면 mobile 말고는 html5 지원율은 높지 않을 (낮을?) 것이고, web socket 침투율은 더 낮을 것 같다. 특히 브라우저 벤더에 따라 기본 보안 설정이 상이할 가능성이 높을 것 같음.

뭔가 별도 플러그인으로 가기엔 모바일 지원이 매우 힘들 것 같고, 강연에서 언급한 몇 가지 방식을 잘 조합하거나, 성숙도 높은 미들웨어를 고르지 않을까 하는 정도.

대부분의 문제를 잘 해결해주는(…) 미들웨어 솔루션을 만들어서 팔 수 있다면 좋겠다는 생각도 좀 들긴한다.

NDC 참관기: 실시간 HTTP 양방향 통신

수요일(2012-04-25) 오후에 있었던 이승재 군의 발표.

발표 자료는 http://ricanet.com/new/view.php?id=blog/120425 에서.

HTTP Protocol의 한계

http는 request/response protocol이다. 이로 인해서 클라이언트 쪽의 이벤트는
서버 쪽에 쉽게 전달할 수 있지만, 서버 쪽의 이벤트는 클라이언트가 요청하기
전에는 전달할 수 없다.

그런데 현재의 웹 쪽 트렌드를 보자면, twitter나 facebook, google mail (or talk)
같은 경우 실시간으로 메시지를 보낸다. 어떻게 하는걸까?

이를 극복하기 위한 기법들

기본적으로 꼼수다 — 프로토콜의 한계 때문에.

Polling

웹 브라우저에서 주기적으로 요청을 보낸다. (클라이언트 쪽 타이머 이용)
문제:

  • 트래픽이 많다 / 서버 쪽 부하가 걸린다
  • 지연 시간이 크다; 이벤트-클라이언트 요청 시간 차이 때문에. 그렇다고지연 시간을 줄이면 트래픽/서버 부하가 더 커진다.

Long-polling

클라이언트가 미리 요청을 보내고, 서버는 이벤트가 생기는 순간까지 기다렸다가
이를 모아서 (이미 온 요청에) 응답을 보낸다.
Facebook 메신저 구현이 이를 이용한다.
문제:

  • 구현 복잡도. 서버가 요청이 이미 와 있는 경우와 그렇지 않은 경우를 구분해서 처리해야하는 등.
  • 지연 시간; 응답을 보낸 후 클라이언트가 다시 요청을 보내올 때까지의 시차.

Hidden iframe

페이지에 숨겨 놓은 iframe을 통해서 메시지를 계속 흘려 보낸다. (서버가 응답을
끝내지 않는다) 그래서 http streaming이라고 부르기도 한다.
Gmail messenger(=google talk)에서 사용하는 방법이다.

문제:

  • 응답이 끝나지 않기 때문에 클라이언트 쪽 웹 브라우저에 메모리 릭이 생긴다.
  • 프록시 / 보안 프로그램이 응답이 완전히 끝나야만 이를 넘겨주는 경우가 있다.

Browser plugin

Flash, ActiveX 등을 이용. 사실 상 TCP 소켓처럼 쓸 수 있다.
호환성 문제가 너무 커서…

WebSocket (html5)

javascript 단에서 진짜 소켓을 쓸 수 있다. 표준화가 아직이라 (protocol은
결정되었지만, API가 아직 unstable).
기존 웹브라우저와의 호환성 문제.

WebIRC (=IRC web-bridge for smartphones) 만들기

Long-polling이 호환성이 좋고 (최소한 iOS, android를 지원해야 했음),
구현이 재밌어 보여서(…) 이를 구현함.

프로토콜

  • InitLog: 각 채널 최근 로그 k 줄을 요청
  • UpdateLog(last\[\]): 각 채널에서내가 마지막으로 받은 로그 ID가 last일 때 그 이후 로그를 요청

서버 구현 이슈

HTTP 핸들러가 새로운 내용이 없으면 대기하는 것.
vs.
Event listener가 새로운 내용이 왔을 때 대기 중인 스레드(의 요청)를 깨우는 것
사이의 레이스 컨디션.[1]

node.js 류를 사용하면 오히려 쉬웠을지도 모르지만 이미 python으로 구현.

Webserver Architecture

동시에 살아있는 연결이 많아서,

  • 커넥션 당 1 스레드 때문에 메모리 병목
  • 고전적인 웹 서버의 경우 더 중요한 페이지 뷰보다 동시 접속 수가 문제
  • Gevent로 쉽게 해결
  • Long-polling에 맞춰서 구현했더니 stateless 프로토콜이 되어 네트워크 단절에 강해졌다.
  • 채팅 보내는 것이 네트워크 불안정엔 약했음. 이걸 극복하려니 사실상 TCP 류의 프로토콜을 HTTP 위에 재구현하는 형태가 되어버리게 되서…

Middlewares

앞에서 언급한 방법들엔 정답이 없다. 각 방법의 장단점이 다름.

orbited2, socket.io 같은 미들웨어가 있다.
그렇지만 정작 제작 시점에 사용하려던 orbited 사이트가 내려가 있어서
long-polling을 직접 구현.

Orbited

orbited.js + *application.js* — orbited server — application server

위의 형태로 구성. Web-router + firewall의 역할. Legacy TCP 응용프로그램
서버인 경우에도 쉽게 통신할 수 있다.

socket.io

nopde.js 기반. 메시지 단위 전송을 지원한다.

확인해야 할 사항

  • 연결 당 서버 리소스 소모량
  • 연결이 불안정하면 어떻게 되는가?
  • 웹 브라우저를 껐다켜도 괜찮은가?

웹-게임 연동

이런 기술을 쓰면 웹 게임에서도 네트워크 제약(http 문제)이 *거의* 없어진다.

WoW 전정실, 아이온, 마비의 거래소, 넥슨 홈이나 스팀의 업적 시스템 구현이라거나,
게임 웹 채팅, 친구 게임 참여 알리기, 우편 도착 알림 등의 실시간 기능이 가능해질듯.

결론(?): 취미 프로젝트 좋아요(…)

  1. 내 생각, 그리고 최치선 군의 의견을 조합하자면, 저건 pthread condvar 류의 동기화 도구를 사용하면 해결 될듯 함. 치선 군이 실 서비스에서 사용하고 있는 추천 구현체는 gevent의 Queue (monkey-patching하는). []