Post

Stateless(무상태)가 Idempotent(멱등성)을 의미하는가?

“Stateless(무상태)”가 “Idempotent(멱등성)”을 의미하는가?

결론부터 말하면 “아니다”. 두 개념은 관련은 있지만 완전히 다른 의미를 가지며, Stateless하다고 해서 반드시 Idempotent한 것은 아니다.

Stateless(무상태)하다고 해서 무조건 Idempotent(멱등성)을 의미하지는 않는다. Stateless 애플리케이션은 종종 멱등성을 고려해 설계되며, 멱등성은 무상태 서비스에서 바람직한 특성이지만, 이 두 개념은 서로 다르다. Stateless한 애플리케이션은 각 요청을 독립적으로 처리하며, 저장된 세션 정보에 의존하지 않는다. 그러나 그렇다고 해서 모든 작업이 멱등성을 가지는 것은 아니다.

그렇다면, 역은 성립할까? 즉, 멱등성이 보장되면 무상태일까? 이것도 아니다. 멱등성은 요청을 여러 번 반복해도 시스템의 최종 상태가 동일한지를 보는 개념이다. Stateless는 요청 처리 시 과거의 상태나 세션을 저장하고 사용하지 않는지에 관한 개념이다. 즉, 멱등성은 “결과”에 관한 것이고, Stateless는 “처리 방식”에 관한 것이다.

실생활에서의 예시를 살펴보자. 리모컨의 채널이나 볼륨의 +/- 조작은 Stateless하면서 멱등적이지 않다.

  • 리모컨은 현재 채널이나 볼륨 상태를 기억하지 않는다.
  • 오직 “채널 올려”, “볼륨 내려” 같은 입력 명령만 보낸다.
  • TV가 현재 상태를 추적하며 해당 입력을 해석해 반응한다.

즉, 리모컨은 명령을 기억하지 않으며, 각 입력은 독립적이다(Stateless).

하지만 동일한 명령을 반복할 경우 시스템 상태가 계속 바뀐다(Not Idempotent).

  • 볼륨 올리기 명령을 3번 보내면, 볼륨이 1 → 2 → 3 으로 변한다.
  • 따라서 같은 명령을 반복하면 상태가 계속 변화

리모컨에서 채널 or 볼륨을 숫자로 설정한다면 어떨까?

  • 볼륨을 10으로 설정멱등적입니다 → 몇 번 보내든 결과는 항상 볼륨 10.
  • 채널을 11번으로 설정은 멱등적이다. → 몇 번 보내든 결과는 항상 채널 11번.

💡 즉, “명령의 유형”에 따라 멱등성 여부가 달라진다.

이처럼, 멱등성을 확보하려면, “상태 변화량”이 아닌 “목표 상태”를 명시하는 방식으로 설계해야 한다. (예: 볼륨을 15로 설정 → 멱등적, 볼륨을 한 칸 올려라 → 비멱등적)

이제 API에서의 멱등성과 상태성에 대해서 살펴보자.


왜 Stateless ≠ Idempotent 인가? (반례)

  • Stateless한 API라도, 요청을 여러 번 보내면 서로 다른 결과를 낼 수 있다.
  • 예를 들어 POST /order 요청은 매번 새로운 주문을 생성하므로, 반복하면 주문이 계속 생성된다 → Stateless하지만 멱등하지 않음.
  • 반면 PUT /user/123은 같은 데이터를 보낸다면 반복해도 항상 같은 결과 → Stateless하고 멱등함.

좀 더 구체적인 예시를 살펴보자.

멱등하지만 Stateful한 API

  • 어떤 API가 사용자 요청을 처리할 때, 서버가 클라이언트의 세션 정보나 이전 요청 로그를 내부적으로 저장하고 사용한다면, 이는 Stateful이다.
  • 그러나 이 API가 요청을 여러 번 받아도 최종 시스템 상태가 동일하다면, 이는 멱등성은 유지하는 것이다.

e.g. 내부적으로 세션 캐시를 기반으로 처리 결과를 관리하여 멱등성을 보장하는 API

예시: 로그인 시도 제한

로그인 API는 보통 stateless하고 멱등하지 않은 API이다. 예를 들어, 로그인을 요청할때 사용자의 자격증명을 받아서 즉시 인증한다. 이 서버는 과거에 이 사용자가 로그인 했는지 여부를 신경쓰지 않는다. 각 로그인 요청은 서로 독립적이며, 서버는 오직 현재 들어온 요청 정보(아이디/비밀번호 등)만으로 판단한다. 따라서 이 API는 stateless하다. 하지만 로그인 요청을 여러번 반복하면, 매번 새로운 세션이 생성되거나, 다른 JWT 토큰이 발급될 수 있다. 다시 말해, 요청을 여러번 했을 때 응답 결과나 시스템 상태가 달라질 수 있다. 따라서 이는 멱등하지 않다.

그런데, 어떤 시스템이 보안 정책상 로그인 실패 횟수를 세션이나 Redis에 저장하며, 같은 자격 증명으로 여러 번 로그인 시도해도 처리 결과가 동일하게 유지되도록 한다면, 이는 멱등성은 있지만 stateful한 경우이다.


Stateful/Stateless + Idempotent 조합 Cases

1. Stateful + Idempotent

상태를 기억하지만, 같은 요청을 여러 번 해도 결과가 같다.

예시: 결제 승인 요청 추적 시스템

클라이언트가 결제 승인 요청을 보낼 때 request_id를 함께 보낸다. 서버는 이 request_id를 DB에 저장하고, 이전에 처리한 내역이 있다면 해당 결과를 그대로 반환한다. 따라서 요청은 중복되어도 처리 결과가 항상 동일하다.

1
2
POST /payments
Body: { "amount": 1000, "request_id": "abc123" }
  • 첫 번째 요청: 결제 승인 → 응답 저장
  • 두 번째 요청: 같은 request_id → 저장된 결과 재사용

이때 결제 API는 항상 동일한 처리결과를 보장하므로 멱등성이 있다. 그리고 멱등성을 보장하기 위해서 상태(request_id 처리 이력)를 기억하므로 stateful하다.

2. Stateless + Idempotent

상태를 기억하지 않지만, 같은 요청을 여러 번 해도 결과가 같다.

예시: 리소스 업데이트 API (PUT)

1
2
PUT /users/123
Body: { "name": "Alice", "email": "alice@example.com" }

매 요청마다 서버는 요청에 포함된 값으로 사용자 정보를 덮어쓰기한다. 이전 상태나 요청 이력을 기억하지 않는다(stateless). 업데이트 API를 여러 번 호출해도 사용자 정보는 동일하게 유지된다(idempotent).

이 사용자 업데이트 API는 동일한 요청을 여러번해도 결과가 같으므로 멱등성이 있다. 서버는 이전 요청에 기반한 정보나 상태를 저장하지 않으므로 stateless이다.

서버리스 아키텍처에서는 stateless + idempotent가 강하게 권장된다.

3. Stateful + Not Idempotent

상태를 기억하고, 같은 요청을 여러 번 하면 결과가 달라진다.

예시: 로그인 실패 시도 제한 시스템

1
2
POST /login
Body: { "username": "user", "password": "wrong-pass" }

서버는 로그인 실패 횟수를 세션 또는 Redis에 저장한다. 같은 요청을 반복하면 로그인 실패 횟수가 증가하고, 일정 횟수 초과 시 계정이 잠긴다.

이때 로그인 실패 횟수라는 상태를 상태 저장하므로 stateful하다. 요청을 반복했을 때 결과가 달라지므로 멱등하지 않다. (요청 반복 → 상태 변화 발생)

4. Stateless + Not Idempotent

상태는 저장하지 않지만, 요청을 여러 번 하면 결과가 달라진다.

예시: 새로운 주문 생성 API (POST)

1
2
POST /orders
Body: { "item_id": 1, "quantity": 2 }

요청할 때마다 서버는 새로운 주문 ID를 생성하고 DB에 저장하는 API가 있다고 하자. 이 API는 과거 요청과 무관하게 항상 새로운 리소스를 생성한다(stateless). 반복 호출 시 주문이 중복으로 생성된다(not idempotent).

상태 저장이 없으므로 stateless하며, 요청 반복 시 결과가 다르므로 멱등하지도 않다.


결론

멱등성(idempotency)은 요청 결과의 일관성/안전성을 의미한다. 무상태성(statelessness)은 요청 처리의 독립성/구현 방식을 의미한다. 두 개념은 서로 독립적이며, 어느 하나가 다른 하나를 보장하지 않는다.

좀 더 확장해서 멱등성과 상태성을 비교해보면 그 차이가 명확해진다.

  • 멱등성은 안전한 재시도를 위한 개념
  • 상태성은 서버가 과거 요청을 기억하는지 여부
  • 멱등성과 상태성은 서로 독립적인 성질로, 조합에 따라 다양한 설계가 가능
조건설명
Stateless ⇒ Idempotent?아니요. (e.g. POST 요청은 Stateless하지만 멱등하지 않음)
Idempotent ⇒ Stateless?아니요. (e.g. 세션 상태나 캐시를 저장하는 멱등 API는 stateful)

이 글에서는 웹 기반으로 설명했지만, 좀 더 낮은 수준에서의 멱등성과 무상태성에 대한 고찰을 작성한 글이 있다. 이 글에서는


참고자료

This post is licensed under CC BY 4.0 by the author.