Skip to content

Latest commit

ย 

History

History
621 lines (470 loc) ยท 20.4 KB

File metadata and controls

621 lines (470 loc) ยท 20.4 KB

๋ชฉ์ฐจ



JAVA๋กœ gRPC ์‹ค์Šตํ•ด๋ณด๊ธฐ (feat. 4๊ฐ€์ง€ ํ†ต์‹  ๊ธฐ๋ฒ•)

JAVA๋กœ gRPC์˜ Server์™€ Client๋ฅผ ๊ฐ„๋‹จํ•œ ํ…Œ์ŠคํŠธ ํ˜•์‹์œผ๋กœ ๊ตฌํ˜„ํ•ด๋ณธ๋‹ค.

gRPC์˜ Hello World.


1 gRPC๊ฐ€ ๋ฌด์—‡์ธ๊ฐ€?

gRPC๋Š” ๊ตฌ๊ธ€์—์„œ ๊ฐœ๋ฐœํ•œ ์˜คํ”ˆ ์†Œ์Šค์˜ ๊ณ ์„ฑ๋Šฅ RPC (Remote Procedure Call) ํ”„๋ ˆ์ž„์›Œํฌ์ด๋‹ค.

๊ตฌํ˜„์ฒด๋กœ์„œ์˜ ํŠน์ง•์œผ๋ก  IDL๋กœ ๊ตฌ๊ธ€์—์„œ ๊ฐœ๋ฐœํ•œ protocol buffers (protobuf)๋ฅผ ์‚ฌ์šฉํ•˜๋ฉฐ, ์ „์†ก ํ”„๋กœํ† ์ฝœ๋กœ HTTP/2.0์„ ์‚ฌ์šฉํ•œ๋‹ค.


2 REST๋Œ€์‹  gRPC๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ด์œ 


๐Ÿ’โ€โ™‚๏ธ RPC

gRPC๋Š” RPC๋ฅผ ๊ตฌํ˜„ํ•œ ๊ณ ์„ฑ๋Šฅ ํ”„๋ ˆ์ž„์›Œํฌ์ด๋ฏ€๋กœ, ๋‹น์—ฐํžˆ RPC์˜ ์•„ํ‚คํ…์ฒ˜๋ฅผ ๊ธฐ๋ณธ์ ์œผ๋กœ ์ค€์ˆ˜ํ•œ๋‹ค.

RPC๋Š” Remote Procedure Call์˜ ์ค„์ž„๋ง๋กœ ๋ฒˆ์—ญํ•˜๋ฉด "์›๊ฒฉ ํ”„๋กœ์‹œ์ € ํ˜ธ์ถœ"์„ ์˜๋ฏธํ•˜๋ฉฐ, ์ด๋Š” ์›๊ฒฉ์— ์œ„์น˜ํ•œ ํ”„๋กœ๊ทธ๋žจ์„ ๋กœ์ปฌ์— ์žˆ๋Š” ํ”„๋กœ๊ทธ๋žจ์ฒ˜๋Ÿผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์˜๋ฏธ๋ฅผ ๊ฐ€์ง„๋‹ค.

ํด๋ผ์ด์–ธํŠธ์™€ ์„œ๋ฒ„ ๋ชจ๋‘ ์ผ๋ฐ˜์ ์ธ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ๋งŒ ํ˜ธ์ถœํ•˜๋ฉด ์„œ๋กœ ํ†ต์‹ ํ•˜๊ธฐ๋•Œ๋ฌธ์—, REST์™€ ๋‹ค๋ฅด๊ฒŒ network ํ†ต์‹ ๊ด€ ๊ด€๋ จ๋œ ์ž‘์—…์„ ์‹ ๊ฒฝ์“ฐ์ง€ ์•Š์•„๋„ ๋œ๋‹ค.


๐Ÿ’โ€โ™‚๏ธ JSON/XML ๋Œ€์‹  protobuf

REST๋Š” ๋ชจ๋‘ ์•Œ๋‹ค์‹ถ์ด JSON์„ ์‚ฌ์šฉํ•˜์—ฌ ๋ฉ”์‹œ์ง€๋ฅผ ์ฃผ๊ณ ๋ฐ›๋Š”๋‹ค.

JSON์€ ์œ ์—ฐํ•˜๊ณ  ํ…์ŠคํŠธ ๊ธฐ๋ฐ˜์ด๋ฉฐ ์‚ฌ๋žŒ์ด ์‰ฝ๊ฒŒ ์ฝ๊ณ  ์ดํ•ดํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, ์‹œ์Šคํ…œ ๊ฐ„์— ๋ฐ์ดํ„ฐ๋ฅผ ์ „์†กํ•˜๊ธด ์ถฉ๋ถ„ํžˆ ๋น ๋ฅด๊ฑฐ๋‚˜ ๊ฐ€๋ณ์ง€ ์•Š๋‹ค.

gRPC๋Š” ๋ฐ์ดํ„ฐ ์ „์†ก์„ ๋” ๋น ๋ฅด๊ณ  ํšจ์œจ์ ์ธ Protobuf๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฉ”์‹œ์ง€๋ฅผ ์ฃผ๊ณ ๋ฐ›๋Š”๋‹ค.

๋” ๋น ๋ฅด๊ณ  ํšจ์œจ์ ์ธ ์ด์œ ๋Š” protobuf๋Š” ๊ตฌ์กฐํ™”๋œ ๋ฐ์ดํ„ฐ๋ฅผ ์ด์ง„ ํ˜•์‹์œผ๋กœ ํšจ์œจ์ ์ด๊ณ  ์ปดํŒฉํŠธํ•˜๊ฒŒ ์ €์žฅํ•˜์—ฌ ๋„คํŠธ์›Œํฌ ์—ฐ๊ฒฐ์„ ํ†ตํ•ด ๋” ๋น ๋ฅด๊ฒŒ ์ „์†กํ•  ์ˆ˜ ์žˆ๊ธฐ๋•Œ๋ฌธ์ด๋‹ค.

protobuf์— ๋Œ€ํ•œ ๋” ์ž์„ธํ•œ ๋‚ด์šฉ์€ protobuf doc๋ฅผ ์ฐธ๊ณ ํ•˜๋Š”๊ฑธ๋กœํ•˜๊ณ , ์ด ๊ธ€์—์„  protobuf๊ฐ€ JSON๋ณด๋‹ค ์–ธ์–ด์™€ ํ”Œ๋žซํผ ์ค‘๋ฆฝ์ ์ด๋ฉฐ ๋†’์€ ์••์ถ•๋ฅ ๋กœ ๋” ๋น ๋ฅด๋‹ค๊ณ  ์ดํ•ดํ•˜๊ณ  ๋„˜์–ด๊ฐ„๋‹ค.


๐Ÿ’โ€โ™‚๏ธ HTTP/2.0 ๊ธฐ๋ฐ˜

REST๋Š” ์š”์ฒญ-์‘๋‹ต ๊ธฐ๋ฐ˜์˜ ํ†ต์‹ ์„ HTTP/1.1์„ ๊ธฐ๋ฐ˜์œผ๋กœํ•œ๋‹ค.

gRPC๋Š” HTTP/2.0์„ ์‚ฌ์šฉํ•จ์œผ๋กœ์จ ๋‹ค์ค‘ํ†ต์‹ , ์–‘๋ฐฉํ–ฅ ์ŠคํŠธ๋ฆผ, ํšจ์œจ์ ์ธ ํ—ค๋” ์‚ฌ์šฉ๋“ฑ HTTP/2.0์˜ ์žฅ์ ์„ ๊ทธ๋Œ€๋กœ ํ™œ์šฉํ•œ๋‹ค.


3 gRPC 4๊ฐ€์ง€ ํ†ต์‹  ๋ฐฉ์‹

gRPC๋Š” 4๊ฐœ์˜ ํ†ต์‹  ๋ฐฉ์‹์„ ์ง€์›ํ•œ๋‹ค.


์ถœ์ฒ˜: https://pamodaaw.medium.com/handson-introduction-to-grpc-with-java-1195870027fb

  • Unary - 1๊ฐœ request, 1๊ฐœ response
    • ๊ธฐ์กด API์™€ ๋™์ผํ•˜๊ฒŒ ์š”์ฒญ ํ•˜๋‚˜๋‹น ์‘๋‹ต ํ•˜๋‚˜๋ฅผ ๋ฐ›๋Š” ๋ฐฉ์‹.
  • Server Stream - 1๊ฐœ request, n๊ฐœ response.
    • HTTP/2.0์˜ ํŠน์ง•์„ ํ™œ์šฉํ•œ ์ƒˆ๋กœ์šด ํ˜•ํƒœ์˜ RPC API.
    • ํด๋ผ์ด์–ธํŠธ์˜ ์š”์ฒญ ํ•œ ๋ฒˆ์œผ๋กœ, ์„œ๋ฒ„๊ฐ€ ๋ฐ์ดํ„ฐ๋ฅผ ์—ฌ๋Ÿฌ ๋ฒˆ ์ „์†กํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ์‹.
  • Client Stream - n๊ฐœ request, 1๊ฐœ response.
    • HTTP/2.0์˜ ํŠน์ง•์„ ํ™œ์šฉํ•œ ์ƒˆ๋กœ์šด ํ˜•ํƒœ์˜ RPC API.
    • ํด๋ผ์ด์–ธํŠธ๋Š” ์—ฌ๋Ÿฌ ๋ฒˆ ์„œ๋ฒ„์— ๋ฐ์ดํ„ฐ๋ฅผ ์ „์†กํ•˜๊ณ , ์„œ๋ฒ„๋Š” ํ•œ๋ฒˆ ์‘๋‹ต์„ ์ „์†กํ•˜๋Š” ๋ฐฉ์‹.
    • ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์‘๋‹ต์„ ์–ธ์ œ ๋ฐ›์„ ์ˆ˜ ์žˆ๋Š”์ง€๋Š” ์ „์ ์œผ๋กœ ์„œ๋ฒ„์— ๋‹ฌ๋ ค์žˆ๋‹ค.
  • Bidirectional Stream - n๊ฐœ request, n๊ฐœ response.
    • ํด๋ผ์ด์–ธํŠธ๊ณผ ์„œ๋ฒ„ ๋ชจ๋‘ Stream์„ ์‚ฌ์šฉํ•˜๋ฉฐ, ๋‘ ๊ฐœ์˜ Stream์€ ๋…๋ฆฝ์ ์œผ๋กœ ์šด์šฉ๋œ๋‹ค.
    • ๊ทธ๋Ÿฌ๋ฏ€๋กœ ํด๋ผ์ด์–ธํŠธ๊ณผ ์„œ๋ฒ„๋Š” ์–ด๋–ค ์ˆœ์„œ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋“ ์ง€, ์ „์†ก ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ๊ฑฐ๋‚˜ ์“ธ ์ˆ˜ ์žˆ๋‹ค.

4 Java๋กœ ๊ตฌํ˜„ํ•˜๋Š” gRPC

๐Ÿ’โ€โ™‚๏ธ JAVA ๋ฒ ์ด์Šค๋กœ gRPC๋ฅผ ์ด์šฉํ•œ ํ†ต์‹ ์„ ํ•˜๊ธฐ์œ„ํ•ด์„  ์•„๋ž˜ ๋‹จ๊ณ„๋กœ ๊ตฌํ˜„ํ•ด์ฃผ๋ฉด๋œ๋‹ค.

  1. ํ”„๋กœ์ ํŠธ ์ƒ์„ฑ ๋ฐ ์˜์กด์„ฑ ์ถ”๊ฐ€
  2. IDL (Interface Defintion Language) ์ •์˜.
    • ํด๋ผ์ด์–ธํŠธ์™€ ์„œ๋ฒ„๊ฐ„์˜ ํ†ต์‹  ๊ทœ์•ฝ์„ ์ •์˜ํ•˜๋Š” ๋‹จ๊ณ„๋กœ gRPC์˜ ๊ฒฝ์šฐ .protoํŒŒ์ผ์„ ์ •์˜ํ•œ๋‹ค.
    • protobuf ์ปดํŒŒ์ผ๋Ÿฌ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํด๋ผ์ด์–ธํŠธ์™€ ์„œ๋ฒ„ ์ฝ”๋“œ ์ž‘์„ฑ.
  3. ์„œ๋ฒ„ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ตฌํ˜„
    • ์„œ๋ฒ„ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋นŒ๋“œํ›„ gRPC ์„œ๋ฒ„๋ฅผ ์œ„ํ•ด ์ƒ์„ฑ๋œ ์„œ๋น„์Šค ์ธํ„ฐํŽ˜์ด์Šค ๊ตฌํ˜„.
  4. ํด๋ผ์ด์–ธํŠธ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ตฌํ˜„
    • ํด๋ผ์ด์–ธํŠธ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋นŒ๋“œํ›„ ์ƒ์„ฑ๋œ gRPC ์Šคํ…์„ ์‚ฌ์šฉํ•˜์—ฌ ์„œ๋ฒ„ ๋Œ€์ƒ RPC ํ˜ธ์ถœ.

4-1 ํ”„๋กœ์ ํŠธ ์ƒ์„ฑ ๋ฐ ์˜์กด์„ฑ ์ถ”๊ฐ€

Gradle๋กœ ํ”„๋กœ์ ํŠธ๋ฅผ ์ƒ์„ฑํ•˜๊ณ , ์•„๋ž˜์™€ ๊ฐ™์ด ์˜์กด์„ฑ์„ ์„ค์ •ํ•œ๋‹ค.

build.gradle

plugins {
    id 'java'
    id 'com.google.protobuf' version '0.9.4' // protobuf ์„ค์ •์„ ์œ„ํ•œ plugins ์ถ”๊ฐ€
}

group 'com.binghe'
version '1.0-SNAPSHOT'

sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11

repositories {
    mavenCentral()
}

dependencies {
    runtimeOnly 'io.grpc:grpc-netty-shaded:1.57.1'
    implementation 'io.grpc:grpc-protobuf:1.57.1'
    implementation 'io.grpc:grpc-stub:1.57.1'
    compileOnly 'org.apache.tomcat:annotations-api:6.0.53' // necessary for Java 9+

    testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.1'
    testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1'
}

test {
    useJUnitPlatform()
}

// IDL (protobuf) ์ƒ์„ฑ ๊ด€๋ จ Gradle ์„ค์ •
protobuf {
    protoc {
        artifact = "com.google.protobuf:protoc:3.22.3"
    }
    plugins {
        grpc {
            artifact = 'io.grpc:protoc-gen-grpc-java:1.57.1'
        }
    }
    generateProtoTasks {
        all()*.plugins {
            grpc {}
        }
    }
}

// fat-jar setting for server
task gRpcServerJar(type: Jar) {
    manifest {
        attributes 'Main-Class': 'com.binghe.server.HelloServiceGrpcServer'
    }
    duplicatesStrategy = DuplicatesStrategy.EXCLUDE
    from { configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) } }
    with jar
}

// fat-jar setting for client
task gRpcClientJar(type: Jar) {
    manifest {
        attributes 'Main-Class': 'com.binghe.client.HelloServiceClient'
    }
    duplicatesStrategy = DuplicatesStrategy.EXCLUDE
    from { configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) } }
    with jar
}

4-2 IDL ์ •์˜

ํ”„๋กœ์ ํŠธ ์ƒ์„ฑ ๋ฐ ๋นŒ๋“œ ์Šคํฌ๋ฆฝํŠธ ์ž‘์„ฑ์ด ์™„๋ฃŒ๋˜์—ˆ๋‹ค๋ฉด, ์ด์ œ ํด๋ผ์ด์–ธํŠธ์™€ ์„œ๋ฒ„๊ฐ„์˜ ํ†ต์‹  ๊ทœ์•ฝ์„ ์ •์˜ํ•˜๋Š” ๋‹จ๊ณ„๋กœ gRPC์˜ ๊ฒฝ์šฐ .protoํŒŒ์ผ์„ ์ •์˜ํ•œ๋‹ค.


hello.proto

syntax = "proto3";
option java_multiple_files = true;
option java_package = "com.binghe.proto";

message HelloRequest {
  string firstName = 1;
  string lastName = 2;
}

message HelloResponse {
  string greeting = 1;
}

service HelloService {
  rpc hello(HelloRequest) returns (HelloResponse);
  rpc helloServerStream(HelloRequest) returns (stream HelloResponse);
  rpc helloClientStream(stream HelloRequest) returns (HelloResponse);
  rpc helloBiStream(stream HelloRequest) returns (stream HelloResponse);
}
  • ๋ฉ”์‹œ์ง€
    • HelloRequest
      • ํด๋ผ์ด์–ธํŠธ -> ์„œ๋ฒ„ ์š”์ฒญ์‹œ ๋„คํŠธ์›Œํฌ๋ฅผ ํƒ€๊ณ  ์ „์†ก๋  ๋ฉ”์‹œ์ง€ ํฌ๋งท.
    • HelloResponse
      • ์„œ๋ฒ„ -> ํด๋ผ์ด์–ธํŠธ ์‘๋‹ต์‹œ ๋„คํŠธ์›Œํฌ๋ฅผ ํƒ€๊ณ  ์ „์„ฑ๋  ๋ฉ”์‹œ์ง€ ํฌ๋งท.
  • ์„œ๋น„์Šค
    • ํด๋ผ์ด์–ธํŠธ -> ์„œ๋ฒ„ ์š”์ฒญ์‹œ ํ˜ธ์ถœํ•  RPC ๋ฉ”์„œ๋“œ.

๐Ÿ’โ€โ™‚๏ธ proto ์ •์˜๊ฐ€ ์™„๋ฃŒ๋˜์—ˆ๋‹ค๋ฉด ๋นŒ๋“œ ํ•ด์ค€๋‹ค.

์ด์ œ proto ์ •์˜๊ฐ€ ์™„๋ฃŒ๋˜์—ˆ๋‹ค๋ฉด, Gradle๋กœ build Task๋ฅผ ์‹คํ–‰์‹œ์ผœ์ค€๋‹ค.


4-3 gRPC ์„œ๋ฒ„ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ตฌํ˜„

ํด๋ผ์ด์–ธํŠธ์™€ ์„œ๋ฒ„๊ฐ€ ์„œ๋กœ ์ฃผ๊ณ ๋ฐ›์„ ํ†ต์‹  ๊ทœ์•ฝ๊ณผ ์š”์ฒญํ•  ๋ฉ”์„œ๋“œ๋“ฑ์„ ์ •์˜ํ–ˆ๋‹ค๋ฉด, ์ด์ œ ์„œ๋ฒ„ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๊ตฌํ˜„ํ•ด์ค€๋‹ค.


HelloServiceImpl.java

import com.binghe.proto.HelloRequest;
import com.binghe.proto.HelloResponse;
import com.binghe.proto.HelloServiceGrpc;
import io.grpc.stub.StreamObserver;

import java.util.ArrayList;
import java.util.List;

public class HelloServiceImpl extends HelloServiceGrpc.HelloServiceImplBase {

    private static final String HELLO = "Hello ! ";

    // unary
    @Override
    public void hello(HelloRequest request, StreamObserver<HelloResponse> responseObserver) {

        String greeting = HELLO + request.getFirstName() + "," + request.getLastName();

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

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

    // server stream
    @Override
    public void helloServerStream(HelloRequest request,
                                  StreamObserver<HelloResponse> responseObserver) {

        List<String> greetingList = new ArrayList<>();

        for (int i = 1; i <= 3; i++) {
            greetingList.add(HELLO + request.getFirstName() + "," + request.getLastName() + ":" + i);
        }

        for (String greeting : greetingList) {
            HelloResponse response = HelloResponse.newBuilder()
                    .setGreeting(greeting)
                    .build();
            
            responseObserver.onNext(response);
        }

        responseObserver.onCompleted();
    }

    // client stream
    @Override
    public StreamObserver<HelloRequest> helloClientStream(
            StreamObserver<HelloResponse> responseObserver) {
        return new StreamObserver<HelloRequest>() {
            @Override
            public void onNext(HelloRequest helloRequest) {
                System.out.println(HELLO + helloRequest.getFirstName() + "," + helloRequest.getLastName());
            }

            @Override
            public void onError(Throwable throwable) {
                System.out.println("error");
            }

            @Override
            public void onCompleted() {
                responseObserver.onNext(HelloResponse.newBuilder().setGreeting("success").build());
                responseObserver.onCompleted();
            }
        };
    }

    // bi stream
    @Override
    public StreamObserver<HelloRequest> helloBiStream(
            StreamObserver<HelloResponse> responseObserver) {
        return new StreamObserver<HelloRequest>() {
            @Override
            public void onNext(HelloRequest helloRequest) {
                String greeting = HELLO + helloRequest.getFirstName() + "," + helloRequest.getLastName();
                System.out.println(greeting);

                responseObserver.onNext(HelloResponse.newBuilder().setGreeting(greeting+"1").build());
                responseObserver.onNext(HelloResponse.newBuilder().setGreeting(greeting+"2").build());
            }

            @Override
            public void onError(Throwable throwable) {
                System.out.println("error");
            }

            @Override
            public void onCompleted() {
                responseObserver.onCompleted();
            }
        };
    }
}

ํด๋ผ์ด์–ธํŠธ์˜ ์š”์ฒญ์„ ๋ฐ›์•˜์„ ๋•Œ, ์–ด๋–ป๊ฒŒ ์ฒ˜๋ฆฌํ›„ ์‘๋‹ตํ• ์ง€๋ฅผ ์ •์˜ํ•ด์ค€๋‹ค.

์ค‘์š”ํ•œ ์ ์€ ์ถ”์ƒ ํด๋ž˜์Šค์ธ HelloServiceGrpc.HelloServiceImplBase๋ฅผ ์ƒ์†๋ฐ›๊ณ ์žˆ์œผ๋ฉฐ, ๊ตฌํ˜„ํ•œ ๋ชจ๋“  ๋ฉ”์„œ๋“œ๊ฐ€ ์˜ค๋ฒ„๋ผ์ด๋”ฉํ•œ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค.

์ •์˜ํ•œ ์  ์—†๋Š” HelloServiceGrpc๊ฐ€ ์–ด๋””์„œ ํŠ€์–ด๋‚˜์™”์ง€..? ๋ผ๊ณ  ํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ, ์ด๋Š” proto๋ฅผ buildํ•  ๋•Œ protobuf์— ์˜ํ•ด์„œ ์ž๋™์œผ๋กœ ์ƒ๊ฒจ๋‚œ ์ถ”์ƒ ํด๋ž˜์Šค์ด๋‹ค.

์ด ์ถ”์ƒ ํด๋ž˜์Šค๋Š” gRPC๋ฅผ ์ด์šฉํ•˜์—ฌ ํ†ต์‹ ํ•˜๋Š”๋ฐ ํ•„์š”ํ•œ ๋ชจ๋“  ์ ˆ์ฐจ๋ฅผ ๋Œ€์‹  ์ˆ˜ํ–‰ํ•ด์ค€๋‹ค. (ํ…œํ”Œ๋ฆฟ ๋ฉ”์„œ๋“œ ํŒจํ„ด)


๊ทธ๋ฆฌ๊ณ  ์„œ๋ฒ„๋ฅผ ์ž‘๋™ํ•ด์•ผํ•˜๋‹ˆ gRPC์—์„œ ์ œ๊ณตํ•ด์ฃผ๋Š” Server ๊ฐ์ฒด๋ฅผ ํ™œ์šฉํ•˜์—ฌ ์„œ๋ฒ„ ๊ตฌ๋™ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•ด์ฃผ๋ฉด ๋œ๋‹ค.

HelloServiceGrpcServer.java

import io.grpc.Server;
import io.grpc.ServerBuilder;

import java.io.IOException;

public class HelloServiceGrpcServer {

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

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

๊ทธ๋ฆฌ๊ณ  ์œ„ main ๋ฉ”์„œ๋“œ๋ฅผ ์‹คํ–‰ํ•˜๋ฉด ์ด์ œ gRPC ์„œ๋ฒ„๊ฐ€ ๊ตฌ๋™๋œ๋‹ค.


4-4 gRPC ํด๋ผ์ด์–ธํŠธ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ตฌํ˜„

์ด์ œ ๋งˆ์ง€๋ง‰์œผ๋กœ ํด๋ผ์ด์–ธํŠธ ๋ถ€๋ถ„์„ ๊ตฌํ˜„ํ•ด์ค€๋‹ค.

HelloServiceCaller.java

import com.binghe.proto.HelloRequest;
import com.binghe.proto.HelloResponse;
import com.binghe.proto.HelloServiceGrpc;
import com.google.common.util.concurrent.ListenableFuture;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import io.grpc.stub.StreamObserver;

import java.util.Iterator;
import java.util.List;
import java.util.concurrent.TimeUnit;

public class HelloServiceCaller {

    private ManagedChannel channel;
    private HelloServiceGrpc.HelloServiceBlockingStub blockingStub;
    private HelloServiceGrpc.HelloServiceStub asynStub;
    private HelloServiceGrpc.HelloServiceFutureStub futureStub;

    public HelloServiceCaller(String domain, int port) {
        channel = ManagedChannelBuilder.forAddress(domain, port)
                .usePlaintext()
                .build();
        blockingStub = HelloServiceGrpc.newBlockingStub(channel);
        asynStub = HelloServiceGrpc.newStub(channel);
        futureStub = HelloServiceGrpc.newFutureStub(channel);
    }

    public void sendBlockingUnary(HelloRequest request) {
        System.out.println("[step1] client 1 server 1 blocking");
        HelloResponse helloResponse = blockingStub.hello(request);
        System.out.println("[step1 ๊ฒฐ๊ณผ] " + helloResponse.getGreeting());
        System.out.println("[step1 ๋]");
    }

    public void sendAsynUnary(HelloRequest request) {
        System.out.println("[step2] client1 server 1 asyn");
        asynStub.hello(request, new StreamObserver<HelloResponse>() {
            @Override
            public void onNext(HelloResponse helloResponse) {
                System.out.println("[step2 ๊ฒฐ๊ณผ] " + helloResponse.getGreeting());
            }

            @Override
            public void onError(Throwable throwable) {
                System.out.println("error");
            }

            @Override
            public void onCompleted() {
                System.out.println("[step2 ํ†ต์‹  ๋]");
            }
        });
        System.out.println("[step2 ๋]");
    }

    public void sendFutureUnary(HelloRequest request) {
        System.out.println("[step3] client 1 server 1 future");
        ListenableFuture<HelloResponse> future = futureStub.hello(request);
        HelloResponse response = null;
        try {
            response = future.get(2, TimeUnit.SECONDS);
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("[step3 ๊ฒฐ๊ณผ] " + response.getGreeting());
        System.out.println("[step3 ๋]");
    }

    public void sendBlockingServerStream(HelloRequest request) {
        System.out.println("[step4] client 1 server n blocking");
        Iterator<HelloResponse> responseIter = blockingStub.helloServerStream(request);
        responseIter.forEachRemaining(response -> {
            System.out.println("[step4 ๊ฒฐ๊ณผ] " + response.getGreeting());
        });
        System.out.println("[step4 ๋]");
    }

    public void sendAsynServerStream(HelloRequest request) {
        System.out.println("[step5] client 1 server n asyn");
        asynStub.helloServerStream(request, new StreamObserver<HelloResponse>() {
            @Override
            public void onNext(HelloResponse helloResponse) {
                System.out.println("[step5 ๊ฒฐ๊ณผ] " + helloResponse.getGreeting());
            }

            @Override
            public void onError(Throwable throwable) {
                System.out.println("error");
            }

            @Override
            public void onCompleted() {
                System.out.println("[step5 ํ†ต์‹  ๋]");
            }
        });
        System.out.println("[step5 ๋]");
    }

    public void sendAsynClientStream(List<HelloRequest> requestList) {
        System.out.println("[step6] client n server 1 asyn");
        StreamObserver<HelloResponse> responseObserver = new StreamObserver<HelloResponse>() {
            @Override
            public void onNext(HelloResponse helloResponse) {
                System.out.println("[step6 ๊ฒฐ๊ณผ] " + helloResponse.getGreeting());
            }

            @Override
            public void onError(Throwable throwable) {
                System.out.println("error");
            }

            @Override
            public void onCompleted() {
                System.out.println("[step6 ํ†ต์‹  ๋]");
            }
        };
        StreamObserver<HelloRequest> requestObserver = asynStub.helloClientStream(responseObserver);
        for (HelloRequest request : requestList) {
            requestObserver.onNext(request);
        }
        requestObserver.onCompleted();
        System.out.println("[step6 ๋]");
    }

    public void sendAsynBiStream(List<HelloRequest> requestList) {
        System.out.println("[step7] client n server n asny");
        StreamObserver<HelloResponse> responseObsever = new StreamObserver<HelloResponse>() {
            @Override
            public void onNext(HelloResponse helloResponse) {
                System.out.println("[step7 ๊ฒฐ๊ณผ] " + helloResponse.getGreeting());
            }

            @Override
            public void onError(Throwable throwable) {
                System.out.println("error");
            }

            @Override
            public void onCompleted() {
                System.out.println("[step7 ํ†ต์‹  ๋]");
            }
        };

        StreamObserver<HelloRequest> requestObsever = asynStub.helloBiStream(responseObsever);

        for (HelloRequest request : requestList) {
            requestObsever.onNext(request);
        }

        requestObsever.onCompleted();
        System.out.println("[step7 ๋]");
    }
}

gRPC ์„œ๋ฒ„๋ฅผ ํ˜ธ์ถœํ•  ๋•Œ ์‚ฌ์šฉ๋˜๋Š” ํด๋ผ์ด์–ธํŠธ ์ฝ”๋“œ์ด๋ฉฐ, ์ด์ œ ๊ฐ„๋‹จํžˆ main ๋ฉ”์„œ๋“œ๋กœ ํ…Œ์ŠคํŠธ๋ฅผ ๋งŒ๋“ค์–ด ์„œ๋ฒ„์— ์š”์ฒญ์„ ๋ณด๋‚ธ๋‹ค.


HelloServiceClientTest.java

import com.binghe.proto.HelloRequest;

import java.util.List;

public class HelloServiceClientTest {

    public static void main(String[] args) throws InterruptedException {
        // channel, stub
        HelloServiceCaller caller = new HelloServiceCaller("localhost", 9090);

        // requests
        HelloRequest A = HelloRequest.newBuilder().setFirstName("A").setLastName("AA").build();;
        HelloRequest B = HelloRequest.newBuilder().setFirstName("b").setLastName("bb").build();;
        HelloRequest C = HelloRequest.newBuilder().setFirstName("c").setLastName("cc").build();

        caller.sendBlockingUnary(A);
        caller.sendAsynUnary(A);
        caller.sendFutureUnary(A);
        caller.sendBlockingServerStream(A);
        caller.sendAsynServerStream(A);
        caller.sendAsynClientStream(List.of(A, B, C));
        caller.sendAsynBiStream(List.of(A, B, C));

        Thread.sleep(10000);
    }
}
[step1] client 1 server 1 blocking
[step1 ๊ฒฐ๊ณผ] Hello ! A,AA
[step1 ๋]

[step2] client1 server 1 asyn
[step2 ๋]

[step3] client 1 server 1 future
[step2 ๊ฒฐ๊ณผ] Hello ! A,AA
[step2 ํ†ต์‹  ๋]
[step3 ๊ฒฐ๊ณผ] Hello ! A,AA
[step3 ๋]

[step4] client 1 server n blocking
[step4 ๊ฒฐ๊ณผ] Hello ! A,AA:1
[step4 ๊ฒฐ๊ณผ] Hello ! A,AA:2
[step4 ๊ฒฐ๊ณผ] Hello ! A,AA:3
[step4 ๋]

[step5] client 1 server n asyn
[step5 ๋]

[step6] client n server 1 asyn
[step6 ๋]

[step7] client n server n asny
[step7 ๋]

[step6 ๊ฒฐ๊ณผ] success
[step6 ํ†ต์‹  ๋]
[step5 ๊ฒฐ๊ณผ] Hello ! A,AA:2
[step5 ๊ฒฐ๊ณผ] Hello ! A,AA:3
[step5 ํ†ต์‹  ๋]
[step7 ๊ฒฐ๊ณผ] Hello ! A,AA1
[step7 ๊ฒฐ๊ณผ] Hello ! A,AA2
[step7 ๊ฒฐ๊ณผ] Hello ! b,bb1
[step7 ๊ฒฐ๊ณผ] Hello ! b,bb2
[step7 ๊ฒฐ๊ณผ] Hello ! c,cc1
[step7 ๊ฒฐ๊ณผ] Hello ! c,cc2
[step7 ํ†ต์‹  ๋]

์ฐธ๊ณ