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

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

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

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

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