main-logo

멱등성

프로그래밍에서 멱등성이란

profile
강영민
2024년 10월 31일 · 0 분 소요

들어가며

최근 개인적으로 학습을 하며 적지않게 마주친 단어가 있었습니다.
‘멱등성’이라는 용어를 종종 접하게 되어서 좀더 해당용어에 대해서 알아보고자 찾아보게 되었습니다.
개인적으로 찾아보고든 생각은 멱등성은 현재의 개발에 있어서 분산 시스템이 일반화되고 API 사용이 많아지면서 중요한 개념이 되어있는 용어라 생각이 들었습니다.
이번 글에서는 멱등성의 의미와 필요성, 구현 방법을 살펴보며 이를 실제로 어떻게 적용할 수 있는지 정리해보겠습니다.

멱등성이란?

프로그래밍에 있어서 멱등성(Idempotency)이란 소프트웨어 개발, 특히 API 설계에서 중요한 개념 중 하나입니다.
멱등성이란 동일한 연산을 여러 번 수행해도 결과가 달라지지 않는 성질을 말합니다 왜냐하면 이러한 성질은 데이터의 일관성과 안정성을 보장하는 데 핵심적인 역할을 하기 때문입니다.

API를 설계할 때 멱등성을 고려하는 것은 중요합니다. 클라이언트가 같은 요청을 여러 번 보내더라도 서버의 상태가 변하지 않도록 보장해야 하기 때문입니다. 이는 네트워크 지연이나 오류로 인해 같은 요청이 중복해서 전송될 경우에도 시스템의 안정성을 유지할 수 있게 합니다.

멱등성이 중요한 이유

1. 데이터 일관성 유지

  • 중복 요청 처리: 분산 시스템에서는 네트워크 지연, 서버 장애 또는 타임아웃으로 인해 동일한 요청이 여러 번 발생할 수 있습니다. 멱등성이 보장되지 않으면 데이터베이스에 중복 레코드가 삽입되거나 업데이트가 중복 적용되어 데이터 불일치 문제가 생길 수 있습니다. 멱등성을 보장함으로써 중복 요청이 있더라도 데이터가 일정한 상태를 유지하게 됩니다.
  • 데이터 무결성 보호: 동일한 작업을 반복해도 데이터 상태가 변하지 않도록 함으로써 시스템의 무결성을 보장합니다. 예를 들어, 결제 시스템에서 멱등성을 보장하지 않으면 동일한 결제 요청이 중복 처리되어 사용자 계좌에서 동일한 금액이 여러 번 차감되는 문제가 발생할 수 있습니다.

2. 안전한 재시도 및 실패 처리

  • 재시도 전략 구현: 네트워크 불안정성, 서버 장애 등으로 인해 작업이 실패할 때는 재시도가 필요합니다. 멱등성을 보장하면 여러 번 재시도하더라도 동일한 결과가 유지되므로 안전하게 재시도할 수 있습니다.
  • 오류 회복 용이성: 작업이 중간에 실패했을 때에도 멱등성을 유지하면 복구가 쉬워집니다. 예를 들어, 트랜잭션 중간에 오류가 발생해도 멱등성이 보장된 작업은 오류가 발생한 부분부터 재실행하여 데이터 일관성을 유지할 수 있습니다.

3. 캐싱 및 성능 최적화

  • 캐시 활용의 용이성: 멱등성을 가진 작업의 결과는 항상 동일하기 때문에 캐싱이 용이합니다. 동일한 요청이 반복될 때 캐시된 결과를 반환해도 데이터 일관성을 해치지 않으므로, 결과를 캐시하여 성능을 최적화할 수 있습니다.
  • 네트워크 및 서버 부하 감소: 캐싱을 통해 불필요한 재요청이나 반복 작업을 줄여 서버의 부하를 줄일 수 있습니다. 특히 외부 API 요청 시 멱등성을 유지하면 동일한 결과가 필요할 때마다 매번 재요청을 보내는 대신 캐시된 데이터를 재사용하여 효율성을 높일 수 있습니다.

4. 안정적이고 직관적인 API 설계

  • 클라이언트 신뢰성 향상: 멱등성을 고려한 API는 클라이언트 개발자가 안전하게 사용할 수 있어 신뢰성을 높입니다. 예를 들어, 동일한 리소스를 반복해서 수정하는 경우에도 API가 멱등성을 보장하면 클라이언트는 불필요한 로직을 추가하지 않고도 여러 번 요청을 보낼 수 있습니다.
  • 명확하고 예측 가능한 동작: 멱등성은 API의 동작을 명확하게 정의해줍니다. 클라이언트가 동일한 작업을 여러 번 요청해도 API의 결과가 변하지 않으므로, API 사용법이 직관적이고 예측 가능하게 됩니다.
  • HTTP 표준 준수 및 설계 효율성: 멱등성은 특히 HTTP의 GET, PUT, DELETE와 같은 메서드에서 중요한데, HTTP 표준에서 GET, PUT, DELETE는 멱등성을 가져야 한다고 명시하고 있습니다. 따라서, 이를 준수하여 API를 설계하면 RESTful한 인터페이스를 구축할 수 있고, 여러 클라이언트가 같은 방식으로 시스템을 일관되게 이용할 수 있게 됩니다.

5. 분산 시스템의 신뢰성 확보

  • 복제된 서비스와의 일관성 유지: 분산 시스템에서 여러 서비스나 데이터베이스가 복제되어 운용되는 경우, 멱등성을 보장함으로써 어느 노드에서 요청을 처리하더라도 동일한 결과가 보장됩니다. 이는 다수의 서버나 마이크로서비스가 상호작용하는 환경에서 데이터 일관성을 유지하는 데 매우 중요합니다.
  • 복잡한 상태 전환 관리 용이: 분산 시스템에서는 상태가 여러 위치에서 변경될 수 있으므로, 상태 전환에 멱등성을 적용하면 시스템 전반에서 상태 관리가 용이해집니다. 예를 들어, 상태 업데이트 시 동일한 업데이트 요청이 여러 번 발생해도 일관된 최종 상태를 유지할 수 있습니다.

멱등성의 예시

1. 일상 속 멱등성 예시

  • 전등 스위치: 스위치를 여러 번 누른다고 불이 계속 켜지는 것이 아닙니다. 불이 이미 켜져 있다면, 스위치를 여러 번 더 눌러도 상태는 그대로 유지됩니다. 이미 꺼져 있는 불을 다시 끄려고 해도 변화가 없죠. 이런 식으로 전등 스위치는 켜짐과 꺼짐이 반복되지 않고, 최종 상태가 일정하게 유지되도록 보장합니다.

2. HTTP 메서드의 멱등성 예시

HTTP 메서드는 REST API 설계에서 자주 쓰이는데, 멱등성을 보장하는 메서드와 보장하지 않는 메서드가 있습니다.

  • GET: 리소스를 가져오는 요청입니다. 예를 들어, GET /users/1 요청을 여러 번 보내도 동일한 데이터를 반환합니다. 아무리 반복해도 데이터는 변경되지 않으므로 GET은 멱등성을 가진 메서드입니다.

  • PUT: 리소스 전체를 업데이트하는 요청입니다. 예를 들어, PUT /users/1 요청을 통해 특정 유저의 정보를 덮어쓰는 작업을 한다면, 동일한 데이터를 여러 번 요청해도 최종 상태는 한 번 요청한 것과 똑같이 유지됩니다. 그래서 PUT 요청은 멱등성을 보장합니다.

  • DELETE: 리소스를 삭제하는 요청입니다. 예를 들어, DELETE /users/1 요청으로 특정 유저를 삭제하려고 할 때, 이미 삭제된 유저를 다시 삭제하려고 해도 오류는 발생할 수 있지만, 유저가 다시 생기지는 않습니다. DELETE도 멱등성을 보장합니다.

  • POST: 새로운 리소스를 생성하는 요청입니다. 예를 들어, POST /users 요청으로 새 유저를 생성하려고 할 때, 동일한 POST 요청을 반복하면 같은 내용의 새 유저가 계속해서 추가됩니다. 따라서 POST는 멱등성이 없습니다.

요약

  • 멱등성을 가진 메서드 (GET, PUT, DELETE): 요청을 여러 번 반복해도 최종 상태가 동일하게 유지됩니다.
  • 멱등성이 없는 메서드 (POST): 요청을 반복하면 새로운 리소스가 계속해서 생성되므로 결과가 달라집니다.

멱등성 구현 방법

1. 고유 식별자 (Unique Identifier)

  • 요청별 고유 ID 부여: 각 요청에 고유한 ID(예: UUID)를 부여하여 중복 요청을 구분합니다. 동일한 ID를 가진 요청이 여러 번 전달될 경우 중복 요청으로 판단하고, 처음 요청을 한 번만 처리하고 이후의 중복 요청은 무시합니다.
  • 예시: 전자상거래 시스템에서 결제 요청마다 고유한 트랜잭션 ID를 생성하여 관리하면, 결제 요청이 중복되더라도 동일한 트랜잭션 ID를 확인해 한 번만 처리되도록 할 수 있습니다. 이를 통해 결제가 중복 발생하지 않도록 보장합니다.

2. 버전 관리 (Versioning)

  • 자원의 버전 관리: 자원의 상태를 버전으로 관리하여 특정 버전의 자원이 업데이트되었을 때 다른 버전에 영향을 주지 않도록 설계합니다. 이는 자원이 업데이트될 때만 새로운 버전을 생성하므로, 여러 요청이 동일한 자원을 업데이트하더라도 최신 버전을 유지할 수 있습니다.
  • 예시: 문서 편집 시스템에서 문서마다 버전 번호를 두고 업데이트 시 최신 버전 번호를 사용하여 수정합니다. 예를 들어, 특정 사용자가 2번 버전의 문서를 수정하는 동안, 다른 사용자가 동일한 문서의 3번 버전을 수정했다면, 이전 버전 수정은 무시되거나 새로운 버전으로 대체됩니다. 이를 통해 버전 간 충돌을 방지하고 일관성을 유지합니다.

3. 낙관적 동시성 제어 (Optimistic Concurrency Control)

  • 동시 작업 충돌 방지: 여러 사용자가 동시에 데이터를 수정할 때 발생할 수 있는 충돌을 방지하는 기법입니다. 자원의 상태가 갱신될 때마다 특정 버전 번호나 타임스탬프를 할당하고, 클라이언트가 자원을 업데이트할 때 현재 버전 번호와 일치하는지 확인하여, 충돌 시 업데이트를 차단하고 클라이언트에게 재시도를 요청합니다.
  • 예시: 데이터베이스에서 특정 레코드의 updated_at 타임스탬프를 갱신할 때, 요청마다 이 타임스탬프를 확인하여 가장 최신의 상태에서만 수정할 수 있게 합니다. 다른 요청이 이미 데이터를 수정해 타임스탬프가 변경되었다면, 충돌이 발생하여 작업이 거부되므로 안전한 상태 전환을 보장할 수 있습니다.

4. 멱등성 토큰 (Idempotent Token)

  • 클라이언트가 멱등성 토큰 생성: 클라이언트가 각 요청에 고유한 토큰을 생성하여 서버에 전달하면, 서버는 이 토큰을 기반으로 중복 요청을 확인할 수 있습니다. 서버는 동일한 토큰으로 반복된 요청이 발생한 경우 처음 요청만 처리하고 이후 요청은 무시하거나 중복 응답을 반환합니다.
  • 예시: API 요청 시 클라이언트가 고유한 멱등성 토큰을 발급하여 POST /payment 요청 시에 첨부하면, 서버는 이 토큰을 확인하여 동일한 결제 요청을 여러 번 받더라도 한 번만 처리하고 나머지 요청을 무시합니다. 이렇게 하면 클라이언트의 중복 요청이 서버에 부담을 주지 않으며, 결과의 일관성도 유지됩니다.

5. 데이터베이스 제약 조건 및 트랜잭션 활용

  • 중복 방지 제약 조건 설정: 데이터베이스에서 특정 컬럼에 고유 제약 조건을 설정하여 중복된 데이터 입력을 방지할 수 있습니다. 또는 트랜잭션을 활용하여 일괄 작업이 성공적으로 완료되었을 때만 커밋되도록 설정할 수 있습니다.
  • 예시: 사용자 이메일이 중복되지 않도록 데이터베이스에서 이메일 컬럼에 고유 제약 조건을 설정하면, 중복된 이메일을 가진 사용자를 생성하려 할 때 오류가 발생하여 중복 데이터를 방지할 수 있습니다. 트랜잭션을 통해 여러 데이터 작업을 하나의 단위로 처리하여 일부 작업이 실패하더라도 데이터 무결성을 유지할 수 있습니다.

 

멱등성이 중요한 실제 사례

1. 결제 시스템

  • 중복 결제 방지: 결제 시스템에서는 동일한 결제 요청이 여러 번 발생할 가능성이 있습니다. 네트워크 지연이나 사용자 실수로 인해 같은 결제 요청이 반복해서 전달될 수 있으며, 멱등성이 보장되지 않으면 중복 결제가 발생해 사용자 계좌에서 돈이 여러 번 차감될 수 있습니다. 멱등성을 보장하기 위해 고유한 결제 ID나 멱등성 토큰을 사용하면 한 번만 결제가 처리되고 이후 중복 요청은 무시됩니다. 이를 통해 결제가 여러 번 발생하지 않도록 보장할 수 있습니다.

2. 파일 업로드 시스템

  • 최신 파일만 유지: 사용자가 동일한 파일을 여러 번 업로드하거나 업로드가 중단되었다가 다시 시도하는 상황에서, 멱등성을 보장하면 중복된 파일이 계속 저장되지 않고 최신 파일만 유지할 수 있습니다. 예를 들어, 파일 해시값을 사용하여 이미 동일한 파일이 존재하는지 확인하고 중복을 피할 수 있습니다. 이를 통해 저장 공간을 절약하고 업로드 관리가 간편해집니다.

3. 데이터베이스 트랜잭션 시스템

  • 데이터 일관성 유지: 트랜잭션은 작업 도중 오류가 발생하거나 중간에 여러 번 실행되더라도 데이터가 일관된 상태로 유지되어야 합니다. 트랜잭션 관리에서는 특정 작업을 수행할 때 부분 성공이나 중복 실행이 발생하지 않도록 합니다. 예를 들어, 은행 시스템에서 송금 작업이 트랜잭션으로 관리될 때, 동일한 송금 요청이 중복 실행되지 않도록 멱등성을 보장하여 데이터의 무결성정확성을 확보할 수 있습니다.

마치며

멱등성은 시스템의 안정성과 데이터 일관성을 높이는 데 중요한 개념이라고 생각합니다.

특히 HTTP 통신에 있어서는 API 설계 시 멱등성을 고려해 클라이언트의 사용을 더욱 안전하게 할 수 있을거라 생각하며 이를 통해 개발 생산성과 시스템의 신뢰성을 높일 수 있지않을까 생각합니다

읽어주셔서 감사합니다.