-
Notifications
You must be signed in to change notification settings - Fork 5
실시간 200명 플레이어 렌더링을 위한 최적화 과정
Jungi-Kim edited this page Jan 1, 2025
·
5 revisions
- 퀴즈 그라운드는 부스트캠프 인원 200명이 동시에 플레이하는 것이 목표입니다.
- 이를 위해 플레이어가 실시간으로 만드는 움직임을 버벅임 없이 렌더링해야 합니다.
- 이에 따라 성능 테스트를 계획했습니다.
다음과 같은 성능 테스트를 계획했습니다.
- 200명의 더미 플레이어 생성
- 1인당 1초에 1번 움직임
- 200 * 5번의 움직임을 생성(약 5초)
- Performence API로 시작 시간과 종료 시간을 측정
- 빠르게 테스트하기 위해 현재 잘 사용 중인 소켓 목을 이용
아래는 테스트를 위한 코드입니다.
export default class SocketMockLoadTestOnlyMove extends SocketMock {
constructor() {
super();
// 200명의 더미 플레이어 생성
this.createDummyPlayer(200);
// 모든 더미 플레이어가 5초 동안 1초에 한번 씩 움직임
this.performenceTest([this.moveRandom(5, 1)]);
}
}
기존의 코드로 테스트를 한 결과 15초~17초 정도의 시간이 측정되었습니다.
5초 동안 아무것도 안 하는 것보다 3배의 시간이 걸린 것입니다.
우린 이 원인을 찾게 되었고 다음과 같은 이유를 알 수 있었습니다.
한 명이 움직여도 전체 플레이어가 리렌더링 된다!
전체 플레이어가 매 움직임마다 리렌더링되는 이유는 아래와 같습니다. 플레이어 컴포넌트는 QuizOptionBoard에 포함되고, QuizOptionBoard는 players 전역 상태를 구독합니다.
graph TD
subgraph GamePage
Player1
Player2
Player3
QuizOptionBoard --> Player1
QuizOptionBoard --> Player2
QuizOptionBoard --> Player3
end
state["players 전역 상태"]
QuizOptionBoard --->|구독| state
여기서 플레이어가 움직이도록 리렌더링하기 위해선 다음의 과정이 필요합니다.
- players 배열에서 움직일 플레이어를 탐색해 위치를 바꾼다.
- 새로운 배열 객체를 생성한다.
- QuizOptionBoard는 players 배열이 바뀌었음을 알아채고 모든 플레이어를 리렌더링 한다.
이처럼 한 명의 플레이어만 움직여도 전체 플레이어가 리렌더링되는 것입니다.
우리는 이러한 문제가 배열이라는 자료구조의 한계에 의해 발생한다고 생각하였고, 배열을 대신해 Map 자료구조로 바꾸기로 결정했습니다.
// 기존 players
players: Player[];
// 새로운 players(key는 playerId)
players: Map<string, Player>;
이렇게 결정한 이유는 아래와 같습니다.
- 탐색 평균 O(1)
- 삽입, 삭제 평균 O(1)
- 삽입 순서 보장
이제 컴포넌트가 상태를 구독하고 있는 구조를 바꿨습니다.
graph TD
subgraph GamePage
Player1
Player2
Player3
QuizOptionBoard --> Player1
QuizOptionBoard --> Player2
QuizOptionBoard --> Player3
end
subgraph players
PlayerState1
PlayerStete2
PlayerState3
end
QuizOptionBoard -->|구독| players
Player1 -->|구독| PlayerState1
Player2 -->|구독| PlayerStete2
Player3 -->|구독| PlayerState3
여전히 QuizOptionBoard가 players를 구독하고 있지만, 이제는 각 Player 컴포넌트가 자신의 상태를 prop으로 전달 받지 않고 직접 구독합니다.
이에 따라 움직일 때 움직인 플레이어만 리렌더링 됩니다.
개선 후 성능 측정 결과, 6~7초로 측정이 되었습니다. 기존 코드에 비해 무려 2배 이상 시간이 단축되었습니다.
- players 상태를 배열에서 Map으로 바꾸었습니다.
- 각 플레이어가 직접 자신의 상태를 구독하도록 했습니다.
- 성능 측정 결과 16.71초 → 6.31초로 시간이 단축 되었습니다.