16. 채팅 스팸/도배 레이트리밋과 정상 메시지의 경합

난이도 중 해설 보기 →

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

결함 코드 · C#
// ============================================================================
// [코드리뷰 문제] C# - 채팅 스팸/도배 레이트리밋과 정상 메시지의 경합
// ----------------------------------------------------------------------------
// 시나리오:
//   - 채팅 도배를 막으려고 세션(플레이어)마다 "1초당 최대 N개" 레이트리밋을 둔다.
//   - 메시지가 들어오면 Allow(sessionId) 로 허용 여부를 판정하고, 허용이면 브로드캐스트,
//     아니면 드롭(또는 경고)한다.
//   - 한 플레이어의 채팅 패킷이라도 여러 IO 스레드에서 거의 동시에 처리될 수 있다
//     (매크로/도배 클라이언트는 짧은 시간에 패킷을 몰아 보낸다).
//
// 요구사항:
//   - 1초 윈도 안에서 허용 개수는 절대 N 을 넘으면 안 된다(도배가 새어 나가면 안 됨).
//   - 정상 속도의 메시지가 잘못 드롭되면 안 된다(과도 차단 금지).
//   - 동시 처리에도 카운터/윈도 자료구조가 손상되거나 예외로 죽으면 안 된다.
//   - 시각 판정은 NTP 보정/서머타임 점프에 흔들리면 안 된다.
//
// 과제:
//   이 코드의 잠재적 문제를 모두 찾고, 왜/어떻게 깨지는지(동시 인터리빙 포함)
//   설명하고, 수정안과 더 나은 설계를 제시하라.
//   (먼저 직접 리뷰를 적은 뒤 answer.md 와 대조할 것)
// ============================================================================

using System;
using System.Collections.Generic;

public class ChatRateLimiter
{
    private const int LimitPerSec = 5;

    private class Bucket
    {
        public int  Count;
        public long WindowStartMs;
    }

    // 세션 -> 버킷
    private readonly Dictionary<long, Bucket> _buckets = new();

    private Bucket GetOrCreate(long sessionId)
    {
        // (A)
        if (!_buckets.TryGetValue(sessionId, out var b))
        {
            b = new Bucket { Count = 0, WindowStartMs = NowMs() };
            _buckets[sessionId] = b;
        }
        return b;
    }

    public bool Allow(long sessionId)
    {
        var b = GetOrCreate(sessionId);
        long now = NowMs();

        // (B) 윈도 경과 시 리셋
        if (now - b.WindowStartMs >= 1000)
        {
            b.WindowStartMs = now;
            b.Count = 0;
        }

        // (C) 한도 검사 후 증가
        if (b.Count >= LimitPerSec)
            return false;

        b.Count++;
        return true;
    }

    private static long NowMs() => DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
}
내 리뷰 · C#
내 답안 · 자동 저장

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