비동기 멀티 플레이어 참조 아키텍처
비동기 멀티 플레이어 빌드를 위한 백본에서는 게임 세션의 모든 플레이어가 다음 턴을 시작할 때 그리고 푸시 알림 메커니즘이 게임 상태를 검색할 수 있도록 이 정보를 영구 데이터베이스에 저장합니다.
비동기 멀티 플레이어를 정의할 때 고려할 수 있는 여러 변수가 있습니다.
- 여러 게임을 동시 지원 - 예, 아니요.
- 최종 기한 - 플레이어는 턴을 완료할 수 있는 특정 시간(6시간, 12시간, 24시간 등)이 부여되고 실패할 경우 게임이 몰수됩니다.
- 게임 사용자 지정 설정 - 플레이어가 게임에서 특정 설정을 사용하여 새 게임 세션을 만들도록 허용하는 것을 고려합니다.
참조 구현 세부 정보
이 참조 아키텍처에서는 서버리스 틱택토(tic-tac-toe) 게임을 소개합니다. 다음은 동일한 사용 사례를 활용하여 바로 시작할 수 있는 다양한 구현입니다.
- 서버리스 - Azure Functions 사용.
다음 섹션에서는 제공된 다양한 구현에 공통되는 일반적인 디자인 고려 사항을 설명합니다.
플레이어 인증 및 ID
이 참조 아키텍처에서는 플레이어 인증 또는 심층적인 플레이어 ID 관리를 다루지 않으며, 두 가지 모두 독자를 위한 연습입니다.
PlayFab은 여러 형태의 인증을 제공하므로 여러 디바이스에 걸쳐 플레이어를 추적할 수 있습니다.
- 게스트 로그인을 위한 장치 ID
- 사용자 이름/암호
- Google 계정
- GameCenter 계정
- Facebook 계정
- Steam 계정
- Kongregate 계정
- Twitch 계정
- 기타 oAuth 공급자
- Android 장치 ID
- 사용자 지정 플레이어 ID
다중 데이터 센터로 확장
이 참조 아키텍처에서는 백엔드에 단일 지역만 고려합니다. 빌드 중인 게임에 따라 트래픽 관리자를 활용하고 여러 데이터 센터에 배포하는 것은 필요하지 않을 수 있습니다. 트래픽 관리자는 HTTP 호출에 사용되기 때문에 모든 리소스가 한 데이터 센터에 있고 전 세계로 확산되지 않은 경우 실제로 비용이 더 적게 들 수 있습니다. 또한 여러 데이터 센터가 있는 경우 데이터베이스 동기화 메커니즘을 사용하여 서로 다른 데이터 센터 간에 데이터베이스 데이터를 동기화해야 한다는 점도 있습니다. 그러므로 여러 데이터 센터를 보유하려는 경우에는 트래픽 관리자를 사용해야 합니다.
단계별 설명
비동기 멀티 플레이어 타이틀의 일반적인 흐름은 다음과 같습니다.
- 플레이어가 백엔드에 로그인합니다.
- 기존 플레이어의 게임 목록이 백엔드에서 검색됩니다.
- 플레이어가 일련의 설정으로 새 게임을 열거나 특정 상대를 초대합니다.
- 플레이어가 새 게임을 여는 경우 게임 세션 목록에 게임이 추가되고 상대가 참가할 때까지 기다립니다. 플레이어가 새 게임을 연다는 것은 실제로는 상대에 연결하기 위한 요청을 전송하는 것입니다. 설정과 일치하는 다른 적합한 플레이어가 대기 중인 경우 게임이 두 플레이어를 직접 매치 메이킹합니다.
- 플레이어가 특정 플레이어를 초대하는 경우 이는 특정 상대를 지정하여 새 게임을 여는 것과 같습니다. 이 참조 아키텍처에서는 이 기능이 고려되지 않습니다.
- 플레이어가 게임에서 지원되는 동작을 선택하면 이를 제출하여 턴을 완료합니다.
- 일단 턴이 제출되면 이 게임 세션에 대한 영구 데이터베이스 레코드가 업데이트된 게임 상태로 업데이트됩니다.
- 알림이 상대 플레이어로 전송되어 턴을 시작할 수 있습니다.
데이터베이스 스키마
필요한 정보를 저장하는 데 사용되는 Azure Database for MySQL 영구 데이터베이스에는 세 개의 테이블이 있습니다. 플레이어당 한 항목을 포함하고 강력한 플레이어 ID 시스템으로 확장되어야 하는 player 테이블, 게임 세션당 한 항목을 포함하는 gamesession 테이블, 게임당 사용자별로 하나의 항목을 포함하는 gamesession_player 테이블.
Player 테이블
필드 | 형식 | 참고 |
---|---|---|
ID | SERIAL PRIMARY KEY | 이 테이블의 기본 키입니다. |
CreatedTime | TIMESTAMP NOT NULL | 플레이어가 추가된 시간을 저장합니다. |
UpdatedTime | TIMESTAMP NOT NULL | 플레이어가 업데이트된 시간을 저장합니다. |
이름 | VARCHAR(100) | 플레이어의 이름을 저장합니다. |
게임 세션 테이블
필드 | 형식 | 참고 |
---|---|---|
ID | SERIAL PRIMARY KEY | 이 테이블의 기본 키입니다. |
GUID | VARCHAR(36) | 게임 세션의 고유 식별자입니다. |
CreatedTime | TIMESTAMP NOT NULL | 게임 세션이 만들어진 시간을 저장합니다. |
UpdatedTime | TIMESTAMP NOT NULL | 게임 세션이 업데이트된 시간을 저장합니다. |
CreatedPlayer_ID | BIGINT UNSIGNED NOT NULL | 게임 세션을 만든 플레이어입니다. |
GameStatus | TINYINT NOT NULL | 매치 메이킹 중(0), 진행 중(1) 또는 완료됨(2) |
BoardState | VARCHAR(200) NOT NULL | 직렬화된 보드 정보입니다(X 및 O가 보드에 배치됨). |
MovesLeft | TINYINT NOT NULL | 게임 종료 시기를 결정합니다. |
CurrentTurnPlayer_ID | BIGINT UNSIGNED | 어느 플레이어가 플레이할 차례인지 나타냅니다. |
WinningPlayer_ID | BIGINT UNSIGNED | 승리한 플레이어입니다. |
CreatedPlayer_ID | FOREIGN KEY | 플레이어(ID)를 참조합니다. |
CurrentTurnPlayer_ID | FOREIGN KEY | 플레이어(ID)를 참조합니다. |
WinningPlayer_ID | FOREIGN KEY | 플레이어(ID)를 참조합니다. |
게임 세션 플레이어 테이블
필드 | 형식 | 참고 |
---|---|---|
ID | SERIAL PRIMARY KEY | 이 테이블의 기본 키입니다. |
CreatedTime | TIMESTAMP NOT NULL | 플레이어가 추가된 시간을 저장합니다. |
UpdatedTime | TIMESTAMP NOT NULL | 플레이어가 업데이트된 시간을 저장합니다. |
GameSession_ID | BIGINT UNSIGNED NOT NULL | 외래 키입니다. 게임 세션 테이블의 고유한 게임 식별자입니다. |
Player_ID | BIGINT UNSIGNED NOT NULL | 외래 키입니다. 플레이어 테이블의 고유한 플레이어 식별자입니다. |
GameSession_ID | FOREIGN KEY | 게임 세션(ID)을 참조합니다. |
Player_ID | FOREIGN KEY | 플레이어(ID)를 참조합니다. |
데이터베이스 파일 만들기
다음을 사용하여 데이터베이스 연결 정보를 가져오고, 방화벽을 구성하고, 데이터베이스에 대한 연결을 설정하는 방법을 알아보려면 이 자습서를 참조하세요.
- Azure Portal Cloud Shell의 mysql 명령줄 도구를 사용(클라우드 드라이브 계정이 필요).
- MySQL Workbench GUI 도구를 사용.
그런 다음 아래 명령을 실행하여 데이터베이스를 만듭니다.
CREATE DATABASE asyncmpdb;
나중에 이를 사용하기 시작합니다.
USE asyncmpdb;
그런 다음 아래 명령을 사용해 3개의 테이블을 만듭니다.
CREATE TABLE player (
ID SERIAL PRIMARY KEY,
CreatedTime TIMESTAMP NOT NULL,
UpdatedTime TIMESTAMP NOT NULL,
Name VARCHAR(100) NOT NULL
);
CREATE TABLE gamesession (
ID SERIAL PRIMARY KEY,
GUID VARCHAR(36) NOT NULL,
CreatedTime TIMESTAMP NOT NULL,
UpdatedTime TIMESTAMP NOT NULL,
CreatedPlayer_ID BIGINT UNSIGNED NOT NULL,
GameStatus TINYINT NOT NULL,
BoardState VARCHAR(200) NOT NULL,
MovesLeft TINYINT NOT NULL,
CurrentTurnPlayer_ID BIGINT UNSIGNED,
WinningPlayer_ID BIGINT UNSIGNED,
FOREIGN KEY(CreatedPlayer_ID) REFERENCES player(ID),
FOREIGN KEY(CurrentTurnPlayer_ID) REFERENCES player(ID),
FOREIGN KEY(WinningPlayer_ID) REFERENCES player(ID)
);
CREATE TABLE gamesession_player (
ID SERIAL PRIMARY KEY,
CreatedTime TIMESTAMP NOT NULL,
UpdatedTime TIMESTAMP NOT NULL,
GameSession_ID BIGINT UNSIGNED NOT NULL,
Player_ID BIGINT UNSIGNED NOT NULL,
FOREIGN KEY(GameSession_ID) REFERENCES gamesession(ID),
FOREIGN KEY(Player_ID) REFERENCES player(ID)
);
아래 명령을 사용하여 3개의 테이블이 만들어졌는지 확인합니다.
show tables;
테이블이 만들어졌으면 다양한 저장 프로시저를 만들어 보겠습니다.
이는 새 게임 세션을 만들기 위한 것으로, 매치 메이킹 시도에서 적절한 게임 세션을 반환하지 않은 경우 실행됩니다.
DELIMITER //
CREATE PROCEDURE `gamesession_INSERT`
(IN param_guid VARCHAR(36),
IN param_createdplayer_id BIGINT UNSIGNED,
IN param_status TINYINT,
IN param_boardstate VARCHAR(200),
IN param_movesleft TINYINT,
IN param_currentturnplayer_id BIGINT UNSIGNED,
IN param_winningplayer_id BIGINT UNSIGNED)
BEGIN
INSERT INTO gamesession
(GUID,
CreatedTime,
UpdatedTime,
CreatedPlayer_ID,
GameStatus,
BoardState,
MovesLeft)
VALUES
(param_guid,
NOW(),
NOW(),
param_createdplayer_id,
param_status,
param_boardstate,
param_movesleft);
INSERT INTO gamesession_player
(CreatedTime,
UpdatedTime,
GameSession_ID,
Player_ID)
VALUES
(NOW(),
NOW(),
LAST_INSERT_ID(),
param_createdplayer_id);
END //
알림 서비스
알림을 제출하는 데 사용할 수 있는 기본 서비스에는 알림 허브 및 SignalR 두 가지가 있습니다. 다음 표에서는 두 서비스 간의 주요 차이점이 나와 있습니다. 이 구현에서 계단식 배열 패턴을 따릅니다. 즉, 첫 번째 SignalR 알림이 시도되고, 잠시 후 받은 알림이 수신되지 않으면 SignalR 배달이 취소되고 Azure 알림 허브가 대신 사용됩니다.
SignalR | 알림 허브 | |
---|---|---|
메시지 원본 | 게임 서버(브로드캐스트 또는 서버 푸시만) 또는 다른 클라이언트(양방향 채팅) 중 하나를 사용할 수 있으며, 시나리오에 따라 다릅니다. | 플랫폼 공급자(Microsoft, Google, Apple 등)의 기존 인프라 |
전용 서버 필요 | 시나리오에 따라 다름 서비스는 REST API를 지원하므로 메시지 원본/앱은 서버 필요 없이 직접 SignalR Service REST API를 통해 클라이언트에 메시지를 게시할 수 있습니다. 또는 SignalR 서비스를 사용하는 Azure Functions 바인딩을 공식적으로 지원하므로 서버리스 시나리오도 수용할 수 있습니다. | 아니요 |
코드 중립적 | 예 이제 SignalR은 C# 및 JS로 작성된 클라이언트 SDK를 제공하며 Xamarin, Unity 및 Java SDK도 지원합니다. 향후 C++ 및 Object-C/Swift도 지원할 예정입니다. REST API는 REST 가능 언어를 모두 지원합니다. Azure Functions 바인딩은 Azure 함수가 지원하는 모든 언어를 지원합니다. | 예, REST API 및 템플릿을 사용할 수 있습니다. |
메시지 배달 | 즉시(WebSocket을 통해) | 즉시성이 보장되지 않음 |