25. 수용 제어·부하 차단 부재로 인한 메타안정 장애 (C#)
난이도 상 해설 보기 →
결함을 모두 찾고 원인·수정안·더 나은 설계를 제시하라. 마커
(A)(B) 는 주목 위치 힌트다.
결함 코드 · C#
// 시나리오: 게임 백엔드의 인벤토리/매치메이킹 API 서버 한 대.
// - 프런트에서 들어온 요청을 무제한 작업 큐에 넣고, 고정 크기 워커 풀이 순서대로 처리한다.
// - 각 요청에는 클라이언트가 정한 데드라인(DeadlineUtc)이 있고, 데드라인이 지나면
// 클라이언트는 응답을 버리고 재시도한다(같은 작업을 다시 제출).
// - 평상시엔 여유가 있지만, 이벤트 오픈/점검 직후 순간 부하가 스파이크로 몰린다.
//
// 요구사항:
// 1) 순간 부하가 처리 용량을 초과하면, 서버는 초과분을 빠르게 거절해
// 큐가 무한히 자라지 않게 해야 한다.
// 2) 이미 데드라인이 지난(클라가 포기한) 요청은 처리하지 않고 버려, 헛일을 막아야 한다.
// 3) 스파이크가 끝나면 시스템은 스스로 정상 지연으로 회복해야 한다.
//
// 과제: 아래 RequestServer 를 검토하여, 부하 스파이크 시 큐가 폭증하고 재시도가
// 증폭되어 스파이크가 끝난 뒤에도 과부하가 지속되는 지점을
// (A)(B) 마커로 진단하고, 정확한 수정안과 더 나은 설계를 제시하라.
using System;
using System.Collections.Concurrent;
using System.Threading;
public sealed class Request
{
public long Id;
public DateTime DeadlineUtc; // 이 시각 이후엔 클라가 응답을 버리고 재시도
public Action Work; // 실제 처리
}
public sealed class RequestServer
{
private readonly ConcurrentQueue<Request> _queue = new();
private readonly SemaphoreSlim _signal = new(0);
private readonly int _workers;
public RequestServer(int workers)
{
_workers = workers;
for (int i = 0; i < workers; i++)
new Thread(WorkerLoop) { IsBackground = true }.Start();
}
// 프런트가 요청을 제출한다.
public void Submit(Request req)
{
_queue.Enqueue(req); // (A) 들어오는 대로 큐에 넣는다
_signal.Release();
}
private void WorkerLoop()
{
while (true)
{
_signal.Wait();
if (!_queue.TryDequeue(out var req))
continue;
req.Work(); // (B) 데큐한 요청을 실행한다
}
}
} 결함 코드 · C++
// 시나리오: 게임 백엔드 API 서버 한 대 (C++).
// - 요청을 무제한 작업 큐에 넣고 고정 워커 풀이 처리한다.
// - 각 요청에 데드라인(deadline)이 있고, 지나면 클라이언트는 응답을 버리고 재시도한다.
// - 이벤트 오픈 직후 순간 부하 스파이크가 몰린다.
//
// 요구사항:
// 1) 용량 초과 시 초과분을 빠르게 거절해 큐가 무한히 자라지 않게 한다.
// 2) 데드라인이 지난 요청은 처리하지 않고 버린다(헛일 방지).
// 3) 스파이크 종료 후 스스로 정상 지연으로 회복한다.
//
// 과제: RequestServer 를 검토하여, 부하 스파이크 시 큐가 폭증하고 재시도가 증폭되어
// 스파이크 종료 후에도 과부하가 지속되는 지점을 (A)(B) 마커로 진단하고,
// 정확한 수정안과 더 나은 설계를 제시하라.
//
// 컴파일: g++ -std=c++17 -pthread -fsyntax-only problem.cpp
#include <chrono>
#include <condition_variable>
#include <functional>
#include <mutex>
#include <queue>
#include <thread>
#include <vector>
struct Request
{
long id = 0;
std::chrono::steady_clock::time_point deadline; // 이후엔 클라가 재시도
std::function<void()> work;
};
class RequestServer
{
public:
explicit RequestServer(int workers)
{
for (int i = 0; i < workers; ++i)
pool_.emplace_back([this] { workerLoop(); });
}
// 프런트가 요청을 제출한다.
void submit(Request req)
{
{
std::lock_guard<std::mutex> lk(m_);
queue_.push(std::move(req)); // (A) 들어오는 대로 큐에 넣는다
}
cv_.notify_one();
}
private:
void workerLoop()
{
for (;;)
{
Request req;
{
std::unique_lock<std::mutex> lk(m_);
cv_.wait(lk, [this] { return !queue_.empty(); });
req = std::move(queue_.front());
queue_.pop();
}
req.work(); // (B) 데큐한 요청을 실행한다
}
}
std::mutex m_;
std::condition_variable cv_;
std::queue<Request> queue_;
std::vector<std::thread> pool_;
}; 내 리뷰 · C#
내 답안 · 자동 저장
작성 후 위 해설 보기에서 모범 해설과 대조하세요.
내 리뷰 · C++
내 답안 · 자동 저장
작성 후 위 해설 보기에서 모범 해설과 대조하세요.