{"componentChunkName":"component---src-templates-blog-post-js","path":"/etc/gRPC-완전정복-고성능-마이크로서비스-통신의-새로운-패러다임/","result":{"data":{"site":{"siteMetadata":{"title":"Bottlehs Tech Blog","description":"웹·앱·AI 개발자 전병훈(bottlehs)의 기술 블로그. AI·LLM, JavaScript·Vue, Spring Boot, 알고리즘, 블록체인 실무 가이드를 다룹니다","siteUrl":"https://www.bottlehs.dev","author":{"name":"Jeon Byung Hun","summary":"개발을 즐기는 bottlehs - Engineer, MS, AI, FE, BE, OS, IOT, Blockchain, 설계, 테스트"},"social":{"github":"bottlehs","codepen":"bottlehs"}}},"markdownRemark":{"id":"0897e1a6-d413-57a9-9d23-8d304e6541e3","excerpt":"gRPC 완전정복 - 고성능 마이크로서비스 통신의 새로운 패러다임 gRPC는 Google이 개발한 고성능 오픈소스 RPC(Remote Procedure Call) 프레임워크다. HTTP/2 기반의 바이너리 프로토콜을 사용하며, Protocol Buffers…","html":"<h1 id=\"grpc-완전정복---고성능-마이크로서비스-통신의-새로운-패러다임\" style=\"position:relative;\"><a href=\"#grpc-%EC%99%84%EC%A0%84%EC%A0%95%EB%B3%B5---%EA%B3%A0%EC%84%B1%EB%8A%A5-%EB%A7%88%EC%9D%B4%ED%81%AC%EB%A1%9C%EC%84%9C%EB%B9%84%EC%8A%A4-%ED%86%B5%EC%8B%A0%EC%9D%98-%EC%83%88%EB%A1%9C%EC%9A%B4-%ED%8C%A8%EB%9F%AC%EB%8B%A4%EC%9E%84\" aria-label=\"grpc 완전정복   고성능 마이크로서비스 통신의 새로운 패러다임 permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>gRPC 완전정복 - 고성능 마이크로서비스 통신의 새로운 패러다임</h1>\n<p>gRPC는 Google이 개발한 고성능 오픈소스 RPC(Remote Procedure Call) 프레임워크다. HTTP/2 기반의 바이너리 프로토콜을 사용하며, Protocol Buffers를 통해 효율적인 직렬화를 제공한다. 이 글은 gRPC를 활용한 마이크로서비스 통신의 모든 것을 다룬다.</p>\n<h2 id=\"1-grpc-개요와-시작하기\" style=\"position:relative;\"><a href=\"#1-grpc-%EA%B0%9C%EC%9A%94%EC%99%80-%EC%8B%9C%EC%9E%91%ED%95%98%EA%B8%B0\" aria-label=\"1 grpc 개요와 시작하기 permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>1. gRPC 개요와 시작하기</h2>\n<h3 id=\"1-1-grpc의-특징\" style=\"position:relative;\"><a href=\"#1-1-grpc%EC%9D%98-%ED%8A%B9%EC%A7%95\" aria-label=\"1 1 grpc의 특징 permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>1-1. gRPC의 특징</h3>\n<ul>\n<li><strong>고성능</strong>: HTTP/2와 Protocol Buffers를 사용한 효율적인 통신</li>\n<li><strong>다양한 언어 지원</strong>: Java, Python, Go, C++, JavaScript 등</li>\n<li><strong>스트리밍 지원</strong>: 단방향, 양방향 스트리밍</li>\n<li><strong>타입 안전성</strong>: Protocol Buffers를 통한 강력한 타입 시스템</li>\n<li><strong>자동 코드 생성</strong>: .proto 파일로부터 클라이언트/서버 코드 자동 생성</li>\n</ul>\n<h3 id=\"1-2-rest-api-vs-grpc\" style=\"position:relative;\"><a href=\"#1-2-rest-api-vs-grpc\" aria-label=\"1 2 rest api vs grpc permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>1-2. REST API vs gRPC</h3>\n<table>\n<thead>\n<tr>\n<th>구분</th>\n<th>REST API</th>\n<th>gRPC</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>프로토콜</strong></td>\n<td>HTTP/1.1</td>\n<td>HTTP/2</td>\n</tr>\n<tr>\n<td><strong>데이터 형식</strong></td>\n<td>JSON (텍스트)</td>\n<td>Protocol Buffers (바이너리)</td>\n</tr>\n<tr>\n<td><strong>성능</strong></td>\n<td>상대적으로 느림</td>\n<td>매우 빠름</td>\n</tr>\n<tr>\n<td><strong>스트리밍</strong></td>\n<td>제한적 (SSE, WebSocket)</td>\n<td>네이티브 지원</td>\n</tr>\n<tr>\n<td><strong>브라우저 지원</strong></td>\n<td>완벽</td>\n<td>제한적 (gRPC-Web 필요)</td>\n</tr>\n<tr>\n<td><strong>코드 생성</strong></td>\n<td>수동</td>\n<td>자동</td>\n</tr>\n</tbody>\n</table>\n<h3 id=\"1-3-protocol-buffers-기본\" style=\"position:relative;\"><a href=\"#1-3-protocol-buffers-%EA%B8%B0%EB%B3%B8\" aria-label=\"1 3 protocol buffers 기본 permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>1-3. Protocol Buffers 기본</h3>\n<div class=\"gatsby-highlight\" data-language=\"protobuf\"><pre class=\"language-protobuf\"><code class=\"language-protobuf\"><span class=\"token comment\">// user.proto</span>\n<span class=\"token keyword\">syntax</span> <span class=\"token operator\">=</span> <span class=\"token string\">\"proto3\"</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token keyword\">package</span> user<span class=\"token punctuation\">;</span>\n\n<span class=\"token keyword\">option</span> java_package <span class=\"token operator\">=</span> <span class=\"token string\">\"com.example.user\"</span><span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">option</span> java_outer_classname <span class=\"token operator\">=</span> <span class=\"token string\">\"UserProto\"</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token comment\">// 사용자 메시지 정의</span>\n<span class=\"token keyword\">message</span> <span class=\"token class-name\">User</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token builtin\">int64</span> id <span class=\"token operator\">=</span> <span class=\"token number\">1</span><span class=\"token punctuation\">;</span>\n  <span class=\"token builtin\">string</span> name <span class=\"token operator\">=</span> <span class=\"token number\">2</span><span class=\"token punctuation\">;</span>\n  <span class=\"token builtin\">string</span> email <span class=\"token operator\">=</span> <span class=\"token number\">3</span><span class=\"token punctuation\">;</span>\n  <span class=\"token builtin\">int32</span> age <span class=\"token operator\">=</span> <span class=\"token number\">4</span><span class=\"token punctuation\">;</span>\n  <span class=\"token keyword\">repeated</span> <span class=\"token builtin\">string</span> tags <span class=\"token operator\">=</span> <span class=\"token number\">5</span><span class=\"token punctuation\">;</span> <span class=\"token comment\">// 배열</span>\n  <span class=\"token map class-name\">map<span class=\"token punctuation\">&lt;</span><span class=\"token builtin\">string</span><span class=\"token punctuation\">,</span> <span class=\"token builtin\">string</span><span class=\"token punctuation\">></span></span> metadata <span class=\"token operator\">=</span> <span class=\"token number\">6</span><span class=\"token punctuation\">;</span> <span class=\"token comment\">// 맵</span>\n  <span class=\"token positional-class-name class-name\">UserRole</span> role <span class=\"token operator\">=</span> <span class=\"token number\">7</span><span class=\"token punctuation\">;</span> <span class=\"token comment\">// 열거형</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token comment\">// 열거형</span>\n<span class=\"token keyword\">enum</span> <span class=\"token class-name\">UserRole</span> <span class=\"token punctuation\">{</span>\n  UNKNOWN <span class=\"token operator\">=</span> <span class=\"token number\">0</span><span class=\"token punctuation\">;</span>\n  USER <span class=\"token operator\">=</span> <span class=\"token number\">1</span><span class=\"token punctuation\">;</span>\n  ADMIN <span class=\"token operator\">=</span> <span class=\"token number\">2</span><span class=\"token punctuation\">;</span>\n  GUEST <span class=\"token operator\">=</span> <span class=\"token number\">3</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token comment\">// 요청/응답 메시지</span>\n<span class=\"token keyword\">message</span> <span class=\"token class-name\">GetUserRequest</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token builtin\">int64</span> user_id <span class=\"token operator\">=</span> <span class=\"token number\">1</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">message</span> <span class=\"token class-name\">GetUserResponse</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token positional-class-name class-name\">User</span> user <span class=\"token operator\">=</span> <span class=\"token number\">1</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">message</span> <span class=\"token class-name\">CreateUserRequest</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token builtin\">string</span> name <span class=\"token operator\">=</span> <span class=\"token number\">1</span><span class=\"token punctuation\">;</span>\n  <span class=\"token builtin\">string</span> email <span class=\"token operator\">=</span> <span class=\"token number\">2</span><span class=\"token punctuation\">;</span>\n  <span class=\"token builtin\">int32</span> age <span class=\"token operator\">=</span> <span class=\"token number\">3</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">message</span> <span class=\"token class-name\">CreateUserResponse</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token positional-class-name class-name\">User</span> user <span class=\"token operator\">=</span> <span class=\"token number\">1</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token comment\">// 서비스 정의</span>\n<span class=\"token keyword\">service</span> <span class=\"token class-name\">UserService</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token comment\">// 단순 RPC</span>\n  <span class=\"token keyword\">rpc</span> <span class=\"token function\">GetUser</span><span class=\"token punctuation\">(</span><span class=\"token class-name\">GetUserRequest</span><span class=\"token punctuation\">)</span> <span class=\"token keyword\">returns</span> <span class=\"token punctuation\">(</span><span class=\"token class-name\">GetUserResponse</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  \n  <span class=\"token comment\">// 서버 스트리밍</span>\n  <span class=\"token keyword\">rpc</span> <span class=\"token function\">ListUsers</span><span class=\"token punctuation\">(</span><span class=\"token class-name\">ListUsersRequest</span><span class=\"token punctuation\">)</span> <span class=\"token keyword\">returns</span> <span class=\"token punctuation\">(</span><span class=\"token keyword\">stream</span> <span class=\"token class-name\">User</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  \n  <span class=\"token comment\">// 클라이언트 스트리밍</span>\n  <span class=\"token keyword\">rpc</span> <span class=\"token function\">CreateUsers</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">stream</span> <span class=\"token class-name\">CreateUserRequest</span><span class=\"token punctuation\">)</span> <span class=\"token keyword\">returns</span> <span class=\"token punctuation\">(</span><span class=\"token class-name\">CreateUsersResponse</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  \n  <span class=\"token comment\">// 양방향 스트리밍</span>\n  <span class=\"token keyword\">rpc</span> <span class=\"token function\">ChatUsers</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">stream</span> <span class=\"token class-name\">ChatMessage</span><span class=\"token punctuation\">)</span> <span class=\"token keyword\">returns</span> <span class=\"token punctuation\">(</span><span class=\"token keyword\">stream</span> <span class=\"token class-name\">ChatMessage</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<h2 id=\"2-spring-boot에서-grpc-구현\" style=\"position:relative;\"><a href=\"#2-spring-boot%EC%97%90%EC%84%9C-grpc-%EA%B5%AC%ED%98%84\" aria-label=\"2 spring boot에서 grpc 구현 permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>2. Spring Boot에서 gRPC 구현</h2>\n<h3 id=\"2-1-의존성-설정\" style=\"position:relative;\"><a href=\"#2-1-%EC%9D%98%EC%A1%B4%EC%84%B1-%EC%84%A4%EC%A0%95\" aria-label=\"2 1 의존성 설정 permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>2-1. 의존성 설정</h3>\n<div class=\"gatsby-highlight\" data-language=\"xml\"><pre class=\"language-xml\"><code class=\"language-xml\"><span class=\"token comment\">&lt;!-- pom.xml --></span>\n<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>dependencies</span><span class=\"token punctuation\">></span></span>\n    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>dependency</span><span class=\"token punctuation\">></span></span>\n        <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>groupId</span><span class=\"token punctuation\">></span></span>net.devh<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>groupId</span><span class=\"token punctuation\">></span></span>\n        <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>artifactId</span><span class=\"token punctuation\">></span></span>grpc-server-spring-boot-starter<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>artifactId</span><span class=\"token punctuation\">></span></span>\n        <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>version</span><span class=\"token punctuation\">></span></span>2.15.0.RELEASE<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>version</span><span class=\"token punctuation\">></span></span>\n    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>dependency</span><span class=\"token punctuation\">></span></span>\n    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>dependency</span><span class=\"token punctuation\">></span></span>\n        <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>groupId</span><span class=\"token punctuation\">></span></span>net.devh<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>groupId</span><span class=\"token punctuation\">></span></span>\n        <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>artifactId</span><span class=\"token punctuation\">></span></span>grpc-client-spring-boot-starter<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>artifactId</span><span class=\"token punctuation\">></span></span>\n        <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>version</span><span class=\"token punctuation\">></span></span>2.15.0.RELEASE<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>version</span><span class=\"token punctuation\">></span></span>\n    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>dependency</span><span class=\"token punctuation\">></span></span>\n    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>dependency</span><span class=\"token punctuation\">></span></span>\n        <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>groupId</span><span class=\"token punctuation\">></span></span>io.grpc<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>groupId</span><span class=\"token punctuation\">></span></span>\n        <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>artifactId</span><span class=\"token punctuation\">></span></span>grpc-protobuf<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>artifactId</span><span class=\"token punctuation\">></span></span>\n        <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>version</span><span class=\"token punctuation\">></span></span>1.58.0<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>version</span><span class=\"token punctuation\">></span></span>\n    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>dependency</span><span class=\"token punctuation\">></span></span>\n    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>dependency</span><span class=\"token punctuation\">></span></span>\n        <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>groupId</span><span class=\"token punctuation\">></span></span>io.grpc<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>groupId</span><span class=\"token punctuation\">></span></span>\n        <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>artifactId</span><span class=\"token punctuation\">></span></span>grpc-stub<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>artifactId</span><span class=\"token punctuation\">></span></span>\n        <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>version</span><span class=\"token punctuation\">></span></span>1.58.0<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>version</span><span class=\"token punctuation\">></span></span>\n    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>dependency</span><span class=\"token punctuation\">></span></span>\n<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>dependencies</span><span class=\"token punctuation\">></span></span>\n\n<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>build</span><span class=\"token punctuation\">></span></span>\n    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>extensions</span><span class=\"token punctuation\">></span></span>\n        <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>extension</span><span class=\"token punctuation\">></span></span>\n            <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>groupId</span><span class=\"token punctuation\">></span></span>kr.motd.maven<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>groupId</span><span class=\"token punctuation\">></span></span>\n            <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>artifactId</span><span class=\"token punctuation\">></span></span>os-maven-plugin<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>artifactId</span><span class=\"token punctuation\">></span></span>\n            <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>version</span><span class=\"token punctuation\">></span></span>1.7.1<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>version</span><span class=\"token punctuation\">></span></span>\n        <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>extension</span><span class=\"token punctuation\">></span></span>\n    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>extensions</span><span class=\"token punctuation\">></span></span>\n    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>plugins</span><span class=\"token punctuation\">></span></span>\n        <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>plugin</span><span class=\"token punctuation\">></span></span>\n            <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>groupId</span><span class=\"token punctuation\">></span></span>org.xolstice.maven.plugins<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>groupId</span><span class=\"token punctuation\">></span></span>\n            <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>artifactId</span><span class=\"token punctuation\">></span></span>protobuf-maven-plugin<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>artifactId</span><span class=\"token punctuation\">></span></span>\n            <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>version</span><span class=\"token punctuation\">></span></span>0.6.1<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>version</span><span class=\"token punctuation\">></span></span>\n            <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>configuration</span><span class=\"token punctuation\">></span></span>\n                <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>protocArtifact</span><span class=\"token punctuation\">></span></span>com.google.protobuf:protoc:3.24.0:exe:${os.detected.classifier}<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>protocArtifact</span><span class=\"token punctuation\">></span></span>\n                <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>pluginId</span><span class=\"token punctuation\">></span></span>grpc-java<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>pluginId</span><span class=\"token punctuation\">></span></span>\n                <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>pluginArtifact</span><span class=\"token punctuation\">></span></span>io.grpc:protoc-gen-grpc-java:1.58.0:exe:${os.detected.classifier}<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>pluginArtifact</span><span class=\"token punctuation\">></span></span>\n            <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>configuration</span><span class=\"token punctuation\">></span></span>\n            <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>executions</span><span class=\"token punctuation\">></span></span>\n                <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>execution</span><span class=\"token punctuation\">></span></span>\n                    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>goals</span><span class=\"token punctuation\">></span></span>\n                        <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>goal</span><span class=\"token punctuation\">></span></span>compile<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>goal</span><span class=\"token punctuation\">></span></span>\n                        <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>goal</span><span class=\"token punctuation\">></span></span>compile-custom<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>goal</span><span class=\"token punctuation\">></span></span>\n                    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>goals</span><span class=\"token punctuation\">></span></span>\n                <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>execution</span><span class=\"token punctuation\">></span></span>\n            <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>executions</span><span class=\"token punctuation\">></span></span>\n        <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>plugin</span><span class=\"token punctuation\">></span></span>\n    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>plugins</span><span class=\"token punctuation\">></span></span>\n<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>build</span><span class=\"token punctuation\">></span></span></code></pre></div>\n<div class=\"gatsby-highlight\" data-language=\"yaml\"><pre class=\"language-yaml\"><code class=\"language-yaml\"><span class=\"token comment\"># application.yml</span>\n<span class=\"token key atrule\">grpc</span><span class=\"token punctuation\">:</span>\n  <span class=\"token key atrule\">server</span><span class=\"token punctuation\">:</span>\n    <span class=\"token key atrule\">port</span><span class=\"token punctuation\">:</span> <span class=\"token number\">9090</span>\n  <span class=\"token key atrule\">client</span><span class=\"token punctuation\">:</span>\n    <span class=\"token key atrule\">user-service</span><span class=\"token punctuation\">:</span>\n      <span class=\"token key atrule\">address</span><span class=\"token punctuation\">:</span> <span class=\"token string\">'static://localhost:9090'</span>\n      <span class=\"token key atrule\">negotiationType</span><span class=\"token punctuation\">:</span> plaintext</code></pre></div>\n<h3 id=\"2-2-grpc-서버-구현\" style=\"position:relative;\"><a href=\"#2-2-grpc-%EC%84%9C%EB%B2%84-%EA%B5%AC%ED%98%84\" aria-label=\"2 2 grpc 서버 구현 permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>2-2. gRPC 서버 구현</h3>\n<div class=\"gatsby-highlight\" data-language=\"java\"><pre class=\"language-java\"><code class=\"language-java\"><span class=\"token comment\">// UserServiceImpl.java</span>\n<span class=\"token annotation punctuation\">@GrpcService</span>\n<span class=\"token keyword\">public</span> <span class=\"token keyword\">class</span> <span class=\"token class-name\">UserServiceImpl</span> <span class=\"token keyword\">extends</span> <span class=\"token class-name\">UserServiceGrpc<span class=\"token punctuation\">.</span>UserServiceImplBase</span> <span class=\"token punctuation\">{</span>\n    \n    <span class=\"token annotation punctuation\">@Autowired</span>\n    <span class=\"token keyword\">private</span> <span class=\"token class-name\">UserRepository</span> userRepository<span class=\"token punctuation\">;</span>\n    \n    <span class=\"token annotation punctuation\">@Override</span>\n    <span class=\"token keyword\">public</span> <span class=\"token keyword\">void</span> <span class=\"token function\">getUser</span><span class=\"token punctuation\">(</span><span class=\"token class-name\">GetUserRequest</span> request<span class=\"token punctuation\">,</span> \n                       <span class=\"token class-name\">StreamObserver</span><span class=\"token generics\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">GetUserResponse</span><span class=\"token punctuation\">></span></span> responseObserver<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token keyword\">try</span> <span class=\"token punctuation\">{</span>\n            <span class=\"token class-name\">Long</span> userId <span class=\"token operator\">=</span> request<span class=\"token punctuation\">.</span><span class=\"token function\">getUserId</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n            <span class=\"token class-name\">UserEntity</span> userEntity <span class=\"token operator\">=</span> userRepository<span class=\"token punctuation\">.</span><span class=\"token function\">findById</span><span class=\"token punctuation\">(</span>userId<span class=\"token punctuation\">)</span>\n                <span class=\"token punctuation\">.</span><span class=\"token function\">orElseThrow</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">-></span> <span class=\"token class-name\">Status</span><span class=\"token punctuation\">.</span><span class=\"token constant\">NOT_FOUND</span>\n                    <span class=\"token punctuation\">.</span><span class=\"token function\">withDescription</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"User not found\"</span><span class=\"token punctuation\">)</span>\n                    <span class=\"token punctuation\">.</span><span class=\"token function\">asRuntimeException</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n            \n            <span class=\"token class-name\">User</span> user <span class=\"token operator\">=</span> <span class=\"token class-name\">User</span><span class=\"token punctuation\">.</span><span class=\"token function\">newBuilder</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n                <span class=\"token punctuation\">.</span><span class=\"token function\">setId</span><span class=\"token punctuation\">(</span>userEntity<span class=\"token punctuation\">.</span><span class=\"token function\">getId</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n                <span class=\"token punctuation\">.</span><span class=\"token function\">setName</span><span class=\"token punctuation\">(</span>userEntity<span class=\"token punctuation\">.</span><span class=\"token function\">getName</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n                <span class=\"token punctuation\">.</span><span class=\"token function\">setEmail</span><span class=\"token punctuation\">(</span>userEntity<span class=\"token punctuation\">.</span><span class=\"token function\">getEmail</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n                <span class=\"token punctuation\">.</span><span class=\"token function\">setAge</span><span class=\"token punctuation\">(</span>userEntity<span class=\"token punctuation\">.</span><span class=\"token function\">getAge</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n                <span class=\"token punctuation\">.</span><span class=\"token function\">setRole</span><span class=\"token punctuation\">(</span><span class=\"token class-name\">UserRole</span><span class=\"token punctuation\">.</span><span class=\"token function\">valueOf</span><span class=\"token punctuation\">(</span>userEntity<span class=\"token punctuation\">.</span><span class=\"token function\">getRole</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">name</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n                <span class=\"token punctuation\">.</span><span class=\"token function\">build</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n            \n            <span class=\"token class-name\">GetUserResponse</span> response <span class=\"token operator\">=</span> <span class=\"token class-name\">GetUserResponse</span><span class=\"token punctuation\">.</span><span class=\"token function\">newBuilder</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n                <span class=\"token punctuation\">.</span><span class=\"token function\">setUser</span><span class=\"token punctuation\">(</span>user<span class=\"token punctuation\">)</span>\n                <span class=\"token punctuation\">.</span><span class=\"token function\">build</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n            \n            responseObserver<span class=\"token punctuation\">.</span><span class=\"token function\">onNext</span><span class=\"token punctuation\">(</span>response<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n            responseObserver<span class=\"token punctuation\">.</span><span class=\"token function\">onCompleted</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n            \n        <span class=\"token punctuation\">}</span> <span class=\"token keyword\">catch</span> <span class=\"token punctuation\">(</span><span class=\"token class-name\">Exception</span> e<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n            responseObserver<span class=\"token punctuation\">.</span><span class=\"token function\">onError</span><span class=\"token punctuation\">(</span><span class=\"token class-name\">Status</span><span class=\"token punctuation\">.</span><span class=\"token constant\">INTERNAL</span>\n                <span class=\"token punctuation\">.</span><span class=\"token function\">withDescription</span><span class=\"token punctuation\">(</span>e<span class=\"token punctuation\">.</span><span class=\"token function\">getMessage</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n                <span class=\"token punctuation\">.</span><span class=\"token function\">asRuntimeException</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        <span class=\"token punctuation\">}</span>\n    <span class=\"token punctuation\">}</span>\n    \n    <span class=\"token annotation punctuation\">@Override</span>\n    <span class=\"token keyword\">public</span> <span class=\"token keyword\">void</span> <span class=\"token function\">createUser</span><span class=\"token punctuation\">(</span><span class=\"token class-name\">CreateUserRequest</span> request<span class=\"token punctuation\">,</span>\n                          <span class=\"token class-name\">StreamObserver</span><span class=\"token generics\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">CreateUserResponse</span><span class=\"token punctuation\">></span></span> responseObserver<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token keyword\">try</span> <span class=\"token punctuation\">{</span>\n            <span class=\"token class-name\">UserEntity</span> userEntity <span class=\"token operator\">=</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">UserEntity</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n            userEntity<span class=\"token punctuation\">.</span><span class=\"token function\">setName</span><span class=\"token punctuation\">(</span>request<span class=\"token punctuation\">.</span><span class=\"token function\">getName</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n            userEntity<span class=\"token punctuation\">.</span><span class=\"token function\">setEmail</span><span class=\"token punctuation\">(</span>request<span class=\"token punctuation\">.</span><span class=\"token function\">getEmail</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n            userEntity<span class=\"token punctuation\">.</span><span class=\"token function\">setAge</span><span class=\"token punctuation\">(</span>request<span class=\"token punctuation\">.</span><span class=\"token function\">getAge</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n            userEntity <span class=\"token operator\">=</span> userRepository<span class=\"token punctuation\">.</span><span class=\"token function\">save</span><span class=\"token punctuation\">(</span>userEntity<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n            \n            <span class=\"token class-name\">User</span> user <span class=\"token operator\">=</span> <span class=\"token function\">convertToProto</span><span class=\"token punctuation\">(</span>userEntity<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n            \n            <span class=\"token class-name\">CreateUserResponse</span> response <span class=\"token operator\">=</span> <span class=\"token class-name\">CreateUserResponse</span><span class=\"token punctuation\">.</span><span class=\"token function\">newBuilder</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n                <span class=\"token punctuation\">.</span><span class=\"token function\">setUser</span><span class=\"token punctuation\">(</span>user<span class=\"token punctuation\">)</span>\n                <span class=\"token punctuation\">.</span><span class=\"token function\">build</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n            \n            responseObserver<span class=\"token punctuation\">.</span><span class=\"token function\">onNext</span><span class=\"token punctuation\">(</span>response<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n            responseObserver<span class=\"token punctuation\">.</span><span class=\"token function\">onCompleted</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n            \n        <span class=\"token punctuation\">}</span> <span class=\"token keyword\">catch</span> <span class=\"token punctuation\">(</span><span class=\"token class-name\">Exception</span> e<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n            responseObserver<span class=\"token punctuation\">.</span><span class=\"token function\">onError</span><span class=\"token punctuation\">(</span><span class=\"token class-name\">Status</span><span class=\"token punctuation\">.</span><span class=\"token constant\">INTERNAL</span>\n                <span class=\"token punctuation\">.</span><span class=\"token function\">withDescription</span><span class=\"token punctuation\">(</span>e<span class=\"token punctuation\">.</span><span class=\"token function\">getMessage</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n                <span class=\"token punctuation\">.</span><span class=\"token function\">asRuntimeException</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        <span class=\"token punctuation\">}</span>\n    <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<h3 id=\"2-3-grpc-클라이언트-구현\" style=\"position:relative;\"><a href=\"#2-3-grpc-%ED%81%B4%EB%9D%BC%EC%9D%B4%EC%96%B8%ED%8A%B8-%EA%B5%AC%ED%98%84\" aria-label=\"2 3 grpc 클라이언트 구현 permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>2-3. gRPC 클라이언트 구현</h3>\n<div class=\"gatsby-highlight\" data-language=\"java\"><pre class=\"language-java\"><code class=\"language-java\"><span class=\"token comment\">// UserServiceClient.java</span>\n<span class=\"token annotation punctuation\">@Service</span>\n<span class=\"token keyword\">public</span> <span class=\"token keyword\">class</span> <span class=\"token class-name\">UserServiceClient</span> <span class=\"token punctuation\">{</span>\n    \n    <span class=\"token annotation punctuation\">@GrpcClient</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"user-service\"</span><span class=\"token punctuation\">)</span>\n    <span class=\"token keyword\">private</span> <span class=\"token class-name\">UserServiceGrpc<span class=\"token punctuation\">.</span>UserServiceBlockingStub</span> blockingStub<span class=\"token punctuation\">;</span>\n    \n    <span class=\"token annotation punctuation\">@GrpcClient</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"user-service\"</span><span class=\"token punctuation\">)</span>\n    <span class=\"token keyword\">private</span> <span class=\"token class-name\">UserServiceGrpc<span class=\"token punctuation\">.</span>UserServiceStub</span> asyncStub<span class=\"token punctuation\">;</span>\n    \n    <span class=\"token keyword\">public</span> <span class=\"token class-name\">User</span> <span class=\"token function\">getUser</span><span class=\"token punctuation\">(</span><span class=\"token class-name\">Long</span> userId<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token class-name\">GetUserRequest</span> request <span class=\"token operator\">=</span> <span class=\"token class-name\">GetUserRequest</span><span class=\"token punctuation\">.</span><span class=\"token function\">newBuilder</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n            <span class=\"token punctuation\">.</span><span class=\"token function\">setUserId</span><span class=\"token punctuation\">(</span>userId<span class=\"token punctuation\">)</span>\n            <span class=\"token punctuation\">.</span><span class=\"token function\">build</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        \n        <span class=\"token class-name\">GetUserResponse</span> response <span class=\"token operator\">=</span> blockingStub<span class=\"token punctuation\">.</span><span class=\"token function\">getUser</span><span class=\"token punctuation\">(</span>request<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        <span class=\"token keyword\">return</span> response<span class=\"token punctuation\">.</span><span class=\"token function\">getUser</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span>\n    \n    <span class=\"token keyword\">public</span> <span class=\"token class-name\">CompletableFuture</span><span class=\"token generics\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">User</span><span class=\"token punctuation\">></span></span> <span class=\"token function\">getUserAsync</span><span class=\"token punctuation\">(</span><span class=\"token class-name\">Long</span> userId<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token class-name\">GetUserRequest</span> request <span class=\"token operator\">=</span> <span class=\"token class-name\">GetUserRequest</span><span class=\"token punctuation\">.</span><span class=\"token function\">newBuilder</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n            <span class=\"token punctuation\">.</span><span class=\"token function\">setUserId</span><span class=\"token punctuation\">(</span>userId<span class=\"token punctuation\">)</span>\n            <span class=\"token punctuation\">.</span><span class=\"token function\">build</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        \n        <span class=\"token class-name\">CompletableFuture</span><span class=\"token generics\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">User</span><span class=\"token punctuation\">></span></span> future <span class=\"token operator\">=</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">CompletableFuture</span><span class=\"token generics\"><span class=\"token punctuation\">&lt;</span><span class=\"token punctuation\">></span></span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        \n        asyncStub<span class=\"token punctuation\">.</span><span class=\"token function\">getUser</span><span class=\"token punctuation\">(</span>request<span class=\"token punctuation\">,</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">StreamObserver</span><span class=\"token generics\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">GetUserResponse</span><span class=\"token punctuation\">></span></span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n            <span class=\"token annotation punctuation\">@Override</span>\n            <span class=\"token keyword\">public</span> <span class=\"token keyword\">void</span> <span class=\"token function\">onNext</span><span class=\"token punctuation\">(</span><span class=\"token class-name\">GetUserResponse</span> response<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n                future<span class=\"token punctuation\">.</span><span class=\"token function\">complete</span><span class=\"token punctuation\">(</span>response<span class=\"token punctuation\">.</span><span class=\"token function\">getUser</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n            <span class=\"token punctuation\">}</span>\n            \n            <span class=\"token annotation punctuation\">@Override</span>\n            <span class=\"token keyword\">public</span> <span class=\"token keyword\">void</span> <span class=\"token function\">onError</span><span class=\"token punctuation\">(</span><span class=\"token class-name\">Throwable</span> t<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n                future<span class=\"token punctuation\">.</span><span class=\"token function\">completeExceptionally</span><span class=\"token punctuation\">(</span>t<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n            <span class=\"token punctuation\">}</span>\n            \n            <span class=\"token annotation punctuation\">@Override</span>\n            <span class=\"token keyword\">public</span> <span class=\"token keyword\">void</span> <span class=\"token function\">onCompleted</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n                <span class=\"token comment\">// 이미 onNext에서 완료 처리</span>\n            <span class=\"token punctuation\">}</span>\n        <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        \n        <span class=\"token keyword\">return</span> future<span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<h2 id=\"3-스트리밍\" style=\"position:relative;\"><a href=\"#3-%EC%8A%A4%ED%8A%B8%EB%A6%AC%EB%B0%8D\" aria-label=\"3 스트리밍 permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>3. 스트리밍</h2>\n<h3 id=\"3-1-서버-스트리밍\" style=\"position:relative;\"><a href=\"#3-1-%EC%84%9C%EB%B2%84-%EC%8A%A4%ED%8A%B8%EB%A6%AC%EB%B0%8D\" aria-label=\"3 1 서버 스트리밍 permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>3-1. 서버 스트리밍</h3>\n<div class=\"gatsby-highlight\" data-language=\"protobuf\"><pre class=\"language-protobuf\"><code class=\"language-protobuf\"><span class=\"token comment\">// .proto</span>\n<span class=\"token keyword\">service</span> <span class=\"token class-name\">UserService</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">rpc</span> <span class=\"token function\">ListUsers</span><span class=\"token punctuation\">(</span><span class=\"token class-name\">ListUsersRequest</span><span class=\"token punctuation\">)</span> <span class=\"token keyword\">returns</span> <span class=\"token punctuation\">(</span><span class=\"token keyword\">stream</span> <span class=\"token class-name\">User</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">message</span> <span class=\"token class-name\">ListUsersRequest</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token builtin\">int32</span> page <span class=\"token operator\">=</span> <span class=\"token number\">1</span><span class=\"token punctuation\">;</span>\n  <span class=\"token builtin\">int32</span> page_size <span class=\"token operator\">=</span> <span class=\"token number\">2</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<div class=\"gatsby-highlight\" data-language=\"java\"><pre class=\"language-java\"><code class=\"language-java\"><span class=\"token comment\">// 서버 구현</span>\n<span class=\"token annotation punctuation\">@Override</span>\n<span class=\"token keyword\">public</span> <span class=\"token keyword\">void</span> <span class=\"token function\">listUsers</span><span class=\"token punctuation\">(</span><span class=\"token class-name\">ListUsersRequest</span> request<span class=\"token punctuation\">,</span>\n                     <span class=\"token class-name\">StreamObserver</span><span class=\"token generics\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">User</span><span class=\"token punctuation\">></span></span> responseObserver<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">try</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token keyword\">int</span> page <span class=\"token operator\">=</span> request<span class=\"token punctuation\">.</span><span class=\"token function\">getPage</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        <span class=\"token keyword\">int</span> pageSize <span class=\"token operator\">=</span> request<span class=\"token punctuation\">.</span><span class=\"token function\">getPageSize</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        \n        <span class=\"token class-name\">Pageable</span> pageable <span class=\"token operator\">=</span> <span class=\"token class-name\">PageRequest</span><span class=\"token punctuation\">.</span><span class=\"token function\">of</span><span class=\"token punctuation\">(</span>page<span class=\"token punctuation\">,</span> pageSize<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        <span class=\"token class-name\">Page</span><span class=\"token generics\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">UserEntity</span><span class=\"token punctuation\">></span></span> users <span class=\"token operator\">=</span> userRepository<span class=\"token punctuation\">.</span><span class=\"token function\">findAll</span><span class=\"token punctuation\">(</span>pageable<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        \n        <span class=\"token keyword\">for</span> <span class=\"token punctuation\">(</span><span class=\"token class-name\">UserEntity</span> userEntity <span class=\"token operator\">:</span> users<span class=\"token punctuation\">.</span><span class=\"token function\">getContent</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n            <span class=\"token class-name\">User</span> user <span class=\"token operator\">=</span> <span class=\"token function\">convertToProto</span><span class=\"token punctuation\">(</span>userEntity<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n            responseObserver<span class=\"token punctuation\">.</span><span class=\"token function\">onNext</span><span class=\"token punctuation\">(</span>user<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        <span class=\"token punctuation\">}</span>\n        \n        responseObserver<span class=\"token punctuation\">.</span><span class=\"token function\">onCompleted</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        \n    <span class=\"token punctuation\">}</span> <span class=\"token keyword\">catch</span> <span class=\"token punctuation\">(</span><span class=\"token class-name\">Exception</span> e<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n        responseObserver<span class=\"token punctuation\">.</span><span class=\"token function\">onError</span><span class=\"token punctuation\">(</span><span class=\"token class-name\">Status</span><span class=\"token punctuation\">.</span><span class=\"token constant\">INTERNAL</span>\n            <span class=\"token punctuation\">.</span><span class=\"token function\">withDescription</span><span class=\"token punctuation\">(</span>e<span class=\"token punctuation\">.</span><span class=\"token function\">getMessage</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n            <span class=\"token punctuation\">.</span><span class=\"token function\">asRuntimeException</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token comment\">// 클라이언트 구현</span>\n<span class=\"token keyword\">public</span> <span class=\"token class-name\">List</span><span class=\"token generics\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">User</span><span class=\"token punctuation\">></span></span> <span class=\"token function\">listUsers</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">int</span> page<span class=\"token punctuation\">,</span> <span class=\"token keyword\">int</span> pageSize<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token class-name\">ListUsersRequest</span> request <span class=\"token operator\">=</span> <span class=\"token class-name\">ListUsersRequest</span><span class=\"token punctuation\">.</span><span class=\"token function\">newBuilder</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n        <span class=\"token punctuation\">.</span><span class=\"token function\">setPage</span><span class=\"token punctuation\">(</span>page<span class=\"token punctuation\">)</span>\n        <span class=\"token punctuation\">.</span><span class=\"token function\">setPageSize</span><span class=\"token punctuation\">(</span>pageSize<span class=\"token punctuation\">)</span>\n        <span class=\"token punctuation\">.</span><span class=\"token function\">build</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    \n    <span class=\"token class-name\">List</span><span class=\"token generics\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">User</span><span class=\"token punctuation\">></span></span> users <span class=\"token operator\">=</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">ArrayList</span><span class=\"token generics\"><span class=\"token punctuation\">&lt;</span><span class=\"token punctuation\">></span></span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    \n    blockingStub<span class=\"token punctuation\">.</span><span class=\"token function\">listUsers</span><span class=\"token punctuation\">(</span>request<span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">forEachRemaining</span><span class=\"token punctuation\">(</span>response <span class=\"token operator\">-></span> <span class=\"token punctuation\">{</span>\n        users<span class=\"token punctuation\">.</span><span class=\"token function\">add</span><span class=\"token punctuation\">(</span>response<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    \n    <span class=\"token keyword\">return</span> users<span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<h3 id=\"3-2-클라이언트-스트리밍\" style=\"position:relative;\"><a href=\"#3-2-%ED%81%B4%EB%9D%BC%EC%9D%B4%EC%96%B8%ED%8A%B8-%EC%8A%A4%ED%8A%B8%EB%A6%AC%EB%B0%8D\" aria-label=\"3 2 클라이언트 스트리밍 permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>3-2. 클라이언트 스트리밍</h3>\n<div class=\"gatsby-highlight\" data-language=\"protobuf\"><pre class=\"language-protobuf\"><code class=\"language-protobuf\"><span class=\"token comment\">// .proto</span>\n<span class=\"token keyword\">service</span> <span class=\"token class-name\">UserService</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">rpc</span> <span class=\"token function\">CreateUsers</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">stream</span> <span class=\"token class-name\">CreateUserRequest</span><span class=\"token punctuation\">)</span> <span class=\"token keyword\">returns</span> <span class=\"token punctuation\">(</span><span class=\"token class-name\">CreateUsersResponse</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">message</span> <span class=\"token class-name\">CreateUsersResponse</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token builtin\">int32</span> created_count <span class=\"token operator\">=</span> <span class=\"token number\">1</span><span class=\"token punctuation\">;</span>\n  <span class=\"token keyword\">repeated</span> <span class=\"token positional-class-name class-name\">User</span> users <span class=\"token operator\">=</span> <span class=\"token number\">2</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<div class=\"gatsby-highlight\" data-language=\"java\"><pre class=\"language-java\"><code class=\"language-java\"><span class=\"token comment\">// 서버 구현</span>\n<span class=\"token annotation punctuation\">@Override</span>\n<span class=\"token keyword\">public</span> <span class=\"token class-name\">StreamObserver</span><span class=\"token generics\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">CreateUserRequest</span><span class=\"token punctuation\">></span></span> <span class=\"token function\">createUsers</span><span class=\"token punctuation\">(</span>\n    <span class=\"token class-name\">StreamObserver</span><span class=\"token generics\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">CreateUsersResponse</span><span class=\"token punctuation\">></span></span> responseObserver<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    \n    <span class=\"token keyword\">return</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">StreamObserver</span><span class=\"token generics\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">CreateUserRequest</span><span class=\"token punctuation\">></span></span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token keyword\">private</span> <span class=\"token class-name\">List</span><span class=\"token generics\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">User</span><span class=\"token punctuation\">></span></span> createdUsers <span class=\"token operator\">=</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">ArrayList</span><span class=\"token generics\"><span class=\"token punctuation\">&lt;</span><span class=\"token punctuation\">></span></span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        \n        <span class=\"token annotation punctuation\">@Override</span>\n        <span class=\"token keyword\">public</span> <span class=\"token keyword\">void</span> <span class=\"token function\">onNext</span><span class=\"token punctuation\">(</span><span class=\"token class-name\">CreateUserRequest</span> request<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n            <span class=\"token class-name\">UserEntity</span> userEntity <span class=\"token operator\">=</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">UserEntity</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n            userEntity<span class=\"token punctuation\">.</span><span class=\"token function\">setName</span><span class=\"token punctuation\">(</span>request<span class=\"token punctuation\">.</span><span class=\"token function\">getName</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n            userEntity<span class=\"token punctuation\">.</span><span class=\"token function\">setEmail</span><span class=\"token punctuation\">(</span>request<span class=\"token punctuation\">.</span><span class=\"token function\">getEmail</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n            userEntity<span class=\"token punctuation\">.</span><span class=\"token function\">setAge</span><span class=\"token punctuation\">(</span>request<span class=\"token punctuation\">.</span><span class=\"token function\">getAge</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n            userEntity <span class=\"token operator\">=</span> userRepository<span class=\"token punctuation\">.</span><span class=\"token function\">save</span><span class=\"token punctuation\">(</span>userEntity<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n            \n            <span class=\"token class-name\">User</span> user <span class=\"token operator\">=</span> <span class=\"token function\">convertToProto</span><span class=\"token punctuation\">(</span>userEntity<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n            createdUsers<span class=\"token punctuation\">.</span><span class=\"token function\">add</span><span class=\"token punctuation\">(</span>user<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        <span class=\"token punctuation\">}</span>\n        \n        <span class=\"token annotation punctuation\">@Override</span>\n        <span class=\"token keyword\">public</span> <span class=\"token keyword\">void</span> <span class=\"token function\">onError</span><span class=\"token punctuation\">(</span><span class=\"token class-name\">Throwable</span> t<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n            responseObserver<span class=\"token punctuation\">.</span><span class=\"token function\">onError</span><span class=\"token punctuation\">(</span>t<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        <span class=\"token punctuation\">}</span>\n        \n        <span class=\"token annotation punctuation\">@Override</span>\n        <span class=\"token keyword\">public</span> <span class=\"token keyword\">void</span> <span class=\"token function\">onCompleted</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n            <span class=\"token class-name\">CreateUsersResponse</span> response <span class=\"token operator\">=</span> <span class=\"token class-name\">CreateUsersResponse</span><span class=\"token punctuation\">.</span><span class=\"token function\">newBuilder</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n                <span class=\"token punctuation\">.</span><span class=\"token function\">setCreatedCount</span><span class=\"token punctuation\">(</span>createdUsers<span class=\"token punctuation\">.</span><span class=\"token function\">size</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n                <span class=\"token punctuation\">.</span><span class=\"token function\">addAllUsers</span><span class=\"token punctuation\">(</span>createdUsers<span class=\"token punctuation\">)</span>\n                <span class=\"token punctuation\">.</span><span class=\"token function\">build</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n            \n            responseObserver<span class=\"token punctuation\">.</span><span class=\"token function\">onNext</span><span class=\"token punctuation\">(</span>response<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n            responseObserver<span class=\"token punctuation\">.</span><span class=\"token function\">onCompleted</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        <span class=\"token punctuation\">}</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token comment\">// 클라이언트 구현</span>\n<span class=\"token keyword\">public</span> <span class=\"token class-name\">CreateUsersResponse</span> <span class=\"token function\">createUsers</span><span class=\"token punctuation\">(</span><span class=\"token class-name\">List</span><span class=\"token generics\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">CreateUserRequest</span><span class=\"token punctuation\">></span></span> requests<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token class-name\">StreamObserver</span><span class=\"token generics\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">CreateUserRequest</span><span class=\"token punctuation\">></span></span> requestObserver <span class=\"token operator\">=</span> \n        asyncStub<span class=\"token punctuation\">.</span><span class=\"token function\">createUsers</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">new</span> <span class=\"token class-name\">StreamObserver</span><span class=\"token generics\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">CreateUsersResponse</span><span class=\"token punctuation\">></span></span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n            <span class=\"token annotation punctuation\">@Override</span>\n            <span class=\"token keyword\">public</span> <span class=\"token keyword\">void</span> <span class=\"token function\">onNext</span><span class=\"token punctuation\">(</span><span class=\"token class-name\">CreateUsersResponse</span> response<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n                <span class=\"token comment\">// 응답 처리</span>\n            <span class=\"token punctuation\">}</span>\n            \n            <span class=\"token annotation punctuation\">@Override</span>\n            <span class=\"token keyword\">public</span> <span class=\"token keyword\">void</span> <span class=\"token function\">onError</span><span class=\"token punctuation\">(</span><span class=\"token class-name\">Throwable</span> t<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n                <span class=\"token comment\">// 에러 처리</span>\n            <span class=\"token punctuation\">}</span>\n            \n            <span class=\"token annotation punctuation\">@Override</span>\n            <span class=\"token keyword\">public</span> <span class=\"token keyword\">void</span> <span class=\"token function\">onCompleted</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n                <span class=\"token comment\">// 완료 처리</span>\n            <span class=\"token punctuation\">}</span>\n        <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    \n    <span class=\"token keyword\">for</span> <span class=\"token punctuation\">(</span><span class=\"token class-name\">CreateUserRequest</span> request <span class=\"token operator\">:</span> requests<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n        requestObserver<span class=\"token punctuation\">.</span><span class=\"token function\">onNext</span><span class=\"token punctuation\">(</span>request<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span>\n    \n    requestObserver<span class=\"token punctuation\">.</span><span class=\"token function\">onCompleted</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    \n    <span class=\"token comment\">// 실제로는 CompletableFuture 등을 사용하여 응답을 기다림</span>\n    <span class=\"token keyword\">return</span> <span class=\"token keyword\">null</span><span class=\"token punctuation\">;</span> <span class=\"token comment\">// 예시</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<h3 id=\"3-3-양방향-스트리밍\" style=\"position:relative;\"><a href=\"#3-3-%EC%96%91%EB%B0%A9%ED%96%A5-%EC%8A%A4%ED%8A%B8%EB%A6%AC%EB%B0%8D\" aria-label=\"3 3 양방향 스트리밍 permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>3-3. 양방향 스트리밍</h3>\n<div class=\"gatsby-highlight\" data-language=\"protobuf\"><pre class=\"language-protobuf\"><code class=\"language-protobuf\"><span class=\"token comment\">// .proto</span>\n<span class=\"token keyword\">service</span> <span class=\"token class-name\">ChatService</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">rpc</span> <span class=\"token function\">Chat</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">stream</span> <span class=\"token class-name\">ChatMessage</span><span class=\"token punctuation\">)</span> <span class=\"token keyword\">returns</span> <span class=\"token punctuation\">(</span><span class=\"token keyword\">stream</span> <span class=\"token class-name\">ChatMessage</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">message</span> <span class=\"token class-name\">ChatMessage</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token builtin\">string</span> user_id <span class=\"token operator\">=</span> <span class=\"token number\">1</span><span class=\"token punctuation\">;</span>\n  <span class=\"token builtin\">string</span> message <span class=\"token operator\">=</span> <span class=\"token number\">2</span><span class=\"token punctuation\">;</span>\n  <span class=\"token builtin\">int64</span> timestamp <span class=\"token operator\">=</span> <span class=\"token number\">3</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<div class=\"gatsby-highlight\" data-language=\"java\"><pre class=\"language-java\"><code class=\"language-java\"><span class=\"token comment\">// 서버 구현</span>\n<span class=\"token annotation punctuation\">@Override</span>\n<span class=\"token keyword\">public</span> <span class=\"token class-name\">StreamObserver</span><span class=\"token generics\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">ChatMessage</span><span class=\"token punctuation\">></span></span> <span class=\"token function\">chat</span><span class=\"token punctuation\">(</span>\n    <span class=\"token class-name\">StreamObserver</span><span class=\"token generics\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">ChatMessage</span><span class=\"token punctuation\">></span></span> responseObserver<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    \n    <span class=\"token keyword\">return</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">StreamObserver</span><span class=\"token generics\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">ChatMessage</span><span class=\"token punctuation\">></span></span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token annotation punctuation\">@Override</span>\n        <span class=\"token keyword\">public</span> <span class=\"token keyword\">void</span> <span class=\"token function\">onNext</span><span class=\"token punctuation\">(</span><span class=\"token class-name\">ChatMessage</span> message<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n            <span class=\"token comment\">// 메시지 수신 처리</span>\n            <span class=\"token class-name\">String</span> userId <span class=\"token operator\">=</span> message<span class=\"token punctuation\">.</span><span class=\"token function\">getUserId</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n            <span class=\"token class-name\">String</span> text <span class=\"token operator\">=</span> message<span class=\"token punctuation\">.</span><span class=\"token function\">getMessage</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n            \n            <span class=\"token comment\">// 응답 메시지 생성</span>\n            <span class=\"token class-name\">ChatMessage</span> response <span class=\"token operator\">=</span> <span class=\"token class-name\">ChatMessage</span><span class=\"token punctuation\">.</span><span class=\"token function\">newBuilder</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n                <span class=\"token punctuation\">.</span><span class=\"token function\">setUserId</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"server\"</span><span class=\"token punctuation\">)</span>\n                <span class=\"token punctuation\">.</span><span class=\"token function\">setMessage</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"Echo: \"</span> <span class=\"token operator\">+</span> text<span class=\"token punctuation\">)</span>\n                <span class=\"token punctuation\">.</span><span class=\"token function\">setTimestamp</span><span class=\"token punctuation\">(</span><span class=\"token class-name\">System</span><span class=\"token punctuation\">.</span><span class=\"token function\">currentTimeMillis</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n                <span class=\"token punctuation\">.</span><span class=\"token function\">build</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n            \n            responseObserver<span class=\"token punctuation\">.</span><span class=\"token function\">onNext</span><span class=\"token punctuation\">(</span>response<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        <span class=\"token punctuation\">}</span>\n        \n        <span class=\"token annotation punctuation\">@Override</span>\n        <span class=\"token keyword\">public</span> <span class=\"token keyword\">void</span> <span class=\"token function\">onError</span><span class=\"token punctuation\">(</span><span class=\"token class-name\">Throwable</span> t<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n            responseObserver<span class=\"token punctuation\">.</span><span class=\"token function\">onError</span><span class=\"token punctuation\">(</span>t<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        <span class=\"token punctuation\">}</span>\n        \n        <span class=\"token annotation punctuation\">@Override</span>\n        <span class=\"token keyword\">public</span> <span class=\"token keyword\">void</span> <span class=\"token function\">onCompleted</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n            responseObserver<span class=\"token punctuation\">.</span><span class=\"token function\">onCompleted</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        <span class=\"token punctuation\">}</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<h2 id=\"4-인터셉터와-미들웨어\" style=\"position:relative;\"><a href=\"#4-%EC%9D%B8%ED%84%B0%EC%85%89%ED%84%B0%EC%99%80-%EB%AF%B8%EB%93%A4%EC%9B%A8%EC%96%B4\" aria-label=\"4 인터셉터와 미들웨어 permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>4. 인터셉터와 미들웨어</h2>\n<h3 id=\"4-1-서버-인터셉터\" style=\"position:relative;\"><a href=\"#4-1-%EC%84%9C%EB%B2%84-%EC%9D%B8%ED%84%B0%EC%85%89%ED%84%B0\" aria-label=\"4 1 서버 인터셉터 permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>4-1. 서버 인터셉터</h3>\n<div class=\"gatsby-highlight\" data-language=\"java\"><pre class=\"language-java\"><code class=\"language-java\"><span class=\"token comment\">// LoggingServerInterceptor.java</span>\n<span class=\"token annotation punctuation\">@GrpcGlobalServerInterceptor</span>\n<span class=\"token keyword\">public</span> <span class=\"token keyword\">class</span> <span class=\"token class-name\">LoggingServerInterceptor</span> <span class=\"token keyword\">implements</span> <span class=\"token class-name\">ServerInterceptor</span> <span class=\"token punctuation\">{</span>\n    \n    <span class=\"token keyword\">private</span> <span class=\"token keyword\">static</span> <span class=\"token keyword\">final</span> <span class=\"token class-name\">Logger</span> logger <span class=\"token operator\">=</span> <span class=\"token class-name\">LoggerFactory</span><span class=\"token punctuation\">.</span><span class=\"token function\">getLogger</span><span class=\"token punctuation\">(</span>\n        <span class=\"token class-name\">LoggingServerInterceptor</span><span class=\"token punctuation\">.</span><span class=\"token keyword\">class</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    \n    <span class=\"token annotation punctuation\">@Override</span>\n    <span class=\"token keyword\">public</span> <span class=\"token generics\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">ReqT</span><span class=\"token punctuation\">,</span> <span class=\"token class-name\">RespT</span><span class=\"token punctuation\">></span></span> <span class=\"token class-name\">ServerCall<span class=\"token punctuation\">.</span>Listener</span><span class=\"token generics\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">ReqT</span><span class=\"token punctuation\">></span></span> <span class=\"token function\">interceptCall</span><span class=\"token punctuation\">(</span>\n        <span class=\"token class-name\">ServerCall</span><span class=\"token generics\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">ReqT</span><span class=\"token punctuation\">,</span> <span class=\"token class-name\">RespT</span><span class=\"token punctuation\">></span></span> call<span class=\"token punctuation\">,</span>\n        <span class=\"token class-name\">Metadata</span> headers<span class=\"token punctuation\">,</span>\n        <span class=\"token class-name\">ServerCallHandler</span><span class=\"token generics\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">ReqT</span><span class=\"token punctuation\">,</span> <span class=\"token class-name\">RespT</span><span class=\"token punctuation\">></span></span> next<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n        \n        <span class=\"token class-name\">String</span> methodName <span class=\"token operator\">=</span> call<span class=\"token punctuation\">.</span><span class=\"token function\">getMethodDescriptor</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">getFullMethodName</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        logger<span class=\"token punctuation\">.</span><span class=\"token function\">info</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"gRPC call: {}\"</span><span class=\"token punctuation\">,</span> methodName<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        \n        <span class=\"token keyword\">return</span> next<span class=\"token punctuation\">.</span><span class=\"token function\">startCall</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">new</span> <span class=\"token class-name\">ForwardingServerCall<span class=\"token punctuation\">.</span>SimpleForwardingServerCall</span><span class=\"token generics\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">ReqT</span><span class=\"token punctuation\">,</span> <span class=\"token class-name\">RespT</span><span class=\"token punctuation\">></span></span><span class=\"token punctuation\">(</span>call<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n            <span class=\"token annotation punctuation\">@Override</span>\n            <span class=\"token keyword\">public</span> <span class=\"token keyword\">void</span> <span class=\"token function\">sendMessage</span><span class=\"token punctuation\">(</span><span class=\"token class-name\">RespT</span> message<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n                logger<span class=\"token punctuation\">.</span><span class=\"token function\">info</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"Response sent for method: {}\"</span><span class=\"token punctuation\">,</span> methodName<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n                <span class=\"token keyword\">super</span><span class=\"token punctuation\">.</span><span class=\"token function\">sendMessage</span><span class=\"token punctuation\">(</span>message<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n            <span class=\"token punctuation\">}</span>\n        <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> headers<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<h3 id=\"4-2-인증-인터셉터\" style=\"position:relative;\"><a href=\"#4-2-%EC%9D%B8%EC%A6%9D-%EC%9D%B8%ED%84%B0%EC%85%89%ED%84%B0\" aria-label=\"4 2 인증 인터셉터 permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>4-2. 인증 인터셉터</h3>\n<div class=\"gatsby-highlight\" data-language=\"java\"><pre class=\"language-java\"><code class=\"language-java\"><span class=\"token comment\">// AuthenticationServerInterceptor.java</span>\n<span class=\"token annotation punctuation\">@GrpcGlobalServerInterceptor</span>\n<span class=\"token keyword\">public</span> <span class=\"token keyword\">class</span> <span class=\"token class-name\">AuthenticationServerInterceptor</span> <span class=\"token keyword\">implements</span> <span class=\"token class-name\">ServerInterceptor</span> <span class=\"token punctuation\">{</span>\n    \n    <span class=\"token annotation punctuation\">@Override</span>\n    <span class=\"token keyword\">public</span> <span class=\"token generics\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">ReqT</span><span class=\"token punctuation\">,</span> <span class=\"token class-name\">RespT</span><span class=\"token punctuation\">></span></span> <span class=\"token class-name\">ServerCall<span class=\"token punctuation\">.</span>Listener</span><span class=\"token generics\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">ReqT</span><span class=\"token punctuation\">></span></span> <span class=\"token function\">interceptCall</span><span class=\"token punctuation\">(</span>\n        <span class=\"token class-name\">ServerCall</span><span class=\"token generics\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">ReqT</span><span class=\"token punctuation\">,</span> <span class=\"token class-name\">RespT</span><span class=\"token punctuation\">></span></span> call<span class=\"token punctuation\">,</span>\n        <span class=\"token class-name\">Metadata</span> headers<span class=\"token punctuation\">,</span>\n        <span class=\"token class-name\">ServerCallHandler</span><span class=\"token generics\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">ReqT</span><span class=\"token punctuation\">,</span> <span class=\"token class-name\">RespT</span><span class=\"token punctuation\">></span></span> next<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n        \n        <span class=\"token class-name\">String</span> token <span class=\"token operator\">=</span> headers<span class=\"token punctuation\">.</span><span class=\"token function\">get</span><span class=\"token punctuation\">(</span><span class=\"token class-name\">Metadata<span class=\"token punctuation\">.</span>Key</span><span class=\"token punctuation\">.</span><span class=\"token function\">of</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"authorization\"</span><span class=\"token punctuation\">,</span> \n            <span class=\"token class-name\">Metadata</span><span class=\"token punctuation\">.</span><span class=\"token constant\">ASCII_STRING_MARSHALLER</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        \n        <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>token <span class=\"token operator\">==</span> <span class=\"token keyword\">null</span> <span class=\"token operator\">||</span> <span class=\"token operator\">!</span><span class=\"token function\">isValidToken</span><span class=\"token punctuation\">(</span>token<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n            call<span class=\"token punctuation\">.</span><span class=\"token function\">close</span><span class=\"token punctuation\">(</span><span class=\"token class-name\">Status</span><span class=\"token punctuation\">.</span><span class=\"token constant\">UNAUTHENTICATED</span>\n                <span class=\"token punctuation\">.</span><span class=\"token function\">withDescription</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"Invalid or missing token\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n                <span class=\"token keyword\">new</span> <span class=\"token class-name\">Metadata</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n            <span class=\"token keyword\">return</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">ServerCall<span class=\"token punctuation\">.</span>Listener</span><span class=\"token generics\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">ReqT</span><span class=\"token punctuation\">></span></span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span>\n        <span class=\"token punctuation\">}</span>\n        \n        <span class=\"token comment\">// 토큰에서 사용자 정보 추출</span>\n        <span class=\"token class-name\">String</span> userId <span class=\"token operator\">=</span> <span class=\"token function\">extractUserId</span><span class=\"token punctuation\">(</span>token<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        <span class=\"token class-name\">Context</span> context <span class=\"token operator\">=</span> <span class=\"token class-name\">Context</span><span class=\"token punctuation\">.</span><span class=\"token function\">current</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n            <span class=\"token punctuation\">.</span><span class=\"token function\">withValue</span><span class=\"token punctuation\">(</span><span class=\"token constant\">USER_ID_KEY</span><span class=\"token punctuation\">,</span> userId<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        \n        <span class=\"token keyword\">return</span> <span class=\"token class-name\">Contexts</span><span class=\"token punctuation\">.</span><span class=\"token function\">interceptCall</span><span class=\"token punctuation\">(</span>context<span class=\"token punctuation\">,</span> call<span class=\"token punctuation\">,</span> headers<span class=\"token punctuation\">,</span> next<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span>\n    \n    <span class=\"token keyword\">private</span> <span class=\"token keyword\">boolean</span> <span class=\"token function\">isValidToken</span><span class=\"token punctuation\">(</span><span class=\"token class-name\">String</span> token<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token comment\">// 토큰 검증 로직</span>\n        <span class=\"token keyword\">return</span> <span class=\"token boolean\">true</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span>\n    \n    <span class=\"token keyword\">private</span> <span class=\"token class-name\">String</span> <span class=\"token function\">extractUserId</span><span class=\"token punctuation\">(</span><span class=\"token class-name\">String</span> token<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token comment\">// 토큰에서 사용자 ID 추출</span>\n        <span class=\"token keyword\">return</span> <span class=\"token string\">\"user123\"</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span>\n    \n    <span class=\"token keyword\">private</span> <span class=\"token keyword\">static</span> <span class=\"token keyword\">final</span> <span class=\"token class-name\">Context<span class=\"token punctuation\">.</span>Key</span><span class=\"token generics\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">String</span><span class=\"token punctuation\">></span></span> <span class=\"token constant\">USER_ID_KEY</span> <span class=\"token operator\">=</span> \n        <span class=\"token class-name\">Context</span><span class=\"token punctuation\">.</span><span class=\"token function\">key</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"userId\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<h3 id=\"4-3-클라이언트-인터셉터\" style=\"position:relative;\"><a href=\"#4-3-%ED%81%B4%EB%9D%BC%EC%9D%B4%EC%96%B8%ED%8A%B8-%EC%9D%B8%ED%84%B0%EC%85%89%ED%84%B0\" aria-label=\"4 3 클라이언트 인터셉터 permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>4-3. 클라이언트 인터셉터</h3>\n<div class=\"gatsby-highlight\" data-language=\"java\"><pre class=\"language-java\"><code class=\"language-java\"><span class=\"token comment\">// LoggingClientInterceptor.java</span>\n<span class=\"token annotation punctuation\">@GrpcGlobalClientInterceptor</span>\n<span class=\"token keyword\">public</span> <span class=\"token keyword\">class</span> <span class=\"token class-name\">LoggingClientInterceptor</span> <span class=\"token keyword\">implements</span> <span class=\"token class-name\">ClientInterceptor</span> <span class=\"token punctuation\">{</span>\n    \n    <span class=\"token keyword\">private</span> <span class=\"token keyword\">static</span> <span class=\"token keyword\">final</span> <span class=\"token class-name\">Logger</span> logger <span class=\"token operator\">=</span> <span class=\"token class-name\">LoggerFactory</span><span class=\"token punctuation\">.</span><span class=\"token function\">getLogger</span><span class=\"token punctuation\">(</span>\n        <span class=\"token class-name\">LoggingClientInterceptor</span><span class=\"token punctuation\">.</span><span class=\"token keyword\">class</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    \n    <span class=\"token annotation punctuation\">@Override</span>\n    <span class=\"token keyword\">public</span> <span class=\"token generics\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">ReqT</span><span class=\"token punctuation\">,</span> <span class=\"token class-name\">RespT</span><span class=\"token punctuation\">></span></span> <span class=\"token class-name\">ClientCall</span><span class=\"token generics\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">ReqT</span><span class=\"token punctuation\">,</span> <span class=\"token class-name\">RespT</span><span class=\"token punctuation\">></span></span> <span class=\"token function\">interceptCall</span><span class=\"token punctuation\">(</span>\n        <span class=\"token class-name\">MethodDescriptor</span><span class=\"token generics\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">ReqT</span><span class=\"token punctuation\">,</span> <span class=\"token class-name\">RespT</span><span class=\"token punctuation\">></span></span> method<span class=\"token punctuation\">,</span>\n        <span class=\"token class-name\">CallOptions</span> callOptions<span class=\"token punctuation\">,</span>\n        <span class=\"token class-name\">Channel</span> next<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n        \n        <span class=\"token keyword\">return</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">ForwardingClientCall<span class=\"token punctuation\">.</span>SimpleForwardingClientCall</span><span class=\"token generics\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">ReqT</span><span class=\"token punctuation\">,</span> <span class=\"token class-name\">RespT</span><span class=\"token punctuation\">></span></span><span class=\"token punctuation\">(</span>\n            next<span class=\"token punctuation\">.</span><span class=\"token function\">newCall</span><span class=\"token punctuation\">(</span>method<span class=\"token punctuation\">,</span> callOptions<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n            \n            <span class=\"token annotation punctuation\">@Override</span>\n            <span class=\"token keyword\">public</span> <span class=\"token keyword\">void</span> <span class=\"token function\">sendMessage</span><span class=\"token punctuation\">(</span><span class=\"token class-name\">ReqT</span> message<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n                logger<span class=\"token punctuation\">.</span><span class=\"token function\">info</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"Request sent to method: {}\"</span><span class=\"token punctuation\">,</span> \n                    method<span class=\"token punctuation\">.</span><span class=\"token function\">getFullMethodName</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n                <span class=\"token keyword\">super</span><span class=\"token punctuation\">.</span><span class=\"token function\">sendMessage</span><span class=\"token punctuation\">(</span>message<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n            <span class=\"token punctuation\">}</span>\n            \n            <span class=\"token annotation punctuation\">@Override</span>\n            <span class=\"token keyword\">public</span> <span class=\"token keyword\">void</span> <span class=\"token function\">start</span><span class=\"token punctuation\">(</span><span class=\"token class-name\">Listener</span><span class=\"token generics\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">RespT</span><span class=\"token punctuation\">></span></span> responseListener<span class=\"token punctuation\">,</span> <span class=\"token class-name\">Metadata</span> headers<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n                <span class=\"token keyword\">super</span><span class=\"token punctuation\">.</span><span class=\"token function\">start</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">new</span> <span class=\"token class-name\">ForwardingClientCallListener<span class=\"token punctuation\">.</span>SimpleForwardingClientCallListener</span><span class=\"token generics\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">RespT</span><span class=\"token punctuation\">></span></span><span class=\"token punctuation\">(</span>\n                    responseListener<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n                    <span class=\"token annotation punctuation\">@Override</span>\n                    <span class=\"token keyword\">public</span> <span class=\"token keyword\">void</span> <span class=\"token function\">onMessage</span><span class=\"token punctuation\">(</span><span class=\"token class-name\">RespT</span> message<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n                        logger<span class=\"token punctuation\">.</span><span class=\"token function\">info</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"Response received from method: {}\"</span><span class=\"token punctuation\">,</span> \n                            method<span class=\"token punctuation\">.</span><span class=\"token function\">getFullMethodName</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n                        <span class=\"token keyword\">super</span><span class=\"token punctuation\">.</span><span class=\"token function\">onMessage</span><span class=\"token punctuation\">(</span>message<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n                    <span class=\"token punctuation\">}</span>\n                <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> headers<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n            <span class=\"token punctuation\">}</span>\n        <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<h2 id=\"5-에러-처리\" style=\"position:relative;\"><a href=\"#5-%EC%97%90%EB%9F%AC-%EC%B2%98%EB%A6%AC\" aria-label=\"5 에러 처리 permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>5. 에러 처리</h2>\n<h3 id=\"5-1-상태-코드와-에러-처리\" style=\"position:relative;\"><a href=\"#5-1-%EC%83%81%ED%83%9C-%EC%BD%94%EB%93%9C%EC%99%80-%EC%97%90%EB%9F%AC-%EC%B2%98%EB%A6%AC\" aria-label=\"5 1 상태 코드와 에러 처리 permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>5-1. 상태 코드와 에러 처리</h3>\n<div class=\"gatsby-highlight\" data-language=\"java\"><pre class=\"language-java\"><code class=\"language-java\"><span class=\"token comment\">// 에러 처리 예시</span>\n<span class=\"token annotation punctuation\">@Override</span>\n<span class=\"token keyword\">public</span> <span class=\"token keyword\">void</span> <span class=\"token function\">getUser</span><span class=\"token punctuation\">(</span><span class=\"token class-name\">GetUserRequest</span> request<span class=\"token punctuation\">,</span>\n                   <span class=\"token class-name\">StreamObserver</span><span class=\"token generics\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">GetUserResponse</span><span class=\"token punctuation\">></span></span> responseObserver<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">try</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token class-name\">Long</span> userId <span class=\"token operator\">=</span> request<span class=\"token punctuation\">.</span><span class=\"token function\">getUserId</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        \n        <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>userId <span class=\"token operator\">&lt;=</span> <span class=\"token number\">0</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n            responseObserver<span class=\"token punctuation\">.</span><span class=\"token function\">onError</span><span class=\"token punctuation\">(</span><span class=\"token class-name\">Status</span><span class=\"token punctuation\">.</span><span class=\"token constant\">INVALID_ARGUMENT</span>\n                <span class=\"token punctuation\">.</span><span class=\"token function\">withDescription</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"User ID must be positive\"</span><span class=\"token punctuation\">)</span>\n                <span class=\"token punctuation\">.</span><span class=\"token function\">asRuntimeException</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n            <span class=\"token keyword\">return</span><span class=\"token punctuation\">;</span>\n        <span class=\"token punctuation\">}</span>\n        \n        <span class=\"token class-name\">UserEntity</span> userEntity <span class=\"token operator\">=</span> userRepository<span class=\"token punctuation\">.</span><span class=\"token function\">findById</span><span class=\"token punctuation\">(</span>userId<span class=\"token punctuation\">)</span>\n            <span class=\"token punctuation\">.</span><span class=\"token function\">orElseThrow</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">-></span> <span class=\"token class-name\">Status</span><span class=\"token punctuation\">.</span><span class=\"token constant\">NOT_FOUND</span>\n                <span class=\"token punctuation\">.</span><span class=\"token function\">withDescription</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"User not found: \"</span> <span class=\"token operator\">+</span> userId<span class=\"token punctuation\">)</span>\n                <span class=\"token punctuation\">.</span><span class=\"token function\">asRuntimeException</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        \n        <span class=\"token comment\">// 성공 처리</span>\n        <span class=\"token class-name\">User</span> user <span class=\"token operator\">=</span> <span class=\"token function\">convertToProto</span><span class=\"token punctuation\">(</span>userEntity<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        <span class=\"token class-name\">GetUserResponse</span> response <span class=\"token operator\">=</span> <span class=\"token class-name\">GetUserResponse</span><span class=\"token punctuation\">.</span><span class=\"token function\">newBuilder</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n            <span class=\"token punctuation\">.</span><span class=\"token function\">setUser</span><span class=\"token punctuation\">(</span>user<span class=\"token punctuation\">)</span>\n            <span class=\"token punctuation\">.</span><span class=\"token function\">build</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        \n        responseObserver<span class=\"token punctuation\">.</span><span class=\"token function\">onNext</span><span class=\"token punctuation\">(</span>response<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        responseObserver<span class=\"token punctuation\">.</span><span class=\"token function\">onCompleted</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        \n    <span class=\"token punctuation\">}</span> <span class=\"token keyword\">catch</span> <span class=\"token punctuation\">(</span><span class=\"token class-name\">StatusRuntimeException</span> e<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n        responseObserver<span class=\"token punctuation\">.</span><span class=\"token function\">onError</span><span class=\"token punctuation\">(</span>e<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span> <span class=\"token keyword\">catch</span> <span class=\"token punctuation\">(</span><span class=\"token class-name\">Exception</span> e<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n        responseObserver<span class=\"token punctuation\">.</span><span class=\"token function\">onError</span><span class=\"token punctuation\">(</span><span class=\"token class-name\">Status</span><span class=\"token punctuation\">.</span><span class=\"token constant\">INTERNAL</span>\n            <span class=\"token punctuation\">.</span><span class=\"token function\">withDescription</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"Internal server error: \"</span> <span class=\"token operator\">+</span> e<span class=\"token punctuation\">.</span><span class=\"token function\">getMessage</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n            <span class=\"token punctuation\">.</span><span class=\"token function\">withCause</span><span class=\"token punctuation\">(</span>e<span class=\"token punctuation\">)</span>\n            <span class=\"token punctuation\">.</span><span class=\"token function\">asRuntimeException</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<h3 id=\"5-2-커스텀-에러-처리\" style=\"position:relative;\"><a href=\"#5-2-%EC%BB%A4%EC%8A%A4%ED%85%80-%EC%97%90%EB%9F%AC-%EC%B2%98%EB%A6%AC\" aria-label=\"5 2 커스텀 에러 처리 permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>5-2. 커스텀 에러 처리</h3>\n<div class=\"gatsby-highlight\" data-language=\"protobuf\"><pre class=\"language-protobuf\"><code class=\"language-protobuf\"><span class=\"token comment\">// error_details.proto</span>\n<span class=\"token keyword\">import</span> <span class=\"token string\">\"google/rpc/error_details.proto\"</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token keyword\">message</span> <span class=\"token class-name\">ErrorDetail</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token builtin\">string</span> field <span class=\"token operator\">=</span> <span class=\"token number\">1</span><span class=\"token punctuation\">;</span>\n  <span class=\"token builtin\">string</span> message <span class=\"token operator\">=</span> <span class=\"token number\">2</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<div class=\"gatsby-highlight\" data-language=\"java\"><pre class=\"language-java\"><code class=\"language-java\"><span class=\"token comment\">// 커스텀 에러 처리</span>\n<span class=\"token keyword\">public</span> <span class=\"token keyword\">void</span> <span class=\"token function\">handleValidationError</span><span class=\"token punctuation\">(</span><span class=\"token class-name\">StreamObserver</span><span class=\"token generics\"><span class=\"token punctuation\">&lt;</span><span class=\"token operator\">?</span><span class=\"token punctuation\">></span></span> responseObserver<span class=\"token punctuation\">,</span>\n                                 <span class=\"token class-name\">List</span><span class=\"token generics\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">ValidationError</span><span class=\"token punctuation\">></span></span> errors<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token class-name\">Status</span> status <span class=\"token operator\">=</span> <span class=\"token class-name\">Status</span><span class=\"token punctuation\">.</span><span class=\"token constant\">INVALID_ARGUMENT</span>\n        <span class=\"token punctuation\">.</span><span class=\"token function\">withDescription</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"Validation failed\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    \n    <span class=\"token class-name\"><span class=\"token namespace\">com<span class=\"token punctuation\">.</span>google<span class=\"token punctuation\">.</span>rpc<span class=\"token punctuation\">.</span></span>Status<span class=\"token punctuation\">.</span>Builder</span> statusBuilder <span class=\"token operator\">=</span> <span class=\"token class-name\"><span class=\"token namespace\">com<span class=\"token punctuation\">.</span>google<span class=\"token punctuation\">.</span>rpc<span class=\"token punctuation\">.</span></span>Status</span><span class=\"token punctuation\">.</span><span class=\"token function\">newBuilder</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n        <span class=\"token punctuation\">.</span><span class=\"token function\">setCode</span><span class=\"token punctuation\">(</span><span class=\"token class-name\">Code</span><span class=\"token punctuation\">.</span><span class=\"token constant\">INVALID_ARGUMENT</span><span class=\"token punctuation\">.</span><span class=\"token function\">getNumber</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n        <span class=\"token punctuation\">.</span><span class=\"token function\">setMessage</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"Validation failed\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    \n    <span class=\"token keyword\">for</span> <span class=\"token punctuation\">(</span><span class=\"token class-name\">ValidationError</span> error <span class=\"token operator\">:</span> errors<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token class-name\">BadRequest<span class=\"token punctuation\">.</span>FieldViolation</span> fieldViolation <span class=\"token operator\">=</span> \n            <span class=\"token class-name\">BadRequest<span class=\"token punctuation\">.</span>FieldViolation</span><span class=\"token punctuation\">.</span><span class=\"token function\">newBuilder</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n                <span class=\"token punctuation\">.</span><span class=\"token function\">setField</span><span class=\"token punctuation\">(</span>error<span class=\"token punctuation\">.</span><span class=\"token function\">getField</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n                <span class=\"token punctuation\">.</span><span class=\"token function\">setDescription</span><span class=\"token punctuation\">(</span>error<span class=\"token punctuation\">.</span><span class=\"token function\">getMessage</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n                <span class=\"token punctuation\">.</span><span class=\"token function\">build</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        \n        <span class=\"token class-name\">BadRequest</span> badRequest <span class=\"token operator\">=</span> <span class=\"token class-name\">BadRequest</span><span class=\"token punctuation\">.</span><span class=\"token function\">newBuilder</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n            <span class=\"token punctuation\">.</span><span class=\"token function\">addFieldViolations</span><span class=\"token punctuation\">(</span>fieldViolation<span class=\"token punctuation\">)</span>\n            <span class=\"token punctuation\">.</span><span class=\"token function\">build</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        \n        statusBuilder<span class=\"token punctuation\">.</span><span class=\"token function\">addDetails</span><span class=\"token punctuation\">(</span><span class=\"token class-name\">Any</span><span class=\"token punctuation\">.</span><span class=\"token function\">pack</span><span class=\"token punctuation\">(</span>badRequest<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span>\n    \n    <span class=\"token class-name\">Metadata</span> metadata <span class=\"token operator\">=</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">Metadata</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    metadata<span class=\"token punctuation\">.</span><span class=\"token function\">put</span><span class=\"token punctuation\">(</span><span class=\"token class-name\">StatusProto</span><span class=\"token punctuation\">.</span><span class=\"token constant\">CODE_KEY</span><span class=\"token punctuation\">,</span> statusBuilder<span class=\"token punctuation\">.</span><span class=\"token function\">build</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    \n    responseObserver<span class=\"token punctuation\">.</span><span class=\"token function\">onError</span><span class=\"token punctuation\">(</span>status<span class=\"token punctuation\">.</span><span class=\"token function\">asRuntimeException</span><span class=\"token punctuation\">(</span>metadata<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<h2 id=\"6-성능-최적화\" style=\"position:relative;\"><a href=\"#6-%EC%84%B1%EB%8A%A5-%EC%B5%9C%EC%A0%81%ED%99%94\" aria-label=\"6 성능 최적화 permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>6. 성능 최적화</h2>\n<h3 id=\"6-1-연결-풀링\" style=\"position:relative;\"><a href=\"#6-1-%EC%97%B0%EA%B2%B0-%ED%92%80%EB%A7%81\" aria-label=\"6 1 연결 풀링 permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>6-1. 연결 풀링</h3>\n<div class=\"gatsby-highlight\" data-language=\"yaml\"><pre class=\"language-yaml\"><code class=\"language-yaml\"><span class=\"token comment\"># application.yml</span>\n<span class=\"token key atrule\">grpc</span><span class=\"token punctuation\">:</span>\n  <span class=\"token key atrule\">client</span><span class=\"token punctuation\">:</span>\n    <span class=\"token key atrule\">user-service</span><span class=\"token punctuation\">:</span>\n      <span class=\"token key atrule\">address</span><span class=\"token punctuation\">:</span> <span class=\"token string\">'static://localhost:9090'</span>\n      <span class=\"token key atrule\">negotiationType</span><span class=\"token punctuation\">:</span> plaintext\n      <span class=\"token key atrule\">enableKeepAlive</span><span class=\"token punctuation\">:</span> <span class=\"token boolean important\">true</span>\n      <span class=\"token key atrule\">keepAliveWithoutCalls</span><span class=\"token punctuation\">:</span> <span class=\"token boolean important\">true</span>\n      <span class=\"token key atrule\">keepAliveTime</span><span class=\"token punctuation\">:</span> 30s\n      <span class=\"token key atrule\">keepAliveTimeout</span><span class=\"token punctuation\">:</span> 5s\n      <span class=\"token key atrule\">maxInboundMessageSize</span><span class=\"token punctuation\">:</span> <span class=\"token number\">4194304</span>  <span class=\"token comment\"># 4MB</span>\n      <span class=\"token key atrule\">maxInboundMetadataSize</span><span class=\"token punctuation\">:</span> <span class=\"token number\">8192</span>     <span class=\"token comment\"># 8KB</span></code></pre></div>\n<h3 id=\"6-2-압축\" style=\"position:relative;\"><a href=\"#6-2-%EC%95%95%EC%B6%95\" aria-label=\"6 2 압축 permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>6-2. 압축</h3>\n<div class=\"gatsby-highlight\" data-language=\"java\"><pre class=\"language-java\"><code class=\"language-java\"><span class=\"token comment\">// 서버에서 압축 활성화</span>\n<span class=\"token annotation punctuation\">@GrpcService</span>\n<span class=\"token keyword\">public</span> <span class=\"token keyword\">class</span> <span class=\"token class-name\">UserServiceImpl</span> <span class=\"token keyword\">extends</span> <span class=\"token class-name\">UserServiceGrpc<span class=\"token punctuation\">.</span>UserServiceImplBase</span> <span class=\"token punctuation\">{</span>\n    \n    <span class=\"token annotation punctuation\">@Override</span>\n    <span class=\"token keyword\">public</span> <span class=\"token keyword\">void</span> <span class=\"token function\">getUser</span><span class=\"token punctuation\">(</span><span class=\"token class-name\">GetUserRequest</span> request<span class=\"token punctuation\">,</span>\n                       <span class=\"token class-name\">StreamObserver</span><span class=\"token generics\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">GetUserResponse</span><span class=\"token punctuation\">></span></span> responseObserver<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token comment\">// gzip 압축 사용</span>\n        call<span class=\"token punctuation\">.</span><span class=\"token function\">setCompression</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"gzip\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        \n        <span class=\"token comment\">// 응답 처리</span>\n    <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token comment\">// 클라이언트에서 압축 요청</span>\n<span class=\"token class-name\">CallOptions</span> callOptions <span class=\"token operator\">=</span> <span class=\"token class-name\">CallOptions</span><span class=\"token punctuation\">.</span><span class=\"token constant\">DEFAULT</span>\n    <span class=\"token punctuation\">.</span><span class=\"token function\">withCompression</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"gzip\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token class-name\">UserServiceGrpc<span class=\"token punctuation\">.</span>UserServiceBlockingStub</span> stub <span class=\"token operator\">=</span> \n    <span class=\"token class-name\">UserServiceGrpc</span><span class=\"token punctuation\">.</span><span class=\"token function\">newBlockingStub</span><span class=\"token punctuation\">(</span>channel<span class=\"token punctuation\">)</span>\n        <span class=\"token punctuation\">.</span><span class=\"token function\">withCallOptions</span><span class=\"token punctuation\">(</span>callOptions<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre></div>\n<h3 id=\"6-3-타임아웃-설정\" style=\"position:relative;\"><a href=\"#6-3-%ED%83%80%EC%9E%84%EC%95%84%EC%9B%83-%EC%84%A4%EC%A0%95\" aria-label=\"6 3 타임아웃 설정 permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>6-3. 타임아웃 설정</h3>\n<div class=\"gatsby-highlight\" data-language=\"java\"><pre class=\"language-java\"><code class=\"language-java\"><span class=\"token comment\">// 타임아웃 설정</span>\n<span class=\"token class-name\">CallOptions</span> callOptions <span class=\"token operator\">=</span> <span class=\"token class-name\">CallOptions</span><span class=\"token punctuation\">.</span><span class=\"token constant\">DEFAULT</span>\n    <span class=\"token punctuation\">.</span><span class=\"token function\">withDeadlineAfter</span><span class=\"token punctuation\">(</span><span class=\"token number\">5</span><span class=\"token punctuation\">,</span> <span class=\"token class-name\">TimeUnit</span><span class=\"token punctuation\">.</span><span class=\"token constant\">SECONDS</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token class-name\">UserServiceGrpc<span class=\"token punctuation\">.</span>UserServiceBlockingStub</span> stub <span class=\"token operator\">=</span> \n    <span class=\"token class-name\">UserServiceGrpc</span><span class=\"token punctuation\">.</span><span class=\"token function\">newBlockingStub</span><span class=\"token punctuation\">(</span>channel<span class=\"token punctuation\">)</span>\n        <span class=\"token punctuation\">.</span><span class=\"token function\">withCallOptions</span><span class=\"token punctuation\">(</span>callOptions<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token keyword\">try</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token class-name\">GetUserResponse</span> response <span class=\"token operator\">=</span> stub<span class=\"token punctuation\">.</span><span class=\"token function\">getUser</span><span class=\"token punctuation\">(</span>request<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span> <span class=\"token keyword\">catch</span> <span class=\"token punctuation\">(</span><span class=\"token class-name\">StatusRuntimeException</span> e<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>e<span class=\"token punctuation\">.</span><span class=\"token function\">getStatus</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">getCode</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">==</span> <span class=\"token class-name\">Status<span class=\"token punctuation\">.</span>Code</span><span class=\"token punctuation\">.</span><span class=\"token constant\">DEADLINE_EXCEEDED</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token comment\">// 타임아웃 처리</span>\n    <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<h2 id=\"7-grpc-web-브라우저-지원\" style=\"position:relative;\"><a href=\"#7-grpc-web-%EB%B8%8C%EB%9D%BC%EC%9A%B0%EC%A0%80-%EC%A7%80%EC%9B%90\" aria-label=\"7 grpc web 브라우저 지원 permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>7. gRPC-Web (브라우저 지원)</h2>\n<h3 id=\"7-1-grpc-web-설정\" style=\"position:relative;\"><a href=\"#7-1-grpc-web-%EC%84%A4%EC%A0%95\" aria-label=\"7 1 grpc web 설정 permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>7-1. gRPC-Web 설정</h3>\n<div class=\"gatsby-highlight\" data-language=\"xml\"><pre class=\"language-xml\"><code class=\"language-xml\"><span class=\"token comment\">&lt;!-- pom.xml --></span>\n<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>dependency</span><span class=\"token punctuation\">></span></span>\n    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>groupId</span><span class=\"token punctuation\">></span></span>io.grpc<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>groupId</span><span class=\"token punctuation\">></span></span>\n    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>artifactId</span><span class=\"token punctuation\">></span></span>grpc-web<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>artifactId</span><span class=\"token punctuation\">></span></span>\n    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>version</span><span class=\"token punctuation\">></span></span>1.4.2<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>version</span><span class=\"token punctuation\">></span></span>\n<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>dependency</span><span class=\"token punctuation\">></span></span></code></pre></div>\n<div class=\"gatsby-highlight\" data-language=\"java\"><pre class=\"language-java\"><code class=\"language-java\"><span class=\"token comment\">// gRPC-Web 서버 설정</span>\n<span class=\"token annotation punctuation\">@Configuration</span>\n<span class=\"token keyword\">public</span> <span class=\"token keyword\">class</span> <span class=\"token class-name\">GrpcWebConfig</span> <span class=\"token punctuation\">{</span>\n    \n    <span class=\"token annotation punctuation\">@Bean</span>\n    <span class=\"token keyword\">public</span> <span class=\"token class-name\">ServletRegistrationBean</span><span class=\"token generics\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">GrpcWebServlet</span><span class=\"token punctuation\">></span></span> <span class=\"token function\">grpcWebServlet</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token class-name\">GrpcWebServlet</span> servlet <span class=\"token operator\">=</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">GrpcWebServlet</span><span class=\"token punctuation\">(</span>\n            <span class=\"token class-name\">Arrays</span><span class=\"token punctuation\">.</span><span class=\"token function\">asList</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">new</span> <span class=\"token class-name\">UserServiceImpl</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        \n        <span class=\"token class-name\">ServletRegistrationBean</span><span class=\"token generics\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">GrpcWebServlet</span><span class=\"token punctuation\">></span></span> registration <span class=\"token operator\">=</span> \n            <span class=\"token keyword\">new</span> <span class=\"token class-name\">ServletRegistrationBean</span><span class=\"token generics\"><span class=\"token punctuation\">&lt;</span><span class=\"token punctuation\">></span></span><span class=\"token punctuation\">(</span>servlet<span class=\"token punctuation\">,</span> <span class=\"token string\">\"/grpc/*\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        registration<span class=\"token punctuation\">.</span><span class=\"token function\">setName</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"GrpcWebServlet\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        <span class=\"token keyword\">return</span> registration<span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<h3 id=\"7-2-javascript-클라이언트\" style=\"position:relative;\"><a href=\"#7-2-javascript-%ED%81%B4%EB%9D%BC%EC%9D%B4%EC%96%B8%ED%8A%B8\" aria-label=\"7 2 javascript 클라이언트 permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>7-2. JavaScript 클라이언트</h3>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token comment\">// gRPC-Web 클라이언트</span>\n<span class=\"token keyword\">const</span> <span class=\"token punctuation\">{</span> UserServiceClient <span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> <span class=\"token function\">require</span><span class=\"token punctuation\">(</span><span class=\"token string\">'./user_grpc_web_pb'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">const</span> <span class=\"token punctuation\">{</span> GetUserRequest <span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> <span class=\"token function\">require</span><span class=\"token punctuation\">(</span><span class=\"token string\">'./user_pb'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token keyword\">const</span> client <span class=\"token operator\">=</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">UserServiceClient</span><span class=\"token punctuation\">(</span><span class=\"token string\">'http://localhost:8080'</span><span class=\"token punctuation\">,</span> <span class=\"token keyword\">null</span><span class=\"token punctuation\">,</span> <span class=\"token keyword\">null</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token keyword\">const</span> request <span class=\"token operator\">=</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">GetUserRequest</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\nrequest<span class=\"token punctuation\">.</span><span class=\"token function\">setUserId</span><span class=\"token punctuation\">(</span><span class=\"token number\">123</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\nclient<span class=\"token punctuation\">.</span><span class=\"token function\">getUser</span><span class=\"token punctuation\">(</span>request<span class=\"token punctuation\">,</span> <span class=\"token punctuation\">{</span><span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">err<span class=\"token punctuation\">,</span> response</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>err<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    console<span class=\"token punctuation\">.</span><span class=\"token function\">error</span><span class=\"token punctuation\">(</span><span class=\"token string\">'Error:'</span><span class=\"token punctuation\">,</span> err<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">return</span><span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span>\n  console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token string\">'User:'</span><span class=\"token punctuation\">,</span> response<span class=\"token punctuation\">.</span><span class=\"token function\">getUser</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">toObject</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre></div>\n<h2 id=\"8-모니터링과-로깅\" style=\"position:relative;\"><a href=\"#8-%EB%AA%A8%EB%8B%88%ED%84%B0%EB%A7%81%EA%B3%BC-%EB%A1%9C%EA%B9%85\" aria-label=\"8 모니터링과 로깅 permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>8. 모니터링과 로깅</h2>\n<h3 id=\"8-1-메트릭-수집\" style=\"position:relative;\"><a href=\"#8-1-%EB%A9%94%ED%8A%B8%EB%A6%AD-%EC%88%98%EC%A7%91\" aria-label=\"8 1 메트릭 수집 permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>8-1. 메트릭 수집</h3>\n<div class=\"gatsby-highlight\" data-language=\"java\"><pre class=\"language-java\"><code class=\"language-java\"><span class=\"token comment\">// Prometheus 메트릭 수집</span>\n<span class=\"token annotation punctuation\">@GrpcGlobalServerInterceptor</span>\n<span class=\"token keyword\">public</span> <span class=\"token keyword\">class</span> <span class=\"token class-name\">MetricsServerInterceptor</span> <span class=\"token keyword\">implements</span> <span class=\"token class-name\">ServerInterceptor</span> <span class=\"token punctuation\">{</span>\n    \n    <span class=\"token keyword\">private</span> <span class=\"token keyword\">final</span> <span class=\"token class-name\">Counter</span> requestCounter<span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">private</span> <span class=\"token keyword\">final</span> <span class=\"token class-name\">Timer</span> requestTimer<span class=\"token punctuation\">;</span>\n    \n    <span class=\"token keyword\">public</span> <span class=\"token class-name\">MetricsServerInterceptor</span><span class=\"token punctuation\">(</span><span class=\"token class-name\">MeterRegistry</span> meterRegistry<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>requestCounter <span class=\"token operator\">=</span> <span class=\"token class-name\">Counter</span><span class=\"token punctuation\">.</span><span class=\"token function\">builder</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"grpc.server.requests\"</span><span class=\"token punctuation\">)</span>\n            <span class=\"token punctuation\">.</span><span class=\"token function\">description</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"gRPC server requests\"</span><span class=\"token punctuation\">)</span>\n            <span class=\"token punctuation\">.</span><span class=\"token function\">register</span><span class=\"token punctuation\">(</span>meterRegistry<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        \n        <span class=\"token keyword\">this</span><span class=\"token punctuation\">.</span>requestTimer <span class=\"token operator\">=</span> <span class=\"token class-name\">Timer</span><span class=\"token punctuation\">.</span><span class=\"token function\">builder</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"grpc.server.duration\"</span><span class=\"token punctuation\">)</span>\n            <span class=\"token punctuation\">.</span><span class=\"token function\">description</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"gRPC server request duration\"</span><span class=\"token punctuation\">)</span>\n            <span class=\"token punctuation\">.</span><span class=\"token function\">register</span><span class=\"token punctuation\">(</span>meterRegistry<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span>\n    \n    <span class=\"token annotation punctuation\">@Override</span>\n    <span class=\"token keyword\">public</span> <span class=\"token generics\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">ReqT</span><span class=\"token punctuation\">,</span> <span class=\"token class-name\">RespT</span><span class=\"token punctuation\">></span></span> <span class=\"token class-name\">ServerCall<span class=\"token punctuation\">.</span>Listener</span><span class=\"token generics\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">ReqT</span><span class=\"token punctuation\">></span></span> <span class=\"token function\">interceptCall</span><span class=\"token punctuation\">(</span>\n        <span class=\"token class-name\">ServerCall</span><span class=\"token generics\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">ReqT</span><span class=\"token punctuation\">,</span> <span class=\"token class-name\">RespT</span><span class=\"token punctuation\">></span></span> call<span class=\"token punctuation\">,</span>\n        <span class=\"token class-name\">Metadata</span> headers<span class=\"token punctuation\">,</span>\n        <span class=\"token class-name\">ServerCallHandler</span><span class=\"token generics\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">ReqT</span><span class=\"token punctuation\">,</span> <span class=\"token class-name\">RespT</span><span class=\"token punctuation\">></span></span> next<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n        \n        <span class=\"token class-name\">String</span> methodName <span class=\"token operator\">=</span> call<span class=\"token punctuation\">.</span><span class=\"token function\">getMethodDescriptor</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">getFullMethodName</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        <span class=\"token class-name\">Timer<span class=\"token punctuation\">.</span>Sample</span> sample <span class=\"token operator\">=</span> <span class=\"token class-name\">Timer</span><span class=\"token punctuation\">.</span><span class=\"token function\">start</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        \n        <span class=\"token keyword\">return</span> next<span class=\"token punctuation\">.</span><span class=\"token function\">startCall</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">new</span> <span class=\"token class-name\">ForwardingServerCall<span class=\"token punctuation\">.</span>SimpleForwardingServerCall</span><span class=\"token generics\"><span class=\"token punctuation\">&lt;</span><span class=\"token class-name\">ReqT</span><span class=\"token punctuation\">,</span> <span class=\"token class-name\">RespT</span><span class=\"token punctuation\">></span></span><span class=\"token punctuation\">(</span>call<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n            <span class=\"token annotation punctuation\">@Override</span>\n            <span class=\"token keyword\">public</span> <span class=\"token keyword\">void</span> <span class=\"token function\">close</span><span class=\"token punctuation\">(</span><span class=\"token class-name\">Status</span> status<span class=\"token punctuation\">,</span> <span class=\"token class-name\">Metadata</span> trailers<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n                requestCounter<span class=\"token punctuation\">.</span><span class=\"token function\">increment</span><span class=\"token punctuation\">(</span>\n                    <span class=\"token class-name\">Tags</span><span class=\"token punctuation\">.</span><span class=\"token function\">of</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"method\"</span><span class=\"token punctuation\">,</span> methodName<span class=\"token punctuation\">,</span> <span class=\"token string\">\"status\"</span><span class=\"token punctuation\">,</span> status<span class=\"token punctuation\">.</span><span class=\"token function\">getCode</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">name</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n                sample<span class=\"token punctuation\">.</span><span class=\"token function\">stop</span><span class=\"token punctuation\">(</span>requestTimer<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n                <span class=\"token keyword\">super</span><span class=\"token punctuation\">.</span><span class=\"token function\">close</span><span class=\"token punctuation\">(</span>status<span class=\"token punctuation\">,</span> trailers<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n            <span class=\"token punctuation\">}</span>\n        <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> headers<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<h2 id=\"9-보안\" style=\"position:relative;\"><a href=\"#9-%EB%B3%B4%EC%95%88\" aria-label=\"9 보안 permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>9. 보안</h2>\n<h3 id=\"9-1-tlsssl-설정\" style=\"position:relative;\"><a href=\"#9-1-tlsssl-%EC%84%A4%EC%A0%95\" aria-label=\"9 1 tlsssl 설정 permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>9-1. TLS/SSL 설정</h3>\n<div class=\"gatsby-highlight\" data-language=\"yaml\"><pre class=\"language-yaml\"><code class=\"language-yaml\"><span class=\"token comment\"># application.yml</span>\n<span class=\"token key atrule\">grpc</span><span class=\"token punctuation\">:</span>\n  <span class=\"token key atrule\">server</span><span class=\"token punctuation\">:</span>\n    <span class=\"token key atrule\">port</span><span class=\"token punctuation\">:</span> <span class=\"token number\">9090</span>\n    <span class=\"token key atrule\">security</span><span class=\"token punctuation\">:</span>\n      <span class=\"token key atrule\">enabled</span><span class=\"token punctuation\">:</span> <span class=\"token boolean important\">true</span>\n      <span class=\"token key atrule\">certificateChain</span><span class=\"token punctuation\">:</span> classpath<span class=\"token punctuation\">:</span>server.crt\n      <span class=\"token key atrule\">privateKey</span><span class=\"token punctuation\">:</span> classpath<span class=\"token punctuation\">:</span>server.key\n  <span class=\"token key atrule\">client</span><span class=\"token punctuation\">:</span>\n    <span class=\"token key atrule\">user-service</span><span class=\"token punctuation\">:</span>\n      <span class=\"token key atrule\">address</span><span class=\"token punctuation\">:</span> <span class=\"token string\">'static://localhost:9090'</span>\n      <span class=\"token key atrule\">negotiationType</span><span class=\"token punctuation\">:</span> tls\n      <span class=\"token key atrule\">trustCertCollection</span><span class=\"token punctuation\">:</span> classpath<span class=\"token punctuation\">:</span>ca.crt</code></pre></div>\n<h3 id=\"9-2-mtls-mutual-tls\" style=\"position:relative;\"><a href=\"#9-2-mtls-mutual-tls\" aria-label=\"9 2 mtls mutual tls permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>9-2. mTLS (Mutual TLS)</h3>\n<div class=\"gatsby-highlight\" data-language=\"yaml\"><pre class=\"language-yaml\"><code class=\"language-yaml\"><span class=\"token comment\"># application.yml</span>\n<span class=\"token key atrule\">grpc</span><span class=\"token punctuation\">:</span>\n  <span class=\"token key atrule\">server</span><span class=\"token punctuation\">:</span>\n    <span class=\"token key atrule\">security</span><span class=\"token punctuation\">:</span>\n      <span class=\"token key atrule\">enabled</span><span class=\"token punctuation\">:</span> <span class=\"token boolean important\">true</span>\n      <span class=\"token key atrule\">certificateChain</span><span class=\"token punctuation\">:</span> classpath<span class=\"token punctuation\">:</span>server.crt\n      <span class=\"token key atrule\">privateKey</span><span class=\"token punctuation\">:</span> classpath<span class=\"token punctuation\">:</span>server.key\n      <span class=\"token key atrule\">trustCertCollection</span><span class=\"token punctuation\">:</span> classpath<span class=\"token punctuation\">:</span>ca.crt\n      <span class=\"token key atrule\">clientAuth</span><span class=\"token punctuation\">:</span> REQUIRE</code></pre></div>\n<h2 id=\"10-실전-패턴\" style=\"position:relative;\"><a href=\"#10-%EC%8B%A4%EC%A0%84-%ED%8C%A8%ED%84%B4\" aria-label=\"10 실전 패턴 permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>10. 실전 패턴</h2>\n<h3 id=\"10-1-재시도-패턴\" style=\"position:relative;\"><a href=\"#10-1-%EC%9E%AC%EC%8B%9C%EB%8F%84-%ED%8C%A8%ED%84%B4\" aria-label=\"10 1 재시도 패턴 permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>10-1. 재시도 패턴</h3>\n<div class=\"gatsby-highlight\" data-language=\"java\"><pre class=\"language-java\"><code class=\"language-java\"><span class=\"token comment\">// 재시도 로직</span>\n<span class=\"token keyword\">public</span> <span class=\"token class-name\">User</span> <span class=\"token function\">getUserWithRetry</span><span class=\"token punctuation\">(</span><span class=\"token class-name\">Long</span> userId<span class=\"token punctuation\">,</span> <span class=\"token keyword\">int</span> maxRetries<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">int</span> attempts <span class=\"token operator\">=</span> <span class=\"token number\">0</span><span class=\"token punctuation\">;</span>\n    \n    <span class=\"token keyword\">while</span> <span class=\"token punctuation\">(</span>attempts <span class=\"token operator\">&lt;</span> maxRetries<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token keyword\">try</span> <span class=\"token punctuation\">{</span>\n            <span class=\"token class-name\">GetUserRequest</span> request <span class=\"token operator\">=</span> <span class=\"token class-name\">GetUserRequest</span><span class=\"token punctuation\">.</span><span class=\"token function\">newBuilder</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n                <span class=\"token punctuation\">.</span><span class=\"token function\">setUserId</span><span class=\"token punctuation\">(</span>userId<span class=\"token punctuation\">)</span>\n                <span class=\"token punctuation\">.</span><span class=\"token function\">build</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n            \n            <span class=\"token keyword\">return</span> blockingStub<span class=\"token punctuation\">.</span><span class=\"token function\">getUser</span><span class=\"token punctuation\">(</span>request<span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">getUser</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n            \n        <span class=\"token punctuation\">}</span> <span class=\"token keyword\">catch</span> <span class=\"token punctuation\">(</span><span class=\"token class-name\">StatusRuntimeException</span> e<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n            attempts<span class=\"token operator\">++</span><span class=\"token punctuation\">;</span>\n            \n            <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>e<span class=\"token punctuation\">.</span><span class=\"token function\">getStatus</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">getCode</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">==</span> <span class=\"token class-name\">Status<span class=\"token punctuation\">.</span>Code</span><span class=\"token punctuation\">.</span><span class=\"token constant\">UNAVAILABLE</span> <span class=\"token operator\">&amp;&amp;</span> \n                attempts <span class=\"token operator\">&lt;</span> maxRetries<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n                <span class=\"token comment\">// 지수 백오프</span>\n                <span class=\"token keyword\">long</span> delay <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token keyword\">long</span><span class=\"token punctuation\">)</span> <span class=\"token class-name\">Math</span><span class=\"token punctuation\">.</span><span class=\"token function\">pow</span><span class=\"token punctuation\">(</span><span class=\"token number\">2</span><span class=\"token punctuation\">,</span> attempts<span class=\"token punctuation\">)</span> <span class=\"token operator\">*</span> <span class=\"token number\">1000</span><span class=\"token punctuation\">;</span>\n                <span class=\"token keyword\">try</span> <span class=\"token punctuation\">{</span>\n                    <span class=\"token class-name\">Thread</span><span class=\"token punctuation\">.</span><span class=\"token function\">sleep</span><span class=\"token punctuation\">(</span>delay<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n                <span class=\"token punctuation\">}</span> <span class=\"token keyword\">catch</span> <span class=\"token punctuation\">(</span><span class=\"token class-name\">InterruptedException</span> ie<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n                    <span class=\"token class-name\">Thread</span><span class=\"token punctuation\">.</span><span class=\"token function\">currentThread</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">interrupt</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n                    <span class=\"token keyword\">throw</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">RuntimeException</span><span class=\"token punctuation\">(</span>ie<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n                <span class=\"token punctuation\">}</span>\n            <span class=\"token punctuation\">}</span> <span class=\"token keyword\">else</span> <span class=\"token punctuation\">{</span>\n                <span class=\"token keyword\">throw</span> e<span class=\"token punctuation\">;</span>\n            <span class=\"token punctuation\">}</span>\n        <span class=\"token punctuation\">}</span>\n    <span class=\"token punctuation\">}</span>\n    \n    <span class=\"token keyword\">throw</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">RuntimeException</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"Max retries exceeded\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<h3 id=\"10-2-서킷-브레이커-패턴\" style=\"position:relative;\"><a href=\"#10-2-%EC%84%9C%ED%82%B7-%EB%B8%8C%EB%A0%88%EC%9D%B4%EC%BB%A4-%ED%8C%A8%ED%84%B4\" aria-label=\"10 2 서킷 브레이커 패턴 permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>10-2. 서킷 브레이커 패턴</h3>\n<div class=\"gatsby-highlight\" data-language=\"java\"><pre class=\"language-java\"><code class=\"language-java\"><span class=\"token comment\">// Resilience4j와 통합</span>\n<span class=\"token annotation punctuation\">@Service</span>\n<span class=\"token keyword\">public</span> <span class=\"token keyword\">class</span> <span class=\"token class-name\">UserServiceClient</span> <span class=\"token punctuation\">{</span>\n    \n    <span class=\"token annotation punctuation\">@GrpcClient</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"user-service\"</span><span class=\"token punctuation\">)</span>\n    <span class=\"token keyword\">private</span> <span class=\"token class-name\">UserServiceGrpc<span class=\"token punctuation\">.</span>UserServiceBlockingStub</span> blockingStub<span class=\"token punctuation\">;</span>\n    \n    <span class=\"token annotation punctuation\">@CircuitBreaker</span><span class=\"token punctuation\">(</span>name <span class=\"token operator\">=</span> <span class=\"token string\">\"userService\"</span><span class=\"token punctuation\">,</span> fallbackMethod <span class=\"token operator\">=</span> <span class=\"token string\">\"getUserFallback\"</span><span class=\"token punctuation\">)</span>\n    <span class=\"token keyword\">public</span> <span class=\"token class-name\">User</span> <span class=\"token function\">getUser</span><span class=\"token punctuation\">(</span><span class=\"token class-name\">Long</span> userId<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token class-name\">GetUserRequest</span> request <span class=\"token operator\">=</span> <span class=\"token class-name\">GetUserRequest</span><span class=\"token punctuation\">.</span><span class=\"token function\">newBuilder</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n            <span class=\"token punctuation\">.</span><span class=\"token function\">setUserId</span><span class=\"token punctuation\">(</span>userId<span class=\"token punctuation\">)</span>\n            <span class=\"token punctuation\">.</span><span class=\"token function\">build</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        \n        <span class=\"token keyword\">return</span> blockingStub<span class=\"token punctuation\">.</span><span class=\"token function\">getUser</span><span class=\"token punctuation\">(</span>request<span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">getUser</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span>\n    \n    <span class=\"token keyword\">private</span> <span class=\"token class-name\">User</span> <span class=\"token function\">getUserFallback</span><span class=\"token punctuation\">(</span><span class=\"token class-name\">Long</span> userId<span class=\"token punctuation\">,</span> <span class=\"token class-name\">Exception</span> e<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token comment\">// 폴백 로직</span>\n        <span class=\"token keyword\">return</span> <span class=\"token class-name\">User</span><span class=\"token punctuation\">.</span><span class=\"token function\">newBuilder</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n            <span class=\"token punctuation\">.</span><span class=\"token function\">setId</span><span class=\"token punctuation\">(</span>userId<span class=\"token punctuation\">)</span>\n            <span class=\"token punctuation\">.</span><span class=\"token function\">setName</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"Unknown\"</span><span class=\"token punctuation\">)</span>\n            <span class=\"token punctuation\">.</span><span class=\"token function\">setEmail</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"unknown@example.com\"</span><span class=\"token punctuation\">)</span>\n            <span class=\"token punctuation\">.</span><span class=\"token function\">build</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<h2 id=\"11-결론\" style=\"position:relative;\"><a href=\"#11-%EA%B2%B0%EB%A1%A0\" aria-label=\"11 결론 permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>11. 결론</h2>\n<p>gRPC는 마이크로서비스 간 고성능 통신을 위한 강력한 도구다. 이 글에서 다룬 내용:</p>\n<ol>\n<li><strong>기본 개념</strong>: Protocol Buffers, gRPC 아키텍처</li>\n<li><strong>Spring Boot 통합</strong>: 서버/클라이언트 구현</li>\n<li><strong>스트리밍</strong>: 단방향, 양방향 스트리밍</li>\n<li><strong>인터셉터</strong>: 로깅, 인증, 모니터링</li>\n<li><strong>에러 처리</strong>: 상태 코드, 커스텀 에러</li>\n<li><strong>성능 최적화</strong>: 연결 풀링, 압축, 타임아웃</li>\n<li><strong>gRPC-Web</strong>: 브라우저 지원</li>\n<li><strong>보안</strong>: TLS/SSL, mTLS</li>\n<li><strong>실전 패턴</strong>: 재시도, 서킷 브레이커</li>\n</ol>\n<p>이러한 기능들을 조합하면 확장 가능하고 견고한 마이크로서비스 통신 시스템을 구축할 수 있다.</p>\n<h2 id=\"참고-자료\" style=\"position:relative;\"><a href=\"#%EC%B0%B8%EA%B3%A0-%EC%9E%90%EB%A3%8C\" aria-label=\"참고 자료 permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>참고 자료</h2>\n<ul>\n<li><a href=\"https://grpc.io/docs/\">gRPC 공식 문서</a></li>\n<li><a href=\"https://protobuf.dev/\">Protocol Buffers 가이드</a></li>\n<li><a href=\"https://github.com/yidongnan/grpc-spring-boot-starter\">Spring Boot gRPC 스타터</a></li>\n<li><a href=\"https://github.com/grpc/grpc-java\">gRPC Java 예제</a></li>\n</ul>","tableOfContents":"<ul>\n<li>\n<p><a href=\"/etc/gRPC-%EC%99%84%EC%A0%84%EC%A0%95%EB%B3%B5-%EA%B3%A0%EC%84%B1%EB%8A%A5-%EB%A7%88%EC%9D%B4%ED%81%AC%EB%A1%9C%EC%84%9C%EB%B9%84%EC%8A%A4-%ED%86%B5%EC%8B%A0%EC%9D%98-%EC%83%88%EB%A1%9C%EC%9A%B4-%ED%8C%A8%EB%9F%AC%EB%8B%A4%EC%9E%84/#grpc-%EC%99%84%EC%A0%84%EC%A0%95%EB%B3%B5---%EA%B3%A0%EC%84%B1%EB%8A%A5-%EB%A7%88%EC%9D%B4%ED%81%AC%EB%A1%9C%EC%84%9C%EB%B9%84%EC%8A%A4-%ED%86%B5%EC%8B%A0%EC%9D%98-%EC%83%88%EB%A1%9C%EC%9A%B4-%ED%8C%A8%EB%9F%AC%EB%8B%A4%EC%9E%84\">gRPC 완전정복 - 고성능 마이크로서비스 통신의 새로운 패러다임</a></p>\n<ul>\n<li>\n<p><a href=\"/etc/gRPC-%EC%99%84%EC%A0%84%EC%A0%95%EB%B3%B5-%EA%B3%A0%EC%84%B1%EB%8A%A5-%EB%A7%88%EC%9D%B4%ED%81%AC%EB%A1%9C%EC%84%9C%EB%B9%84%EC%8A%A4-%ED%86%B5%EC%8B%A0%EC%9D%98-%EC%83%88%EB%A1%9C%EC%9A%B4-%ED%8C%A8%EB%9F%AC%EB%8B%A4%EC%9E%84/#1-grpc-%EA%B0%9C%EC%9A%94%EC%99%80-%EC%8B%9C%EC%9E%91%ED%95%98%EA%B8%B0\">1. gRPC 개요와 시작하기</a></p>\n<ul>\n<li><a href=\"/etc/gRPC-%EC%99%84%EC%A0%84%EC%A0%95%EB%B3%B5-%EA%B3%A0%EC%84%B1%EB%8A%A5-%EB%A7%88%EC%9D%B4%ED%81%AC%EB%A1%9C%EC%84%9C%EB%B9%84%EC%8A%A4-%ED%86%B5%EC%8B%A0%EC%9D%98-%EC%83%88%EB%A1%9C%EC%9A%B4-%ED%8C%A8%EB%9F%AC%EB%8B%A4%EC%9E%84/#1-1-grpc%EC%9D%98-%ED%8A%B9%EC%A7%95\">1-1. gRPC의 특징</a></li>\n<li><a href=\"/etc/gRPC-%EC%99%84%EC%A0%84%EC%A0%95%EB%B3%B5-%EA%B3%A0%EC%84%B1%EB%8A%A5-%EB%A7%88%EC%9D%B4%ED%81%AC%EB%A1%9C%EC%84%9C%EB%B9%84%EC%8A%A4-%ED%86%B5%EC%8B%A0%EC%9D%98-%EC%83%88%EB%A1%9C%EC%9A%B4-%ED%8C%A8%EB%9F%AC%EB%8B%A4%EC%9E%84/#1-2-rest-api-vs-grpc\">1-2. REST API vs gRPC</a></li>\n<li><a href=\"/etc/gRPC-%EC%99%84%EC%A0%84%EC%A0%95%EB%B3%B5-%EA%B3%A0%EC%84%B1%EB%8A%A5-%EB%A7%88%EC%9D%B4%ED%81%AC%EB%A1%9C%EC%84%9C%EB%B9%84%EC%8A%A4-%ED%86%B5%EC%8B%A0%EC%9D%98-%EC%83%88%EB%A1%9C%EC%9A%B4-%ED%8C%A8%EB%9F%AC%EB%8B%A4%EC%9E%84/#1-3-protocol-buffers-%EA%B8%B0%EB%B3%B8\">1-3. Protocol Buffers 기본</a></li>\n</ul>\n</li>\n<li>\n<p><a href=\"/etc/gRPC-%EC%99%84%EC%A0%84%EC%A0%95%EB%B3%B5-%EA%B3%A0%EC%84%B1%EB%8A%A5-%EB%A7%88%EC%9D%B4%ED%81%AC%EB%A1%9C%EC%84%9C%EB%B9%84%EC%8A%A4-%ED%86%B5%EC%8B%A0%EC%9D%98-%EC%83%88%EB%A1%9C%EC%9A%B4-%ED%8C%A8%EB%9F%AC%EB%8B%A4%EC%9E%84/#2-spring-boot%EC%97%90%EC%84%9C-grpc-%EA%B5%AC%ED%98%84\">2. Spring Boot에서 gRPC 구현</a></p>\n<ul>\n<li><a href=\"/etc/gRPC-%EC%99%84%EC%A0%84%EC%A0%95%EB%B3%B5-%EA%B3%A0%EC%84%B1%EB%8A%A5-%EB%A7%88%EC%9D%B4%ED%81%AC%EB%A1%9C%EC%84%9C%EB%B9%84%EC%8A%A4-%ED%86%B5%EC%8B%A0%EC%9D%98-%EC%83%88%EB%A1%9C%EC%9A%B4-%ED%8C%A8%EB%9F%AC%EB%8B%A4%EC%9E%84/#2-1-%EC%9D%98%EC%A1%B4%EC%84%B1-%EC%84%A4%EC%A0%95\">2-1. 의존성 설정</a></li>\n<li><a href=\"/etc/gRPC-%EC%99%84%EC%A0%84%EC%A0%95%EB%B3%B5-%EA%B3%A0%EC%84%B1%EB%8A%A5-%EB%A7%88%EC%9D%B4%ED%81%AC%EB%A1%9C%EC%84%9C%EB%B9%84%EC%8A%A4-%ED%86%B5%EC%8B%A0%EC%9D%98-%EC%83%88%EB%A1%9C%EC%9A%B4-%ED%8C%A8%EB%9F%AC%EB%8B%A4%EC%9E%84/#2-2-grpc-%EC%84%9C%EB%B2%84-%EA%B5%AC%ED%98%84\">2-2. gRPC 서버 구현</a></li>\n<li><a href=\"/etc/gRPC-%EC%99%84%EC%A0%84%EC%A0%95%EB%B3%B5-%EA%B3%A0%EC%84%B1%EB%8A%A5-%EB%A7%88%EC%9D%B4%ED%81%AC%EB%A1%9C%EC%84%9C%EB%B9%84%EC%8A%A4-%ED%86%B5%EC%8B%A0%EC%9D%98-%EC%83%88%EB%A1%9C%EC%9A%B4-%ED%8C%A8%EB%9F%AC%EB%8B%A4%EC%9E%84/#2-3-grpc-%ED%81%B4%EB%9D%BC%EC%9D%B4%EC%96%B8%ED%8A%B8-%EA%B5%AC%ED%98%84\">2-3. gRPC 클라이언트 구현</a></li>\n</ul>\n</li>\n<li>\n<p><a href=\"/etc/gRPC-%EC%99%84%EC%A0%84%EC%A0%95%EB%B3%B5-%EA%B3%A0%EC%84%B1%EB%8A%A5-%EB%A7%88%EC%9D%B4%ED%81%AC%EB%A1%9C%EC%84%9C%EB%B9%84%EC%8A%A4-%ED%86%B5%EC%8B%A0%EC%9D%98-%EC%83%88%EB%A1%9C%EC%9A%B4-%ED%8C%A8%EB%9F%AC%EB%8B%A4%EC%9E%84/#3-%EC%8A%A4%ED%8A%B8%EB%A6%AC%EB%B0%8D\">3. 스트리밍</a></p>\n<ul>\n<li><a href=\"/etc/gRPC-%EC%99%84%EC%A0%84%EC%A0%95%EB%B3%B5-%EA%B3%A0%EC%84%B1%EB%8A%A5-%EB%A7%88%EC%9D%B4%ED%81%AC%EB%A1%9C%EC%84%9C%EB%B9%84%EC%8A%A4-%ED%86%B5%EC%8B%A0%EC%9D%98-%EC%83%88%EB%A1%9C%EC%9A%B4-%ED%8C%A8%EB%9F%AC%EB%8B%A4%EC%9E%84/#3-1-%EC%84%9C%EB%B2%84-%EC%8A%A4%ED%8A%B8%EB%A6%AC%EB%B0%8D\">3-1. 서버 스트리밍</a></li>\n<li><a href=\"/etc/gRPC-%EC%99%84%EC%A0%84%EC%A0%95%EB%B3%B5-%EA%B3%A0%EC%84%B1%EB%8A%A5-%EB%A7%88%EC%9D%B4%ED%81%AC%EB%A1%9C%EC%84%9C%EB%B9%84%EC%8A%A4-%ED%86%B5%EC%8B%A0%EC%9D%98-%EC%83%88%EB%A1%9C%EC%9A%B4-%ED%8C%A8%EB%9F%AC%EB%8B%A4%EC%9E%84/#3-2-%ED%81%B4%EB%9D%BC%EC%9D%B4%EC%96%B8%ED%8A%B8-%EC%8A%A4%ED%8A%B8%EB%A6%AC%EB%B0%8D\">3-2. 클라이언트 스트리밍</a></li>\n<li><a href=\"/etc/gRPC-%EC%99%84%EC%A0%84%EC%A0%95%EB%B3%B5-%EA%B3%A0%EC%84%B1%EB%8A%A5-%EB%A7%88%EC%9D%B4%ED%81%AC%EB%A1%9C%EC%84%9C%EB%B9%84%EC%8A%A4-%ED%86%B5%EC%8B%A0%EC%9D%98-%EC%83%88%EB%A1%9C%EC%9A%B4-%ED%8C%A8%EB%9F%AC%EB%8B%A4%EC%9E%84/#3-3-%EC%96%91%EB%B0%A9%ED%96%A5-%EC%8A%A4%ED%8A%B8%EB%A6%AC%EB%B0%8D\">3-3. 양방향 스트리밍</a></li>\n</ul>\n</li>\n<li>\n<p><a href=\"/etc/gRPC-%EC%99%84%EC%A0%84%EC%A0%95%EB%B3%B5-%EA%B3%A0%EC%84%B1%EB%8A%A5-%EB%A7%88%EC%9D%B4%ED%81%AC%EB%A1%9C%EC%84%9C%EB%B9%84%EC%8A%A4-%ED%86%B5%EC%8B%A0%EC%9D%98-%EC%83%88%EB%A1%9C%EC%9A%B4-%ED%8C%A8%EB%9F%AC%EB%8B%A4%EC%9E%84/#4-%EC%9D%B8%ED%84%B0%EC%85%89%ED%84%B0%EC%99%80-%EB%AF%B8%EB%93%A4%EC%9B%A8%EC%96%B4\">4. 인터셉터와 미들웨어</a></p>\n<ul>\n<li><a href=\"/etc/gRPC-%EC%99%84%EC%A0%84%EC%A0%95%EB%B3%B5-%EA%B3%A0%EC%84%B1%EB%8A%A5-%EB%A7%88%EC%9D%B4%ED%81%AC%EB%A1%9C%EC%84%9C%EB%B9%84%EC%8A%A4-%ED%86%B5%EC%8B%A0%EC%9D%98-%EC%83%88%EB%A1%9C%EC%9A%B4-%ED%8C%A8%EB%9F%AC%EB%8B%A4%EC%9E%84/#4-1-%EC%84%9C%EB%B2%84-%EC%9D%B8%ED%84%B0%EC%85%89%ED%84%B0\">4-1. 서버 인터셉터</a></li>\n<li><a href=\"/etc/gRPC-%EC%99%84%EC%A0%84%EC%A0%95%EB%B3%B5-%EA%B3%A0%EC%84%B1%EB%8A%A5-%EB%A7%88%EC%9D%B4%ED%81%AC%EB%A1%9C%EC%84%9C%EB%B9%84%EC%8A%A4-%ED%86%B5%EC%8B%A0%EC%9D%98-%EC%83%88%EB%A1%9C%EC%9A%B4-%ED%8C%A8%EB%9F%AC%EB%8B%A4%EC%9E%84/#4-2-%EC%9D%B8%EC%A6%9D-%EC%9D%B8%ED%84%B0%EC%85%89%ED%84%B0\">4-2. 인증 인터셉터</a></li>\n<li><a href=\"/etc/gRPC-%EC%99%84%EC%A0%84%EC%A0%95%EB%B3%B5-%EA%B3%A0%EC%84%B1%EB%8A%A5-%EB%A7%88%EC%9D%B4%ED%81%AC%EB%A1%9C%EC%84%9C%EB%B9%84%EC%8A%A4-%ED%86%B5%EC%8B%A0%EC%9D%98-%EC%83%88%EB%A1%9C%EC%9A%B4-%ED%8C%A8%EB%9F%AC%EB%8B%A4%EC%9E%84/#4-3-%ED%81%B4%EB%9D%BC%EC%9D%B4%EC%96%B8%ED%8A%B8-%EC%9D%B8%ED%84%B0%EC%85%89%ED%84%B0\">4-3. 클라이언트 인터셉터</a></li>\n</ul>\n</li>\n<li>\n<p><a href=\"/etc/gRPC-%EC%99%84%EC%A0%84%EC%A0%95%EB%B3%B5-%EA%B3%A0%EC%84%B1%EB%8A%A5-%EB%A7%88%EC%9D%B4%ED%81%AC%EB%A1%9C%EC%84%9C%EB%B9%84%EC%8A%A4-%ED%86%B5%EC%8B%A0%EC%9D%98-%EC%83%88%EB%A1%9C%EC%9A%B4-%ED%8C%A8%EB%9F%AC%EB%8B%A4%EC%9E%84/#5-%EC%97%90%EB%9F%AC-%EC%B2%98%EB%A6%AC\">5. 에러 처리</a></p>\n<ul>\n<li><a href=\"/etc/gRPC-%EC%99%84%EC%A0%84%EC%A0%95%EB%B3%B5-%EA%B3%A0%EC%84%B1%EB%8A%A5-%EB%A7%88%EC%9D%B4%ED%81%AC%EB%A1%9C%EC%84%9C%EB%B9%84%EC%8A%A4-%ED%86%B5%EC%8B%A0%EC%9D%98-%EC%83%88%EB%A1%9C%EC%9A%B4-%ED%8C%A8%EB%9F%AC%EB%8B%A4%EC%9E%84/#5-1-%EC%83%81%ED%83%9C-%EC%BD%94%EB%93%9C%EC%99%80-%EC%97%90%EB%9F%AC-%EC%B2%98%EB%A6%AC\">5-1. 상태 코드와 에러 처리</a></li>\n<li><a href=\"/etc/gRPC-%EC%99%84%EC%A0%84%EC%A0%95%EB%B3%B5-%EA%B3%A0%EC%84%B1%EB%8A%A5-%EB%A7%88%EC%9D%B4%ED%81%AC%EB%A1%9C%EC%84%9C%EB%B9%84%EC%8A%A4-%ED%86%B5%EC%8B%A0%EC%9D%98-%EC%83%88%EB%A1%9C%EC%9A%B4-%ED%8C%A8%EB%9F%AC%EB%8B%A4%EC%9E%84/#5-2-%EC%BB%A4%EC%8A%A4%ED%85%80-%EC%97%90%EB%9F%AC-%EC%B2%98%EB%A6%AC\">5-2. 커스텀 에러 처리</a></li>\n</ul>\n</li>\n<li>\n<p><a href=\"/etc/gRPC-%EC%99%84%EC%A0%84%EC%A0%95%EB%B3%B5-%EA%B3%A0%EC%84%B1%EB%8A%A5-%EB%A7%88%EC%9D%B4%ED%81%AC%EB%A1%9C%EC%84%9C%EB%B9%84%EC%8A%A4-%ED%86%B5%EC%8B%A0%EC%9D%98-%EC%83%88%EB%A1%9C%EC%9A%B4-%ED%8C%A8%EB%9F%AC%EB%8B%A4%EC%9E%84/#6-%EC%84%B1%EB%8A%A5-%EC%B5%9C%EC%A0%81%ED%99%94\">6. 성능 최적화</a></p>\n<ul>\n<li><a href=\"/etc/gRPC-%EC%99%84%EC%A0%84%EC%A0%95%EB%B3%B5-%EA%B3%A0%EC%84%B1%EB%8A%A5-%EB%A7%88%EC%9D%B4%ED%81%AC%EB%A1%9C%EC%84%9C%EB%B9%84%EC%8A%A4-%ED%86%B5%EC%8B%A0%EC%9D%98-%EC%83%88%EB%A1%9C%EC%9A%B4-%ED%8C%A8%EB%9F%AC%EB%8B%A4%EC%9E%84/#6-1-%EC%97%B0%EA%B2%B0-%ED%92%80%EB%A7%81\">6-1. 연결 풀링</a></li>\n<li><a href=\"/etc/gRPC-%EC%99%84%EC%A0%84%EC%A0%95%EB%B3%B5-%EA%B3%A0%EC%84%B1%EB%8A%A5-%EB%A7%88%EC%9D%B4%ED%81%AC%EB%A1%9C%EC%84%9C%EB%B9%84%EC%8A%A4-%ED%86%B5%EC%8B%A0%EC%9D%98-%EC%83%88%EB%A1%9C%EC%9A%B4-%ED%8C%A8%EB%9F%AC%EB%8B%A4%EC%9E%84/#6-2-%EC%95%95%EC%B6%95\">6-2. 압축</a></li>\n<li><a href=\"/etc/gRPC-%EC%99%84%EC%A0%84%EC%A0%95%EB%B3%B5-%EA%B3%A0%EC%84%B1%EB%8A%A5-%EB%A7%88%EC%9D%B4%ED%81%AC%EB%A1%9C%EC%84%9C%EB%B9%84%EC%8A%A4-%ED%86%B5%EC%8B%A0%EC%9D%98-%EC%83%88%EB%A1%9C%EC%9A%B4-%ED%8C%A8%EB%9F%AC%EB%8B%A4%EC%9E%84/#6-3-%ED%83%80%EC%9E%84%EC%95%84%EC%9B%83-%EC%84%A4%EC%A0%95\">6-3. 타임아웃 설정</a></li>\n</ul>\n</li>\n<li>\n<p><a href=\"/etc/gRPC-%EC%99%84%EC%A0%84%EC%A0%95%EB%B3%B5-%EA%B3%A0%EC%84%B1%EB%8A%A5-%EB%A7%88%EC%9D%B4%ED%81%AC%EB%A1%9C%EC%84%9C%EB%B9%84%EC%8A%A4-%ED%86%B5%EC%8B%A0%EC%9D%98-%EC%83%88%EB%A1%9C%EC%9A%B4-%ED%8C%A8%EB%9F%AC%EB%8B%A4%EC%9E%84/#7-grpc-web-%EB%B8%8C%EB%9D%BC%EC%9A%B0%EC%A0%80-%EC%A7%80%EC%9B%90\">7. gRPC-Web (브라우저 지원)</a></p>\n<ul>\n<li><a href=\"/etc/gRPC-%EC%99%84%EC%A0%84%EC%A0%95%EB%B3%B5-%EA%B3%A0%EC%84%B1%EB%8A%A5-%EB%A7%88%EC%9D%B4%ED%81%AC%EB%A1%9C%EC%84%9C%EB%B9%84%EC%8A%A4-%ED%86%B5%EC%8B%A0%EC%9D%98-%EC%83%88%EB%A1%9C%EC%9A%B4-%ED%8C%A8%EB%9F%AC%EB%8B%A4%EC%9E%84/#7-1-grpc-web-%EC%84%A4%EC%A0%95\">7-1. gRPC-Web 설정</a></li>\n<li><a href=\"/etc/gRPC-%EC%99%84%EC%A0%84%EC%A0%95%EB%B3%B5-%EA%B3%A0%EC%84%B1%EB%8A%A5-%EB%A7%88%EC%9D%B4%ED%81%AC%EB%A1%9C%EC%84%9C%EB%B9%84%EC%8A%A4-%ED%86%B5%EC%8B%A0%EC%9D%98-%EC%83%88%EB%A1%9C%EC%9A%B4-%ED%8C%A8%EB%9F%AC%EB%8B%A4%EC%9E%84/#7-2-javascript-%ED%81%B4%EB%9D%BC%EC%9D%B4%EC%96%B8%ED%8A%B8\">7-2. JavaScript 클라이언트</a></li>\n</ul>\n</li>\n<li>\n<p><a href=\"/etc/gRPC-%EC%99%84%EC%A0%84%EC%A0%95%EB%B3%B5-%EA%B3%A0%EC%84%B1%EB%8A%A5-%EB%A7%88%EC%9D%B4%ED%81%AC%EB%A1%9C%EC%84%9C%EB%B9%84%EC%8A%A4-%ED%86%B5%EC%8B%A0%EC%9D%98-%EC%83%88%EB%A1%9C%EC%9A%B4-%ED%8C%A8%EB%9F%AC%EB%8B%A4%EC%9E%84/#8-%EB%AA%A8%EB%8B%88%ED%84%B0%EB%A7%81%EA%B3%BC-%EB%A1%9C%EA%B9%85\">8. 모니터링과 로깅</a></p>\n<ul>\n<li><a href=\"/etc/gRPC-%EC%99%84%EC%A0%84%EC%A0%95%EB%B3%B5-%EA%B3%A0%EC%84%B1%EB%8A%A5-%EB%A7%88%EC%9D%B4%ED%81%AC%EB%A1%9C%EC%84%9C%EB%B9%84%EC%8A%A4-%ED%86%B5%EC%8B%A0%EC%9D%98-%EC%83%88%EB%A1%9C%EC%9A%B4-%ED%8C%A8%EB%9F%AC%EB%8B%A4%EC%9E%84/#8-1-%EB%A9%94%ED%8A%B8%EB%A6%AD-%EC%88%98%EC%A7%91\">8-1. 메트릭 수집</a></li>\n</ul>\n</li>\n<li>\n<p><a href=\"/etc/gRPC-%EC%99%84%EC%A0%84%EC%A0%95%EB%B3%B5-%EA%B3%A0%EC%84%B1%EB%8A%A5-%EB%A7%88%EC%9D%B4%ED%81%AC%EB%A1%9C%EC%84%9C%EB%B9%84%EC%8A%A4-%ED%86%B5%EC%8B%A0%EC%9D%98-%EC%83%88%EB%A1%9C%EC%9A%B4-%ED%8C%A8%EB%9F%AC%EB%8B%A4%EC%9E%84/#9-%EB%B3%B4%EC%95%88\">9. 보안</a></p>\n<ul>\n<li><a href=\"/etc/gRPC-%EC%99%84%EC%A0%84%EC%A0%95%EB%B3%B5-%EA%B3%A0%EC%84%B1%EB%8A%A5-%EB%A7%88%EC%9D%B4%ED%81%AC%EB%A1%9C%EC%84%9C%EB%B9%84%EC%8A%A4-%ED%86%B5%EC%8B%A0%EC%9D%98-%EC%83%88%EB%A1%9C%EC%9A%B4-%ED%8C%A8%EB%9F%AC%EB%8B%A4%EC%9E%84/#9-1-tlsssl-%EC%84%A4%EC%A0%95\">9-1. TLS/SSL 설정</a></li>\n<li><a href=\"/etc/gRPC-%EC%99%84%EC%A0%84%EC%A0%95%EB%B3%B5-%EA%B3%A0%EC%84%B1%EB%8A%A5-%EB%A7%88%EC%9D%B4%ED%81%AC%EB%A1%9C%EC%84%9C%EB%B9%84%EC%8A%A4-%ED%86%B5%EC%8B%A0%EC%9D%98-%EC%83%88%EB%A1%9C%EC%9A%B4-%ED%8C%A8%EB%9F%AC%EB%8B%A4%EC%9E%84/#9-2-mtls-mutual-tls\">9-2. mTLS (Mutual TLS)</a></li>\n</ul>\n</li>\n<li>\n<p><a href=\"/etc/gRPC-%EC%99%84%EC%A0%84%EC%A0%95%EB%B3%B5-%EA%B3%A0%EC%84%B1%EB%8A%A5-%EB%A7%88%EC%9D%B4%ED%81%AC%EB%A1%9C%EC%84%9C%EB%B9%84%EC%8A%A4-%ED%86%B5%EC%8B%A0%EC%9D%98-%EC%83%88%EB%A1%9C%EC%9A%B4-%ED%8C%A8%EB%9F%AC%EB%8B%A4%EC%9E%84/#10-%EC%8B%A4%EC%A0%84-%ED%8C%A8%ED%84%B4\">10. 실전 패턴</a></p>\n<ul>\n<li><a href=\"/etc/gRPC-%EC%99%84%EC%A0%84%EC%A0%95%EB%B3%B5-%EA%B3%A0%EC%84%B1%EB%8A%A5-%EB%A7%88%EC%9D%B4%ED%81%AC%EB%A1%9C%EC%84%9C%EB%B9%84%EC%8A%A4-%ED%86%B5%EC%8B%A0%EC%9D%98-%EC%83%88%EB%A1%9C%EC%9A%B4-%ED%8C%A8%EB%9F%AC%EB%8B%A4%EC%9E%84/#10-1-%EC%9E%AC%EC%8B%9C%EB%8F%84-%ED%8C%A8%ED%84%B4\">10-1. 재시도 패턴</a></li>\n<li><a href=\"/etc/gRPC-%EC%99%84%EC%A0%84%EC%A0%95%EB%B3%B5-%EA%B3%A0%EC%84%B1%EB%8A%A5-%EB%A7%88%EC%9D%B4%ED%81%AC%EB%A1%9C%EC%84%9C%EB%B9%84%EC%8A%A4-%ED%86%B5%EC%8B%A0%EC%9D%98-%EC%83%88%EB%A1%9C%EC%9A%B4-%ED%8C%A8%EB%9F%AC%EB%8B%A4%EC%9E%84/#10-2-%EC%84%9C%ED%82%B7-%EB%B8%8C%EB%A0%88%EC%9D%B4%EC%BB%A4-%ED%8C%A8%ED%84%B4\">10-2. 서킷 브레이커 패턴</a></li>\n</ul>\n</li>\n<li><a href=\"/etc/gRPC-%EC%99%84%EC%A0%84%EC%A0%95%EB%B3%B5-%EA%B3%A0%EC%84%B1%EB%8A%A5-%EB%A7%88%EC%9D%B4%ED%81%AC%EB%A1%9C%EC%84%9C%EB%B9%84%EC%8A%A4-%ED%86%B5%EC%8B%A0%EC%9D%98-%EC%83%88%EB%A1%9C%EC%9A%B4-%ED%8C%A8%EB%9F%AC%EB%8B%A4%EC%9E%84/#11-%EA%B2%B0%EB%A1%A0\">11. 결론</a></li>\n<li><a href=\"/etc/gRPC-%EC%99%84%EC%A0%84%EC%A0%95%EB%B3%B5-%EA%B3%A0%EC%84%B1%EB%8A%A5-%EB%A7%88%EC%9D%B4%ED%81%AC%EB%A1%9C%EC%84%9C%EB%B9%84%EC%8A%A4-%ED%86%B5%EC%8B%A0%EC%9D%98-%EC%83%88%EB%A1%9C%EC%9A%B4-%ED%8C%A8%EB%9F%AC%EB%8B%A4%EC%9E%84/#%EC%B0%B8%EA%B3%A0-%EC%9E%90%EB%A3%8C\">참고 자료</a></li>\n</ul>\n</li>\n</ul>","wordCount":{"words":277},"fields":{"slug":"/etc/gRPC-완전정복-고성능-마이크로서비스-통신의-새로운-패러다임/","image":null,"faq":[]},"frontmatter":{"title":"gRPC 완전정복 - 고성능 마이크로서비스 통신의 새로운 패러다임","date":"2025년 12월 7일","dateISO":"2025-12-07T00:00:00.000Z","updatedISO":null,"category":"etc","description":"gRPC 기초부터 고급 활용까지. Protocol Buffers, 스트리밍, 인터셉터, 에러 처리, Spring Boot 통합, 성능 최적화까지 실무에서 바로 사용할 수 있는 완벽한 가이드를 제공합니다.","tags":["gRPC","Protocol Buffers","마이크로서비스","고성능 통신","RPC","스트리밍","Spring Boot","분산 시스템"]}}},"pageContext":{"slug":"/etc/gRPC-완전정복-고성능-마이크로서비스-통신의-새로운-패러다임/","previous":{"fields":{"slug":"/javascript/WebAssembly-WASM-브라우저와-서버를-넘나드는-범용-런타임/"},"frontmatter":{"title":"WebAssembly (WASM) - 브라우저와 서버를 넘나드는 범용 런타임","tags":["WebAssembly","WASM","JavaScript","Rust","Go","고성능","브라우저","Node.js","컴파일"]}},"next":{"fields":{"slug":"/ai/AI-명세서-자동-생성-기술-아이디어를-기능-명세서로-바꾸는-마법/"},"frontmatter":{"title":"AI 명세서 자동 생성 기술 아이디어를 기능 명세서로 바꾸는 마법","tags":["AI 명세서 생성","기능 명세서","프로젝트 기획","AI 자동화","블루버튼","AI","프로젝트 관리"]}}}},"staticQueryHashes":["213619243","3262363727"]}