16. 성급한 장애 감지와 플래핑으로 인한 불필요한 리밸런싱 (C#)
난이도 상 해설 보기 →
결함을 모두 찾고 원인·수정안·더 나은 설계를 제시하라. 마커
(A)(B) 는 주목 위치 힌트다.
결함 코드 · C#
// 시나리오: 게임 노드 클러스터의 장애 감지와 세션 리밸런싱 (C#)
//
// 코디네이터는 각 게임 노드로부터 하트비트를 받는다. 노드가 죽었다고 판단되면
// 그 노드가 담당하던 세션(존/방)을 살아있는 노드로 재배치(리밸런싱)한다.
//
// 요구사항:
// - 일시적 네트워크 지연/지터로 하트비트가 한두 번 늦는 것으로 노드를 죽었다고 판단하면 안 된다.
// - 리밸런싱은 비싸고 파괴적이므로(세션 이관·재접속 유발) 정말 죽었을 때만 해야 한다.
// - 하트비트가 늦었다가 곧 돌아온 노드는 계속 정상으로 취급해야 한다.
//
// HeartbeatMonitor 는 1초마다 Tick() 이 호출된다. 표시된 지점 (A)(B)(C).
using System;
using System.Collections.Generic;
public sealed class NodeInfo
{
public string NodeId = "";
public DateTime LastHeartbeat;
public bool Alive = true;
}
public sealed class HeartbeatMonitor
{
private readonly Dictionary<string, NodeInfo> _nodes = new();
private readonly TimeSpan _timeout = TimeSpan.FromSeconds(2);
private readonly Action<string> _rebalanceFrom;
public HeartbeatMonitor(Action<string> rebalanceFrom) { _rebalanceFrom = rebalanceFrom; }
public void OnHeartbeat(string nodeId)
{
if (!_nodes.TryGetValue(nodeId, out var n))
_nodes[nodeId] = n = new NodeInfo { NodeId = nodeId };
n.LastHeartbeat = DateTime.UtcNow; // 갱신
}
public void Tick()
{
DateTime now = DateTime.UtcNow;
foreach (var n in _nodes.Values)
{
// (A) 마지막 하트비트 이후 timeout 초과면 죽음으로 판정
bool timedOut = (now - n.LastHeartbeat) > _timeout;
if (timedOut && n.Alive)
{
n.Alive = false; // (B) 죽음 표시
_rebalanceFrom(n.NodeId); // (C) 즉시 리밸런싱 트리거
}
else if (!timedOut && !n.Alive)
{
n.Alive = true; // 하트비트 돌아오면 다시 살림
}
}
}
} 결함 코드 · C++
// 시나리오: 게임 노드 클러스터의 장애 감지와 세션 리밸런싱 (C++)
//
// 코디네이터는 각 게임 노드의 하트비트를 받는다. 노드가 죽었다고 판단되면 그 노드가 담당하던
// 세션(존/방)을 살아있는 노드로 재배치(리밸런싱)한다.
//
// 요구사항:
// - 일시적 지연/지터로 하트비트가 한두 번 늦은 것으로 노드를 죽었다고 판단하면 안 된다.
// - 리밸런싱은 비싸고 파괴적이므로(세션 이관·재접속) 정말 죽었을 때만 한다.
// - 늦었다가 곧 돌아온 노드는 계속 정상으로 취급한다.
//
// HeartbeatMonitor::Tick() 은 1초마다 호출된다. 표시된 지점 (A)(B)(C).
#include <chrono>
#include <functional>
#include <string>
#include <unordered_map>
using SysClock = std::chrono::system_clock;
struct NodeInfo {
std::string nodeId;
SysClock::time_point lastHeartbeat;
bool alive = true;
};
class HeartbeatMonitor {
public:
explicit HeartbeatMonitor(std::function<void(const std::string&)> rebalanceFrom)
: rebalanceFrom_(std::move(rebalanceFrom)) {}
void OnHeartbeat(const std::string& nodeId) {
auto& n = nodes_[nodeId];
n.nodeId = nodeId;
n.lastHeartbeat = SysClock::now();
}
void Tick() {
auto now = SysClock::now();
for (auto& [id, n] : nodes_) {
// (A) 마지막 하트비트 이후 timeout(2s) 초과면 죽음 판정
bool timedOut =
std::chrono::duration_cast<std::chrono::seconds>(now - n.lastHeartbeat).count() > 2;
if (timedOut && n.alive) {
n.alive = false; // (B) 죽음 표시
rebalanceFrom_(n.nodeId); // (C) 즉시 리밸런싱
} else if (!timedOut && !n.alive) {
n.alive = true; // 하트비트 돌아오면 다시 살림
}
}
}
private:
std::unordered_map<std::string, NodeInfo> nodes_;
std::function<void(const std::string&)> rebalanceFrom_;
}; 내 리뷰 · C#
내 답안 · 자동 저장
작성 후 위 해설 보기에서 모범 해설과 대조하세요.
내 리뷰 · C++
내 답안 · 자동 저장
작성 후 위 해설 보기에서 모범 해설과 대조하세요.