본문 용어 정리 (펼쳐 보기)
이 글 본문에 나온 용어만 한 줄씩 정리했습니다.
- TCP: 연결을 맺은 뒤 순서 확인과 재전송으로 데이터를 빠짐없이 전달하는 신뢰성 있는 전송 프로토콜입니다.
- HTTP: 웹에서 요청과 응답을 주고받는 프로토콜입니다.
- 방화벽(Firewall): 정해진 규칙에 따라 들어오고 나가는 트래픽을 허용하거나 차단하는 보안 장치입니다.
- 프록시(Proxy): 클라이언트와 서버 사이에서 요청을 대신 전달하는 중계 서버로, 캐싱, 필터링, 주소 숨김에 쓰입니다.
- 로드밸런서(Load Balancer): 들어오는 요청을 여러 서버에 나눠 보내서 부하를 분산하고 장애를 줄이는 장치입니다.
- 핸드셰이크(Handshake): 본격적인 통신을 시작하기 전에 양쪽이 연결 조건을 확인하고 합의하는 절차입니다.
- 양방향(전이중, Full-duplex): 양쪽이 동시에 자유롭게 주고받을 수 있는 방식입니다(예: 전화).
- 요청/응답(Request/Response): 클라이언트가 요청하면 서버가 응답하는, 항상 클라이언트가 먼저 시작하는 방식입니다.
- 푸시(Push): 서버가 요청을 받지 않고도 먼저 클라이언트에게 데이터를 보내는 것입니다.
- 엔드포인트(Endpoint): API가 요청을 받는 주소(URL)입니다.
- 오버헤드(Overhead): 실제 데이터 전달 외에 추가로 드는 비용(헤더, 연결 설정 등)입니다.
- RFC: 인터넷 프로토콜의 표준을 정리한 공식 문서입니다(WebSocket은 RFC 6455).
- 캐시(Cache): 한 번 받은 결과를 저장해 두었다가 다시 요청이 오면 재사용해서 속도를 높이는 것입니다.
- HTTP 캐싱: 브라우저나 프록시가
Cache-Control같은 헤더에 따라 응답을 저장하고 재사용하는 방식입니다. - curl: 터미널에서 URL로 HTTP 요청을 보내고 응답을 확인하는 명령줄 도구입니다.
- L4 로드밸런서: IP와 포트 같은 전송 계층 정보만 보고 서버에 트래픽을 나누는 로드밸런서입니다.
- L7 프록시: HTTP 경로나 헤더 같은 응용 계층 내용을 보고 요청 단위로 나눠 전달하는 프록시(로드밸런서)입니다.
- 마이크로서비스: 하나의 큰 앱을 작고 독립적인 여러 서비스로 쪼개서 만드는 구조입니다.
- 디버깅: 프로그램의 오류 원인을 찾아 고치는 작업입니다.
- 직렬화(Serialization): 메모리 안의 데이터를 전송하거나 저장할 수 있는 바이트나 문자열로 바꾸는 것입니다(반대는 역직렬화).
- JSON: 사람이 읽을 수 있는 키-값 형태의 텍스트 데이터 형식입니다.
- 바이너리(Binary) 포맷: 데이터를 사람이 읽을 수 없는 바이트 그대로 인코딩해 작고 빠르지만 눈으로 확인하기는 어려운 형식입니다.
- Protocol Buffers(Protobuf): Google이 만든 바이너리 직렬화 형식으로,
.proto파일에 구조를 정의합니다. .proto파일: gRPC의 서비스와 메시지 타입을 정의하는 파일이자 클라이언트와 서버의 약속(계약)입니다.- RPC(Remote Procedure Call): 다른 서버에 있는 함수를 내 로컬 함수처럼 호출하는 방식입니다.
- stub: 원격 함수를 로컬 함수처럼 부를 수 있게 자동 생성되는 클라이언트 쪽 코드입니다.
- 코드 생성(codegen): 정의 파일(
.proto)에서 클라이언트와 서버 코드를 자동으로 만들어 내는 것입니다. - HTTP/2: HTTP/1.1을 개선해 한 연결에서 여러 요청을 동시에 처리하고 헤더를 압축하는 프로토콜입니다.
- 멀티플렉싱(Multiplexing): 하나의 연결로 여러 요청과 응답을 섞어서 동시에 주고받는 기술입니다.
- 스트리밍(Streaming): 데이터를 한 번에 다 보내지 않고 계속 이어서 흘려보내는 방식입니다.
- Unary: 요청 하나에 응답 하나를 주고받는 가장 기본적인 gRPC 호출 방식입니다.
- Deadline: 호출이 이 시간 안에 끝나야 한다는 제한 시간으로, 넘기면 호출이 실패합니다.
- gRPC-Web: 브라우저에서 gRPC 서버를 호출할 수 있게 해 주는 변형 프로토콜로, 프록시가 필요합니다.
- 쿼리 언어: 원하는 데이터를 요청하기 위한 전용 문법입니다.
- Schema / SDL: GraphQL의 타입과 필드를 정의하는 계약이고, SDL(Schema Definition Language)은 이를 쓰는 문법입니다.
- Query: 데이터를 조회하는 GraphQL 연산입니다.
- Mutation: 데이터를 생성, 수정, 삭제하는 GraphQL 연산입니다.
- Subscription: 서버의 변경을 실시간으로 받아 보는 GraphQL 연산으로, 보통 WebSocket 위에서 동작합니다.
- Resolver: 스키마의 각 필드 값을 실제로 가져오는 서버 쪽 함수입니다.
- Introspection: 클라이언트가 서버에 스키마 자체를 물어볼 수 있게 하는 기능으로, 도구의 자동 완성에 쓰입니다.
- Over-fetching: 필요하지 않은 필드까지 받아 오는 문제입니다.
- Under-fetching: 필요한 데이터가 한 번에 오지 않아 요청을 여러 번 보내야 하는 문제입니다.
- N+1 문제: 목록을 1번 조회한 뒤 항목마다 추가 쿼리를 N번 날려서 총 N+1번의 조회가 일어나는 비효율입니다.
- DataLoader: 같은 종류의 조회를 모아 한 번에 처리하고 캐시해서 N+1 문제를 줄이는 도구입니다.
- depth/complexity 제한: 쿼리의 깊이나 계산 비용에 상한을 두어 지나치게 무거운 쿼리를 막는 방어 장치입니다.
- Upgrade 핸드셰이크: HTTP 요청으로 시작해서 “프로토콜을 WebSocket으로 바꾸자”고 합의하는 절차입니다.
- 101 Switching Protocols: 서버가 프로토콜 전환을 승인한다는 HTTP 응답 코드입니다.
ws:///wss://: WebSocket 주소 형식이고,wss는 TLS로 암호화된 연결입니다.- stateful: 서버가 이전 연결이나 요청의 상태를 기억하고 있는 방식입니다(반대는 stateless).
- sticky session: 같은 클라이언트의 요청을 계속 같은 서버로 보내도록 고정하는 설정입니다.
- 메시지 브로커: 서버들 사이에서 메시지를 중계해 주는 시스템입니다.
- Redis: 메모리 기반 데이터 저장소로, 발행/구독(pub/sub) 기능을 메시지 브로커처럼 써서 서버들 사이에 메시지를 전달할 수 있습니다.
- 하트비트(ping/pong): 연결이 아직 살아 있는지 확인하려고 주기적으로 주고받는 신호입니다.
아래 두 게시물에서 다룬 주제 중 gRPC, GraphQL, WebSocket 세 가지만 골라 정리했습니다.
- Top 8 API Styles — AlgoMaster.io
- 20 Must-Know Networking Concepts — AlgoMaster.io
먼저 구분하기
세 가지는 같은 종류가 아닙니다. 그래서 서로 대체재라기보다 문제에 따라 고르는 도구에 가깝습니다.
| 정체 | |
|---|---|
| gRPC | RPC 프레임워크 (HTTP/2 + Protocol Buffers) |
| GraphQL | API 쿼리 언어 + 런타임 (전송은 보통 HTTP) |
| WebSocket | 양방향 전송 프로토콜 (HTTP로 시작해 업그레이드) |
1. gRPC
Google이 만든 RPC 프레임워크입니다. 원격 서버의 함수를 로컬 함수처럼 호출합니다.
동작 방식
.proto파일에 서비스와 메시지 타입을 정의합니다.- 이 파일에서 클라이언트(stub)와 서버 코드가 자동 생성됩니다.
- 호출은 HTTP/2 위에서 Protocol Buffers(바이너리) 로 직렬화되어 오갑니다.
service UserService {
rpc GetUser (GetUserRequest) returns (User);
}
message GetUserRequest { int64 id = 1; }
message User { int64 id = 1; string name = 2; }
통신 방식 4가지
- Unary: 요청 1개, 응답 1개
- Server streaming: 요청 1개, 응답 여러 개
- Client streaming: 요청 여러 개, 응답 1개
- Bidirectional streaming: 양쪽이 동시에 계속 주고받기
장점
- 바이너리 포맷이라 JSON보다 작고 빠릅니다.
.proto가 곧 계약서라 강한 타입과 다언어 코드 생성이 됩니다.- HTTP/2 멀티플렉싱으로 한 연결에서 여러 요청을 처리합니다.
- Deadline, 취소, 인증 같은 기능이 기본으로 있습니다.
단점
- 브라우저에서 직접 호출할 수 없어 gRPC-Web과 프록시가 필요합니다.
- 바이너리라 눈으로 확인하며 디버깅하기 어렵습니다.
- HTTP 캐시, curl 같은 일반 도구와 궁합이 좋지 않습니다.
- HTTP/2 연결을 오래 유지해서, L4 로드밸런서에서는 요청이 한 서버로 쏠릴 수 있습니다. L7 프록시나 클라이언트 측 로드밸런싱이 필요합니다.
어울리는 곳: 서비스 간 내부 통신(마이크로서비스), 지연 시간이 중요한 호출, 스트리밍
2. GraphQL
Facebook이 만든 API 쿼리 언어입니다. 보통 단일 엔드포인트(/graphql) 하나로, 클라이언트가 필요한 필드만 골라 요청합니다.
해결하려는 문제
- Over-fetching: 쓰지 않는 필드까지 받아오는 문제
- Under-fetching: 한 화면을 그리려고 요청을 여러 번 보내는 문제
query {
user(id: 1) {
name
posts { title }
}
}
요청한 name과 posts.title만 JSON으로 돌아옵니다.
핵심 개념
- Schema: 타입과 필드를 정의하는 강타입 계약 (SDL)
- Query / Mutation / Subscription: 조회 / 변경 / 실시간 구독
- Resolver: 각 필드의 값을 가져오는 함수
장점
- 요청 한 번에 연관 데이터를 가져옵니다.
- 스키마가 곧 문서이고, introspection으로 도구가 자동 완성을 지원합니다.
- 서버를 고치지 않고도 프론트엔드가 응답 모양을 바꿀 수 있습니다.
단점
- N+1 문제: resolver가 항목마다 쿼리를 날리기 쉽습니다. DataLoader로 배치 처리합니다.
- 보통 POST 하나로 통신해서 HTTP 캐싱이 어렵습니다.
- 너무 깊거나 큰 쿼리를 막으려면 depth/complexity 제한이 필요합니다.
- 에러가 HTTP 200으로 오는 경우가 많아 모니터링에 주의해야 합니다.
어울리는 곳: 웹/모바일 등 클라이언트가 여러 종류이고 데이터 관계가 복잡한 서비스
3. WebSocket
HTTP로 시작해서 Upgrade 핸드셰이크를 거친 뒤, 하나의 TCP 연결 위에서 양방향(full-duplex) 으로 통신합니다. (ws://, wss://, RFC 6455)
동작 방식
- 클라이언트가
Upgrade: websocket헤더로 HTTP 요청을 보냅니다. - 서버가
101 Switching Protocols로 응답합니다. - 이후 연결이 열린 채로 유지되며, 양쪽이 언제든 메시지를 보냅니다.
const ws = new WebSocket('wss://example.com/chat');
ws.onopen = () => ws.send('hello');
ws.onmessage = (e) => console.log(e.data);
장점
- 서버가 요청 없이도 먼저 데이터를 푸시할 수 있습니다.
- 연결 이후에는 메시지마다 HTTP 헤더를 반복해서 보내지 않아 오버헤드가 작고 지연이 낮습니다.
- 브라우저가 기본 지원합니다.
단점
- 연결이 상태를 가져서(stateful) 서버를 여러 대로 늘리기 어렵습니다. sticky session이나 Redis 같은 메시지 브로커로 서버 간 이벤트를 전달해야 합니다.
- 재연결과 하트비트(ping/pong) 를 직접 구현해야 합니다.
- 일부 프록시와 방화벽에서 문제가 생길 수 있습니다.
- 연결 수만큼 서버 자원을 계속 점유합니다.
어울리는 곳: 채팅, 실시간 협업, 온라인 게임, 시세와 알림
비교
| gRPC | GraphQL | WebSocket | |
|---|---|---|---|
| 전송 | HTTP/2 | 주로 HTTP (구독은 WebSocket 위) | TCP (HTTP 업그레이드) |
| 데이터 형식 | Protobuf (바이너리) | JSON | 자유 (텍스트/바이너리) |
| 통신 방향 | 요청/응답 + 스트리밍 4종 | 요청/응답 (+구독) | 양방향 |
| 브라우저 | 프록시 필요 | 바로 가능 | 바로 가능 |
| 연결 | 요청 단위 | 요청 단위 | 영속 연결 |
| 강점 | 속도, 타입 계약 | 유연한 조회 | 실시간 |
| 약점 | 디버깅, 브라우저 | 캐싱, N+1 | 확장성, 상태 관리 |
어떻게 고를까
- 서버끼리 빠르고 타입이 명확하게 통신해야 한다 → gRPC
- 클라이언트마다 필요한 데이터가 다르고 관계가 복잡하다 → GraphQL
- 서버가 즉시 푸시하고 양쪽이 계속 주고받아야 한다 → WebSocket