6. 인스턴스 서버 failover 의 split-brain 과 보상 중복

난이도 상 해설 보기 →

결함을 모두 찾고 원인·수정안·더 나은 설계를 제시하라. 마커 (A)(B) 는 주목 위치 힌트다.

결함 코드 · C#
// 시나리오: 던전/레이드 인스턴스를 상태가 있는(stateful) 인스턴스 서버 노드들이
//   호스팅한다. 오케스트레이터가 노드 헬스체크를 돌리고, 한 노드가 무응답이면
//   그 노드가 맡던 인스턴스를 다른 백업 노드에서 다시 띄운다(failover).
//   각 인스턴스는 진행 상태를 주기적으로 체크포인트로 저장한다.
//
// 요구사항:
//   - 한 인스턴스는 어느 순간에도 "정확히 한 노드"에서만 활성이어야 한다.
//     두 노드가 같은 인스턴스를 동시에 돌리면(보스 보상 이중 지급 등) 안 된다.
//   - 노드가 일시적으로 느려지거나(긴 GC 멈춤·네트워크 순단) 헬스체크를 한두 번
//     놓쳤다고 해서 살아있는 노드를 함부로 죽은 것으로 단정하면 안 된다.
//   - failover 후 보상/진행이 중복 처리되면 안 된다.
//
// 과제: 이 failover 로직이 어떤 상황에서 한 인스턴스가 두 노드에서 동시에 활성화되거나
//       보상 중복을 일으키는지 (A)~(C) 지점을 중심으로 진단하고 고쳐라.

using System.Collections.Generic;

public sealed class InstanceOrchestrator
{
    private readonly Dictionary<long, string> _owner = new();   // instanceId -> nodeId
    private readonly Dictionary<string, INode> _nodes = new();

    // 헬스체크가 노드 무응답을 감지하면 호출(단발 타임아웃 기반)
    public void OnNodeUnhealthy(string deadNode)               // (C) 단발 감지로 호출됨
    {
        var toMove = new List<long>();
        foreach (var kv in _owner)
            if (kv.Value == deadNode) toMove.Add(kv.Key);

        foreach (var instanceId in toMove)
        {
            string backup = PickBackup(deadNode);
            var state = LoadLastCheckpoint(instanceId);        // (B) 마지막 체크포인트 로드
            _nodes[backup].StartInstance(instanceId, state);   // (A) 백업에서 인스턴스 기동
            _owner[instanceId] = backup;                       // (A) 소유권 이전
        }
    }

    private string PickBackup(string dead) { /* 가용 노드 선택 */ return ""; }
    private InstanceState LoadLastCheckpoint(long id) { return new InstanceState(); }
}

public sealed class InstanceState { /* 진행 상태 */ }
public interface INode { void StartInstance(long instanceId, InstanceState state); }
내 리뷰 · C#
내 답안 · 자동 저장

작성 후 위 해설 보기에서 모범 해설과 대조하세요.