//
요즘 개발자를 위한 시스템 설계 수업 · 디렌드라 신하, 테자스 초프라
3부는 API 설계에서 시작한다. 앞선 장들이 시스템 내부의 구성 요소를 다뤘다면, 여기서는 그 시스템이 외부와 만나는 표면을 다룬다.
REST(REpresentational State Transfer)는 네트워크 애플리케이션을 설계하는 아키텍처 스타일이다. 설계 원칙은 네 가지로 정리된다.
네 번째가 REST의 핵심이다. 클라이언트가 서버에 요청을 보낼 때 요청을 처리하는 데 필요한 모든 정보를 요청 안에 포함해야 한다. 서버가 상태를 기억할 필요가 없어지므로 동작이 더 안정적이고 예측 가능해진다.
무상태성이 실제로 무엇을 가능하게 하는지가 중요하다. 서버가 세션 상태를 들고 있지 않으면 어떤 요청을 어떤 서버가 처리해도 결과가 같다. 5장에서 본 로드 밸런서가 자유롭게 트래픽을 분산할 수 있는 것도, 서버를 수평 확장할 수 있는 것도 이 성질에서 나온다.
REST는 인터넷에 공개되는 API에 적합하며, CRUD 기반 작업과 잘 어울린다. 장점은 간단하고 이해하기 쉬운 구조이고, 단점은 여러 요청을 한 번에 처리해야 하는 복잡한 작업에서 비효율적이며 JSON 형식이라 페이로드가 커진다는 점이다.
gRPC(Google Remote Procedure Call)는 원격 프로시저 호출을 실행하는 고성능 오픈 소스 프레임워크다. 구글이 개발했고 HTTP/2를 기반으로 한다. REST가 리소스 중심이라면 gRPC는 함수 중심으로 설계됐다.
설계 원칙은 이렇다.
활용에 적합한 곳은 마이크로서비스 아키텍처처럼 서비스 간에 빠르고 빈번한 통신이 필요한 환경이다. 메시지 크기가 작고 양방향 스트리밍을 지원하므로 실시간 애플리케이션에도 잘 맞는다.
단점도 분명하다. 바이너리 형식과 HTTP/2를 요구해 설정과 디버깅이 복잡하고, 통신 방식을 바꾸려면 데이터 구조를 새로 정의해 코드로 반영하고 배포해야 하므로 변경에 시간이 더 걸린다.
| 축 | REST | gRPC |
|---|---|---|
| 성능 | HTTP/1.1 + JSON. 페이로드가 크다 | HTTP/2 + 프로토콜 버퍼. 단일 TCP 연결로 여러 요청을 동시 처리해 지연 시간이 낮다 |
| 사용 편의성 | HTTP 메서드와 상태 코드를 아는 개발자에게 간단. cURL, 포스트맨으로 바로 테스트 | 바이너리 형식이라 테스트와 디버깅에 전용 도구가 필요 |
| 호환성 | HTTP 기반이라 인터넷에 연결된 거의 모든 장치에서 사용 가능 | HTTP/2가 필요하며 지원하지 않는 환경에서는 사용 불가 |
| 스트리밍 | 요청-응답만 주고받는 방식 | 양방향 스트리밍 지원 |
| 적합한 곳 | 공개 API, CRUD 작업, 넓은 호환성이 필요한 곳 | 내부 서비스 간 통신, 실시간 애플리케이션 |
둘 중 하나를 고르는 문제로 보이지만, 실제로는 경계에 따라 나누는 문제다. 외부에 노출되는 표면은 REST로 열어 호환성과 디버깅 편의를 챙기고, 내부 서비스 간 호출은 gRPC로 처리해 지연 시간과 대역폭을 아끼는 조합이 일반적이다. 5장의 애플리케이션 게이트웨이가 바로 그 경계에서 프로토콜을 번역하는 지점이 된다.
보안 논의는 두 단어를 구분하는 것에서 출발한다.
인증은 신원을 확인하는 과정으로 API 보안의 첫 번째 방어선이다. 구현 방식은 세 가지다.
| 방식 | 특징 |
|---|---|
| API 키 | 요청 헤더에 키를 포함해 전송하는 간단한 방식 |
| OAuth | 사용자가 계정 정보를 직접 제공하지 않고도, 한 웹사이트에서 다른 웹사이트의 리소스에 제한적인 접근 권한을 부여하는 방식 |
| JWT | 두 시스템 간에 정보를 안전하게 주고받는 간결한 방법 |
JWT(JSON Web Token)의 구조를 조금 더 보면, 정보는 JSON 형식의 클레임(Claim) 으로 구성되고 이 클레임을 JWS(JSON Web Signature) 구조로 감싼다. 이렇게 하면 메시지 인증 코드(MAC)나 디지털 서명으로 무결성을 확인할 수 있다.
JWT가 REST의 무상태성과 잘 맞는 이유가 여기 있다. 토큰 자체에 사용자 정보와 서명이 들어 있으므로, 서버가 세션 저장소를 조회하지 않고도 요청만 보고 신원을 검증할 수 있다.
JWT의 무상태성은 장점이지만 동시에 약점이다. 서버가 세션을 들고 있지 않으므로 발급한 토큰을 즉시 무효화할 수 없다. 로그아웃이나 권한 회수가 만료 시각까지 지연된다. 그래서 실무에서는 액세스 토큰의 만료를 짧게(수 분~수십 분) 두고, 상태를 가진 리프레시 토큰으로 갱신하는 구조를 쓴다. 무상태성을 어디까지 유지할지 스스로 선을 그어야 한다.
인가 구현 방식은 두 가지다.
RBAC는 "이 사람이 어떤 역할인가"를 묻고, ABAC는 "이 요청의 주체·대상·환경 속성이 어떤 조합인가"를 묻는다. 후자는 "본인이 소속된 부서의 문서만, 업무 시간에만" 같은 조건을 표현할 수 있지만 정책이 늘어날수록 관리 비용이 급격히 오른다.
데이터 전송을 보호하려면 HTTPS가 필수다. HTTPS는 클라이언트와 서버 간 통신을 암호화해 전송 데이터를 해독하기 어렵게 만든다. 그리고 TLS 설정을 최신 상태로 유지하는 것도 중요하다. 보안 취약점이 새로 발견되거나 보안 표준이 발전함에 따라 설정을 갱신해야 새로운 위협을 예방할 수 있다.
요청 속도 제한(Rate Limiting)은 특정 시간 내 과도한 API 사용을 제한해 서비스 거부(DoS) 공격을 방어하는 메커니즘이다. 알고리즘은 세 가지가 소개된다.
토큰 버킷(Token Bucket)
버킷에 토큰이 일정한 간격으로 채워진다
요청 하나를 처리할 때마다 토큰 하나가 소비된다
버킷에 토큰이 없으면 요청을 거부한다
버킷 크기만큼의 버스트 트래픽을 허용한다는 것이 특징이다. 평소에 요청이 없었다면 토큰이 쌓여 있으므로 순간적인 폭주를 흡수할 수 있다.
누수 버킷(Leaky Bucket)
토큰 버킷과 유사하지만, 버킷에 토큰이 일정한 속도로 추가되는 동시에 일정한 속도로 새어 나간다. 버킷이 가득 차면 새 요청을 거부한다. 출력 속도가 일정하게 평탄화되므로 백엔드가 받는 부하가 균일해진다.
슬라이딩 윈도우(Sliding Window)
특정 시간 내에서 처리된 요청 수를 추적하고, 설정된 한도를 초과하면 이후 요청을 거부한다. 고정 윈도우 방식이 경계 시점에 두 배 트래픽을 허용하는 문제를 해결한다.
| 알고리즘 | 버스트 허용 | 특징 |
|---|---|---|
| 토큰 버킷 | 허용 | 버킷 크기만큼의 순간 폭주를 흡수 |
| 누수 버킷 | 제한적 | 출력 속도가 일정해 백엔드 부하가 평탄 |
| 슬라이딩 윈도우 | 시간 창 기준 | 경계 시점의 이중 허용 문제를 해결 |
이 장의 전반부는 API 설계와 보안을 다룬다. REST와 gRPC 비교는 표로 정리된 항목들이 명확해서 실제로 프로토콜을 고를 때 참조할 만하다. 성능만 보면 gRPC가 앞서지만 호환성과 디버깅 편의에서 REST가 앞선다는 트레이드오프가 분명하게 드러난다.
보안 절은 인증과 인가를 구분하고, 각각의 구현 방식과 요청 속도 제한 알고리즘까지 훑는다. 넓게 짚어 주지만 깊이는 개요 수준이다. OAuth의 플로우 종류나 JWT의 서명 알고리즘 선택 같은 실제 구현 결정은 다루지 않으므로 별도 자료가 필요하다.
책의 정리를 그대로 옮기면 이렇다. 적절한 API 설계를 선택하고, API 보안을 최우선으로 고려하라. 뻔한 문장이지만, 보안을 나중에 얹으려면 인증 경계를 다시 그려야 한다는 점을 생각하면 순서에 관한 조언으로 읽을 만하다.
이 글이 도움이 되셨나요?