순서보장과 저장방식

1. 한 유저에 대한 Job 순서 보장

같은 유저의 DB Job이 순서가 뒤바뀌면 데이터 정합성이 깨질 수 있다. EntityID 기반으로 워커를 고정 분배하면 구조적으로 순서가 보장된다.

// EntityID 기반 워커 분배
int workerIndex = entityId % workerCount;
workers_[workerIndex].Push(job);

??? 이 경우 유저가 동등하게 분포되었다고 하더라도 활동량이 많은 유저가 특정 스레드쪽으로 쏠리면 문제가 있지 않나? 괜찮나? 어차피 서버는항시 유저가 가득찼을때를 가정한다. 각 1000개를 부담한다면 1000개까지 감당하면 그만. 이라고이해했음.

⚠ 다만 이 보장은 한 프로세스 안에서만 유효하다. 워커 분배는 그 프로세스의 큐에만 걸리므로, 유저가 다른 프로세스로 넘어가면 순서 관계가 끊긴다. 존/채널이 여러 프로세스로 나뉘는 구조에서는 앞 프로세스의 미완료 Job과 뒤 프로세스의 새 Job이 서로를 모르므로, 이동 시점의 인계 장치가 따로 필요하다. (아래 「재 접속 Stale Read 문제」)


2. 크로스-엔티티 거래는 하나의 Job으로 묶는다

A와 B가 거래했을 때, 분리해서 각자의 워커에 넣으면 안 된다.

[거래: A가 B에게 칼을 주고, B가 A에게 골드를 줌]

분리 저장 시 문제:
  Worker 0 → A 저장 완료 (골드 증가, 칼 삭제)  ✅
  Worker 1 → B 저장 대기 중...
                  ↓
              서버 크래시
                  ↓
  DB: A는 골드+칼 없음 (신규), B는 골드+칼 없음 (구데이터)
  → 골드 복제, 칼 소실

거래처럼 여러 엔티티의 데이터를 동시에 변경하는 작업은 반드시 하나의 DB 트랜잭션 Job으로 묶어야 한다. 크래시 시점과 무관하게 "둘 다 반영" 또는 "둘 다 미반영"이 보장되어야 함.

라우팅: 크로스-엔티티 Job은 아무 워커에나 넣어도 된다. 중요한 것은 DB 트랜잭션으로 원자적 실행이 보장되는 것이지, 어느 워커가 실행하느냐가 아니다. (이걸로인해서 DB부하량의 밸런스가 꺠지지는않는가?)


저장 방식: 전체 상태 저장 (Full State Save)

일방향 백업 모델에서는 절대값 덮어쓰기가 유일하게 올바른 방식이다.

방식 예시 재시도 안전 실패 후 복구
전체 상태 (= 300) UPDATE SET gold = 300 멱등 (몇 번 해도 동일) 다음 Job이 최신 값을 덮어쓰므로 안전
변경분 (+= 200) UPDATE SET gold = gold + 200 재시도 시 중복 적용 (500, 700...) 누락분 영구 유실

서버 메모리가 source of truth인 이상, 서버는 항상 현재 절대값(=최신값) 을 알고 있다. 변경분 방식은 서버가 이미 보유한 정보를 버리고 DB에게 불필요한 연산을 위임하는 것으로, 장점이 없고 단점만 있다.