gRPC 인터셉터
gRPC 인터셉터 (Interceptors)
RPC 메서드를 하나씩 구현하다 보면, "이 로직은 이 메서드가 아니라 모든 호출에 적용되면 좋겠다" 싶은 것들이 늘어나요. 로깅, 인증, 메트릭 같은 것들이 대표적이죠. gRPC 인터셉터는 이렇게 특정 메서드에 얽매이지 않는 공통 로직을 깔끔하게 구현할 수 있게 해 주는 확장 지점입니다. '필터'나 '미들웨어'라는 이름으로 알고 있는 개념이라면 바로 그거예요.
출처: Interceptors
언제 쓸까
인터셉터는 단일 RPC 메서드에 국한되지 않는 로직을 구현하는 데 아주 잘 맞아요. 여러 클라이언트나 서버에서 쉽게 공유할 수도 있고, gRPC를 확장하는 중요한·자주 쓰는 방법이기도 합니다. 웬만하면 원하는 기능이 이미 gRPC 생태계에 인터셉터로 존재할 수도 있으니, 만들기 전에 먼저 찾아보는 게 좋아요.
주요 사용 사례는 다음과 같습니다.
- 메타데이터 처리
- 로깅(Logging)
- 결함 주입(Fault injection)
- 캐싱(Caching)
- 메트릭(Metrics)
- 정책 적용(Policy enforcement)
- 서버 측 인증(Authentication)
- 서버 측 인가(Authorization)
참고로 클라이언트 측 인증은 인터셉터로도 할 수 있지만, gRPC가 이에 더 잘 맞는 전용 "call credentials" API를 제공하니 Authentication 가이드를 참고하는 게 좋아요.
어떻게 쓸까
인터셉터는 gRPC 채널이나 서버를 만들 때 추가할 수 있어요. 한 번 추가하면 그 채널·서버의 모든 RPC에서 호출됩니다. 인터셉터 API는 클라이언트 측과 서버 측이 다르기 때문에, 인터셉터는 "클라이언트 인터셉터"이거나 "서버 인터셉터" 중 하나가 돼요.
인터셉터는 본질적으로 호출 단위(per-call)라서, TCP 연결 관리나 TCP 포트 설정, TLS 구성 같은 것에는 쓰지 못해요. 대부분의 커스터마이징에 적합한 도구지만, 모든 것을 다 해결해 주진 않는다는 점을 알아 두세요.
인터셉터 순서
인터셉터를 여러 개 쓸 때는 순서가 중요해요. 여러분이 쓰는 gRPC 구현이 어떤 순서로 실행하는지 반드시 이해해야 합니다. 인터셉터들이 애플리케이션과 네트워크 사이에 줄지어 있다고 상상해 보세요. 어떤 인터셉터는 네트워크에 가까워 보내는 것에 더 많은 제어를 갖고, 어떤 것은 애플리케이션에 가까워 애플리케이션 동작을 더 잘 들여다봅니다.
예를 들어 캐싱 인터셉터와 로깅 인터셉터, 두 개의 클라이언트 인터셉터가 있다고 해볼게요. 어떤 순서로 두는 게 좋을까요? 로깅 인터셉터를 네트워크에 더 가깝게 두면 애플리케이션의 통신을 더 잘 감시하고, 캐시에 걸린 RPC는 로그에서 제외할 수 있어요.
flowchart LR
APP(Application) --> INT1
INT1(Caching\nInterceptor) -->|Cache miss| INT2
INT2(Logging\nInterceptor) --> NET
NET(Network)
반대로 로깅 인터셉터를 애플리케이션에 더 가깝게 두면, 애플리케이션의 동작과 로드하는 정보를 더 잘 이해할 수 있어요.
flowchart LR
APP(Application) --> INT2
INT1(Caching\nInterceptor) -->|Cache miss| NET
INT2(Logging\nInterceptor) --> INT1
NET(Network)
인터셉터의 순서만 바꿔서 두 방식 사이에서 선택하면 됩니다.
언어별 지원
| 언어 | 예제 |
|---|---|
| C++ | C++ 예제 |
| Go | Go 예제 |
| Java | Java 예제 |
| Python | Python 예제 |
더 알아보기 (Learn more)
- gRPC 메타데이터 가이드 — 인터셉터로 처리하는 대표 사례
- gRPC Authentication 가이드 — 서버 측 인증·인가
- Core concepts, architecture and lifecycle — RPC 수명주기