지금까지는 외부 데이터(ADS-B/AIS)를 우리가 끌어오는 쪽이라, 정작 이 서버가 "요청을 받아 처리하는 서버"로서 부하를 받는 일이 거의 없었다. 이걸 개선하고 싶다는 논의에서 시작해서, DMZ 드론 스웜 시나리오를 구현·배포하고, 그 과정에서 실제로 클러스터 자원 한계를 건드린 장애까지 겪은 전체 기록.

1. 처음 생각한 방향 — 동시 접속자 부하 테스트, 그리고 기각한 이유

처음엔 k6 같은 도구로 WebSocket/REST 동시 접속자를 시뮬레이션해서 Grafana로 관찰하는 방향을 제안했다. 그럴듯해 보였지만, 다시 생각해보니 이 프로젝트의 서사와 안 맞는다는 지적을 받았다:

"이 프로젝트에서 서버가 부하를 받는 일이 거의 없다는 게 좀 아쉬운데? 대규모 데이터 처리 같은 느낌은 될 수 있지 않을까"

맞는 지적이었다. C4I(지휘통제) 시스템은 "동시 접속자가 몇 명이냐"로 부하가 걸리는 서비스가 아니다 — 실제 C4I 시스템의 부하는 센서가 한 번에 얼마나 많은 표적을 쏟아내느냐다. 사용자가 적은 게 이 도메인에서는 정상이고, 오히려 "동시 접속자 100명"을 억지로 만드는 게 서사에 안 맞는 이야기였다.

2. 방향 전환 — 합성 대량 표적 생성기 (드론 스웜/포화 공격 시나리오)

그래서 방향을 바꿨다: 외부 API(adsb.fi/aisstream.io)는 레이트리밋이 있어서 그쪽으로 부하를 키우는 건 애초에 이용약관 위반이 되고, 대신 우리가 통제할 수 있는 합성 표적 생성기로 대량의 이벤트를 Kafka에 쏟아부어서 파이프라인 자체를 시험하는 쪽이 낫다.

이렇게 하면 시험 대상이 이미 만들어둔 전체 파이프라인이 된다:

그리고 Prometheus/Grafana(이미 구축됨)로 "초당 N표적 유입 시 컨슈머 랙/DB 쓰기 지연"을 그래프로 보여줄 수 있어서, 포트폴리오 그림으로도 부하 테스트 스크린샷 하나보다 훨씬 설득력 있다.

3. 기존 DroneSimulator를 그대로 못 쓰는 이유 — 순간이동 문제

대량 생성기를 만들려고 기존 DroneSimulator(src/main/java/com/c4i/tracking/simulator/DroneSimulator.java)를 보니, 규모만 다를 뿐 그대로 확장하면 안 되는 근본적인 문제가 있었다.

public void simulate(int rounds) {
    for (int i = 0; i < rounds; i++) {
        DRONE_IDS.forEach(droneId -> {
            TargetEvent event = TargetEvent.builder()
                    .targetId(droneId)
                    .latitude(34.0 + random.nextDouble() * 4.0)   // 매 라운드 완전 새로 뽑음
                    .longitude(126.0 + random.nextDouble() * 4.0) // 이전 위치와 무관
                    ...

매 라운드 좌표를 이전 위치와 무관하게 random.nextDouble()로 완전히 새로 뽑는다 — 즉 이동이 아니라 **순간이동(teleport)**이다. 이 문제는 사실 처음이 아니다. 04-adsb-fi-live-feed-integration.md에서 실제 ADS-B 데이터를 붙인 이유 중 하나가 정확히 이거였다:

"매 라운드 완전 랜덤 좌표라 궤적이 물리적으로 말이 안 되던 문제(실제 항공기는 진짜 물리 법칙에 따라 이어지는 궤적을 가지니까)"

대량 생성기를 이 방식 그대로 수천 배 복제하면, 화면에는 수천 개의 점이 매 틱마다 무작위로 깜빡이는 것처럼 보일 뿐 "스웜이 접근해온다"는 그림이 안 나온다. 최근 프론트엔드에서 마커 보간(useInterpolatedTargets)과 궤적 스무딩(smoothPath)까지 다듬어놓은 게 있는데, 순간이동 데이터로는 그 작업이 무의미해진다.

4. 필요한 수정 방향 — 표적별 상태 유지 + dead reckoning