스프링

Spring Webflux + grpc + Armeria

du.study 2021. 2. 7. 22:02
728x90

이번엔 스프링으로 grpc를 사용하는 과정에서 armeria를 사용하는법에 대해 기록하려합니다.

github.com/line/armeria

 

line/armeria

Your go-to microservice framework for any situation, from the creator of Netty et al. You can build any type of microservice leveraging your favorite technologies, including gRPC, Thrift, Kotlin, ...

github.com

 

우선 armeria 이전에 grpc-gateway를 먼저 간략하게 기록해보려합니다.

github.com/grpc-ecosystem/grpc-gateway

 

grpc-ecosystem/grpc-gateway

gRPC to JSON proxy generator following the gRPC HTTP spec - grpc-ecosystem/grpc-gateway

github.com

grpc를 메인으로 통신하지만, 부분으적으로 http 통신을 같이 받아야하는 일이 종종 있습니다. 이경우, grpc통신을 메인으로 하되, 해당 라이브러리를 적용하여 http 통신또한 받을 수 있도록 적용하였습니다.

 

이 경우,  spring project와는 별도로 grpc-gateway를 두어야하며, 스프링 grpc port, server port별도 오픈이 필요하며,  grpc-gateway 에서도 http port를 스프링 grpc post에 매핑이 필요하게 됩니다.

 

글로 간략하게 썼지만,  만약 postman같은 툴을 통해서 http로 테스트를 하는경우 해당방식은 매우매우 귀찮아 질 수 있습니다. 서비스외 ,grpc-gateway를 띄워야하고, port 설정 봐주고.. 등등

 

복합적인 이유로 armeria를 적용해보고 있습니다. ( 내부코드 계속 보는중..)

armeria를 적용하게된 이유로 다음과 같은 이유들이 있습니다.

1. grpc port와 http port를 동일하게 지원해준다.

2. spring webflux와 간결하게 도킹이 가능하다.

3. gpc 스트림 지원 

이외에 여러가지..

 

 

우선 테스트에 사용할 proto 예시입니다. (공식 github example grpc)

syntax = "proto3";

package example.grpc.hello;
option java_package = "example.armeria.grpc";

service HelloService {
  rpc Hello (HelloRequest) returns (HelloReply) {}
  rpc LazyHello (HelloRequest) returns (HelloReply) {}
  rpc BlockingHello (HelloRequest) returns (HelloReply) {}
  rpc LotsOfReplies (HelloRequest) returns (stream HelloReply) {}
  rpc LotsOfGreetings (stream HelloRequest) returns (HelloReply) {}
  rpc BidiHello (stream HelloRequest) returns (stream HelloReply) {}
}

message HelloRequest {
  string name = 1;
}

message HelloReply {
  string message = 1;
}

 

spring 에서 Armeria 관련 configuration입니다.

@Configuration
@RequiredArgsConstructor
public class ArmeriaConfiguration {
  private final GrpcService grpcService;

  @Bean
  public ArmeriaServerConfigurator armeriaServerConfigurator() {
    return serverBuilder -> {

      serverBuilder.decorator(LoggingService.newDecorator());
      serverBuilder.accessLogWriter(AccessLogWriter.combined(), false);

      serverBuilder.service(
          GrpcService.builder()
              .addService(grpcService)
              .supportedSerializationFormats(GrpcSerializationFormats.values())
              .enableUnframedRequests(true)
              .build());

      serverBuilder.serviceUnder("/docs", new DocService());
    };
  }
}

해당 proto를 빌드 및 armeria를 적용하면서 grpc를 별도 설정없이 사용하는경우 다음과 같은 proto의 http 경로는 다음과 같습니다.

package + serviceName + "/" +methodName

즉 rpc Hello의 경우 아래와 같은 Path를 가지게 됩니다.

/example.grpc.hello/Hello

또한 /docs설정을 통해 grpc에 매핑된 정보를 admin처럼 볼 수 있습니다.

추가로 grpc 함수에 대해서 별도의 http 경로를 설정해줄 수도 있습니다.

ServerBuilder sb = ...
sb.service(GrpcService.builder()
                      // Bind 'getProfile()' method to '/v1/api/users/profile'
                      .addService("/v1/api/users/profile", userService,
                                  UserServiceGrpc.getProfile())
                      // Bind 'getFriends()' method to '/v1/api/users/friends'
                      .addService("/v1/api/users/friends", userService,
                                  UserServiceGrpc.getFriends())
                      .build());

 

해당코드 참고 경로 : github.com/line/armeria/blob/8c57ecbcb2fef9e496cabdeddb7ad2c0f3a2e26d/site/src/pages/release-notes/1.2.0.mdx

 

다만 grpc-gateway 대비 아쉬운부분? ( 내가 못찾고 있는 부분..)은 grpc method를 http로 호출하는 경우, 전부 httpMethod.POST 로 적용되는것 같습니다. (service에 분명 method를 넘기는 게 있는것 같은데..)

해당부분 혹시 방법을 아신다면 댓글좀 부탁드립니다!

728x90