AI로 MSA 서버 만들어 보기 #4 : Write-Behind

2025. 12. 9. 17:11·Study/C++ & C#

1. 컨셉

단순한 서버는 "DB 트랜잭션이 끝나야만 유저에게 OK를 보낸다"는 Write-Through 방식을 많이 사용한다.

하지만, 이는 DB가 병목이 될 경우 전체 서버의 반응성을 크게 저하할 수 있다.
Write-Behind (Write-Back) 패턴은 이를 해결할 수 있다.

  1. Memory First: 메모리(또는 빠른 캐시인 Redis)에 먼저 쓰고, 유저에게 즉시 OK를 준다.
  2. Disk Later: 실제 견고한 저장소(RDBMS)에는 별도의 워커가 천천히, 모아서 기록한다.
    본 서버는 이 패턴을 Redis Streams를 통해 구현했다.

 

2. 아키텍처

  • Decoupling: 채팅 로직(Fast)과 저장 로직(Slow)이 완벽히 분리된다.
  • Peak Load Handling: 트래픽이 폭주하면 Redis Stream에 데이터가 쌓일 뿐, 서버의 응답 속도는 느려지지 않는다.

 

3. 생산자 구현 (emit_write_behind_event)

서버 코드(server/src/chat/chat_service_core.cpp)에서 이벤트를 발행하는 부분이다.

void ChatService::emit_write_behind_event(const std::string& type, 
                                          const std::string& session_id,
                                          ...) {
    // 1. 데이터 준비 (Key-Value Vector)
    std::vector<std::pair<std::string, std::string>> fields;
    fields.emplace_back("type", type);
    fields.emplace_back("ts_ms", std::to_string(now_ms));
    fields.emplace_back("session_id", session_id);
    // ... (user_id, room_id 등 추가 필드)
    // 2. Redis Stream XADD (Non-blocking)
    // "stream:events" 라는 키에 데이터를 append 한다.
    // maxlen을 설정하여 스트림이 무한히 커지는 것을 방지한다. (Ring Buffer 효과)
    redis_->xadd("stream:events", fields, nullptr, 100000 /*maxlen*/, true /*approx*/);
}
  • 특징:
    • JSON Free: 문자열 파싱/생성 비용을 줄이기 위해 Redis의 Native Map 구조를 사용한다.
    • Fire and Forget: xadd의 결과를 기다리지 않거나, 실패해도 로그만 남기고 넘어간다 (서버 동작이 우선).

 

4. Redis Stream

서버가 사용하는 주요 Redis Stream 커맨드이다.

Command Usage Role
XADD key * field value ... Producer 스트림 끝에 새 항목 추가. ID는 자동 생성(timestamp-sequence).
XREADGROUP GROUP g1 CONSUMER c1 BLOCK 2000 STREAMS key > Consumer 컨슈머 그룹 g1의 멤버 c1이 되어, 아직 아무도 안 읽은(>) 메시지를 읽어옴. 없으면 2초 대기.
XACK key g1 id ... Consumer "처리 완료" 서명. 이 처리가 되어야 PEL(Pending Entries List)에서 제거됨.

 

5. 소비자 구현 (The Worker)

현재 구현체는 독립 프로그램 (wb_worker)으로 제공된다.

scripts/smoke_wb.ps1을 통해 빌드 및 간단한 스모크 테스트를 수행할 수 있다.

흐름 (wb_worker)

  1. Fetch: XREADGROUP으로 배치 단위(예: 100개)로 이벤트를 가져온다.
  2. Transform: 이벤트 타입(type=chat_msg)에 따라 적절한 SQL(INSERT INTO messages ...)을 생성한다.
  3. Batch Insert: DB 부하를 줄이기 위해 INSERT를 한 번의 트랜잭션으로 묶어서 실행한다 (Bulk Insert).
  4. Acknowledge: DB 커밋이 성공하면 XACK를 날려 Redis에서 해당 항목을 처리 완료로 마킹한다.

 

6. 문제 대응

"메모리에만 썼는데 서버가 죽으면 어떡하지?"

  1. Redis Persistence: Redis 자체의 AOF (Append Only File) 기능을 켜두면, Redis가 죽었다 살아나도 스트림 데이터는 보존된다.
  2. Consumer Crash:
    • 워커가 데이터를 읽어갔는데(XREADGROUP) DB에 넣기 전에 죽었다면?
    • XACK를 못 보냈으므로 해당 메시지는 PEL (Pending Entries List)에 남는다.
    • 워커가 재가동되면 XREAD ... 0 (또는 XAUTOCLAIM)을 통해 처리되지 않은 메시지를 다시 가져와서 재시도한다. -> At-least-once Delivery 보장.

 

Trade-offs

  • Consistency Gap: 아주 짧은 순간(수 ms ~ 수 초) DB와 캐시(메모리) 간의 데이터 불일치가 존재할 수 있다.
  • Complexity: 시스템 구성 요소가 늘어난다. (Redis 관리, 워커 모니터링 필요)
    • 하지만 큰 트래픽을 받는 서버에서 "압도적인 쓰기 성능"을 얻기 위해 이 정도의 복잡도는 충분히 감수할 가치가 있다.

 


이러면 대충 백엔드 쪽은 간단하게나마 정리됐다.

다른 기능이나 클러스터링을 구현하면 그때 내용을 추가로 보충할 수 있을 것이다.

클라이언트는 ImGui로 다시 작성하고 나면 그 때 글로 정리해 볼 수 있을 것 같다.

'Study > C++ & C#' 카테고리의 다른 글

AI로 MSA 서버 만들어 보기 #3 : Gateway  (0) 2025.12.09
AI로 MSA 서버 만들어 보기 #2 : Server  (0) 2025.12.07
AI로 MSA 서버 만들어 보기 #1 : Core  (0) 2025.12.03
[C++] 채팅서버에 DB 실장  (0) 2024.05.14
[C#] ###Clicker 동작 개선  (0) 2024.05.05
'Study/C++ & C#' 카테고리의 다른 글
  • AI로 MSA 서버 만들어 보기 #3 : Gateway
  • AI로 MSA 서버 만들어 보기 #2 : Server
  • AI로 MSA 서버 만들어 보기 #1 : Core
  • [C++] 채팅서버에 DB 실장
BVM
BVM
  • BVM
    E:\
    BVM
  • 전체
    오늘
    어제
    • 분류 전체보기 (173)
      • Thoughts (14)
      • Study (75)
        • Japanese (3)
        • C++ & C# (50)
        • Javascript (3)
        • Python (14)
        • Others (5)
      • Play (1)
        • Battlefield (1)
      • Others (10)
      • Camp (73)
        • T.I.L. (57)
        • Temp (1)
        • Standard (10)
        • Challenge (3)
        • Project (1)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

    • 본 블로그 개설의 목적
  • 인기 글

  • 태그

    Server
    Dalamud
    네트워크
    서버
    Python
    docker
    bot
    FF14
    Asio
    네트워크 프로그래밍
    boost
    cloudtype
    7계층
    로깅
    discord py
    암호화
    JS
    베데스다
    C++
    프로그래머스
    스타필드
    IOCP
    포인터
    Network
    db
    클라우드
    c#
    OSI
    discord
    Selenium
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.2
BVM
AI로 MSA 서버 만들어 보기 #4 : Write-Behind
상단으로

티스토리툴바