[게임 서버] 10.2 데이터베이스의 수평 확장
카테고리: GameServer
태그: GameServer
이 글은 아래의 책을 자세히 정리한 후, 정리한 글을 GPT에게 요약을 요청하여 작성되었습니다.
게임 서버 프로그래밍 교과서, 배현직 저자
📦 10. 분산 서버 구조 사례
👉🏻 2. 데이터베이스의 수평 확장
📌 상황
---
config:
look: handDrawn
theme: dark
layout: dagre
---
flowchart LR
C1[클라이언트]
C2[클라이언트]
subgraph AUTH[인증 서버]
A1[인증 서버]
A2[인증 서버]
A3[인증 서버]
A4[인증 서버]
end
DB[유저 DB]
C1 --> A2
A2 --> DB
C2 --> A3
A3 --> DB
- DB 서버는 여전히 과부하
- 플레이어 간 상호작용은 없다는 전제
수평 확장:
- 플레이어 정보를 여러 샤드에 저장
- 클라이언트는 인증 서버 접속, ID/PW 전송
- 서버는
ID → 해시 함수를 통해, DB 샤드 인덱스 획득 - 해당 샤드에 질의 전송
- 샤드 인덱스를 얻기 위해 사용된 키(ID)를 샤드 키(파티션 키) 라고 한다.
- 더 많은 서버가 필요하면, 인증 서버/데이터베이스 샤드 증설
- 그러나 데이터베이스 샤드를 늘리는 일은 단순하지 않다.
🔧 데이터베이스 샤드 증설
- 샤드 10개에서 11개로 늘리려 하면 리해시가 발생한다.
- 항목 개수가 달라지므로, 데이터 항목 재배치가 필요해진다.
- 기존 레코드도 리해시해주어야 한다.
- 문제점: 리해시해야 하는 레코드가 많으면, 게임 서버를 장시간 점검해야 한다.
해결 방법:
- 레코드 이동 개수 최소화 → 일관된 해시 알고리즘 사용
- 이동할 일이 없게 만듦 → 매핑 DB
- 레코드 이동 크기 최소화
1️⃣ 레코드 이동 개수 최소화: 일관된 해시 알고리즘
- 샤드 개수 변동 1개 당, 샤드 1개만 재배치 연산을 수행하면 된다.
---
config:
look: handDrawn
theme: dark
layout: dagre
title: 일반적인 해시 테이블
---
graph
0; 1; 2; 3; 4;
- 일반적인 해시 테이블은 항목이 해시 함수 값에 일대일 대응된다.
---
config:
look: handDrawn
theme: dark
layout: dagre
title: 해시 테이블 (샤드 2개)
---
graph BT
subgraph 샤드 2
3[500]; 4[...]; 5[999];
end
subgraph 샤드 1
0[0]; 1[...]; 2[499];
end
- 항목 개수를 많게 고정시킨다.
- 이제 샤드 1개는 해시 함수 값 다수에 대응된다. → 해시 값들의 집합
| 해시 | 항목 | 샤드 |
|---|---|---|
| hash(“A”) | 17 | 1 |
| hash(“B”) | 23 | 1 |
| hash(“C”) | 745 | 2 |
---
config:
look: handDrawn
theme: dark
layout: dagre
title: 해시 테이블 (샤드 3개)
---
graph BT
subgraph 샤드 3
6[750]; 7[...]; 8[999];
end
subgraph 샤드 2
3[500]; 4[...]; 5[749];
end
subgraph 샤드 1
0[0]; 1[...]; 2[499];
end
- 샤드 추가: 기존 샤드가 맡던 해시 집합을 두 샤드가 나누어 가진다.
- 샤드 삭제: 기존 샤드가 맡던 해시 집합을 인접 샤드에 나누어 준다.
특징:
- 해시 테이블은 링형이라고 보아야 한다. (샤드 3과 1은 인접)
- 일부 레코드에만 리해시해주면 된다.
- 샤드가 크게 늘어나거나 줄어들 때 결국 많은 양을 리해시해야 한다.
2️⃣ 매핑 DB
입력(키) → 샤드 인덱스를 가지는 DB를 따로 만든다.
---
config:
look: handDrawn
theme: dark
layout: dagre
---
flowchart LR
C1[클라이언트]
C2[클라이언트]
subgraph AUTH[인증 서버]
A1[인증 서버]
A2[인증 서버]
A3[인증 서버]
A4[인증 서버]
end
MDB[매핑 DB]
DB1[유저 DB]
DB2[유저 DB]
C1 --> A2
A2 -.-> DB1
C2 --> A3
A3 -.-> DB2
A2 --> MDB
A3 --> MDB
- 클라이언트: 인증 서버 중 하나 접속
- 인증 서버: 매핑 DB에 질의 → DB 인덱스(샤드 넘버) 획득
- 인증 서버: 해당 DB에 플레이어 관련 CRUD 질의 수행
- 샤드 추가: 레코드 이동 없이 채우기만 하면 된다.
- 샤드 제거: 매핑 DB에서 레코드 이동, 유저 DB에서 바뀐 위치 반영 필요
- 매핑 DB에 과부하가 걸리면 의미가 없다. → 단일 실패 지점(SPOF)
---
config:
look: handDrawn
theme: dark
layout: dagre
---
flowchart LR
C1[클라이언트]
C2[클라이언트]
subgraph AUTH[인증 서버]
A1[인증 서버]
A2[인증 서버]
A3[인증 서버]
A4[인증 서버]
end
MDB1[매핑 DB]
MDB2[매핑 DB]
MDB3[매핑 DB]
DB1[유저 DB]
DB2[유저 DB]
MDB1<-->MDB2
MDB2<-->MDB3
MDB3<-->MDB1
C1 --> A2
A2 -.-> DB1
C2 --> A3
A3 -.-> DB2
A2 --> MDB1
A3 --> MDB1
- 매핑 DB에도 확장성을 추가한다. → 레코드를 여러 샤드에 나눈다.
🔄 접속 프로세스 시퀀스
- 클라이언트: 인증 서버 중 하나 접속
- 인증 서버: 매핑 DB 중 선택 → DB 인덱스(샤드 넘버) 획득
- 인증 서버: 해당 DB에 CRUD 질의 수행
- 한 서버에서 인증하고 나서, 다른 서버에서 또 거치는 것은 비효율적이다.
🎫 인증 정보 Credential
---
config:
look: handDrawn
theme: dark
---
sequenceDiagram
participant C as 클라이언트
participant A as 인증 서버
participant B as 서버 B
C->>A: ① 로그인 요청
activate A
deactivate A
A-->>C: ② 로그인 결과
activate C
deactivate C
A->>B: ③ 비밀 징표, 유저 ID
activate B
deactivate B
B-->>A: ④ 잘 받았음!
activate A
deactivate A
A-->>C: ⑤ 비밀 징표
activate C
deactivate C
C->>B: ⑥ 연결
activate B
deactivate B
C->>B: ⑦ 비밀 징표로 로그인
activate B
deactivate B
B-->>C: ⑧ 로그인 결과
activate C
deactivate C
- 한번 인증하고 나면, 비밀 증표(Credential) 를 통해 재인증할 필요가 없도록 한다.
댓글남기기