1. 개요
gRPC는 Google에서 개발한 언어 및 플랫폼 중립적인 리모트 프로시져 콜 (RPC) 프레임워크 및 도구 모음입니다. 특히 강력한 바이너리 직렬화 툴셋 및 언어인 프로토콜 버퍼를 사용하여 서비스를 정의할 수 있습니다. 그런 다음 다양한 언어로 된 서비스 정의에서 직관적인 클라이언트 및 서버 스텁을 생성할 수 있습니다.
이 Codelab에서는 gRPC 프레임워크를 사용하여 API를 노출하는 Java 기반 서비스를 빌드한 다음 생성된 gRPC 클라이언트 측 스텁을 사용할 클라이언트를 작성하는 방법을 알아봅니다.
학습할 내용
- 프로토콜 버퍼 언어
- 자바를 사용하여 gRPC 서비스를 구현하는 방법
- 자바를 사용하여 gRPC 클라이언트를 구현하는 방법
이 튜토리얼을 어떻게 사용하실 계획인가요?
귀하의 Node.js 앱 빌드 경험을 평가해 주세요.
Go 앱을 빌드한 경험을 평가해 주세요.
<ph type="x-smartling-placeholder">2. 설정 및 요구사항
자습형 환경 설정
- Cloud 콘솔에 로그인하고 새 프로젝트를 만들거나 기존 프로젝트를 다시 사용합니다. 아직 Gmail이나 Google Workspace 계정이 없는 경우 계정을 만들어야 합니다.



모든 Google Cloud 프로젝트에서 고유한 이름인 프로젝트 ID를 기억하세요(위의 이름은 이미 사용되었으므로 사용할 수 없습니다). 이 ID는 나중에 이 Codelab에서 PROJECT_ID라고 부릅니다.
- 그런 후 Google Cloud 리소스를 사용할 수 있도록 Cloud Console에서 결제를 사용 설정해야 합니다.
이 Codelab 실행에는 많은 비용이 들지 않습니다. 이 가이드를 마친 후 비용이 결제되지 않도록 리소스 종료 방법을 알려주는 '삭제' 섹션의 안내를 따르세요. Google Cloud 신규 사용자에게는 미화$300 상당의 무료 체험판 프로그램에 참여할 수 있는 자격이 부여됩니다.
Google Cloud Shell
이 Codelab은 컴퓨터에서 실행할 수 있지만 이 Codelab에서는 Cloud에서 실행되는 명령줄 환경인 Google Cloud Shell을 사용합니다.
이 Debian 기반 가상 머신에는 필요한 모든 개발 도구가 로드되어 있습니다. 영구적인 5GB 홈 디렉터리를 제공하고 Google Cloud에서 실행되므로 네트워크 성능과 인증이 크게 개선됩니다. 즉, 이 Codelab에 필요한 것은 브라우저뿐입니다(Chromebook에서도 작동 가능).
- Cloud Console에서 Cloud Shell을 활성화하려면 단순히 Cloud Shell 활성화
를 클릭합니다. 환경을 프로비저닝하고 연결하는 데 몇 정도만 소요됩니다.


Cloud Shell에 연결되면 사용자 인증이 이미 완료되었고 프로젝트가 내 PROJECT_ID에 설정되어 있음을 확인할 수 있습니다.
gcloud auth list
명령어 결과
Credentialed accounts: - <myaccount>@<mydomain>.com (active)
gcloud config list project
명령어 결과
[core] project = <PROJECT_ID>
어떤 이유로든 프로젝트가 설정되지 않았으면 다음 명령어를 실행하면 됩니다.
gcloud config set project <PROJECT_ID>
PROJECT_ID를 찾고 계신가요? 설정 단계에서 사용한 ID를 확인하거나 Cloud Console 대시보드에서 확인하세요.

또한 Cloud Shell은 기본적으로 이후 명령어를 실행할 때 유용할 수 있는 몇 가지 환경 변수를 설정합니다.
echo $GOOGLE_CLOUD_PROJECT
명령어 결과
<PROJECT_ID>
- 마지막으로 기본 영역 및 프로젝트 구성을 설정합니다.
gcloud config set compute/zone us-central1-f
다양한 영역을 선택할 수 있습니다. 자세한 내용은 리전 및 영역을 참조하세요.
3. gRPC 서비스 만들기
Maven으로 새 Java 프로젝트를 만듭니다.
$ mvn archetype:generate -DgroupId=com.example.grpc \ -DartifactId=grpc-hello-server \ -DarchetypeArtifactId=maven-archetype-quickstart \ -DinteractiveMode=false $ cd grpc-hello-server
gRPC 정의 파일 추가
gRPC에서는 서비스 페이로드 (요청 및 응답)와 서비스 작업을 IDL (인터페이스 정의 언어)로 캡처해야 합니다. gRPC는 Protobuffer 3 문법을 사용하여 메시지 페이로드와 작업을 정의합니다. Hello 요청과 Hello 응답이 포함된 간단한 인사말 서비스의 proto 파일을 만들어 보겠습니다.
먼저 새 proto 파일을 저장할 새 proto 디렉터리를 만듭니다.
$ mkdir -p src/main/proto
그런 다음 새 proto 파일 src/main/proto/GreetingService.proto를 만듭니다.
vim,nano, 또는 emacs를 사용하여 파일을 수정할 수 있습니다.
src/main/proto/GreetingService.proto
syntax = "proto3";
package com.example.grpc;
// Request payload
message HelloRequest {
// Each message attribute is strongly typed.
// You also must assign a "tag" number.
// Each tag number is unique within the message.
string name = 1;
// This defines a strongly typed list of String
repeated string hobbies = 2;
// There are many more basics types, like Enum, Map
// See https://developers.google.com/protocol-buffers/docs/proto3
// for more information.
}
message HelloResponse {
string greeting = 1;
}
// Defining a Service, a Service can have multiple RPC operations
service GreetingService {
// Define a RPC operation
rpc greeting(HelloRequest) returns (HelloResponse);
}
gRPC 종속 항목 및 플러그인 추가
정의가 지정되면 이 파일에서 서버 측 스텁과 클라이언트 측 스텁을 모두 생성할 수 있습니다. gRPC 종속 항목과 플러그인을 추가해야 합니다.
먼저 pom.xml에 gRPC 종속 항목을 추가합니다.
pom.xml
<project>
...
<dependencies>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-netty-shaded</artifactId>
<version>1.24.0</version>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-protobuf</artifactId>
<version>1.24.0</version>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-stub</artifactId>
<version>1.24.0</version>
</dependency>
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>1.3.2</version>
</dependency>
...
</dependencies>
...
</project>
그런 다음 플러그인을 추가합니다.
pom.xml
<project>
...
<dependencies>
...
</dependencies>
<build>
<extensions>
<extension>
<groupId>kr.motd.maven</groupId>
<artifactId>os-maven-plugin</artifactId>
<version>1.6.2</version>
</extension>
</extensions>
<plugins>
<plugin>
<groupId>org.xolstice.maven.plugins</groupId>
<artifactId>protobuf-maven-plugin</artifactId>
<version>0.6.1</version>
<configuration>
<protocArtifact>com.google.protobuf:protoc:3.9.0:exe:${os.detected.classifier}</protocArtifact>
<pluginId>grpc-java</pluginId>
<pluginArtifact>io.grpc:protoc-gen-grpc-java:1.24.0:exe:${os.detected.classifier}</pluginArtifact>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>compile-custom</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
스텁 생성
애플리케이션을 빌드할 때 플러그인은 proto 정의를 Java 코드로 변환합니다.
$ mvn -DskipTests package
생성된 파일을 보려면 다음 안내를 따르세요.
$ find target/generated-sources
서비스 구현
먼저 greeting 작업을 구현할 새 GreetingServiceImpl 클래스를 만듭니다.
src/main/java/com/example/grpc/GreetingServiceImpl.java
package com.example.grpc;
import io.grpc.stub.StreamObserver;
public class GreetingServiceImpl extends GreetingServiceGrpc.GreetingServiceImplBase {
@Override
public void greeting(GreetingServiceOuterClass.HelloRequest request,
StreamObserver<GreetingServiceOuterClass.HelloResponse> responseObserver) {
// HelloRequest has toString auto-generated.
System.out.println(request);
// You must use a builder to construct a new Protobuffer object
GreetingServiceOuterClass.HelloResponse response = GreetingServiceOuterClass.HelloResponse.newBuilder()
.setGreeting("Hello there, " + request.getName())
.build();
// Use responseObserver to send a single response back
responseObserver.onNext(response);
// When you are done, you must call onCompleted.
responseObserver.onCompleted();
}
}
서버 구현
마지막으로 포트에서 수신 대기하는 서버를 시작하고 이 서비스 구현을 등록해야 합니다. App 클래스 및 기본 메서드를 수정합니다.
src/main/java/com/example/grpc/App.java
package com.example.grpc;
import io.grpc.*;
public class App
{
public static void main( String[] args ) throws Exception
{
// Create a new server to listen on port 8080
Server server = ServerBuilder.forPort(8080)
.addService(new GreetingServiceImpl())
.build();
// Start the server
server.start();
// Server threads are running in the background.
System.out.println("Server started");
// Don't exit the main thread. Wait until server is terminated.
server.awaitTermination();
}
}
마지막으로 서버를 실행합니다.
$ mvn -DskipTests package exec:java -Dexec.mainClass=com.example.grpc.App ... Server Started
4. 서비스 사용
생성기에서 이미 모든 클라이언트 측 스텁을 생성했습니다. 실습의 편의를 위해 동일한 Maven 프로젝트를 사용하지만 새로운 기본 메서드를 사용하여 새 Client 클래스를 추가하기만 하면 됩니다.
먼저 +를 클릭하여 새 Cloud Shell 세션을 엽니다. 그러면 서버를 종료할 필요가 없습니다.

새 세션에서 grpc-hello-server 디렉터리로 전환합니다.
$ cd grpc-hello-server
그런 다음 새 Client 클래스를 추가합니다.
src/main/java/com/example/grpc/Client.java
package com.example.grpc;
import io.grpc.*;
public class Client
{
public static void main( String[] args ) throws Exception
{
// Channel is the abstraction to connect to a service endpoint
// Let's use plaintext communication because we don't have certs
final ManagedChannel channel = ManagedChannelBuilder.forTarget("localhost:8080")
.usePlaintext(true)
.build();
// It is up to the client to determine whether to block the call
// Here we create a blocking stub, but an async stub,
// or an async stub with Future are always possible.
GreetingServiceGrpc.GreetingServiceBlockingStub stub = GreetingServiceGrpc.newBlockingStub(channel);
GreetingServiceOuterClass.HelloRequest request =
GreetingServiceOuterClass.HelloRequest.newBuilder()
.setName("Ray")
.build();
// Finally, make the call using the stub
GreetingServiceOuterClass.HelloResponse response =
stub.greeting(request);
System.out.println(response);
// A Channel should be shutdown before stopping the process.
channel.shutdownNow();
}
}
마지막으로 클라이언트를 실행합니다.
$ mvn -DskipTests package exec:java -Dexec.mainClass=com.example.grpc.Client ... greeting: "Hello there, Ray"
작업이 끝났습니다. 간단하죠?
5. 스트리밍 서비스
이 외에도 다양한 방법을 시도해 볼 수 있습니다. 예를 들어 proto 파일의 stream 키워드를 요청 또는 응답 매개변수에 추가하면 간단하게 스트리밍 서비스를 빌드할 수 있습니다. 예를 들어
src/main/proto/GreetingService.proto
syntax = "proto3";
package com.example.grpc;
...
// Defining a Service, a Service can have multiple RPC operations
service GreetingService {
// MODIFY HERE: Update the return to streaming return.
rpc greeting(HelloRequest) returns (stream HelloResponse);
}
하나의 응답이 아닌 여러 응답을 보내도록 서버를 업데이트합니다. 이렇게 하려면 responseObserver.onNext(...)를 여러 번 호출하면 됩니다.
src/main/java/com/example/grpc/GreetingServiceImpl.java
package com.example.grpc;
import io.grpc.stub.StreamObserver;
public class GreetingServiceImpl extends GreetingServiceGrpc.GreetingServiceImplBase {
@Override
public void greeting(GreetingServiceOuterClass.HelloRequest request,
StreamObserver<GreetingServiceOuterClass.HelloResponse> responseObserver) {
...
// Feel free to construct different responses if you'd like.
responseObserver.onNext(response);
responseObserver.onNext(response);
responseObserver.onNext(response);
// When you are done, you must call onCompleted.
responseObserver.onCompleted();
}
}
클라이언트는 차단 스텁 대신 비동기 스텁을 사용해야 합니다. 클라이언트 코드를 업데이트하여 stub 유형을 GreetingServiceStub로 업데이트합니다.
src/main/java/com/example/grpc/Client.java
package com.example.grpc;
import io.grpc.*;
// New import
import io.grpc.stub.*;
public class Client
{
public static void main( String[] args ) throws Exception
{
final ManagedChannel channel = ManagedChannelBuilder.forTarget("localhost:8080")
.usePlaintext(true)
.build();
// Replace the previous synchronous code with asynchronous code.
// This time use an async stub:
GreetingServiceGrpc.GreetingServiceStub stub = GreetingServiceGrpc.newStub(channel);
// Construct a request
GreetingServiceOuterClass.HelloRequest request =
GreetingServiceOuterClass.HelloRequest.newBuilder()
.setName("Ray")
.build();
// Make an Asynchronous call. Listen to responses w/ StreamObserver
stub.greeting(request, new StreamObserver<GreetingServiceOuterClass.HelloResponse>() {
public void onNext(GreetingServiceOuterClass.HelloResponse response) {
System.out.println(response);
}
public void onError(Throwable t) {
}
public void onCompleted() {
// Typically you'll shutdown the channel somewhere else.
// But for the purpose of the lab, we are only making a single
// request. We'll shutdown as soon as this request is done.
channel.shutdownNow();
}
});
}
}
애플리케이션을 다시 빌드합니다.
$ mvn -DskipTests package
자체 Cloud Shell 세션에서 서버와 클라이언트를 모두 다시 시작합니다.
서버를 시작하려면 다음 안내를 따르세요.
$ mvn exec:java -Dexec.mainClass=com.example.grpc.App ... Server Started
클라이언트를 시작하려면 다음 안내를 따르세요.
$ mvn exec:java -Dexec.mainClass=com.example.grpc.Client ... greeting: "Hello there, Ray" greeting: "Hello there, Ray" greeting: "Hello there, Ray"
6. 축하합니다.
학습한 내용:
- 프로토콜 버퍼 언어
- 자바를 사용하여 gRPC 서버를 구현하는 방법
- 자바를 사용하여 gRPC 클라이언트를 구현하는 방법
다음 단계:
- gRPC 자바에 대해 자세히 알아보기
- GitHub의 gRPC Java 예 더보기
- gRPC의 스트리밍에 대해 알아보기
- gRPC로 REST 트랜스코딩에 대해 자세히 알아보기
Google에 의견 보내기
- 잠시 시간을 내어 간단한 설문조사에 응해주시기 바랍니다.