Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .env.example

This file was deleted.

2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
.vscode
.config
.omc
98 changes: 98 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
# Matchmaker

Postgres 기반 minimalistic 매치메이커 OSS. Open Match 대안.

## 핵심 원칙

- **의존성은 Postgres만** — Redis, Kafka, NATS 등 외부 큐/캐시 없음
- **Polling 기반 통신** — streaming 회피, 운영 단순성 우선
- **Config 런타임 변경** — 재배포 없이 라이브 튜닝 (API 기반)
- **Allocator-agnostic** — Agones/GameLift/PlayFab 등 모두 통합 가능
- **설치형 배포** — Helm chart 단일 명령으로 설치

## 컴포넌트

- **API Gateway** — gRPC API, stateless, 큐/풀 설정 무지 (단순 transport)
- **Director** — 1초 cycle, Entity Store batch pull, pool 분류, ME로 dispatch (1 active + standby)
- **MatchingEngine (ME)** — pool당 1개, 후보 매치 생성, lazy config fetch
- **Evaluator** — 후보 aggregation, 충돌 해결, 최종 매치 확정 (1 active + standby)
- **Config Syncer** — Config Store polling 캐싱, 컴포넌트에 config API 제공
- **Entity Store** — Postgres (tickets, matches)
- **Config Store** — Postgres (queues, pools, rules, history) — runtime DB와 분리

## 통신 경계

**외부 시스템(Game Backend, External DGS Allocator)은 오직 API Gateway를 통해서만 매치메이커와 통신한다.** Entity Store, Director, ME, Evaluator 등 내부 컴포넌트는 외부에 노출되지 않는다.

## 데이터 흐름

```
[외부 경계]
Client ──→ Game Backend ──┐
├──gRPC──→ API Gateway ──┐
External DGS Allocator ───┘ │
↑ ClaimMatches/Report │
[내부 컴포넌트] Entity Store
↑ polling
Director ← Config Syncer ← Config Store
↓ dispatch (with config_version)
Matching Engine × N
↓ candidates
Evaluator
↓ matches insert
Entity Store

[게임 서버 할당]
External DGS Allocator ──→ DGS Fleet (게임 서버 시작)
──→ API Gateway (ReportAssignment)
```

외부 통신 경로 (모두 API Gateway 경유):

- **Game Backend → Gateway**: CreateTicket, GetTicket (매칭 결과 polling)
- **DGS Allocator → Gateway**: ClaimMatches (polling), ReportAssignment, ReleaseMatch
- **Gateway → 외부**: 없음 (Pull-only)

## 코드 컨벤션

- Go 1.22+
- gRPC 인터페이스는 `proto/` 하위 정의
- DB 접근은 pgx 사용
- CEL 룰 평가는 cel-go
- 컴포넌트 간 통신은 gRPC unary RPC (streaming 지양)

## 부하 기준

목표: 동접 100만, ~600 RPS (CreateTicket 기준)
- Director polling: 1 QPS
- Evaluator → matches insert: ~139 QPS
- DGS Allocator polling: 1 QPS
- 단일 Postgres가 압도적으로 여유 있게 처리

## 디렉토리

```
matchmaker/
├── proto/ # gRPC 정의
├── services/ # 매치메이커 본체
│ ├── gateway/
│ ├── director/
│ ├── engine/
│ ├── evaluator/
│ └── syncer/
├── helm/ # Helm chart
├── examples/
│ ├── agones-adapter/
│ └── kubernetes-adapter/
└── docs/
├── design/ # 컴포넌트별 상세
├── decisions/ # ADR
└── design-discussion.md # 초기 토론 전문
```

## 상세 문서

설계 상세: `docs/design/`
의사결정 이력: `docs/decisions/` (ADR 형식)
초기 토론: `docs/design-discussion.md`
25 changes: 8 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,20 +1,11 @@
# 🎮 matchmaker
# Matchmaker
A minimalistic self hosted matchmaker for multiplayer games.

A lightweight and high-performance matchmaker service written in Go.
Designed for real-time game matchmaking with concurrent player support.
Supports 1M concurrent players.

# Components
## API Server
The API server provides a RESTful interface for managing matchmaking tickets, match candidates, player acknowledgements, and game results.
## System Design
![matchmaker system design](docs/design/matchmaker_0523rev3.png)

### REST API Endpoints

Below is a summary of the REST API endpoints and their purposes:

| Description | HTTP Method | Endpoint |
|--------------------------------------------|-------------|-----------------------------------------|
| Create matchmaking ticket | POST | `/tickets` |
| Cancel matchmaking ticket | DELETE | `/tickets/{ticket_id}` |
| List current match candidates | GET | `/matches/candidates` |
| Create or update player acknowledgement | PUT | `/matches/{match_id}/acknowledgement` |
| Submit game result (win/loss) | POST | `/match-results` |
## Features
- Backfill
-
21 changes: 0 additions & 21 deletions architecture.md

This file was deleted.

60 changes: 0 additions & 60 deletions cmd/apiserver/main.go

This file was deleted.

11 changes: 0 additions & 11 deletions cmd/simulator/main.go

This file was deleted.

23 changes: 0 additions & 23 deletions docker-compose.yml

This file was deleted.

5 changes: 0 additions & 5 deletions docs/README.md

This file was deleted.

79 changes: 79 additions & 0 deletions docs/decisions/001-postgres-only.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
# ADR-001: Postgres-only 의존성

## Status

Accepted (2026-05-23)

## Context

매치메이커는 다음과 같은 데이터 처리가 필요하다:

- Ticket 영속화 및 lifecycle 관리
- 매칭 워커의 분산 컨슈머 패턴
- 매치 결과 저장
- 설정 (큐/풀/룰) 저장
- 컴포넌트 간 이벤트 통보

전통적으로 이런 시스템은 Redis (캐시/큐), Kafka/NATS (메시지 큐), Postgres (영속화)를 조합해서 구현한다. Open Match도 Redis를 핵심 의존성으로 사용한다.

설치형 OSS 도구로 배포할 경우, 사용자(게임사)가 직접 운영해야 한다. 의존성이 많을수록 도입 장벽과 운영 부담이 커진다.

## Decision

**외부 큐/캐시 의존성 없이 Postgres만 사용한다.**

- 분산 컨슈머 패턴: `SELECT ... FOR UPDATE SKIP LOCKED`
- 이벤트 통보: `LISTEN/NOTIFY` (선택적, polling이 기본)
- JSONB로 동적 attribute 저장
- 트랜잭션으로 복잡한 상태 전이 일관성 보장

단, runtime DB와 config DB는 분리 (ADR-006 참조).

## Consequences

### 장점

- **운영 부담 최소**: 사용자가 Postgres 하나만 관리하면 됨
- **Helm chart 단순**: 의존성 명세가 짧음
- **트랜잭션 일관성 자연스러움**: 매치 lifecycle의 복잡한 상태 전이를 native transaction으로 처리
- **JSONB로 동적 attribute 표현 가능**: 큐별 커스텀 schema 지원
- **운영자 친화적 디버깅**: SQL로 모든 상태 조회 가능

### 단점

- **Throughput 상한 존재**: 단일 Postgres는 결국 수만 QPS가 한계
- **Multi-region 시 복잡**: Logical replication 직접 설계 필요
- **GIN 인덱스의 range query 한계**: JSONB attribute의 SQL 쿼리 성능 제한

### 부하 검증

목표 100만 동접 + 600 RPS 환경에서 측정한 부하:

- CreateTicket: ~556 QPS
- Match insert: ~139 QPS
- 나머지 컴포넌트 polling: 1자리 QPS

단일 Postgres가 압도적으로 여유 있게 처리하는 영역.

## Alternatives Considered

### Redis Streams (Open Match 방식)

- 장점: 빠른 throughput, 분산 컨슈머 패턴 (XREADGROUP)
- 단점: 복잡한 상태 전이에 약함 (백필 등), 의존성 추가, Lua 스크립트 필요

### Kafka/NATS 등 메시지 큐

- 장점: 확실한 분리, 백프레셔 표현
- 단점: 트랜잭션 일관성 어려움, 운영 부담 큼

### Postgres + Redis 하이브리드

- 장점: 각자 잘하는 곳에 사용
- 단점: 두 시스템의 일관성 관리, 운영 부담

## Notes

부하 측면에서는 Redis가 빠르지만, 매치메이커는 **상태 전이가 많은 도메인**(ticket lifecycle, match lifecycle, 백필, 취소, 타임아웃)이므로 transaction이 일급 시민인 Postgres가 적합하다.

매치메이커의 본질적 어려움은 throughput이 아니라 매칭 품질, fairness, 다운스트림 통합에 있다 (ADR-003 참조).
Loading