# 체스사이트 Lichess.org에서 한 수를 둘 때 일어나는 일

> Clean Markdown view of GeekNews topic #17404. Use the original source for factual precision when an external source URL is present.

## Metadata

- GeekNews HTML: [https://news.hada.io/topic?id=17404](https://news.hada.io/topic?id=17404)
- GeekNews Markdown: [https://news.hada.io/topic/17404.md](https://news.hada.io/topic/17404.md)
- Type: GN+
- Author: [neo](https://news.hada.io/@neo)
- Published: 2024-10-24T21:33:28+09:00
- Updated: 2024-10-24T21:33:28+09:00
- Original source: [davidreis.me](https://www.davidreis.me/2024/what-happens-when-you-make-a-move-in-lichess)
- Points: 16
- Comments: 1

## Summary

Lichess 가 실시간 체스 게임을 가능하게 하는 백엔드 아키텍처와 프로세스를 상세히 설명하며, WebSocket을 통한 실시간 통신과 Redis Pub/Sub을 활용한 메시지 전달, MongoDB를 통한 데이터 저장 등 주요 기술적 요소를 소개합니다. 또한, Lichess의 아키텍처가 실시간 멀티플레이어 게임뿐만 아니라 채팅, 협업 도구, 소셜 미디어 피드 등 다양한 실시간 웹 애플리케이션에 적용될 수 있는 패턴과 기술을 제시하며, 실시간 시스템 설계 시 고려해야 할 확장성, 안정성, 데이터 정합성 등의 기술적 과제를 해결하기 위한 전략을 제공합니다.

## Topic Body

- Lichess 는 전 세계 수백만 명의 플레이어를 가진 무료 오픈 소스 체스 플랫폼  
- Chrome DevTools의 Network탭을 사용하여 클라이언트와 서버 간 통신을 모니터링  
  
### WebSocket 연결  
- 첫 주목할 만한 네트워크 동작은 다음과 유사한 URL로의 WebSocket 연결임:  
```  
wss://socket2.lichess.org/play/H5uHz0egyvIA/v6?sri=bt6QzcyOiZg5&v=0  
```  
- **`wss`** 프로토콜은 TLS를 사용하는 암호화된 웹소켓 연결을 나타냄  
- WebSocket은 전이중 통신을 허용하여 반복적인 HTTP 요청 없이 클라이언트와 서버 간 실시간 업데이트를 가능케 함  
  
### 로컬 플레이어 차례  
- 동작을 수행하면 데이터 패킷이 교환됨:  
```  
// 22:51:35.280에 보냄  
{  
  "t": "move",   
  "d": {  
    "u": "d2d4",  
    "l": 32,  
    "a": 1  
  }  
}  
```  
- 서버로부터 수신한 메시지:  
```  
// 22:51:35.312에 수신함  
{  
  "t": "ack",  
  "d": 1  
}  
```  
- 서버가 우리의 동작을 수신했음을 알려줌  
```  
// 22:51:35.312에 수신함  
{  
  "t": "move",  
  "v": 1,  
  "d": {  
    "uci": "d2d4",  
    "san": "d4",  
    "fen": "rnbqkbnr/pppppppp/8/8/3P4/8/PPP1PPPP/RNBQKBNR",  
    "ply": 1,  
    "clock": {  
      "white": 300,  
      "black": 300  
    }  
  }  
}  
```  
- 이 메시지는 우리가 한 동작과 업데이트된 게임 상태에 대한 상세 정보를 제공함  
  
### 상대방 차례  
- 상대방이 동작하면 유사한 패킷을 서버로부터 수신함:  
```  
// 22:51:43.489에 수신함  
{   
  "t": "move",  
  "v": 2,  
  "d": {  
    "uci": "d7d5",  
    "san": "d5",  
    "fen": "rnbqkbnr/ppp1pppp/8/3p4/3P4/8/PPP1PPPP/RNBQKBNR",  
    "ply": 2,  
    "dests": {  
      "c2": "c3c4",  
      "g2": "g3g4"  
      // 추가 가능한 동작들  
    },  
    "clock": {   
      "white": 300,  
      "black": 300  
    }  
  }  
}   
```  
- **`dests`** 매개변수는 현재 위치에서 사용 가능한 모든 동작들을 나열함  
  
### Lichess의 아키텍처  
- Lichess의 실시간 플레이 시스템은 주로 두 개의 주요 서비스(둘 다 Scala로 작성됨)로 구성됨:  
  1. **`lila`**: 게임 로직, 상태, 사용자 상호 작용 등 핵심 기능을 관리하는 코어 서비스  
  2. **`lila-ws`**: 클라이언트와 **`lila`** 간 브릿지 역할을 하는 WebSocket 처리 전문 서비스  
  
### 아키텍처 개요   
```  
lila <-> redis <-> lila-ws <-> websocket <-> client  
```  
- **`lila`**는 Redis를 통해 **`lila-ws`**와 통신하고, 이는 클라이언트와의 WebSocket 연결을 관리함  
  
### Redis Pub/Sub을 사용한 통신  
- 동작 이벤트는 Redis Pub/Sub 채널로 게시되며, 여기에 **`lila`**가 구독하여 동작을 처리함  
- Redis Pub/Sub은 at-most-once 전송을 제공함. 메시지 손실이 가능하지만 메모리 사용량은 줄어듦  
  
### MongoDB와의 최종 데이터 영속성  
- **`lila`**는 MongoDB에 게임 상태를 저장하지만, 모든 단일 동작을 즉시 저장하지는 않음  
- 대신 동작을 버퍼링하고 주기적으로 저장하여 DB 부하를 줄임  
- 중요한 이벤트가 발생하면 게임 상태가 플러시됨   
  
### 진행 중인 게임에 참여하기  
- 플레이어가 연결할 때 **`v`** 매개변수를 제공하여 자신이 알고 있는 게임의 최신 버전을 시스템에 알림   
- **`lila-ws`**는 **`ConcurrentHashMap`**을 사용하여 진행 중인 게임의 모든 이벤트를 추적하고 관리함  
  
### 마무리  
Lichess에서의 동작 프로세스를 요약하면 다음과 같음:  
  
1. 클라이언트가 **`lila-ws`**에 WebSocket 연결 설정  
2. 플레이어가 동작을 수행하면 클라이언트가 **`lila-ws`**에 동작 이벤트 전송  
3. **`lila-ws`**는 동작 수신을 확인하는 **`ack`** 응답  
4. 동작 이벤트가 Redis Pub/Sub 채널에 게시되고 **`lila`**가 처리  
5. **`lila`**는 동작을 수신하여 게임 상태 업데이트하고 최종적으로 MongoDB에 저장. 업데이트된 게임 상태는 **`lila-ws`**를 통해 다시 클라이언트로 전송됨  
6. 클라이언트는 새 동작과 게임 상태 변경을 반영하는 업데이트된 게임 상태를 수신함  
  
### GN⁺의 의견  
- 이 게시물은 인기 있는 오픈 소스 체스 플랫폼인 lichess.org의 실시간 게임플레이를 가능하게 만드는 백엔드 아키텍처와 프로세스를 자세히 살펴봄  
- 실시간 웹 애플리케이션을 구축할 때 고려해야 할 주요 기술적 요소들을 소개하는데, 예를 들어 WebSocket을 사용한 실시간 통신, Redis Pub/Sub을 통한 확장성 있는 메시지 전달, MongoDB로 최종 데이터 저장 등  
- Lichess의 아키텍처는 실시간 멀티플레이어 게임에 매우 적합하지만, 채팅, 협업 도구, 소셜 미디어 피드 등 다른 유형의 실시간 웹앱에도 유사한 패턴과 기술을 적용할 수 있음  
- 실시간 기능은 사용자 경험과 상호 작용을 향상시킬 수 있지만, 확장성, 안정성, 데이터 정합성 등 고유한 기술적 과제도 제기함. 이 게시물은 이러한 과제를 해결하기 위한 전략을 제공함  
- 유사한 기술 스택을 사용하는 오픈 소스 프로젝트로는 Socket.IO(Node.js 기반 실시간 애플리케이션 프레임워크)와 RethinkDB(실시간 웹앱에 최적화된 NoSQL 데이터베이스) 등이 있음  
- 이 게시물의 분석은 Lichess의 소스 코드를 직접 검토한 것은 아니므로, 실제 구현에는 차이가 있을 수 있음. 하지만 설명된 기본 개념과 아키텍처 패턴은 여전히 유효함  
- 실시간 시스템을 설계할 때는 at-most-once(메시지 손실 가능성)와 at-least-once(메시지 중복 가능성) 전송 중 어떤 것이 더 적절할지 신중히 고려해야 함. 이는 애플리케이션의 요구 사항과 트레이드오프에 따라 다름

## Comments



### Comment 30377

- Author: neo
- Created: 2024-10-24T21:33:29+09:00
- Points: 1

###### [Hacker News 의견](https://news.ycombinator.com/item?id=41922928) 
- 체스.com의 시간 구조에 대한 불만이 있음. 서버가 시간을 추적하는 것 같아 전송 시간과 지연을 무시하는 것 같음. 모바일 클라이언트에서 시간 제한 게임을 할 때 특히 불편함
  - 네트워크 코드의 문제일 수도 있으며, 퍼즐에서 오류가 자주 발생함
  - Chess.com의 기술이 거칠게 느껴짐

- Lichess는 StackOverflow 접근 방식을 선택했으며, 강력한 서버를 사용함
  - 게임 상태를 주기적으로 저장하지만, 어디에 저장하는지는 명확하지 않음
  - 게임당 비용이 매우 낮음: $0.00027, 3,671 게임당 1달러
  - 단일 데이터센터 의존성으로 인해 10시간의 중단이 발생한 적이 있음

- 서버 측에서 움직임을 계산하는 것은 일관성을 보장하고, 제한된 처리 능력이나 에너지를 가진 클라이언트의 성능을 최적화함
  - 새로운 플랫폼에서 오픈 소스 소프트웨어 클라이언트의 구현 장벽을 낮추기 위한 것일 수 있음
  - 체스 규칙 구현이 번거로울 수 있으며, Lichess도 한때 논리 오류가 있었음

- Redis pub/sub 채널에서 메시지 손실을 어떻게 처리하는지 설명이 부족함
- "l" 매개변수는 서버에서 관찰된 지연을 나타내는 것일 수 있음
- 서버가 모든 합법적인 다음 움직임을 열거하고 전송하는 것이 놀라움
  - 제한된 클라이언트에 유리할 수 있지만, 클라이언트 측에서 계산하는 것보다 저렴한지 의문임

- 웹소켓 서버 보호 방법에 대한 질문이 있음
  - Cloudflare의 무료 플랜을 사용하면 지연이 발생함
  - 무료 솔루션에 대한 궁금증이 있음

- 프로토콜이 왜 ack가 필요한지 궁금함
  - TLS로 감싼 웹소켓이 메시지의 무결성을 보장할 수 있음

- FEN은 보드 상태만 인코딩하며, 게임 상태는 포함하지 않음
  - Scala로 작성된 scalachess 프로젝트는 성공적으로 유지되고 있음
