백엔드 면접 학습 노트 목차

API·REST 설계 — 백엔드 면접 (실제 기출 기반·심화)

"REST와 RESTful의 차이", "HTTP 메서드의 멱등성", "GET과 POST의 근본 차이", "REST vs GraphQL vs gRPC", "결제 중복을 어떻게 막나", "페이지네이션" — 설계 감각을 보는 단골이다. (HTTP 메서드·상태코드의 프로토콜 동작은 네트워크 편, 여기선 API 설계.)

함정형 단골: "POST는 절대 캐싱 안 된다?", "GET은 안전하니 멱등하다?"(safe ≠ idempotent), "REST = HTTP+JSON?"(HATEOAS).


1. REST·RESTful — Fielding 제약 (★ 단골)

실제 질문: "REST와 RESTful의 개념을 설명해주세요." (WeareSoft·gyoogle)

REST(Representational State Transfer) = Roy Fielding이 정의한 아키텍처 스타일. 6제약:

  • 클라이언트-서버·무상태(Stateless)(각 요청 독립)·캐시 가능·균일 인터페이스(Uniform Interface)·계층화·(선택)코드 온디맨드.
  • 실천: 자원을 URI로 식별·행위는 HTTP 메서드·상태는 표현(JSON).

깊이 — Richardson 성숙도: L0(RPC) → L1(자원) → L2(메서드+상태코드·실무 대부분) → L3(HATEOAS·응답에 다음 행동 링크). "진짜 RESTful"은 L3까지지만 대부분 미충족.

꼬리질문: "RESTful의 핵심 제약?" → Uniform Interface(self-descriptive·HATEOAS). / "무상태의 이점?" → 서버 확장 용이(세션 없음).

함정: ❌ "REST = HTTP + JSON" → 아키텍처 스타일. HATEOAS까지 만족해야 진짜 RESTful.


2. 멱등성·안전성 (★★ 단골)

실제 질문: "HTTP Method의 **멱등성**을 설명해주세요." · "GET과 POST의 근본 차이는?" (VSFe·WeareSoft)

메서드안전(safe)멱등(idempotent)
GET·HEAD
PUT·DELETE
POST·PATCH
  • 안전(safe): 서버 상태를 변경하지 않음(읽기). 멱등(idempotent): 여러 번 호출해도 서버 상태가 같음. (safe 메서드 GET·HEAD·OPTIONS·TRACE는 정의상 모두 멱등 — safe ⊂ idempotent, 역은 성립 안 함.)
  • 둘은 다른 개념(★): GET은 안전하면서 멱등, PUT/DELETE는 안전하지 않지만 멱등(같은 상태로 만듦), POST는 둘 다 아님(매번 새로 생성).

깊이 — DELETE 멱등 논쟁: DELETE를 두 번 호출하면 두 번째는 404일 수 있지만, 서버 상태는 "삭제됨"으로 동일 → 멱등 유지(상태코드가 달라도 멱등 정의는 서버 상태).

꼬리질문: "GET은 안전하니 멱등?" → safe ⊂ idempotent지만 별개 개념(안전하면 멱등이나 역은 아님). / "PATCH가 비멱등인 이유?" → balance += 1 같은 상대적 변경은 호출마다 누적.

함정: ❌ "safe = idempotent" → 다른 개념. ❌ "POST는 절대 캐싱 안 됨" → 조건부 캐싱 가능(Cache-Control).


3. 멱등성 키 — 결제 중복 방지 (★★ 결제 단골)

실제 질문: "결제·주문에서 중복 요청을 어떻게 막나요?"(멱등성 키) (현업 면접·결제 시스템)

POST /payments
Idempotency-Key: 9f1c-...-a3   ← 클라가 생성한 고유 키

서버는 같은 키를 한 번만 처리하고, 재시도엔 저장된 결과를 반환 → 네트워크 재시도·더블 클릭에도 결제 1회. IETF가 Idempotency-Key 헤더를 표준화 중(Stripe·Toss 사실상 표준).

꼬리질문: "키 저장은 어디에?" → DB(유니크 제약)·Redis(TTL). / "동시 요청 2개가 같은 키로?" → **유니크 제약/분산 락**으로 하나만 처리·나머지는 진행 중/결과 반환. / "멱등성 키 vs PUT?" → PUT은 본질적 멱등, POST는 키로 멱등성 부여.


4. REST vs GraphQL vs gRPC (★★ 단골)

실제 질문: "REST, GraphQL, gRPC를 비교하라." · "GraphQL의 단점은?" (velog·VSFe)

RESTGraphQLgRPC
형식JSON·다중 엔드포인트쿼리·단일 엔드포인트Protobuf 바이너리·HTTP/2
데이터고정 응답(over/under-fetching)클라가 필요한 필드만계약(.proto)·빠름·양방향 스트리밍
캐시HTTP 캐시 쉬움어려움(POST 단일)자체
용도범용 공개 API복잡한 프론트·다양한 클라MSA 서비스 간·고성능

깊이 — GraphQL 단점(★): ① 리졸버 N+1(각 필드가 쿼리 → DataLoader로 배치) ② 캐싱 어려움(단일 POST 엔드포인트) ③ 쿼리 복잡도 폭탄(깊은 중첩 → 깊이 제한·비용 분석).

꼬리질문: "gRPC는 언제?" → 내부 MSA 서비스 간 고성능·계약 기반(브라우저 공개 API엔 REST). / "GraphQL N+1?" → DataLoader(요청 단위 배치·캐시).

함정: ❌ "GraphQL이 항상 낫다" → 캐싱·복잡도·N+1 비용.


4-bis. 요청 병합 — 세 층을 구분하라 (★★ 트래픽 단골)

실제 질문: "트래픽이 급증하면 어떻게 줄이나요?" · "화면 하나에 API를 몇 번 호출하나요?" · "캐시가 만료되면 DB로 요청이 몰리는데요?"

"요청을 합친다"는 말은 서로 다른 세 가지를 가리킨다. 면접에서 이걸 구분해 답하면 층위를 이해한다는 신호가 된다.

무엇을 합치나어디서줄어드는 것
싱글플라이트같은 키에 대한 동시 중복 조회서버 내부(캐시 미스 시점)원본(DB) 조회 횟수
배치 로딩같은 틱의 여러 키 조회서버 내부(리졸버·서비스)쿼리 왕복 횟수
엔드포인트 통합·BFF클라이언트의 여러 번 호출클라이언트↔서버 경계네트워크 왕복·게이트웨이 부하

① 싱글플라이트 (request coalescing)

캐시가 만료된 순간 같은 키로 1,000개 요청이 동시에 들어오면 DB에 1,000번 간다(캐시 스탬피드).

// 같은 키는 한 건만 원본을 조회하고, 나머지는 그 결과를 기다렸다 공유한다
private final ConcurrentHashMap<String, CompletableFuture<Data>> inFlight = new ConcurrentHashMap<>();

Data load(String key) {
    return inFlight.computeIfAbsent(key, k ->
            CompletableFuture.supplyAsync(() -> fetchFromDb(k))
                             .whenComplete((v, e) -> inFlight.remove(k)))
        .join();
}

DB 조회는 1,000 → 1이 된다. 자세한 내용은 09편 캐시·Redis의 스탬피드 대응(TTL 지터·stale-while-revalidate)과 함께 본다.

② 배치 로딩 (DataLoader 패턴)

목록 100건을 그리며 각 항목의 작성자를 따로 조회하면 1 + 100 쿼리가 된다(N+1). 같은 틱에 모인 키들을 모아 IN 한 번으로 바꾼다.

요청 100건: getUser(1), getUser(2), ... getUser(100)
  ↓ 같은 이벤트 루프 틱에 수집
SELECT * FROM users WHERE id IN (1..100)   // 쿼리 1회

GraphQL 리졸버에서 특히 중요하지만 REST에서도 동일하게 적용된다. JPA라면 fetch join·@BatchSize가 같은 문제를 다른 방식으로 푼다.

③ 엔드포인트 통합 — 왕복 자체를 줄인다

①②가 서버 안의 중복 작업을 줄인다면, 이건 클라이언트가 서버를 부르는 횟수를 줄인다.

Before  화면 하나를 그리려고
        GET /products/{id}      → 상품 정보
        GET /products/{id}/stock → 재고
        GET /users/me/coupons    → 쿠폰
        = 왕복 3회 × 동시접속자 수

After   GET /product-page/{id}   → 세 가지를 한 응답으로
        = 왕복 1회

효과가 서버 내부에 그치지 않는다는 점이 다르다 — 인증·암복호화 게이트웨이, TLS 핸드셰이크, 모바일 네트워크 지연이 호출 횟수에 비례하기 때문이다. 실제로 라이브 커머스 트래픽 사례에서 API 3개를 1개로 합쳐 피크 트래픽을 약 50% 줄였다.

BFF(Backend for Frontend) 가 이 발상을 구조로 만든 것이다.

          ┌── 웹 BFF ──┐
클라이언트 ┤            ├→ 여러 도메인 서비스
          └── 앱 BFF ──┘

화면이 필요로 하는 모양대로 조립해 주는 계층을 클라이언트별로 둔다

대가: 화면과 API가 강하게 묶인다. 화면이 바뀔 때마다 서버를 고쳐야 하고, 클라이언트가 늘면 BFF도 늘어난다. GraphQL클라이언트가 필요한 필드를 고르게 해서 같은 문제를 다르게 푸는 선택지다.

꼬리질문: "그럼 항상 합치는 게 좋나?" → 아니다. 합치면 캐시 단위가 커지고 재사용성이 떨어진다. 재고처럼 자주 바뀌는 데이터와 상품 정보처럼 안 바뀌는 데이터를 한 응답에 묶으면 전체를 짧은 TTL에 맞춰야 한다. 변경 주기가 크게 다른 것은 나눠 두는 편이 낫다.

함정

  • 세 층을 뭉뚱그려 "요청을 합쳤습니다" → 무엇이 줄었는지(DB 조회·쿼리 왕복·네트워크 왕복) 말할 수 있어야 한다.
  • 싱글플라이트를 캐시로 착각 → 캐시는 결과를 저장하고, 싱글플라이트는 동시 진행 중인 작업을 공유한다. 둘은 함께 쓴다.
  • 무조건 통합 → 캐시 효율과 변경 주기를 먼저 본다.

5. 페이지네이션 (★ 단골)

실제 질문: "Offset 기반과 Cursor 기반 페이지네이션의 차이는?" (velog @ygreenb)

-- offset: 단순하나 깊은 페이지에서 앞 행을 다 스캔 → 느림, 삽입 시 중복/누락
SELECT * FROM posts ORDER BY id DESC LIMIT 20 OFFSET 10000;
-- cursor(keyset): 마지막 본 위치 기준 → 안정·대용량·일정 성능
SELECT * FROM posts WHERE id < :lastId ORDER BY id DESC LIMIT 20;
  • offset(페이지 번호 UI·깊을수록 느림·실시간 삽입 시 중복/누락) vs cursor(정렬 키 기준·무한 스크롤·대용량 안정).

꼬리질문: "커서 기반에서 임의 페이지 점프가 안 되는 이유?" → 직전 행 기준이라 N번째 페이지로 바로 못 감. / "깊은 offset이 느린 이유?" → 앞 OFFSET개를 읽고 버림.

함정: ❌ "offset이 항상 단순해서 낫다" → 대용량·실시간엔 커서.


6. 상태코드·에러 설계·rate limiting (★ 심화)

  • 상태코드: 201 Created(+Location)·204 No Content·401(인증) vs 403(인가)·409 Conflict(낙관적 락 충돌)·422 Unprocessable(검증)·429 Too Many Requests(rate limit).
  • 에러 포맷 일관: { "code", "message", "errors":[...] } 또는 RFC 9457 application/problem+json.
  • rate limiting: Token Bucket(버킷에 토큰 충전·burst 허용·가장 흔함)·Leaky Bucket·Sliding Window. 초과 시 429 + Retry-After.
  • 엔티티 직접 노출 X → DTO(API 스펙 분리·LazyInitializationException 방지·보안 — Spring·JPA 편).

꼬리질문: "401 vs 403?" → 인증(누구인지 모름) vs 인가(권한 없음). / "동시 수정 충돌?" → 낙관적 락·ETag/If-Match → 409.


7. 실시간 통신 — 폴링·SSE·WebSocket (★★ 신규 단골)

나오는 질문: "실시간 알림 기능을 설계한다면 어떻게 하시겠어요?" · "WebSocketSSE 중 무엇을 고르시겠어요? 왜죠?" · "폴링 대비 장점이 뭔가요?" · "서버를 여러 대로 늘리면 어떤 문제가 생기죠?"

REST의 전제는 언제나 클라이언트가 먼저 묻는다는 것이다. 서버가 먼저 알려야 하는 일(알림·시세·채팅·진행률)은 이 모델로 표현할 수 없다. 그 우회와 해결의 계보를 아는지가 이 질문의 핵심이다.

방식동작방향재연결비용
폴링주기적으로 같은 요청 반복클라이언트 요청해당 없음헛걸음 요청이 대부분
롱 폴링서버가 응답을 붙잡고 있다가 사건 발생 시 응답클라이언트 요청해당 없음이벤트마다 연결 재수립
SSE응답을 끝내지 않고 계속 흘려보냄서버 → 클라이언트규격 내장(Last-Event-ID)최초 1회
WebSocket101로 프로토콜 전환 후 프레임 교환양방향직접 구현프레임 헤더 2바이트~

깊이 — 폴링의 근본 문제는 트래픽과 지연의 맞바꿈(★). 주기를 3초로 줄이면 지연은 줄지만 요청 대부분이 헛걸음이고, 30초로 늘리면 트래픽은 줄지만 최대 30초 늦게 안다. 둘 다 좋게 만들 방법이 없다는 것이 폴링의 한계다. 롱 폴링은 헛걸음을 없애고, SSE·WebSocket은 연결 재수립까지 없앤다.

깊이 — SSE의 자동 재연결이 실무에서 크다(★★). SSE는 각 이벤트에 id를 붙일 수 있고, 연결이 끊기면 클라이언트가 알아서 다시 붙으면서 마지막 idLast-Event-ID 헤더로 보낸다. 서버가 그 지점부터 이어 주면 끊긴 사이에 놓친 이벤트를 복구할 수 있다. WebSocket에는 이런 규격이 없어서 재연결·유실 복구를 전부 직접 만들어야 한다. "단순한 알림에 WebSocket을 쓰면 오히려 손해" 라는 판단의 근거가 이것이다.

// SSE 응답 본문 — 빈 줄 하나가 메시지 하나의 끝
Content-Type: text/event-stream

id: 42
event: order-status
data: {"orderId":"A-1","status":"SHIPPED"}

핵심 판단 기준: "실시간 = WebSocket"이 아니라 양방향이 정말 필요한가다.

  • 알림·피드·진행률·주문 상태 → SSE(서버가 밀어 주기만 하면 됨)
  • 채팅·협업 편집·게임 → WebSocket(클라이언트도 자주 보냄)

WebSocket 핸드셰이크 — 왜 101인가

GET /chat HTTP/1.1
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Version: 13

HTTP/1.1 101 Switching Protocols        ← 200이 아니다
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=

WebSocket평범한 HTTP 요청으로 시작해서 101을 받는 순간부터 그 TCP 연결에서 HTTP를 쓰지 않는다. 그래서 기존 80·443 포트와 프록시 인프라를 그대로 쓸 수 있다는 게 설계의 실용적 이점이다.

Sec-WebSocket-Accept는 클라이언트 키에 고정 문자열 258EAFA5-E914-47DA-95CA-C5AB0DC85B11 을 붙여 SHA-1 → base64한 값이다. 값이 공개돼 있으니 보안 장치가 아니고, 상대가 WebSocket을 정말 이해하고 답했는지 확인해 중간 캐시·프록시의 오해를 막는 절차다.

서버를 여러 대로 늘리면 — 여기서 답이 갈린다

이게 이 주제의 진짜 심화 질문이다. WebSocket·SSE연결이 특정 서버 인스턴스에 붙어 있는 상태(stateful) 라, REST의 무상태 전제가 깨진다.

다이어그램 로딩 중…

세 가지가 따라온다.

  1. 핸드셰이크 라우팅 — 업그레이드 요청과 이후 트래픽이 같은 인스턴스로 가야 한다. L7 로드밸런서가 WebSocket 업그레이드를 통과시키도록 설정하고, 필요하면 스티키 세션을 건다.
  2. 인스턴스 간 전달 — 서버 1이 서버 2에 붙은 사용자에게 보내야 하는 상황이 반드시 생긴다. 그래서 Redis Pub/Sub이나 메시지 브로커를 두고 모든 인스턴스가 구독한다. 인메모리 브로드캐스트만 쓰면 한 인스턴스의 접속자에게만 닿는다.
  3. 유휴 연결 끊김 — 로드밸런서·프록시는 대개 유휴 연결을 수 분 뒤 끊는다. WebSocket은 ping/pong 제어 프레임으로, SSE는 주석 줄(: keep-alive)을 주기적으로 보내 살려 둔다.

깊이 — 인증은 어떻게 하나(★). 브라우저의 WebSocket API는 커스텀 헤더를 붙일 수 없다. 그래서 Authorization: Bearer ...를 그대로 쓸 수 없고, ① 쿠키(같은 도메인이면 자동 전송), ② 쿼리 파라미터로 짧은 수명의 일회용 티켓 전달, ③ 연결 직후 첫 메시지로 토큰 전송 후 인증 전까지 다른 메시지 거부 — 중 하나를 쓴다. 쿼리 파라미터에 장기 토큰을 넣는 건 로그·리퍼러에 남아 위험하다는 점이 함정이다. 그리고 WebSocket은 동일 출처 정책의 적용을 받지 않으므로 Origin 헤더를 서버가 직접 검증해야 한다(안 하면 Cross-Site WebSocket Hijacking).

STOMP — raw WebSocket 위의 메시징 규약

WebSocket 자체는 바이트를 주고받는 통로일 뿐 목적지·구독 같은 개념이 없다. 채팅방이 여러 개면 "이 메시지는 어느 방 것인가"를 직접 정의해야 한다. **STOMP**는 그 위에 얹는 단순한 텍스트 메시징 프로토콜로, CONNECT·SEND·SUBSCRIBE·MESSAGE 같은 명령과 목적지 헤더를 표준화한다. 목적지 규칙(/topic은 브로드캐스트, /queue는 1:1)과 구독 관리를 프레임워크에 맡길 수 있어, 방·구독이 여러 개인 서비스에서 직접 규약을 만드는 수고를 던다.

꼬리질문: "SSE는 브라우저 연결 제한이 있다던데요?" → HTTP/1.1은 도메인당 6연결이라 탭을 여러 개 열면 막힌다. HTTP/2 멀티플렉싱으로 해소된다(네트워크 편 HTTP 버전과 연결). / "WebSocket이 HTTP/2 위에서도 되나요?" → RFC 8441의 확장 CONNECT로 가능하고 RFC 9220이 HTTP/3까지 넓혔지만, 2026년 기준 HTTP/3 위 프로덕션 구현은 아직 없어 실제로는 1.1·2 위가 대부분이다. / "SSE로 클라이언트가 보내려면?" → 일반 REST 요청을 따로 쓴다. 실제로 SSE(수신) + REST(송신) 조합이 흔하고, 이게 WebSocket보다 단순한 경우가 많다.

함정: ❌ "실시간이면 무조건 WebSocket" → 단방향이면 SSE가 더 단순하고 재연결까지 공짜다. ❌ "WebSocket도 무상태라 그냥 스케일아웃하면 된다" → 연결이 인스턴스에 묶인다. 브로커가 필요하다. ❌ "Authorization 헤더로 인증하면 된다" → 브라우저 WebSocket API는 커스텀 헤더를 못 붙인다.

(출처: RFC 6455 — The WebSocket Protocol·RFC 8441 — Bootstrapping WebSockets with HTTP/2·MDN — Using server-sent events 교차검증. 보강 2026-08.)


흔한 오답·함정 정리

  • safe = idempotent → 다른 개념(GET은 둘 다, PUT/DELETE는 멱등만).
  • 실시간이면 무조건 WebSocket → 단방향이면 SSE가 더 단순하고 재연결이 규격에 있다.
  • WebSocket도 스케일아웃하면 그만 → 연결이 인스턴스에 묶여 브로커(Redis Pub/Sub 등)가 필요하다.
  • WebSocket 인증Authorization 헤더로 → 브라우저 API가 커스텀 헤더를 못 붙인다. 쿠키·티켓·첫 메시지 인증.
  • Sec-WebSocket-Accept가 보안 장치 → 고정 문자열 기반이라 보안이 아니라 프로토콜 확인용.
  • POST는 절대 캐싱 안 됨 → 조건부 캐싱 가능.
  • REST = HTTP + JSON → 아키텍처 스타일(HATEOAS).
  • GraphQL이 항상 낫다 → 캐싱·N+1·복잡도 비용.
  • 결제 중복은 프론트에서만 막으면 됨 → 서버 멱등성 키.

한국 면접 단골 Q&A (답변 골격)

질문핵심 답
REST·RESTful자원/메서드/무상태·Richardson L2/L3·HATEOAS
멱등성·안전성safe(읽기) vs idempotent(상태 동일)·POST 둘 다 X
DELETE 멱등?404여도 서버 상태 동일 → 멱등
결제 중복Idempotency-Key·유니크/분산락
REST vs GraphQL vs gRPC고정/필드선택/MSA 고성능
GraphQL 단점캐싱·리졸버 N+1·복잡도 폭탄
페이지네이션offset(단순·느림) vs cursor(대용량)
상태코드201/204·401 vs 403·409·422·429
rate limitingToken Bucket·429·Retry-After
실시간 알림 설계폴링→롱폴링→SSE→WebSocket 계보·단방향이면 SSE
SSE vs WebSocket단방향+자동재연결 vs 양방향+직접구현
폴링의 한계트래픽↔지연 맞바꿈·둘 다 좋게 못 함
WebSocket 핸드셰이크Upgrade+101·Sec-WebSocket-Accept는 확인용(보안 X)
여러 대로 스케일아웃연결이 인스턴스에 묶임 → 스티키+Redis Pub/Sub·브로커
WebSocket 인증커스텀 헤더 불가 → 쿠키·일회용 티켓·첫 메시지·Origin 검증
STOMPraw WebSocket 위 목적지·구독 규약(/topic·/queue)

꼬리질문 대비 (상 난이도)

  • "결제 더블 클릭?" → 멱등성 키로 1회 처리·결과 재사용.
  • "PUT vs PATCH 멱등성?" → PUT 전체 교체(멱등), PATCH는 구현 따라 비멱등.
  • "GraphQL N+1?" → 각 필드 리졸버가 쿼리 → DataLoader 배치.
  • "API 응답에 엔티티 그대로?" → 결합·LazyInit·보안 → DTO.
  • "버전 안 올리고 필드 추가?" → 호환 변경(클라는 모르는 필드 무시) → 깨는 변경만 버전.
  • "알림 서비스를 처음부터 설계해 보세요" → 단방향이니 **SSE**가 1안. id+Last-Event-ID로 유실 복구, 인스턴스 간 전달은 Redis Pub/Sub, 유휴 끊김은 주기적 keep-alive, 클라이언트 송신은 일반 REST.
  • "채팅에서 상대가 접속 중인지 어떻게 아나요?" → WebSocket ping/pong으로 생존 확인 + 연결 종료 이벤트를 브로커로 전파해 다른 인스턴스에도 알린다.
  • "연결이 자꾸 끊깁니다" → 로드밸런서·프록시의 유휴 타임아웃이 1순위 용의자. keep-alive 주기를 그 값보다 짧게.
  • "WebSocket에 CSRF 같은 공격이 있나요?" → Cross-Site WebSocket Hijacking. 동일 출처 정책이 적용되지 않으므로 서버가 Origin을 직접 검증해야 한다.

한 줄 요약 — REST=자원(URI)+메서드+무상태(Fielding·Richardson L2/L3 HATEOAS). safe≠idempotent(POST 둘 다 X·PUT/DELETE 멱등). 결제 중복은 Idempotency-Key(유니크/분산락). REST↔GraphQL(필드 선택·리졸버 N+1·캐싱 어려움)↔gRPC(MSA·Protobuf). 페이지네이션 offset(단순·느림)↔cursor(대용량). 상태코드(201/204·401 vs 403·409·422·429)·에러 일관(RFC 9457)·rate limit(Token Bucket·429)·DTO. 실시간은 폴링(트래픽↔지연 맞바꿈)→롱 폴링→SSE(단방향·Last-Event-ID로 유실 복구·HTTP 그대로)→WebSocket(Upgrade+101·양방향·재연결 직접 구현)의 계보 — 양방향이 정말 필요한가가 갈림길이고, 스케일아웃 시 연결이 인스턴스에 묶여 스티키+브로커(Redis Pub/Sub)가 필요하며, 인증은 커스텀 헤더 불가라 쿠키·티켓·첫 메시지 + Origin 검증(Cross-Site WebSocket Hijacking)이다.

(출처 — 한국 면접 기출·교차검증 2026-06: VSFe/Tech-Interview — Network·gyoogle — REST API·WeareSoft — network·velog @ygreenb — offset vs cursor · RFC 9110(멱등성·상태코드)·RFC 9457(Problem Details)·draft-ietf-httpapi-idempotency-key-header 교차검증.)

모던 자바·스프링 — 가상 스레드·JEP 491·리액티브·jOOQ·Boot 4인증·인가 — 세션·JWT·OAuth 2.1·CSRF