61
서서 서서서서 1 서서 서서서서서 1 서서 서서 서서서 Nettention

게임 서버 1대에 동시접속자 1만명 넣기

Embed Size (px)

DESCRIPTION

프라우드넷에서 MMO 게임 서버 프로세스 1개에서 멀티 코어를 효율적으로 사용하기 위해 어떠한 기술을 구사했는지 소개합니다.

Citation preview

Page 1: 게임 서버 1대에 동시접속자 1만명 넣기

서버 프로세스 1 개에 동시접속자 1 만명 넣기

배현직Nettention

Page 2: 게임 서버 1대에 동시접속자 1만명 넣기

내 소개

突击 1941

• 1995 년부터 게임회사에서 근무• 토끼와 거북이 3D, Menticide 격투

게임• 오즈 월드 , 블리츠 1941

• Game Programming Gems 5,7

• ProudNet• KGC 2010, 2011, 독일 Quo Vadis

2012, 중국 CGDC 2012, 일본 CEDEC 에서 강연

Page 3: 게임 서버 1대에 동시접속자 1만명 넣기

• 로비형 MO 게임 – 쉽게 해결– 서버 머신 증설만 하면 됨

RoomServer

RoomServer

RoomServer

RoomServer

RoomServer

RoomServer

RoomServer

RoomServer

Page 4: 게임 서버 1대에 동시접속자 1만명 넣기

• 월드 개수가 고정된 MMO 게임– 쉽게 해결– CPU 개수만큼 월드 서버들을 띄우면 됨– 단 , 1 개 CPU 가 1 개 월드를 처리할 수 있으면

ZoneServer

ZoneServer

ZoneServer

ZoneServer

ZoneServer

ZoneServer

ZoneServer

ZoneServer

Page 5: 게임 서버 1대에 동시접속자 1만명 넣기

• 월드 서버 1 개가 CPU 한 개 사용량을 넘어가면 ?

• 서버 프로세스 로직의 병렬화가 필요 !

Zone Server

Zone Server

Page 6: 게임 서버 1대에 동시접속자 1만명 넣기

10,000 소켓 쉬움

그리고 일대일 통신 그럭저럭

그리고 일대다 통신 빡셈

Player_Move

Player_ShowM

ove

Player_ShowM

ove

Player_ShowM

ove

MMO 게임 서버는 이러함 !

Page 7: 게임 서버 1대에 동시접속자 1만명 넣기

용어 정의

Page 8: 게임 서버 1대에 동시접속자 1만명 넣기

Lock(X)

class MyType{ CritSec m_critSec; int a;}

MyType X;

void Something(){ CritSecLock lock(X.m_critSec); ...; }

Page 9: 게임 서버 1대에 동시접속자 1만명 넣기

컨텍스트 스위치

Thread 2Thread 1

컨텍스트 스위치

컨텍스트 스위치

Page 10: 게임 서버 1대에 동시접속자 1만명 넣기

Thread 1{ lock(A); A = A+1; lock(A);}

Thread 2{ lock(A); A = A * 2; unlock(A);}

Object A

Contention

CPU 1 CPU 2

CPU cache sharing!

Page 11: 게임 서버 1대에 동시접속자 1만명 넣기

granulation

A

B

C

D

A

B

C

D

리소스 분할

Page 12: 게임 서버 1대에 동시접속자 1만명 넣기

우리가 겪은 문제

Page 13: 게임 서버 1대에 동시접속자 1만명 넣기

목표

CPU %

동시접속자 + 트래픽

1 개 서버 프로세스가 모든 CPU 를 적절히

활용해야

Page 14: 게임 서버 1대에 동시접속자 1만명 넣기

𝑟=1

(1−𝑃 )+ 𝑃𝑆

처리의 40 %가 병렬화 (P = 0.4)2 배 성능으로 병렬화 (S = 2)

그러나 전체 성능은 겨우 25% 향상(r = 1.25)

Amdahl 의 법칙

Page 15: 게임 서버 1대에 동시접속자 1만명 넣기

Amdahl 의 법칙저주

빈공간이 Amdahl 의 저주

Page 16: 게임 서버 1대에 동시접속자 1만명 넣기

과거에 우리의 상황• 우리가 이러한 것들을 무시했다면

– 하위 호환성– 안정성

• 고객사들이 곤란했을 상황 !

마비노기 영웅전 마계촌 online S4 리그 러스티 하츠

그리고 다른 많은 고객사들

Page 17: 게임 서버 1대에 동시접속자 1만명 넣기

결국 해결 ! 어떻게 ?

Page 18: 게임 서버 1대에 동시접속자 1만명 넣기

APPLE MMLXXX][

]10 프로파일&분석]20 테스트 코딩과 엎어버리기의 반복 ]30 설계 문서 작성]40 구현]50 GOTO 10

]RUN

Page 19: 게임 서버 1대에 동시접속자 1만명 넣기

APPLE MMLXXX][

]10 프로파일&분석]20 테스트 코딩과 엎어버리기의 반복 ]30 설계 문서 작성]40 구현]50 GOTO 10

]RUN

Page 20: 게임 서버 1대에 동시접속자 1만명 넣기
Page 21: 게임 서버 1대에 동시접속자 1만명 넣기

가장 심한 병목• 비동기 socket I/O 함수 호출–WSASend, WSASendTo–WSARecv, WSARecvFrom

Page 22: 게임 서버 1대에 동시접속자 1만명 넣기

send(), recv() ( 블러킹이 일어남 )WSASend, WSARecv ( 블러킹 안 일어남 )

무지무지 긴 idle 시간짧은 CPU 시간

Q. 잠깐 , IOCP 가 최고 빠른 것 아니었어 ?

A. 최고 빠른 것 맞음 .다만 , 사용자 루틴에 비해 느리다는 것이 함정 .

그럼에도 불구하고이것이 병목 !

Page 23: 게임 서버 1대에 동시접속자 1만명 넣기

APPLE MMLXXX][

]10 프로파일&분석]20 테스트 코딩과 엎어버리기의 반복 ]30 설계 문서 작성]40 구현]50 GOTO 10

]RUN

Page 24: 게임 서버 1대에 동시접속자 1만명 넣기
Page 25: 게임 서버 1대에 동시접속자 1만명 넣기

A 를 스퀴즈

B 를 분할하기

Page 26: 게임 서버 1대에 동시접속자 1만명 넣기

Main

Remote host

P2P pair

P2P group

Etc.

이것을 스퀴즈해야 !

Page 27: 게임 서버 1대에 동시접속자 1만명 넣기

Main

Remote host

P2P pair

P2P group

Etc.

Page 28: 게임 서버 1대에 동시접속자 1만명 넣기
Page 29: 게임 서버 1대에 동시접속자 1만명 넣기

심장 심장 + 폐

뇌사 환자

Page 30: 게임 서버 1대에 동시접속자 1만명 넣기

Remote Ob-ject

Joined P2P group stateP2P pair relationship

Traffic status…

Socket handleSend buffer

Receive bufferOverlapped I/O status

Main

Page 31: 게임 서버 1대에 동시접속자 1만명 넣기

Remote Ob-ject

Joined P2P group stateP2P pair relationship

Traffic status…

Socket handleSend buffer

Receive bufferOverlapped I/O status

Main

Page 32: 게임 서버 1대에 동시접속자 1만명 넣기

잦은 잠금은 빡셈 !

안 잠궈진 객체가 살아있음을 어떻게 보증해 ?

Page 33: 게임 서버 1대에 동시접속자 1만명 넣기

Contention 과 잠금 비용과의 관계

Contention-less lockContention-

less lockContention-less lock

Contention-inten-sive lock<

Contention-less lock

Contention-less lockContention-

less lockContention-less lock

Contention-less lock

Contention-less lockContention-

less lockContention-less lock

Contention-less lock

Contention-less lock

Page 34: 게임 서버 1대에 동시접속자 1만명 넣기

잠금 방법에 따른 비용

non-blocking locknon-blocking

locknon-blocking lock

Blocking lock<non-blocking

lock

non-blocking locknon-blocking

locknon-blocking lock

non-blocking lock

non-blocking locknon-blocking

locknon-blocking lock

non-blocking lock

non-blocking lock

Page 35: 게임 서버 1대에 동시접속자 1만명 넣기

원자적 실행 명령어(Atomic operations)

• InterlockedIncrement• InterlockedExchange• InterlockedCompareExchange• InterlockedBlahBlah• InterlockedBlahBlah• InterlockedBlahBlah• InterlockedBlahBlah

Page 36: 게임 서버 1대에 동시접속자 1만명 넣기

Thread 1{ Get B from A; lock(B); do(B);}

Thread 2{ Get B from A; delete B;}

Object A

Object BObject B

CRASH!

Page 37: 게임 서버 1대에 동시접속자 1만명 넣기

Thread 1{ Get B from A; B.use_count+1; lock(B); do(B); unlock(B); B.use_count-1;}

Thread 2{ Get B from A; if(B.use_count=0) delete B;}

Object A

Object B Keep!

Page 38: 게임 서버 1대에 동시접속자 1만명 넣기

Main

Remote host

P2P pair

P2P group Etc.

비파괴 보장

Page 39: 게임 서버 1대에 동시접속자 1만명 넣기

Before squeeze

After squeeze

Lock(main)

Lock(remote#1)

Lock(main)

Lock(remote#2)

Lock(main)

Lock(remote#1)

Lock(main)

Lock(remote#2)

Lock(main)

Lock(remote#3)

Lock(main)

Lock(remote#4)

Amdahl’s Curse

Amdahl’s Curse

Am-dahl’s Curse

Am-dahl’s Curse

Am-dahl’s Curse

Lock(main)

Page 40: 게임 서버 1대에 동시접속자 1만명 넣기

APPLE MMLXXX][

]10 프로파일&분석]20 테스트 코딩과 엎어버리기의 반복 ]30 설계 문서 작성]40 구현]50 GOTO 10

]RUN

Page 41: 게임 서버 1대에 동시접속자 1만명 넣기

대부분의 경우• Lock(main)• r.use_count+1• Unlock(main)• Lock(r)• work(r)• Unlock(r)• r.use_count-1

Main

Remote host

P2P pair

P2P group

비파괴 보장

Page 42: 게임 서버 1대에 동시접속자 1만명 넣기

좀비 오브젝트 파괴• Lock(main)• if r.use_count=0

&& r 의 io 가 더 이상 없음이 체크되어 있으면

• r 제거• 그렇지 않으면 , 다음

기회에 다시 시도

Main

Remote host

P2P pair

P2P group

USE COUNT = 0?

Page 43: 게임 서버 1대에 동시접속자 1만명 넣기

컨텍스트 스위치를 줄이지 않은 루프

Main

Remote 1 Remote 2 Remote 3

CPU time

Idle time!!

CPU time

CPU time

CONTEXT SWITCH!

Page 44: 게임 서버 1대에 동시접속자 1만명 넣기

컨텍스트 스위치를 줄인 루프

Main

Remote 1 Remote 2 Remote 3

CPU time

CPU time

CPU time

NO CONTEXT SWITCH!(if lucky)

Page 45: 게임 서버 1대에 동시접속자 1만명 넣기

1 개 이상의 상대에의 송신 걸기

• lock(main)• 각 r 에 대해 , r.use_count+1• unlock(main)• 각 r 에 대해 , non-blocking

lock 을 수행• Lock(r) 성공시 , r 의 비동기

송신을 건 후• Lock(r) 성공시 unlock(r) &

r.use_count-1• 실패한 r 들에 대해서만 다시 위

과정을 반복 . 단 , 첫번째 항목에 대해서는 blocking lock 을 수행해야 .

Main

Remote host

P2P pair

P2P group

비파괴 보장

Page 46: 게임 서버 1대에 동시접속자 1만명 넣기

송신 완료시

• GetQueuedComple-tionStatus returns r

• r.use_count+1• lock(r)• r 의 비동기 송신을 걸고• unlock(r)• r.use_count-1

Main

Remote host

P2P pair

P2P group

비파괴 보장

Page 47: 게임 서버 1대에 동시접속자 1만명 넣기

수신 완료시

• GetQueuedCompletionStatus returns r

• r.use_count+1• lock(r)• Extract messages• Unlock(r)• Lock(main)• Process messages• Unlock(main)• lock(r)• r 의 비동기 수신을 걸고• Unlock(r)• r.use_count-1

Main

Remote host

P2P pair

P2P group

비파괴 보장

Page 48: 게임 서버 1대에 동시접속자 1만명 넣기

APPLE MMLXXX][

]10 프로파일&분석]20 테스트 코딩과 엎어버리기의 반복 ]30 설계 문서 작성]40 구현]50 GOTO 10

]RUN

Page 49: 게임 서버 1대에 동시접속자 1만명 넣기

테스트 케이스• 운 좋게도 우리는 이미 이런게 있었다– 자체 개발한 테스트 시스템– 여러가지 스트레스 테스트 앱• MMO case• P2P casual game case • P2P super peer case

Page 50: 게임 서버 1대에 동시접속자 1만명 넣기

• 자체제작된 자동화된 유닛 테스트• 여러 인터넷 공유기• 여러 가상 머신들

Belkin G WirelessTPLINK WR304G+TPLINK V108COSY BR674WLIPTIME G104MIPTIME Q304BUFFALO AIRSTATION

UNICORN WB1000

NETGEAR WGR614V9

DLINK DIR300LINKSYS WRV200MERCURY MR804TPLINK TLR410+TPLINK TLR402Samsung SWP1000

ZIO V10IPTIME N5004NEXT 915VSMC WBR14-G2ZYXEL NBG417NLINKSYS WRT54G2

AZTECH WL830RT4

ASUS RX3041DLINK DIR600PROLINK WNR1004LG-1000

리그레션 테스트용For regress test

Page 51: 게임 서버 1대에 동시접속자 1만명 넣기

스트레스 테스트

Windows 2008 Server x64Xeon CPU

Page 52: 게임 서버 1대에 동시접속자 1만명 넣기

Before

Page 53: 게임 서버 1대에 동시접속자 1만명 넣기

after

Page 54: 게임 서버 1대에 동시접속자 1만명 넣기

APPLE MMLXXX][

]10 프로파일&분석]20 테스트 코딩과 엎어버리기의 반복 ]30 설계 문서 작성]40 구현]50 GOTO 10

]RUN

Page 55: 게임 서버 1대에 동시접속자 1만명 넣기

마무리

Page 56: 게임 서버 1대에 동시접속자 1만명 넣기

평소에 공부하자• 컨텍스트 스위치 주의• 컨텐션 주의• 커널 API 호출 주의

Page 57: 게임 서버 1대에 동시접속자 1만명 넣기

공부한 것을 실무에서 이렇게• 최적화는 가급적 마지막에

코드 프로필러를 꼭 써야• 리소스 분할 기법• 스퀴징• 컨텍스트 스위치가 적은 루프

Page 58: 게임 서버 1대에 동시접속자 1만명 넣기

보너스 : 프라우드넷 소개

Page 59: 게임 서버 1대에 동시접속자 1만명 넣기

프라우드넷 3 가지 구성 요소

P2P

C/S

DB cache

Server-to-serverLANClient-to-server

WAN

Page 60: 게임 서버 1대에 동시접속자 1만명 넣기

프라우드넷 기본 사용 예DB cache

Server-to-serverLANClient-to-server

WAN

Connect()

JoinP2PGroup()

MyMessage(sendTo, a,b,c);

LoadData()UniUpdateData()

JoinP2PGroup()

Page 61: 게임 서버 1대에 동시접속자 1만명 넣기

감사합니다 !

[email protected]