16P by neo 1달전 | favorite | 댓글 1개
  • Lichess 는 전 세계 수백만 명의 플레이어를 가진 무료 오픈 소스 체스 플랫폼
  • Chrome DevTools의 Network탭을 사용하여 클라이언트와 서버 간 통신을 모니터링

WebSocket 연결

  • 첫 주목할 만한 네트워크 동작은 다음과 유사한 URL로의 WebSocket 연결임:
wss://socket2.lichess.org/play/H5uHz0egyvIA/…  
  • 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(메시지 중복 가능성) 전송 중 어떤 것이 더 적절할지 신중히 고려해야 함. 이는 애플리케이션의 요구 사항과 트레이드오프에 따라 다름
Hacker News 의견
  • 체스.com의 시간 구조에 대한 불만이 있음. 서버가 시간을 추적하는 것 같아 전송 시간과 지연을 무시하는 것 같음. 모바일 클라이언트에서 시간 제한 게임을 할 때 특히 불편함

    • 네트워크 코드의 문제일 수도 있으며, 퍼즐에서 오류가 자주 발생함
    • Chess.com의 기술이 거칠게 느껴짐
  • Lichess는 StackOverflow 접근 방식을 선택했으며, 강력한 서버를 사용함

    • 게임 상태를 주기적으로 저장하지만, 어디에 저장하는지는 명확하지 않음
    • 게임당 비용이 매우 낮음: $0.00027, 3,671 게임당 1달러
    • 단일 데이터센터 의존성으로 인해 10시간의 중단이 발생한 적이 있음
  • 서버 측에서 움직임을 계산하는 것은 일관성을 보장하고, 제한된 처리 능력이나 에너지를 가진 클라이언트의 성능을 최적화함

    • 새로운 플랫폼에서 오픈 소스 소프트웨어 클라이언트의 구현 장벽을 낮추기 위한 것일 수 있음
    • 체스 규칙 구현이 번거로울 수 있으며, Lichess도 한때 논리 오류가 있었음
  • Redis pub/sub 채널에서 메시지 손실을 어떻게 처리하는지 설명이 부족함

  • "l" 매개변수는 서버에서 관찰된 지연을 나타내는 것일 수 있음

  • 서버가 모든 합법적인 다음 움직임을 열거하고 전송하는 것이 놀라움

    • 제한된 클라이언트에 유리할 수 있지만, 클라이언트 측에서 계산하는 것보다 저렴한지 의문임
  • 웹소켓 서버 보호 방법에 대한 질문이 있음

    • Cloudflare의 무료 플랜을 사용하면 지연이 발생함
    • 무료 솔루션에 대한 궁금증이 있음
  • 프로토콜이 왜 ack가 필요한지 궁금함

    • TLS로 감싼 웹소켓이 메시지의 무결성을 보장할 수 있음
  • FEN은 보드 상태만 인코딩하며, 게임 상태는 포함하지 않음

    • Scala로 작성된 scalachess 프로젝트는 성공적으로 유지되고 있음