개요

gRPC는 Google이 개발한 고성능 RPC 프레임워크로, Protocol Buffers를 사용하여 JSON보다 빠르고 작은 페이로드를 제공합니다. Spring Boot에서 gRPC를 사용하면 REST API 대비 10배 이상 빠른 마이크로서비스 간 통신을 구현할 수 있습니다. 이 문서에서는 Spring Boot 3.5와 gRPC-Spring-Boot-Starter를 활용한 실전 구현 방법을 다룹니다.

의존성 및 플러그인 설정

gRPC와 Protobuf 코드 생성을 위한 의존성을 추가합니다.

<properties>
    <grpc.version>1.60.0</grpc.version>
    <protobuf.version>3.25.1</protobuf.version>
</properties>

<dependencies>
    <dependency>
        <groupId>net.devh</groupId>
        <artifactId>grpc-spring-boot-starter</artifactId>
        <version>3.1.0.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>io.grpc</groupId>
        <artifactId>grpc-protobuf</artifactId>
        <version>1.60.0</version>
    </dependency>
    <dependency>
        <groupId>io.grpc</groupId>
        <artifactId>grpc-stub</artifactId>
        <version>1.60.0</version>
    </dependency>
</dependencies>

<build>
    <extensions>
        <extension>
            <groupId>kr.motd.maven</groupId>
            <artifactId>os-maven-plugin</artifactId>
            <version>1.7.1</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.25.1:exe:detect
                </protocArtifact>
                <pluginId>grpc-java</pluginId>
                <pluginArtifact>
                    io.grpc:protoc-gen-grpc-java:1.60.0:exe:detect
                </pluginArtifact>
            </configuration>
            <executions>
                <execution>
                    <goals>
                        <goal>compile</goal>
                        <goal>compile-custom</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

Protocol Buffers 정의

서비스와 메시지 타입을 .proto 파일로 정의합니다.

// src/main/proto/user_service.proto
syntax = "proto3";

option java_multiple_files = true;
option java_package = "com.example.grpc.user";

package user;

service UserService {
  rpc GetUser(UserRequest) returns (UserResponse);
  rpc CreateUser(CreateUserRequest) returns (UserResponse);
  rpc StreamUsers(StreamRequest) returns (stream UserResponse);
}

message UserRequest {
  int64 id = 1;
}

message CreateUserRequest {
  string name = 1;
  string email = 2;
}

message UserResponse {
  int64 id = 1;
  string name = 2;
  string email = 3;
  int64 created_at = 4;
}

message StreamRequest {
  int32 limit = 1;
}

gRPC 서버 구현

@GrpcService 어노테이션으로 서비스를 구현합니다.

@GrpcService
@RequiredArgsConstructor
public class UserGrpcService extends UserServiceGrpc.UserServiceImplBase {

    private final UserRepository userRepository;

    @Override
    public void getUser(UserRequest request,
                        StreamObserver<UserResponse> responseObserver) {
        User user = userRepository.findById(request.getId())
            .orElseThrow(() -> new StatusRuntimeException(
                Status.NOT_FOUND.withDescription("User not found")
            ));

        UserResponse response = UserResponse.newBuilder()
            .setId(user.getId())
            .setName(user.getName())
            .setEmail(user.getEmail())
            .setCreatedAt(user.getCreatedAt().toEpochSecond())
            .build();

        responseObserver.onNext(response);
        responseObserver.onCompleted();
    }

    @Override
    public void createUser(CreateUserRequest request,
                           StreamObserver<UserResponse> responseObserver) {
        User user = new User(request.getName(), request.getEmail());
        User saved = userRepository.save(user);

        UserResponse response = UserResponse.newBuilder()
            .setId(saved.getId())
            .setName(saved.getName())
            .setEmail(saved.getEmail())
            .setCreatedAt(saved.getCreatedAt().toEpochSecond())
            .build();

        responseObserver.onNext(response);
        responseObserver.onCompleted();
    }

    @Override
    public void streamUsers(StreamRequest request,
                            StreamObserver<UserResponse> responseObserver) {
        userRepository.findAll(PageRequest.of(0, request.getLimit()))
            .forEach(user -> {
                UserResponse response = UserResponse.newBuilder()
                    .setId(user.getId())
                    .setName(user.getName())
                    .setEmail(user.getEmail())
                    .build();

                responseObserver.onNext(response);
            });

        responseObserver.onCompleted();
    }
}

gRPC 클라이언트 구현

@GrpcClient 어노테이션으로 다른 서비스를 호출합니다.

@Service
public class OrderService {

    @GrpcClient("user-service")
    private UserServiceGrpc.UserServiceBlockingStub userStub;

    public Order createOrder(Long userId, OrderRequest request) {
        // gRPC로 사용자 정보 조회
        UserResponse user = userStub.getUser(
            UserRequest.newBuilder()
                .setId(userId)
                .build()
        );

        // 주문 생성 로직
        Order order = new Order(user.getName(), request.getProduct());
        return orderRepository.save(order);
    }
}
# application.yml
grpc:
  server:
    port: 9090
  client:
    user-service:
      address: 'static://localhost:9090'
      negotiationType: plaintext  # 개발 환경
      # 프로덕션: TLS 설정
      # enableKeepAlive: true
      # keepAliveTime: 30s

활용 팁

  • 에러 처리: StatusRuntimeException으로 gRPC 표준 에러 코드를 반환합니다. (NOT_FOUND, INVALID_ARGUMENT, PERMISSION_DENIED 등)
  • 인터셉터: @GrpcGlobalServerInterceptor로 인증, 로깅, 메트릭 수집을 전역 처리할 수 있습니다.
  • 스트리밍: Server/Client/Bidirectional 스트리밍으로 실시간 데이터 전송이 가능합니다.
  • TLS 보안: 프로덕션 환경에서는 반드시 TLS를 활성화하여 데이터를 암호화해야 합니다.
  • 성능: JSON REST API 대비 직렬화 속도가 5~10배 빠르고, 페이로드 크기가 30~50% 작습니다.

마무리

Spring Boot와 gRPC의 조합은 마이크로서비스 간 통신 성능을 극대화합니다. Protocol Buffers의 타입 안정성 덕분에 컴파일 타임에 계약을 검증할 수 있고, HTTP/2 기반으로 멀티플렉싱과 스트리밍을 지원합니다. REST API는 외부 클라이언트용으로 유지하고, 내부 서비스 간 통신은 gRPC로 전환하면 전체 시스템 성능을 크게 개선할 수 있습니다. 특히 높은 처리량이 요구되는 결제, 추천, 검색 등의 서비스에서 즉각적인 효과를 체감할 수 있습니다.