본문 바로가기

gRPC

gRPC 기초 + 실습 예제

GRPC

목차

  1. RPC란?
  2. gRPC란?
  3. start gRPC with java + python
    1. java gRPC server
    2. java gRPC client
    3. python gRPC client
    4. with docker

 

1. RPC란?

Remote Procedure Call의 약자. 원격에 있는 함수를 호출하는 것을 말한다.

과거엔 프로세스간 통신을 위해 많이 사용되었으나 현재는 웹 기술의 발달로 SOAP, REST에 많이 밀려난 상태.

분산컴퓨팅 환경에서 많이 사용하며 MSA에서도 사용하기 적절하다.

 

Skeleton, Stub이라고 부르는 IDL 코드로 request params, response params를 파악해야 함

(작성중)

 

 

2. gRPC란?

구글에서 사용하던 'Stubby' 라는 RPC 스택을 강화하여 오픈소스화한 기술.

http/2 사용

Protocol buffers 사용

Low Latency, Highly scalable, distributed systems

(작성중)

 

 

3. start gRPC with java + python(일단 STEP 나열하고 설명은 나중에)

3-1. java gRPC Server

0. 작업용 디렉토리 생성. 앞으로 '핸즈온 디렉토리'는 여기서 만든 디렉토리를 의미합니다. 이름은 자유! (예 : grpc_handson)

1. 핸즈온 디렉토리에 서버용 프로젝트 생성.(Gradle, jdk 1.8) 이름은 자유! (예 : java_grpc_server)

2. build.gradle 내용 추가

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.8'
    }
}

plugins {
    id 'java'
}

sourceCompatibility = 1.8
targetCompatibility = 1.8

sourceSets {
    src {
        main {
            java {
                srcDirs 'build/generated/source/proto/main/grpc'
                srcDirs 'build/generated/source/proto/main/java'
            }
        }
    }
}

jar {
//  enabled = true
    archivesBaseName   = "grpc_handson_jar"
    from {
        configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) }
    }
    manifest {
        attributes 'Main-Class' : "HelloServerRunner"
    }
}

apply plugin: 'com.google.protobuf'

repositories {
    mavenCentral()
}

dependencies {
    /**
     * gRPC
     */
    compile group: 'io.grpc', name: 'grpc-netty-shaded', version: '1.35.0'
    compile group: 'io.grpc', name: 'grpc-protobuf', version: '1.35.0'
    compile group: 'io.grpc', name: 'grpc-stub', version: '1.35.0'

    implementation 'javax.annotation:javax.annotation-api:1.3.2'
    implementation "com.google.protobuf:protobuf-java-util:3.8.0"
    compile group: 'com.google.protobuf', name: 'protobuf-java', version: '3.8.0'

    testCompile group: 'junit', name: 'junit', version: '4.12'
}

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

3. 프로젝트 디렉토리 > src > main 하위에 'proto' 디렉토리 생성

4. 생성한 디렉토리에 'HelloService.proto' 파일 생성 및 내용 작성

syntax = "proto3";

option java_multiple_files = true;

message HelloRequest {
  string name = 1;
  string alias = 2;
}

message HelloResponse {
  string greeting = 1;
}

service HelloService {
  rpc hello(HelloRequest) returns (HelloResponse);
}

5. 우측 Gradle 탭 > Tasks > other > generateProto 실행 (없을 경우 gradle > Reload All Gradle Projects)

6. src > main > java에 'HelloServiceImpl.java' 클래스 생성 및 내용 작성

public class HelloServiceImpl extends HelloServiceGrpc.HelloServiceImplBase{

  @Override
  public void hello(HelloRequest request, StreamObserver<HelloResponse> responseObserver) {
    String greeting = "Hello, " + request.getName() + " a.k.a. " + request.getAlias();

    System.out.println("Remote client called a service 'hello'.");

    HelloResponse helloResponse = HelloResponse.newBuilder()
        .setGreeting(greeting)
        .build();

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

7. src > main > java에 'HelloServerRunner.java' 클래스 생성 및 내용 작성

public class HelloServerRunner {
  public static void main(String args[]) throws IOException, InterruptedException {
    Server server = ServerBuilder
        .forPort(36200)
        .addService(new HelloServiceImpl()).build();

    System.out.println("Listening port 36200...");

    server.start();
    server.awaitTermination();
  }
}

8. 서버 실행

 

 

3-2. java gRPC Client

1. 핸즈온 디렉토리에 서버 생성 STEP의 1~5번 진행. 프로젝트 이름은 자유! (예 : java_grpc_client)

2. src > main > java에 'HelloClientRunner.java' 생성 및 내용 작성

public class HelloClientRunner {
  public static void main(String[] args) {
    ManagedChannel channel = ManagedChannelBuilder.forAddress("localhost", 36200)
        .usePlaintext()
        .build();

    HelloServiceGrpc.HelloServiceBlockingStub stub
        = HelloServiceGrpc.newBlockingStub(channel);

    HelloResponse helloResponse = stub.hello(HelloRequest.newBuilder()
        .setName("Leo")           //Replace to ur name :)
        .setAlias("grpc newbie")  //Replace to ur alias :)
        .build());

    System.out.println("\n-----------------------------------------");
    System.out.print(helloResponse);
    System.out.println("-----------------------------------------\n");

    channel.shutdown();
  }
}

3. 클라이언트 실행

 

3-3. python gRPC Client 

1. 준비물 준비

pip3 install --upgrade pip
pip3 install grpcio
pip3 install grpcio-tools
pip3 install --upgrade google-api-python-client --ignore-installed

cd ${handson_directory}
mkdir ${python_grpc_client} //as you wanna naming
cd ${python_grpc_client}

2. 'HelloService.proto' 파일 생성. 내용은 서버에서 사용한 것과 정확히 같음.

syntax = "proto3";

option java_multiple_files = true; //이건 빼도 된다.

message HelloRequest {
  string name = 1;
  string alias = 2;
}

message HelloResponse {
  string greeting = 1;
}

service HelloService {
  rpc hello(HelloRequest) returns (HelloResponse);
}

3. 같은 디렉토리에서 protocol buffers 컴파일 진행

python3 -m grpc_tools.protoc -I=./ --python_out=./ --grpc_python_out=./ ./HelloService.proto

4. 같은 디렉토리에 python client 파일 'HelloClient.py' 생성 및 코드 작성

from __future__ import print_function
import grpc
import HelloService_pb2
import HelloService_pb2_grpc

#Replace to ur name and alias :)
_name = "Leo"
_alias = "newbie"

def run():
  channel = grpc.insecure_channel('localhost:36200')
  stub = HelloService_pb2_grpc.HelloServiceStub(channel)
  response = stub.hello(HelloService_pb2.HelloRequest(name=_name, alias=_alias))
  print("Hello client received: " + response.greeting)

if __name__ == '__main__':
    run()

5. 클라이언트 실행

python3 HelloClient.py

 

 

3-4. with docker

1. Gradle build

//프로젝트 홈 디렉토리에서
./gradlew build

 

2. Dockerfile 작성

vi Dockerfile //not 'd'ockerfile!
-------------------------------------------------
FROM openjdk:8-jdk-alpine

ADD ./build/libs/grpc_handson_jar.jar app.jar
ENTRYPOINT java \
-jar /app.jar

 

3. Docker build

docker build -t grpc-[server|client]:1.0 .

 

4. Docker run

docker run -p 36200:36200 grpc-[server|client]:1.0

 

유의할 점. 자바 클라이언트를 도커로 띄울 땐 HelloClientRunner의 "localhost"를 로컬 아이피 주소로 변경해주어야 한다.

추가로 build.gradle에서 jar > manifest의 Main-class 값을 "HelloClientRunner" 로 수정해주어야 한다.

'gRPC' 카테고리의 다른 글

gRPC with (spring, load balancing, TLS, health check) 예제  (0) 2021.07.15
Protobuf 문법  (0) 2021.07.15
Protocol buffers  (5) 2021.03.30