2025. 1. 20. 22:08ㆍ네트워크
공부 자료 : 게임 서버 프로그래밍 교과서 (배현직, 길벗)
책을 읽다가 분산 서버에 관한 챕터가 있었는데 파편적으로 배웠던 분산 서버에 대해 정리해보면 좋을 듯 해서 글을 쓴다.
수직 확장(스케일 업) / 수평 확장(스케일 아웃)
확장성(scalability) : 사용자 수가 늘어나더라도 쉽게 대응할 수 있는 정도
- 수직 확장 : 서버 하드웨어를 강화해서 처리율을 높이는 것 (양보단 질로 승부!)
- 수평 확장 : 서버 하드웨어를 늘리는 것 (질보단 양으로 승부!)
일반적으로 수평 확장이 더 현실적인 방법이다.
수직 확장은 서버 하드웨어의 사양이 경제적으로든 기술적으로든 한계가 있기 때문이다.
반면 수평 확장은 그냥 댓수를 늘리면 되기 때문에 상한선이 거의 없다.
구분 | 수직 확장 | 수평 확장 |
확장 종류 | 서버 머신의 부품을 업그레이드 혹은 서버 머신 안의 CPU, 램을 증설한다. | 서버 머신의 대수를 증설한다. |
서버 소프트웨어 설계 비용 | 낮다. | 높다. |
확장 비용 | 높다 (기하급수적으로 올라감) |
낮다 (선형적 증가) |
과부하 지점 | 서버 컴퓨터 자체 | 네트워크 장치 |
오류 가능성 | 낮다 (하나의 머신에서 동기적으로 프로그래밍하기 때문이다.) |
높다. (여러 머신 간에 비동기 프로그래밍 방식으로 만들어야 하기 때문이다.) |
단위 처리 속도 | 높다. (로컬 컴퓨터의 CPU와 램만 사용한다.) |
낮다 (여러 서버 컴퓨터 간 메시징이 오가면서 처리하기 때문이다.) |
처리 가능 총량 | 낮다. (서버 컴퓨터 한 대만 사용하기 때문에) |
높다. (여러 서버 컴퓨터로 부하 분산되기 때문이다.) |
서버를 왜 분산해야 하는가?
분산하지 않은 서버를 생각하면, 모든 게임 연산이 하나의 서버 프로세스에서 동작한다.
이 상태에서 게임이 대박이 났다!
동접자가 계속 늘어난다.
서버 프로세스에서 너무 많은 동접자에 대한 처리를 하다보면 점점 일감이 생산되는 속도가 일감을 처리하는 속도보다 빨라진다.
그러다보면 일감이 쌓이게 된다. 일감은 결국 메모리를 사용하는 것이다. 일감이 계속 쌓이다보면, 메모리가 부족해지게 된다.
32비트 서버에서는 금방 메모리가 부족해서 malloc이나 new를 쓸 때 nullptr이나 예외가 던져질 것이다.
64비트 서버는 가상 메모리가 굉장히 크기 때문에 메모리가 바로 바닥이 나지는 않겠지만, 대량의 스와핑이 발생하게 되어서 또 다시 서버의 처리량이 줄어들게 되고 그러면 일감이 다시 쌓이는 악순환이 반복된다. 그러다 메모리가 부족해질 것이다.
과한 부하는 서버 프로세스뿐만 아니라 네트워크 기기에서도 문제를 일으킨다.
라우터에게 초당 처리할 수 있는 패킷 수보다 많은 패킷을 쏘게 되면, 패킷이 유실된다.
그러면 TCP에서 재전송을 하게 되는데 이러한 재전송이 빈번하면 또 네트워크가 혼잡해지고 재전송이 늘어난다. 그러다 재전송 타임아웃으로 연결 해제가 발생하게 된다.
쉽게 말해서 서버를 분산하는 이유는 최대 동접자를 늘리기 위함이라고 할 수 있겠다.
고전적인 분산 방법
1. 게임 클라이언트는 인증 서버에 접속한 후 ID와 비밀번호로 로그인 처리를 한다.
2. 로그인에 성공한 게임 클라이언트에서 게임 사용자는 게임 플레이를 할 수 있는 채널 서버를 선택한다.
3. 게임 클라이언트는 사용자가 선택한 채널 서버에 접속하여 게임 플레이를 시작한다.
메이플스토리를 예시로 들면 우리가 로그인 후 클라이언트를 키면 먼저 로그인 서버에 로그인 요청 패킷을 쏘고 인증 DB에서 정보 비교 후 인증을 한다. 그 후 크로아 서버로 접속하면 그 서버 로그인 패킷을 쏘고 그 서버에서 인증 확인하면(로그인 서버에서 인증을 거쳤으므로 간단한 로그인 토큰만으로 인증) 크로아 서버에서 게임 플레이를 할 수 있는 것이다.
이 고전적인 방식의 단점은 게임 기획과 관련되어 있는데 메이플에 비유해서 설명하면 이렇다.
1. 크로아에서 5차 전직까지 다한 미하일 캐릭터가 있는데, 스카니아 서버에서 그 캐릭터로 즐길 수 없다.
2. 플레이어는 자기가 플레이 했던 서버에서만 계속 게임을 해야 한다. 스카니아 서버의 친구들과 함께 할 수 없다.
요즘에는 서버를 선택하지 않는 방식이 추세라고 한다.
그러려면 논리적으로는 단일 서버이지만, 실제로는 서버 클러스터 형태인 서버를 개발할 필요도 있다.
논리적 단일 서버 분산
우선 단일 서버 상에서 테스트 해서 성능을 분석한다.
그 후 성능 병목인 지점을 분산 처리한다.
예를 들어서 LOL과 같은 MOBA(Multiplayer Online Battle Arena) 같은 게임이라면 협곡 내부에서의 게임 플레이를 연산하는 함수가 가장 큰 처리량을 차지할 것이며, 그 다음으로는 매치 메이킹이나 채팅일 것이다.(요즘은 채팅을 잘 안쳐서 채팅은 아닐 수도 있음)
그러면 게임 플레이 부분과 매치 메이킹 부분을 분산 처리하면 되는 것이다.
어떻게 분산하는데?
분산 처리에는 크게 다음과 같은 분산의 단위가 있다.
- 데이터 단위 분산
- 각 서버는 모두 똑같은 종류의 일을 한다. 데이터만 다른 것이다.
- 기능 단위 분산
- 어떠한 처리를 기능 단위로 분산한다. 예를 들어 라면을 끓이는 처리가 있다고 하면, 물 끓이기 담당, 면 삶기 담당, 계란 넣기 담당 처럼 기능 별로 담당이 있는 것이다.
- 예를 들어 경매장 컨텐츠를 따로 분산한다.
기능적 분산은 데이터 분산보다 분산 효율성이 떨어진다. 예를 들어 게임 기능이 A, B, C로 구성되어 있고 A, B, C 기능별로 분산했다면, 서버 B만 과부하가 걸렸을 때 서버 A와 서버 C에 서버 B가 하는 역할을 분배하지 못한다. - 따라서 기능적 분산 처리는 최후 수단이다. 데이터 분산을 해보고 방법이 없으면 기능적 분산을 한다.
게임 로직의 분산 처리 방식은 다음과 같이 나뉜다.
- 동기 분산 처리
- 어떤 연산을 다른 서버에 던져 놓고 그 결과가 올 때까지 대기한다.
대기 뿐만 아니라 그 연산과 관계된 데이터가 도중에 변경되지 않도록 잠금(Lock)을 해야한다.
이런 점이 병목이 될 수 있다.
- 어떤 연산을 다른 서버에 던져 놓고 그 결과가 올 때까지 대기한다.
- 비동기 분산 처리
- 서버 1이 어떤 연산 명령을 서버 2에 송신한다.
서버 1은 서버2의 명령 처리 결과를 기다리지 않는다. 일방적으로 자기가 해야 하는 다음 일을 한다. - 단점은 반환 값이 없는 함수처럼 동작해야 해서 요청에 대한 응답이 필요한 경우 구현이 어려워진다.
- 서버 1이 어떤 연산 명령을 서버 2에 송신한다.
- 데이터 복제 및 로컬 처리
- 각 서버가 원본 데이터를 들고 있고 다른 서버의 데이터가 필요한 경우 사본 데이터를 받아서 사용한다.
- 사본 데이터에 변경을 했으면 그 데이터의 원본을 가지고 있는 서버에 변경했음을 알린다.
- 단점은 간발의 차이로 생기는 스테일 데이터 문제(stale data problem)가 있을 수 있다.
이 때 서버가 가진 데이터를 모두 신뢰할 경우 데이터 불일치로 잘못된 연산이 발생할 수 있다.(하이젠버그)
분산 처리 유형은 이들의 2 x 3의 조합이다.
분산을 할 때 배보다 배꼽이 커지지 않는지 확인해야 한다.
분산으로 인한 네트워크 IO 오버헤드가 분산했을 때의 이득보다 더 큰 경우 오히려 분산한 것이 손해이기 때문이다.
데이터 응집도
응집도가 높은 데이트는 가급적 분산처리를 하지 않는다.
응집도가 낮은 데이터만 분산 처리하는 것이 좋다.
응집도란 특정 영역 안에 얼마나 데이터가 관련되고 뭉쳐 있는지 의미한다.
분산 처리를 엄선해야 하는 이유
1. 디버깅 어려움
2. 서버간 통신으로 인한 성능 저하
3. 네트워크 장비 과부화 가능성
분산 처리는 꼭 해야 하는 이유가 있을 때 하자.
분산 처리 전략
- 성능 분석을 해서 분산 처리가 필요한 지점을 엄선하세요
- 데이터 응집력을 확인하세요.
다룰 데이터 간 상호작용이 높은 것은 분산하지 말고, 다룰 데이터 간 상호 작용이 매우 적은 것들만 골라서 분산합니다.
즉, 응집력이 높은 데이터를 구별하는 기준부터 찾아야 합니다.
ex. MMORPG에서는 게임 월드 안의 지리적 구분 / 매치메이킹 시스템에서 플레이어의 레벨이나 랭크 - 분산 처리 방식은 다음 세 가지 중에 선택
- 동기 분산
- 비동기 분산
- 데이터 동기화에 기반을 둔 로컬 처리
- 어쨌건 분산 처리 자체는 구현과 디버깅이 까다롭고 불필요한 과부하를 일으킨다.
불필요한 분산은 피하자.
'네트워크' 카테고리의 다른 글
NAT, DHCP, 포트포워딩 (0) | 2025.03.02 |
---|---|
Subneting (0) | 2025.03.02 |
스위치, 라우터, IP 클래스 (0) | 2025.03.02 |
스위치, 호스트, IP 주소, Netmask (0) | 2025.02.17 |