gRPC (gRPC Remote Procedure Calls)은 Google에서 개발한 현대적이고 오픈 소스, 고성능의 RPC (Remote Procedure Call) 프레임워크입니다. 이는 분산 시스템 간의 효율적인 통신을 용이하게 하기 위해 설계되었으며, 특히 마이크로서비스 아키텍처에 적합합니다. 아래는 gRPC와 마이크로서비스 통신에서의 역할에 대한 설명입니다:
gRPC란 무엇인가?
gRPC는 클라이언트와 서버 애플리케이션이 투명하게 통신할 수 있는 프로토콜으로, 분산 시스템을 구축하기를 쉽게 만들어줍니다. 이는 HTTP/2를 전송에 사용하며, 인터페이스 정의 언어(IDL)로는 프로토콜 버퍼(Protobuf)를 사용하며, 인증, 부하 분산 등의 기능을 제공합니다.
다음은 gRPC의 몇 가지 특징입니다:
- 언어에 독립적. gRPC는 Java, Python, Go, C++ 등 다양한 프로그래밍 언어를 지원합니다.
- 효율적인 통신. 이는 Protobuf를 사용한 이진 직렬화를 통해 JSON과 같은 텍스트 기반 형식보다 더 빠르고 간결하게 통신합니다.
- HTTP/2 기반. gRPC는 HTTP/2를 활용하여 다중화, 스트리밍, 지연 시간 감소와 같은 기능을 제공합니다.
- 강력한 타입 시스템. 서비스와 메시지는 Protobuf를 사용하여 정의되어 타입 안정성을 보장하고 오류를 줄입니다.
- 스트리밍 지원. gRPC는 단방향, 서버 스트리밍, 클라이언트 스트리밍 및 양방향 스트리밍 네 가지 유형의 스트리밍을 지원합니다.
gRPC 작동 방식
1. 서비스 및 메시지 정의
Protobuf를 사용하여 서비스 인터페이스(메서드)와 교환될 메시지의 구조를 정의합니다.
service Greeter {
rpc SayHello (HelloRequest) returns (HelloResponse);
}
message HelloRequest {
string name = 1;
}
message HelloResponse {
string message = 1;
}
2. 코드 생성
Protobuf 컴파일러(protoc
)는 선택한 프로그래밍 언어로 클라이언트 및 서버 코드를 생성합니다.
service Greeter {
rpc SayHello (HelloRequest) returns (HelloResponse);
}
message HelloRequest {
string name = 1;
}
message HelloResponse {
string message = 1;
}
3. 서버 구현
정의된 서비스의 서버 측 로직을 구현합니다.
4. 클라이언트 생성
생성된 클라이언트 코드를 사용하여 서버 메서드를 호출합니다.
gRPC의 마이크로서비스 통신 역할
마이크로서비스 아키텍처는 네트워크를 통해 통신하는 작은 독립적 서비스로 애플리케이션을 분해합니다. gRPC는 효율성과 유연성으로 인해 이러한 맥락에서 중요한 역할을 합니다.
1. 높은 성능
- gRPC는 Protobuf와 이진 직렬화를 사용하여 JSON 또는 XML과 같은 텍스트 기반 형식보다 빠르고 더 콤팩트합니다.
- HTTP/2는 다중화와 헤더 압축을 통해 지연 시간을 줄이고 처리량을 향상시킵니다.
2. 강력한 계약 정의
- Protobuf는 서비스 간의 엄격한 계약을 강제하여 통신 오류 가능성을 줄입니다.
- 서비스 정의의 변경은 버전 관리를 통해 관리되어 역호환성을 보장합니다.
3. 스트리밍 기능
- gRPC는 양방향 스트리밍을 지원하여 채팅 애플리케이션이나 실시간 데이터 피드와 같은 실시간 통신에 이상적입니다.
- 서버 측 및 클라이언트 측 스트리밍은 대량 데이터나 지속적인 데이터 흐름을 효율적으로 처리할 수 있습니다.
4. 상호 운용성
- gRPC는 언어에 구애받지 않으며, 다른 언어로 작성된 마이크로서비스 간에 원활하게 통신할 수 있습니다.
- 이는 특히 다양한 언어로 구성된 마이크로서비스 환경에서 유용합니다.
5. 내장 기능
- gRPC는 인증, 암호화(TLS를 통한), 그리고 부하 분산과 같은 기능에 대한 내장 지원을 제공하여 추가 라이브러리나 도구의 필요성을 줄입니다.
6. 확장성
- gRPC의 가벼운 특성과 효율적인 통신은 대규모 마이크로서비스 배포에 적합합니다.
- 이는 Kubernetes와 같은 컨테이너 오케스트레이션 플랫폼과 잘 통합됩니다.
마이크로서비스에서 gRPC 사용 사례
- 서비스 간 통신. gRPC는 특히 성능이 중요한 시나리오에서 마이크로서비스 간 통신에 이상적입니다.
- 실시간 시스템. 스트리밍 기능으로 게임, IoT 또는 실시간 분석과 같은 실시간 애플리케이션에 적합합니다.
- 다양한 환경. 마이크로서비스가 서로 다른 언어로 작성된 경우 gRPC는 원활한 통신을 보장합니다.
- 클라우드 네이티브 애플리케이션. gRPC는 Kubernetes 및 서비스 메시(예: Istio)와 같은 클라우드 네이티브 기술과 잘 통합됩니다.
gRPC의 장점은
- 효율성입니다. 이진 직렬화와 HTTP/2를 통해 gRPC는 더 빠르고 자원을 효율적으로 사용합니다.
- 타입 안정성을 제공합니다. Protobuf는 강력한 타입을 보장하여 런타임 오류를 줄입니다.
- 다국어 지원을 제공합니다. 다양한 프로그래밍 언어에서 작동합니다.
- 스트리밍을 지원합니다. 실시간 통신을 위한 고급 스트리밍 패턴을 지원합니다.
gRPC의 도전점은
- 복잡성입니다. gRPC 설정은 Protobuf 정의와 코드 생성이 필요하기 때문에 REST보다 더 복잡할 수 있습니다.
- 도구입니다. gRPC 서비스의 디버깅 및 테스트는 REST보다 어려울 수 있습니다. 왜냐하면 Postman과 같은 도구는 gRPC에 대해 네이티브로 설계되지 않았기 때문입니다.
- 브라우저 지원입니다. gRPC는 브라우저에서 네이티브로 지원되지 않으며, 웹 기반 클라이언트를 위해 gRPC-Web과 같은 도구가 필요합니다.
Spring Boot와 함께 gRPC를 사용하는 이유는
Spring Boot가 Java 애플리케이션을 구축하기 위한 인기있는 프레임워크이며, gRPC와 결합하면 개발자가 고성능, 확장 가능하고 상호 운용 가능한 서비스를 만들 수 있습니다. Spring Boot의 자동 구성 및 의존성 주입을 통해 gRPC 통합이 간단해집니다.
애플리케이션을 구축하는 단계는
간단한 gRPC 서비스인 Greeter
를 구축할 것입니다. 이 서비스는 클라이언트가 서버로 이름을 보내고 “안녕, {이름}!” 응답을 받을 수 있도록 합니다. 이렇게 할 것입니다.
- gRPC 서비스를 프로토콜 버퍼를 사용하여 정의합니다.
-
.proto
파일에서 Java 클래스를 생성합니다. - Spring Boot에서 gRPC 서버를 구현합니다.
- Spring Boot에서 gRPC 클라이언트를 구현합니다.
- 테스트를 위해 gRPC 클라이언트를 호출하는 REST 컨트롤러를 추가합니다.
- 애플리케이션을 실행하고 통신을 테스트합니다.
1. gRPC 서비스 정의 (.proto 파일)
첫 번째 단계는 프로토콜 버퍼를 사용하여 gRPC 서비스를 정의하는 것입니다. src/main/proto
디렉토리에 greeter.proto
라는 파일을 생성합니다:
syntax = "proto3";
option java_multiple_files = true;
option java_package = "com.example.grpc";
option java_outer_classname = "GreeterProto";
service Greeter {
rpc SayHello (HelloRequest) returns (HelloResponse);
}
message HelloRequest {
string name = 1;
}
message HelloResponse {
string message = 1;
}
이 파일은 다음을 정의합니다:
-
SayHello
RPC 메서드를 가진Greeter
서비스. -
name
필드를 포함하는HelloRequest
메시지. -
message
필드를 포함하는HelloResponse
메시지.
2. 종속성 추가
Spring Boot와 함께 gRPC를 사용하려면 pom.xml
에 다음 종속성을 추가합니다:
<dependencies>
<!-- Spring Boot Starter -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!-- Spring Boot Web for REST Controller -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- gRPC dependencies -->
<dependency>
<groupId>net.devh</groupId>
<artifactId>grpc-spring-boot-starter</artifactId>
<version>2.14.0.RELEASE</version>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-netty-shaded</artifactId>
<version>1.54.0</version>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-protobuf</artifactId>
<version>1.54.0</version>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-stub</artifactId>
<version>1.54.0</version>
</dependency>
<!-- Protobuf Java Format -->
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
<version>3.22.2</version>
</dependency>
</dependencies>
<build>
<plugins>
<!-- Protobuf Compiler Plugin -->
<plugin>
<groupId>org.xolstice.maven.plugins</groupId>
<artifactId>protobuf-maven-plugin</artifactId>
<version>0.6.1</version>
<configuration>
<protocArtifact>com.google.protobuf:protoc:3.22.2:exe:${os.detected.classifier}</protocArtifact>
<pluginId>grpc-java</pluginId>
<pluginArtifact>io.grpc:protoc-gen-grpc-java:1.54.0:exe:${os.detected.classifier}</pluginArtifact>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>compile-custom</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
이 종속성에는:
- 기본 애플리케이션 설정을 위한 Spring Boot 스타터.
- REST 컨트롤러 지원을 위한 Spring Boot 웹.
- 서버 및 클라이언트 구현을 위한 gRPC 라이브러리.
- 직렬화 및 역직렬화를 위한 Protobuf.
3. Java 클래스 생성
다음 Maven 명령을 실행하여 .proto
파일에서 Java 클래스를 생성합니다:
mvn clean compile
이것은 GreeterGrpc
및 관련 클래스를 target/generated-sources
디렉토리에서 생성합니다.
4. gRPC 서버 구현
다음으로 Spring Boot에서 gRPC 서버를 구현합니다. GreeterService
라는 이름의 클래스를 생성합니다:
package com.example.grpc.server;
import com.example.grpc.GreeterGrpc;
import com.example.grpc.GreeterProto.HelloRequest;
import com.example.grpc.GreeterProto.HelloResponse;
import io.grpc.stub.StreamObserver;
import net.devh.boot.grpc.server.service.GrpcService;
@GrpcService
public class GreeterService extends GreeterGrpc.GreeterImplBase {
@Override
public void sayHello(HelloRequest request, StreamObserver responseObserver) {
String name = request.getName();
String message = "Hello, " + name + "!";
HelloResponse response = HelloResponse.newBuilder().setMessage(message).build();
// 응답 전송
responseObserver.onNext(response);
responseObserver.onCompleted();
}
}
이 클래스는 생성된 GreeterGrpc.GreeterImplBase
를 확장하고 sayHello
메서드를 구현하여 들어오는 요청을 처리합니다.
5. gRPC 클라이언트 구현
이제 Spring Boot에서 gRPC 클라이언트를 구현합니다. GreeterClient
라는 이름의 클래스를 생성합니다:
package com.example.grpc.client;
import com.example.grpc.GreeterGrpc;
import com.example.grpc.GreeterProto.HelloRequest;
import com.example.grpc.GreeterProto.HelloResponse;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import org.springframework.stereotype.Service;
@Service
public class GreeterClient {
private final GreeterGrpc.GreeterBlockingStub blockingStub;
public GreeterClient() {
ManagedChannel channel = ManagedChannelBuilder.forAddress("localhost", 9090)
.usePlaintext()
.build();
this.blockingStub = GreeterGrpc.newBlockingStub(channel);
}
public String sayHello(String name) {
HelloRequest request = HelloRequest.newBuilder().setName(name).build();
HelloResponse response = blockingStub.sayHello(request);
return response.getMessage();
}
}
이 클라이언트는 gRPC 서버에 연결하고 SayHello
메서드에 요청을 보냅니다.
6. 테스트를 위한 REST 컨트롤러 추가
gRPC 클라이언트를 테스트하기 쉽게 하기 위해 GreeterClient
를 호출하는 엔드포인트를 노출하는 REST 컨트롤러를 추가합니다. GreeterController
라는 이름의 클래스를 생성합니다:
package com.example.grpc.controller;
import com.example.grpc.client.GreeterClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class GreeterController {
private final GreeterClient greeterClient;
@Autowired
public GreeterController(GreeterClient greeterClient) {
this.greeterClient = greeterClient;
}
@GetMapping("/greet")
public String greet(@RequestParam String name) {
return greeterClient.sayHello(name);
}
}
이 컨트롤러는 name
매개변수를 수락하고 gRPC 서버에서 응답을 반환하는 /greet
엔드포인트를 노출합니다.
7. Spring Boot 애플리케이션 생성
마지막으로 서버와 클라이언트를 실행할 Spring Boot 애플리케이션을 생성합니다:
package com.example.grpc;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class GrpcApplication {
public static void main(String[] args) {
SpringApplication.run(GrpcApplication.class, args);
}
}
8. 서버 포트 구성
application.properties
에 다음 구성을 추가합니다:
# gRPC 서버 포트
grpc.server.port=9090
# Spring Boot 서버 포트
server.port=8080
9. 애플리케이션 실행
- Spring Boot 애플리케이션을 시작합니다.
- gRPC 서버는
9090
포트에서 시작됩니다. - REST 컨트롤러는
8080
포트에서 사용할 수 있습니다.
GET 요청을 /greet
엔드포인트로 보내어 응용 프로그램을 테스트할 수 있습니다.
curl http://localhost:8080/greet?name=World
응답은 다음과 같습니다.
"Hello, World!"
Spring Boot용 올바른 gRPC 라이브러리 선택하기
gRPC 통합이 필요한 Spring Boot 응용 프로그램을 빌드할 때, 개발자들은 종종 net.devh.grpc
, org.lognet.grpc
, 그리고 org.springframework.grpc
와 같은 여러 라이브러리 중에서 선택해야 합니다.
각 라이브러리는 각각의 장점, 약점, 그리고 사용 사례가 있습니다. 이러한 라이브러리 간의 차이점, 기능, 그리고 프로젝트에 사용해야 할 라이브러리를 살펴보겠습니다.
1. net.devh.grpc (grpc-spring-boot-starter)
net.devh.grpc
또는 grpc-spring-boot-starter
로도 알려진 이 라이브러리는 gRPC를 Spring Boot와 통합하는 데 널리 사용되는 라이브러리입니다. 활발하게 유지보수되며 Spring Boot 응용 프로그램에서 gRPC 서버 및 클라이언트를 구축하는 데 강력한 기능 세트를 제공합니다.
주요 기능
- 자동 구성. gRPC 서버 및 클라이언트 설정을 간단하게 합니다.
- Spring 통합. 의존성 주입 및 기타 Spring 기능을 지원합니다.
- Spring 보안. 안전한 통신을 위해 Spring Security와 쉽게 통합됩니다.
- 상태 확인. Spring Boot Actuator를 통해 상태 확인을 제공합니다.
- 동기 및 비동기 통신. 두 통신 방식을 지원합니다.
사용 이유
- 적극적인 유지 보수. 라이브러리가 적극적으로 유지 보수되고 업데이트됩니다.
- 포괄적인 문서화. 다양한 지원을 위해 잘 문서화되어 있습니다.
- 제품 준비 상태. 제품 환경에서 널리 사용됩니다.
사용 시기
- 신뢰할 수 있고 기능이 풍부한 gRPC 통합이 필요한 새로운 Spring Boot 애플리케이션을 구축하는 경우.
- 의존성 주입, 보안 및 헬스 체크와 같은 Spring Boot 기능과 완벽하게 통합하고 싶은 경우.
2. org.lognet.grpc (grpc-spring-boot-starter)
org.lognet.grpc
은 Spring Boot와 gRPC를 통합하는 또 다른 라이브러리입니다. 그러나 net.devh.grpc
와 비교할 때 활발하게 유지되지는 않으며 후자가 제공하는 일부 고급 기능이 부족합니다.
주요 기능
- 기본 gRPC 설정. gRPC 서버 및 클라이언트에 대한 기본 지원을 제공합니다.
- Spring Boot 통합. Spring Boot와 함께 작동하지만 기능이 적습니다.
사용 이유
- 역사적 사용. gRPC 및 Spring Boot 통합의 초기 라이브러리 중 하나였습니다.
- 단숨함. 간단한 사용 사례에 적합합니다.
사용 시기
- 이미 이 라이브러리를 사용하는 이전 프로젝트에 작업 중인 경우.
- 새로운 프로젝트에는 추천되지 않습니다. 유지보수가 제한적이며 기능이 적습니다.
3. org.springframework.grpc (Spring gRPC)
org.springframework.grpc
는 gRPC를 Spring과 통합하기 위한 실험적이거나 커뮤니티 주도의 노력입니다. 이것은 공식 Spring 프로젝트가 아니며 net.devh.grpc
만큼 성숙하거나 기능이 풍부하지 않을 수 있습니다.
주요 기능
- 기본 gRPC 통합. gRPC 서버 및 클라이언트에 대한 기본 지원을 제공합니다.
- Spring 생태계 조정. Spring 생태계와 밀접하게 조정되도록 설계되었습니다.
사용 이유
- 실험적 사용. 실험이나 프로젝트에 기여하기에 적합합니다.
- Spring 조정. Spring과 밀접하게 조정된 것을 선호하는 경우.
사용 시기
- 프로젝트를 탐색하거나 기여하는 경우에만 사용하십시오.
- 실험적 성격 때문에 제품 사용을 권장하지 않습니다.
어느 것을 사용해야 하는가?
새로운 프로젝트용
net.devh.grpc
(grpc-spring-boot-starter)를 사용하십시오. gRPC를 Spring Boot와 통합하기 위한 가장 성숙하고 활발히 유지되며 기능이 풍부한 옵션입니다. Spring Boot 기능과의 원활한 통합으로 새로운 프로젝트에 가장 적합한 선택입니다.
기존 프로젝트용
이미 org.lognet.grpc
를 사용 중이라면, 더 나은 지원과 기능을 위해 net.devh.grpc
로 마이그레이션하는 것을 고려해 보세요. org.lognet.grpc
는 오래된 프로젝트에는 작동할 수 있지만, net.devh.grpc
의 활발한 유지 관리와 고급 기능이 부족합니다.
실험적 사용
Spring gRPC 통합을 탐색하거나 기여하고 있다면, org.springframework.grpc
를 살펴볼 수 있습니다. 그러나 실험적인 특성으로 인해 프로덕션 사용에는 권장되지 않습니다.
주요 고려 사항
- 커뮤니티 지원.
net.devh.grpc
는 더 큰 커뮤니티와 더 나은 문서를 가지고 있어 도움과 자료를 찾기가 더 쉽습니다. - 프로덕션 준비 상태.
net.devh.grpc
는 프로덕션 환경에서 널리 사용되며 안정적이고 신뢰할 수 있는 것으로 간주됩니다. - 사용 용이성.
net.devh.grpc
는 자동 구성 및 Spring Boot와의 원활한 통합을 제공하여 설정의 복잡성을 줄입니다.
결론
gRPC는 마이크로서비스 통신을 위한 강력한 도구로, 높은 성능, 강력한 타입 지정 및 스트리밍과 같은 고급 기능을 제공합니다. REST에 비해 초기 설정이 더 필요하지만, 효율성과 확장성 덕분에 현대의 분산 시스템에 적합한 선택입니다.
마이크로서비스 아키텍처가 복잡해지면 gRPC는 서비스 간 원활한 통신을 가능하게 하는 데 점점 더 중요한 역할을 합니다. 이 기사에서는 Spring Boot 3를 사용하여 간단한 gRPC 클라이언트 및 서버 애플리케이션을 구축했습니다. 프로토콜 버퍼를 사용하여 gRPC 서비스를 정의하고 Java 클래스를 생성하고 서버 및 클라이언트를 구현하고 쉬운 테스트를 위해 REST 컨트롤러를 추가했습니다. 이 예제는 gRPC의 강력함과 간결함을 보여주며 고성능, 확장 가능하고 상호 운용 가능한 서비스를 구축하는 데 도움이 됩니다. 더 복잡한 서비스, 스트리밍 또는 오류 처리로 확장할 수 있습니다. 즐거운 코딩 하세요!
GitHub 저장소: grpc-client-and-server-with-spring-boot.
Source:
https://dzone.com/articles/understanding-grpc-and-its-role-in-microservices-c