본문 바로가기
개발/네트워크

gRPC

by Devsong26 2023. 10. 22.

gRPC는 Google에서 개발한 오픈 소스 원격 프로시저 호출 (RPC) 프레임워크입니다. gRPC는 클라이언트와 서버 간의 통신을 위해 고성능, 확장성 및 안정성을 제공하며, 다양한 언어 및 플랫폼 간의 상호 운용성을 지원합니다. 

다음은 gRPC의 주요 특징 및 컨셉트에 대한 설명입니다:

1. 프로토콜 버퍼 (Protocol Buffers): gRPC는 기본적으로 Protocol Buffers (protobuf)를 사용하여 데이터를 직렬화합니다. Protocol Buffers는 Google에서 개발한 이진 직렬화 포맷으로, JSON이나 XML보다 효율적이며 빠르게 데이터를 직렬화/역직렬화할 수 있습니다. gRPC 사용자는 `.proto` 파일에 서비스 및 메시지 타입을 정의하며, 이를 기반으로 다양한 언어의 클라이언트 및 서버 코드를 생성할 수 있습니다.

2. HTTP/2: gRPC는 전송 계층으로 HTTP/2를 사용합니다. 이를 통해 헤더 압축, 다중화된 스트림, 서버 푸시 등과 같은 고급 기능을 지원합니다.

3. 언어 및 플랫폼 지원: gRPC는 여러 프로그래밍 언어 (Java, Go, C++, Python, Node.js 등) 및 플랫폼에서 사용될 수 있습니다. `.proto` 파일에서 생성된 코드는 다양한 언어로의 상호 운용성을 제공합니다.

4. 스트리밍: gRPC는 단방향 및 양방향 스트리밍을 지원합니다. 클라이언트와 서버 모두 스트리밍 요청 또는 응답을 전송할 수 있습니다.

5. 최종 사용자 인증: gRPC는 SSL/TLS 및 Google 토큰 기반 인증과 같은 다양한 인증 메커니즘을 지원합니다.

6. 데드라인/타임아웃: gRPC 호출에는 데드라인 또는 타임아웃을 지정할 수 있습니다. 이는 네트워크 지연이나 서버 장애 시에 클라이언트가 무한정 대기하는 것을 방지하는 데 유용합니다.

7. 취소: 클라이언트는 서버에게 호출을 취소할 수 있으며, 서버는 이 취소를 감지하고 해당 연산을 중단할 수 있습니다.

8. 플로우 컨트롤: gRPC는 HTTP/2 기반의 플로우 컨트롤을 사용하여 데이터 전송을 효율적으로 관리합니다.

9. 에러 처리: gRPC는 표준화된 상태 코드를 사용하여 다양한 에러 유형을 클라이언트에게 알릴 수 있습니다.

gRPC는 마이크로서비스 아키텍처, 클라우드 서비스, 모바일 애플리케이션 및 고성능 원격 프로시저 호출에 적합하도록 설계되었습니다. 효율적인 데이터 전송, 다양한 언어 지원 및 기타 고급 기능 덕분에 많은 조직에서 gRPC를 선택하여 서비스 간의 통신을 구현하고 있습니다.

 

 

 

RESTFul API와 비교

RESTful API와 gRPC는 웹 서비스와 분산 시스템에서 클라이언트와 서버 간의 통신을 위한 인터페이스를 제공합니다. 둘 다 각각의 장점과 특징을 가지고 있습니다. 아래는 RESTful API와 gRPC의 주요 차이점과 특징을 비교한 내용입니다:

RESTful API:

1. 프로토콜: 주로 HTTP/1.1을 사용하지만 HTTP/2를 사용하는 경우도 있습니다.
   
2. 데이터 포맷: 주로 JSON을 사용하여 데이터를 표현합니다. XML 등 다른 포맷을 사용하는 경우도 있습니다.
   
3. 디자인 패러다임: 리소스 중심의 아키텍처를 가지며, 표준 HTTP 메소드 (GET, POST, PUT, DELETE 등)를 사용하여 리소스에 대한 CRUD 연산을 표현합니다.
   
4. 통신 방식: 주로 요청-응답 패턴을 사용합니다.
   
5. 성능: 텍스트 기반의 JSON 포맷과 HTTP/1.1 프로토콜의 제약 때문에 gRPC보다 상대적으로 성능이 떨어질 수 있습니다. 하지만 HTTP/2를 사용하면 성능 개선이 가능합니다.

gRPC:

1. 프로토콜: HTTP/2를 기반으로 합니다. 이로 인해 헤더 압축, 다중화된 스트림, 서버 푸시 등의 기능을 활용할 수 있습니다.
   
2. 데이터 포맷: Protocol Buffers를 사용하여 데이터를 직렬화합니다. 이는 이진 포맷으로, JSON보다 효율적이고 빠른 직렬화 및 역직렬화가 가능합니다.
   
3. 디자인 패러다임: 프로시저 호출을 중심으로 하며, 서비스와 메서드를 정의하여 사용합니다.
   
4. 통신 방식: 단방향, 양방향 스트리밍을 지원합니다. 요청-응답 패턴 뿐만 아니라 연속적인 데이터 교환도 가능합니다.
   
5. 성능: HTTP/2와 Protocol Buffers를 사용하기 때문에 빠른 성능과 낮은 지연 시간을 제공합니다.

결론:

- RESTful API는 웹 표준과 밀접하며, 다양한 플랫폼 및 언어에서의 지원이 광범위합니다. 디버깅이 상대적으로 쉽고, 웹 브라우저와의 호환성이 좋습니다.
  
- gRPC는 고성능 원격 호출에 초점을 맞추고 있으며, 효율적인 데이터 전송과 다양한 통신 패턴을 지원합니다. 마이크로서비스 아키텍처나 클라우드 네이티브 애플리케이션에서 주로 사용됩니다.

따라서, 서비스의 요구 사항과 기대하는 성능, 통신 패턴, 개발 환경 등에 따라 적절한 방식을 선택해야 합니다.RESTful API와 gRPC는 웹 서비스와 분산 시스템에서 클라이언트와 서버 간의 통신을 위한 인터페이스를 제공합니다. 둘 다 각각의 장점과 특징을 가지고 있습니다. 아래는 RESTful API와 gRPC의 주요 차이점과 특징을 비교한 내용입니다:

 

API 응답이 이벤트스트림이면 gRPC가 더 적합한가?

이벤트 스트림을 다룰 때 gRPC는 여러 가지 이유로 유용한 선택이 될 수 있습니다:

1. 양방향 스트리밍: gRPC는 양방향 스트리밍을 지원하며, 이를 통해 서버와 클라이언트 간에 연속적으로 데이터를 교환할 수 있습니다. 이러한 특성은 이벤트 기반의 통신에 매우 적합합니다.

2. 효율적인 데이터 전송: gRPC는 Protocol Buffers를 사용하여 이진 형식으로 데이터를 전송합니다. 이는 텍스트 기반의 이벤트 스트림보다 더 효율적일 수 있으며, 특히 빈번하게 발생하는 이벤트에 대해 높은 효율성을 제공합니다.

3. HTTP/2 기반: gRPC는 HTTP/2를 기반으로 합니다. 이는 효율적인 헤더 압축, 요청 및 응답의 다중화, 서버 푸시 등의 기능을 활용하여 성능을 향상시킵니다. 이벤트 스트림에는 이러한 HTTP/2의 특징들이 유용하게 사용될 수 있습니다.

4. 강력한 타입 및 인터페이스 정의: gRPC에서는 `.proto` 파일을 통해 메시지와 서비스를 명확하게 정의할 수 있습니다. 이로 인해 이벤트의 형식과 서비스의 인터페이스가 명확하게 지정되어, 더 강력한 형식 안정성과 개발자 간의 명확한 커뮤니케이션을 제공합니다.

5. 플랫폼 및 언어 지원: gRPC는 여러 플랫폼 및 언어에서 지원됩니다. 따라서 다양한 시스템과 클라이언트에서 이벤트 스트림을 쉽게 사용할 수 있습니다.

그러나 gRPC를 사용하기 전에 몇 가지 고려 사항이 있습니다:

- 브라우저 지원: 웹 브라우저에서의 이벤트 스트림을 위해 Server-Sent Events (SSE)와 같은 다른 기술을 사용할 계획이라면, gRPC는 기본적으로 SSE를 지원하지 않습니다.
  
- 학습 곡선: gRPC 및 Protocol Buffers에 익숙하지 않은 팀의 경우 학습 곡선이 있을 수 있습니다.

- 통합: 이미 RESTful API나 다른 통신 방법을 사용하는 기존 시스템과의 통합을 고려해야 합니다.

결론적으로, 이벤트 스트림 형태의 응답이 주된 목적이라면 gRPC는 그 목적을 위한 강력하고 효율적인 방법을 제공합니다. 그러나 특정 환경과 요구 사항에 따라 최적의 선택이 될 수도 있고 아닐 수도 있으므로, 여러 관점에서 검토하는 것이 중요합니다.

 

 


 

스프링 부트로 gRPC 통신을 구현해 보겠습니다.

스펙은 스프링 부트 3.x 버전과 gradle입니다.

 

build.gradle에 아래와 같이 설정 코드를 추가합니다.

plugins {
	...
	id 'com.google.protobuf' version '0.8.17'
    ...
}

protobuf {
	protoc {
		artifact = "com.google.protobuf:protoc:3.17.3"
	}
	plugins {
		grpc {
			artifact = "io.grpc:protoc-gen-grpc-java:1.40.1"
		}
	}
	generateProtoTasks {
		all()*.plugins {
			grpc {}
		}
	}
}

dependencies {
	...
    
	implementation 'net.devh:grpc-spring-boot-starter:2.13.0.RELEASE'
	implementation 'io.grpc:grpc-netty-shaded:1.40.1'
	implementation 'io.grpc:grpc-protobuf:1.40.1'
	implementation 'io.grpc:grpc-stub:1.40.1'
	implementation 'javax.annotation:javax.annotation-api:1.3.2' // java 9버전 이상에서는 필요
    
    ...
}

gRPC 의존성은 스프링 부트에서 버전관리를 하지 않습니다.

 

.proto 파일을 추가해야 합니다.

.proto 파일은 Protocol Buffers (protobuf)의 스펙을 사용하여 서비스와 메시지를 정의하는 파일입니다. gRPC에서는 이 파일을 사용하여 RPC 서비스 및 해당 메시지를 정의합니다.

.proto 파일 작성은 전용 언어가 있으므로 아래 페이지를 참고해주세요.

https://protobuf.dev/programming-guides/proto3/

 

src/main/proto 경로를 생성한 다음에 .proto 파일을 아래와 같이 생성합니다.

syntax = "proto3";

package demo;

service Greeter {
  rpc SayHello (HelloRequest) returns (HelloReply);
}

message HelloRequest {
  string name = 1;
}

message HelloReply {
  string message = 1;
}

 

Gradle 프로젝트를 빌드하면 .proto 파일의 설정이 아래 경로에 자바 클래스로 생성됩니다.

build/generated/source/proto/main/grpc/demo/~Grpc

 

 

해당 클래스를 import 하여 @GrpcService 클래스를 개발합니다.

import demo.GreeterGrpc;
import demo.GreeterOuterClass;
import io.grpc.stub.StreamObserver;
import net.devh.boot.grpc.server.service.GrpcService;

@GrpcService
public class GreeterImpl extends GreeterGrpc.GreeterImplBase{

    @Override
    public void sayHello(GreeterOuterClass.HelloRequest req, StreamObserver<GreeterOuterClass.HelloReply> responseObserver) {
        GreeterOuterClass.HelloReply reply = GreeterOuterClass.HelloReply.newBuilder().setMessage("Hello, " + req.getName()).build();
        responseObserver.onNext(reply);
        responseObserver.onCompleted();
    }

}

 

단, 스프링 부트 3.x 버전에서는 gRPC 설정 빈이 자동으로 생성되지 않으므로 이를 수동으로 생성하는 @Configuration을 개발해야 합니다. 아래는 예시입니다.

import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
import org.springframework.context.annotation.Configuration;

@Configuration
@ImportAutoConfiguration({
        net.devh.boot.grpc.common.autoconfigure.GrpcCommonCodecAutoConfiguration.class,
        net.devh.boot.grpc.common.autoconfigure.GrpcCommonTraceAutoConfiguration.class,

        net.devh.boot.grpc.server.autoconfigure.GrpcAdviceAutoConfiguration.class,
        net.devh.boot.grpc.server.autoconfigure.GrpcHealthServiceAutoConfiguration.class,
        net.devh.boot.grpc.server.autoconfigure.GrpcMetadataConsulConfiguration.class,
        net.devh.boot.grpc.server.autoconfigure.GrpcMetadataEurekaConfiguration.class,
        net.devh.boot.grpc.server.autoconfigure.GrpcMetadataNacosConfiguration.class,
        net.devh.boot.grpc.server.autoconfigure.GrpcMetadataZookeeperConfiguration.class,
        net.devh.boot.grpc.server.autoconfigure.GrpcReflectionServiceAutoConfiguration.class,
        net.devh.boot.grpc.server.autoconfigure.GrpcServerAutoConfiguration.class,
        net.devh.boot.grpc.server.autoconfigure.GrpcServerFactoryAutoConfiguration.class,
        net.devh.boot.grpc.server.autoconfigure.GrpcServerMetricAutoConfiguration.class,
        net.devh.boot.grpc.server.autoconfigure.GrpcServerSecurityAutoConfiguration.class,
        net.devh.boot.grpc.server.autoconfigure.GrpcServerTraceAutoConfiguration.class
})
public class GrpcConfig {
}

 

마지막으로 gRPC의 포트를 application.properties 등에 설정해야 합니다.

grpc.port=9090

 

스프링 부트를 기동 시 아래와 같은 로그를 확인할 수 있습니다.

2023-10-25T22:42:58.422+09:00  INFO 10356 --- [           main] n.d.b.g.s.s.AbstractGrpcServerFactory    : Registered gRPC service: demo.Greeter, bean: greeterImpl, class: com.devsong26.blog.grpc.GreeterImpl
2023-10-25T22:42:58.422+09:00  INFO 10356 --- [           main] n.d.b.g.s.s.AbstractGrpcServerFactory    : Registered gRPC service: grpc.health.v1.Health, bean: grpcHealthService, class: io.grpc.protobuf.services.HealthServiceImpl
2023-10-25T22:42:58.422+09:00  INFO 10356 --- [           main] n.d.b.g.s.s.AbstractGrpcServerFactory    : Registered gRPC service: grpc.reflection.v1alpha.ServerReflection, bean: protoReflectionService, class: io.grpc.protobuf.services.ProtoReflectionService
2023-10-25T22:42:58.607+09:00  INFO 10356 --- [           main] n.d.b.g.s.s.GrpcServerLifecycle          : gRPC Server started, listening on address: *, port: 9090

 

포스트맨으로 gRPC 서버와 통신을 해보겠습니다.

1번: g 표시의 기본값이 HTTP이므로 변경해주셔야 합니다.

2번: grpc.port를 설정합니다.

3번: 작성했던 .proto 파일을 셋팅하면 포스트맨이 메서드 명을 나열하며 원하는 것을 선택하면 됩니다.

4번: .proto 파일을 참고하여 요청 포맷을 완성합니다.

5번: invoke 버튼을 눌러 호출합니다.

6번: @GrpcService의 개발된 코드의 응답 메시지 포맷과 일치하는지 확인합니다.

 

 


 

Reference URIs

https://velog.io/@mbsik6082/Spring-Boot-gRPC-Server-%EC%8B%A4%ED%96%89%EC%8B%9C%EC%9E%91-%EC%95%88-%EB%90%98%EB%8A%94-%EC%98%A4%EB%A5%98-gRPC-server-not-start-error-when-using-spring-boot

https://protobuf.dev/programming-guides/proto3/

'개발 > 네트워크' 카테고리의 다른 글

루프백(Loopback)  (0) 2023.12.17
OSI 7 Layer  (0) 2023.10.24
[Network] HTTP 통신  (0) 2021.05.31