การสร้างบริการ gRPC ด้วย Java

การสร้างบริการ gRPC ด้วย Java

เกี่ยวกับ Codelab นี้

subjectอัปเดตล่าสุดเมื่อ ก.ค. 9, 2021
account_circleเขียนโดย Googler

1 ภาพรวม

gRPC เป็นเฟรมเวิร์กและชุดเครื่องมือสำหรับการเรียกกระบวนการทำงานจากระยะไกล (RPC) แบบกลางๆ และเป็นกลางทางภาษาซึ่งพัฒนาที่ Google เครื่องมือนี้จะช่วยให้คุณกำหนดบริการโดยใช้ Protocol Buffers ซึ่งเป็นชุดเครื่องมือและภาษาที่เรียงลำดับแบบไบนารีที่มีประสิทธิภาพเป็นพิเศษ จากนั้นจะให้คุณสร้างสตับเซิร์ฟเวอร์และไคลเอ็นต์ที่มีลักษณะเฉพาะจากคำจำกัดความของบริการในภาษาต่างๆ

ใน Codelab นี้ คุณจะได้เรียนรู้วิธีการสร้างบริการที่ใช้ Java ซึ่งแสดง API ด้วยเฟรมเวิร์ก gRPC จากนั้นจะเขียนไคลเอ็นต์เพื่อใช้สตับฝั่งไคลเอ็นต์ gRPC ที่สร้างขึ้น

สิ่งที่คุณจะได้เรียนรู้

  • ภาษาโปรโตคอลบัฟเฟอร์
  • วิธีติดตั้งใช้งานบริการ gRPC โดยใช้ Java
  • วิธีติดตั้งใช้งานไคลเอ็นต์ gRPC โดยใช้ Java

คุณจะใช้บทแนะนำนี้อย่างไร

คุณจะให้คะแนนประสบการณ์ในการสร้างแอป Node.js อย่างไร

คุณจะให้คะแนนประสบการณ์ในการสร้างแอป Go อย่างไร

2 การตั้งค่าและข้อกำหนด

การตั้งค่าสภาพแวดล้อมตามเวลาที่สะดวก

  1. ลงชื่อเข้าใช้ Cloud Console และสร้างโปรเจ็กต์ใหม่หรือใช้โปรเจ็กต์ที่มีอยู่ซ้ำ หากยังไม่มีบัญชี Gmail หรือ Google Workspace คุณต้องสร้างบัญชี

96a9c957bc475304.png

b9a10ebdf5b5a448.png

a1e3c01a38fa61c2.png

โปรดจดจำรหัสโปรเจ็กต์ ซึ่งเป็นชื่อที่ไม่ซ้ำกันในโปรเจ็กต์ Google Cloud ทั้งหมด (ชื่อด้านบนมีคนใช้แล้ว และจะใช้ไม่ได้ ขออภัย) และจะมีการอ้างอิงใน Codelab ว่า PROJECT_ID ในภายหลัง

  1. ถัดไป คุณจะต้องเปิดใช้การเรียกเก็บเงินใน Cloud Console เพื่อใช้ทรัพยากร Google Cloud

การใช้งาน Codelab นี้น่าจะไม่มีค่าใช้จ่ายใดๆ หากมี ตรวจสอบว่าคุณได้ทำตามวิธีการใน "การล้างข้อมูล" ซึ่งจะแนะนำคุณเกี่ยวกับวิธีปิดทรัพยากรเพื่อไม่ให้มีการเรียกเก็บเงินนอกเหนือจากบทแนะนำนี้ ผู้ใช้ใหม่ของ Google Cloud จะมีสิทธิ์เข้าร่วมโปรแกรมทดลองใช้ฟรี$300 USD

Google Cloud Shell

ในขณะที่ Codelab นี้จะทำงานจากคอมพิวเตอร์ของคุณได้ เราจะใช้ Google Cloud Shell ซึ่งเป็นสภาพแวดล้อมของบรรทัดคำสั่งที่ทำงานในระบบคลาวด์ใน Codelab

เครื่องเสมือนแบบ Debian นี้เต็มไปด้วยเครื่องมือการพัฒนาทั้งหมดที่คุณต้องการ โดยมีไดเรกทอรีหลักขนาด 5 GB ที่ทำงานอย่างต่อเนื่องใน Google Cloud ซึ่งจะช่วยเพิ่มประสิทธิภาพของเครือข่ายและการตรวจสอบสิทธิ์ได้อย่างมาก ซึ่งหมายความว่าสิ่งที่คุณต้องมีสำหรับ Codelab นี้คือเบราว์เซอร์ (ใช่แล้ว ทั้งหมดนี้ทำงานได้บน Chromebook)

  1. หากต้องการเปิดใช้งาน Cloud Shell จาก Cloud Console เพียงคลิกเปิดใช้งาน Cloud Shell a8460e837e9f5fda.png (จะใช้เวลาเพียงไม่นานในการจัดสรรและเชื่อมต่อกับสภาพแวดล้อม)

b532b2f19ab85dda.png

Screen Shot 14-06-2017 เวลา 22.13.43 น.

เมื่อเชื่อมต่อกับ Cloud Shell คุณควรเห็นว่าตนเองผ่านการตรวจสอบสิทธิ์แล้วและโปรเจ็กต์ได้รับการตั้งค่าเป็น PROJECT_ID แล้ว

gcloud auth list

เอาต์พุตจากคำสั่ง

Credentialed accounts:
 - <myaccount>@<mydomain>.com (active)
gcloud config list project

เอาต์พุตจากคำสั่ง

[core]
project = <PROJECT_ID>

หากโปรเจ็กต์ไม่ได้ตั้งค่าไว้ด้วยเหตุผลบางประการ ให้ใช้คำสั่งต่อไปนี้

gcloud config set project <PROJECT_ID>

กำลังมองหา PROJECT_ID ของคุณอยู่ใช่ไหม ตรวจสอบรหัสที่คุณใช้ในขั้นตอนการตั้งค่าหรือดูในแดชบอร์ด Cloud Console

2485e00c1223af09.png

Cloud Shell ยังตั้งค่าตัวแปรสภาพแวดล้อมโดยค่าเริ่มต้นด้วย ซึ่งอาจเป็นประโยชน์เมื่อคุณเรียกใช้คำสั่งในอนาคต

echo $GOOGLE_CLOUD_PROJECT

เอาต์พุตจากคำสั่ง

<PROJECT_ID>
  1. สุดท้าย ให้ตั้งค่าโซนและการกำหนดค่าโปรเจ็กต์เริ่มต้น
gcloud config set compute/zone us-central1-f

คุณเลือกโซนต่างๆ ได้หลากหลาย ดูข้อมูลเพิ่มเติมได้ที่ภูมิภาคและ โซน

3 สร้างบริการ gRPC

สร้างโปรเจ็กต์ Java ใหม่ด้วย Maven ดังนี้

$ mvn archetype:generate -DgroupId=com.example.grpc \
 -DartifactId=grpc-hello-server \
 -DarchetypeArtifactId=maven-archetype-quickstart \
 -DinteractiveMode=false
$ cd grpc-hello-server

เพิ่มไฟล์คำจำกัดความ gRPC

ใน gRPC เพย์โหลดบริการ (คำขอและการตอบกลับ) และการดำเนินการของบริการต้องบันทึกไว้ใน IDL (ภาษานิยามอินเทอร์เฟซ) gRPC ใช้ไวยากรณ์ Protobuffer 3 เพื่อกำหนดเพย์โหลดของข้อความและการดำเนินการ เรามาสร้างไฟล์ Proto สำหรับบริการทักทายอย่างง่ายด้วยคำขอ Hello และการตอบกลับ Hello กัน

ขั้นแรก ให้สร้างไดเรกทอรี Proto ใหม่เพื่อเก็บไฟล์ Proto ใหม่ โดยทำดังนี้

$ mkdir -p src/main/proto

จากนั้นให้สร้างไฟล์ Proto ใหม่ src/main/proto/GreetingService.proto

คุณใช้ vim,nano, หรือ emacs เพื่อแก้ไขไฟล์ได้โดยทำดังนี้

src/main/proto/GreetingService.proto

syntax = "proto3";
package com.example.grpc;

// Request payload
message HelloRequest {
  // Each message attribute is strongly typed.
  // You also must assign a "tag" number.
  // Each tag number is unique within the message.
  string name = 1;

  // This defines a strongly typed list of String
  repeated string hobbies = 2;

  // There are many more basics types, like Enum, Map
  // See https://developers.google.com/protocol-buffers/docs/proto3
  // for more information.
}

message HelloResponse {
  string greeting = 1;
}

// Defining a Service, a Service can have multiple RPC operations
service GreetingService {
  // Define a RPC operation
  rpc greeting(HelloRequest) returns (HelloResponse);
}

เพิ่มการพึ่งพาและปลั๊กอิน gRPC

เมื่อได้คําจํากัดความแล้ว เราจะสร้างทั้งสตับฝั่งเซิร์ฟเวอร์และสตับฝั่งไคลเอ็นต์จากไฟล์นี้ได้ คุณจะต้องเพิ่มทรัพยากร Dependency และปลั๊กอิน gRPC

ก่อนอื่น ให้เพิ่มทรัพยากร Dependency ของ gRPC ไปยัง pom.xml ดังนี้

pom.xml

<project>
  ...
  <dependencies>
    <dependency>
      <groupId>io.grpc</groupId>
      <artifactId>grpc-netty-shaded</artifactId>
      <version>1.24.0</version>
    </dependency>
    <dependency>
      <groupId>io.grpc</groupId>
      <artifactId>grpc-protobuf</artifactId>
      <version>1.24.0</version>
    </dependency>
    <dependency>
      <groupId>io.grpc</groupId>
      <artifactId>grpc-stub</artifactId>
      <version>1.24.0</version>
    </dependency>
    <dependency>
      <groupId>javax.annotation</groupId>
      <artifactId>javax.annotation-api</artifactId>
      <version>1.3.2</version>
    </dependency>
    ...
  </dependencies>
  ...
</project>

จากนั้นเพิ่มปลั๊กอินโดยทำดังนี้

pom.xml

<project>
  ...
  <dependencies>
    ...
  </dependencies>
  <build>
    <extensions>
      <extension>
        <groupId>kr.motd.maven</groupId>
        <artifactId>os-maven-plugin</artifactId>
        <version>1.6.2</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.9.0:exe:${os.detected.classifier}</protocArtifact>
          <pluginId>grpc-java</pluginId>
          <pluginArtifact>io.grpc:protoc-gen-grpc-java:1.24.0:exe:${os.detected.classifier}</pluginArtifact>
        </configuration>
        <executions>
          <execution>
            <goals>
              <goal>compile</goal>
              <goal>compile-custom</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>

</project>

สร้าง Stub

เมื่อคุณสร้างแอปพลิเคชัน ปลั๊กอินจะแปลงคำจำกัดความของโปรโตเป็นโค้ด Java

$ mvn -DskipTests package

วิธีดูไฟล์ที่สร้างขึ้น

$ find target/generated-sources

ใช้บริการ

ขั้นแรก ให้สร้างคลาส GreetingServiceImpl ใหม่ที่จะใช้การดำเนินการ greeting:

src/main/java/com/example/grpc/GreetingServiceImpl.java

package com.example.grpc;

import io.grpc.stub.StreamObserver;

public class GreetingServiceImpl extends GreetingServiceGrpc.GreetingServiceImplBase {
  @Override
  public void greeting(GreetingServiceOuterClass.HelloRequest request,
        StreamObserver<GreetingServiceOuterClass.HelloResponse> responseObserver) {
  // HelloRequest has toString auto-generated.
    System.out.println(request);

    // You must use a builder to construct a new Protobuffer object
    GreetingServiceOuterClass.HelloResponse response = GreetingServiceOuterClass.HelloResponse.newBuilder()
      .setGreeting("Hello there, " + request.getName())
      .build();

    // Use responseObserver to send a single response back
    responseObserver.onNext(response);

    // When you are done, you must call onCompleted.
    responseObserver.onCompleted();
  }
}

ใช้งานเซิร์ฟเวอร์

ขั้นตอนสุดท้าย คุณจะต้องเริ่มเซิร์ฟเวอร์เพื่อฟังพอร์ตและลงทะเบียนการใช้งานบริการนี้ แก้ไขคลาส App และเป็นวิธีการหลัก

src/main/java/com/example/grpc/App.java

package com.example.grpc;

import io.grpc.*;

public class App
{
    public static void main( String[] args ) throws Exception
    {
      // Create a new server to listen on port 8080
      Server server = ServerBuilder.forPort(8080)
        .addService(new GreetingServiceImpl())
        .build();

      // Start the server
      server.start();

      // Server threads are running in the background.
      System.out.println("Server started");
      // Don't exit the main thread. Wait until server is terminated.
      server.awaitTermination();
    }
}

ขั้นตอนสุดท้าย ให้เรียกใช้เซิร์ฟเวอร์ ดังนี้

$ mvn -DskipTests package exec:java -Dexec.mainClass=com.example.grpc.App
...
Server Started

4 การใช้บริการ

โปรแกรมสร้างได้สร้างต้นขั้วฝั่งไคลเอ็นต์ทั้งหมดแล้ว เราจะใช้โปรเจ็กต์ Maven เดียวกัน แต่เพิ่มคลาส Client ใหม่ด้วยวิธีหลักใหม่เพื่อให้ห้องทดลองทำงานง่ายขึ้น

ก่อนอื่น ให้คลิก + เพื่อเปิดเซสชัน Cloud Shell ใหม่ โดยไม่จำเป็นต้องสิ้นสุดเซิร์ฟเวอร์ ดังนี้

1ff0fda960b9adfc.png

ในเซสชันใหม่ ให้สลับไปที่ไดเรกทอรี grpc-hello-server:

$ cd grpc-hello-server

จากนั้นเพิ่มชั้นเรียน Client ใหม่

src/main/java/com/example/grpc/Client.java

package com.example.grpc;

import io.grpc.*;

public class Client
{
    public static void main( String[] args ) throws Exception
    {
      // Channel is the abstraction to connect to a service endpoint
      // Let's use plaintext communication because we don't have certs
      final ManagedChannel channel = ManagedChannelBuilder.forTarget("localhost:8080")
        .usePlaintext(true)
        .build();

      // It is up to the client to determine whether to block the call
      // Here we create a blocking stub, but an async stub,
      // or an async stub with Future are always possible.
      GreetingServiceGrpc.GreetingServiceBlockingStub stub = GreetingServiceGrpc.newBlockingStub(channel);
      GreetingServiceOuterClass.HelloRequest request =
        GreetingServiceOuterClass.HelloRequest.newBuilder()
          .setName("Ray")
          .build();

      // Finally, make the call using the stub
      GreetingServiceOuterClass.HelloResponse response = 
        stub.greeting(request);

      System.out.println(response);

      // A Channel should be shutdown before stopping the process.
      channel.shutdownNow();
    }
}

ขั้นตอนสุดท้าย เรียกใช้ไคลเอ็นต์

$ mvn -DskipTests package exec:java -Dexec.mainClass=com.example.grpc.Client
...
greeting: "Hello there, Ray"

เท่านี้ก็เรียบร้อย ง่ายมากใช่ไหม

5 บริการสตรีมมิง

ยังมีสิ่งอื่นอีกมากมายให้คุณลอง ตัวอย่างเช่น คุณจะสร้างบริการสตรีมมิงได้ง่ายๆ เพียงเพิ่มคีย์เวิร์ด stream ในไฟล์ Proto ไปยังคำขอหรือพารามิเตอร์การตอบกลับ เช่น

src/main/proto/GreetingService.proto

syntax = "proto3";
package com.example.grpc;

...

// Defining a Service, a Service can have multiple RPC operations
service GreetingService {
  // MODIFY HERE: Update the return to streaming return.
  rpc greeting(HelloRequest) returns (stream HelloResponse);
}

อัปเดตเซิร์ฟเวอร์ให้ส่งการตอบกลับหลายรายการแทนที่จะส่งเพียงรายการเดียว ซึ่งทําได้โดยโทรหา responseObserver.onNext(...) หลายๆ ครั้ง

src/main/java/com/example/grpc/GreetingServiceImpl.java

package com.example.grpc;

import io.grpc.stub.StreamObserver;

public class GreetingServiceImpl extends GreetingServiceGrpc.GreetingServiceImplBase {
  @Override
  public void greeting(GreetingServiceOuterClass.HelloRequest request,
        StreamObserver<GreetingServiceOuterClass.HelloResponse> responseObserver) {
 
    ...

    // Feel free to construct different responses if you'd like.
    responseObserver.onNext(response);
    responseObserver.onNext(response);
    responseObserver.onNext(response);

    // When you are done, you must call onCompleted.
    responseObserver.onCompleted();
  }
}

ไคลเอ็นต์ต้องใช้สตับแบบไม่พร้อมกันแทนสตับการบล็อก อัปเดตรหัสไคลเอ็นต์โดยอัปเดตประเภท stub เป็น GreetingServiceStub

src/main/java/com/example/grpc/Client.java

package com.example.grpc;

import io.grpc.*;

// New import
import io.grpc.stub.*;

public class Client
{
    public static void main( String[] args ) throws Exception
    {
      final ManagedChannel channel = ManagedChannelBuilder.forTarget("localhost:8080")
        .usePlaintext(true)
        .build();

      // Replace the previous synchronous code with asynchronous code.
      // This time use an async stub:
       GreetingServiceGrpc.GreetingServiceStub stub = GreetingServiceGrpc.newStub(channel);

      // Construct a request
      GreetingServiceOuterClass.HelloRequest request =
        GreetingServiceOuterClass.HelloRequest.newBuilder()
          .setName("Ray")
          .build();

      // Make an Asynchronous call. Listen to responses w/ StreamObserver
      stub.greeting(request, new StreamObserver<GreetingServiceOuterClass.HelloResponse>() {
        public void onNext(GreetingServiceOuterClass.HelloResponse response) {
          System.out.println(response);
        }
        public void onError(Throwable t) {
        }
        public void onCompleted() {
          // Typically you'll shutdown the channel somewhere else.
          // But for the purpose of the lab, we are only making a single
          // request. We'll shutdown as soon as this request is done.
          channel.shutdownNow();
        }
      });
    }
}

สร้างแอปพลิเคชันอีกครั้ง:

$ mvn -DskipTests package

รีสตาร์ททั้งเซิร์ฟเวอร์และไคลเอ็นต์ในเซสชัน Cloud Shell ของแต่ละเซิร์ฟเวอร์

วิธีเริ่มต้นเซิร์ฟเวอร์

$ mvn exec:java -Dexec.mainClass=com.example.grpc.App
...
Server Started

วิธีเริ่มใช้งานไคลเอ็นต์

$ mvn exec:java -Dexec.mainClass=com.example.grpc.Client
...
greeting: "Hello there, Ray"
greeting: "Hello there, Ray"
greeting: "Hello there, Ray"

6 ยินดีด้วย

หัวข้อที่ครอบคลุมมีดังนี้

  • ภาษาโปรโตคอลบัฟเฟอร์
  • วิธีติดตั้งใช้งานเซิร์ฟเวอร์ gRPC โดยใช้ Java
  • วิธีติดตั้งใช้งานไคลเอ็นต์ gRPC โดยใช้ Java

ขั้นตอนถัดไป:

แสดงความคิดเห็น

  • โปรดสละเวลาสักครู่เพื่อทำแบบสำรวจสั้นๆ ของเรา