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++
// 시나리오: 던전/레이드 인스턴스를 상태가 있는 인스턴스 서버 노드들이 호스팅한다.
// 오케스트레이터가 노드 헬스체크를 돌리고, 한 노드가 무응답이면 그 노드가
// 맡던 인스턴스를 다른 백업 노드에서 다시 띄운다(failover). 각 인스턴스는
// 진행 상태를 주기적으로 체크포인트로 저장한다.
//
// 요구사항:
// - 한 인스턴스는 어느 순간에도 "정확히 한 노드"에서만 활성이어야 한다.
// 두 노드가 같은 인스턴스를 동시에 돌리면(보스 보상 이중 지급 등) 안 된다.
// - 노드가 일시적으로 느려지거나(긴 GC/STW·네트워크 순단) 헬스체크를 한두 번
// 놓쳤다고 해서 살아있는 노드를 함부로 죽은 것으로 단정하면 안 된다.
// - failover 후 보상/진행이 중복 처리되면 안 된다.
//
// 과제: 이 failover 로직이 어떤 상황에서 한 인스턴스가 두 노드에서 동시에 활성화되거나
// 보상 중복을 일으키는지 (A)~(C) 지점을 중심으로 진단하고 고쳐라.
#include <cstdint>
#include <string>
#include <unordered_map>
#include <vector>
struct InstanceState { /* 진행 상태 */ };
struct INode {
virtual void startInstance(int64_t instanceId, const InstanceState& s) = 0;
virtual ~INode() = default;
};
class InstanceOrchestrator {
public:
// 헬스체크가 노드 무응답을 감지하면 호출(단발 타임아웃 기반)
void onNodeUnhealthy(const std::string& deadNode) { // (C) 단발 감지로 호출됨
std::vector<int64_t> toMove;
for (auto& kv : owner_)
if (kv.second == deadNode) toMove.push_back(kv.first);
for (int64_t instanceId : toMove) {
std::string backup = pickBackup(deadNode);
InstanceState state = loadLastCheckpoint(instanceId); // (B) 마지막 체크포인트
nodes_[backup]->startInstance(instanceId, state); // (A) 백업에서 기동
owner_[instanceId] = backup; // (A) 소유권 이전
}
}
private:
std::string pickBackup(const std::string& dead) { return ""; }
InstanceState loadLastCheckpoint(int64_t id) { return {}; }
std::unordered_map<int64_t, std::string> owner_; // instanceId -> nodeId
std::unordered_map<std::string, INode*> nodes_;
}; 내 리뷰 · C#
내 답안 · 자동 저장
작성 후 위 해설 보기에서 모범 해설과 대조하세요.
내 리뷰 · C++
내 답안 · 자동 저장
작성 후 위 해설 보기에서 모범 해설과 대조하세요.