1. סקירה כללית
gRPC הוא framework וערכת כלים לקריאה לשירות מרוחק (RPC) שפותחו ב-Google, והם לא תלויים בשפה או בפלטפורמה. הוא מאפשר להגדיר שירות באמצעות Protocol Buffers, שהם ערכת כלים ושפה בינאריים חזקים במיוחד לסריאליזציה. אחר כך, הוא מאפשר לכם ליצור קובצי stub של לקוח ושרת בשפות שונות מתוך הגדרת השירות.
ב-codelab הזה תלמדו איך ליצור שירות מבוסס-Java שחושף API באמצעות מסגרת gRPC, ואז לכתוב לקוח שישתמש ב-stub שנוצר מצד הלקוח של gRPC.
מה תלמדו
- שפת מאגרי אחסון לפרוטוקולים
- איך מטמיעים שירות gRPC באמצעות Java
- איך מטמיעים לקוח gRPC באמצעות Java
איך תשתמש במדריך הזה?
מה מידת שביעות הרצון שלך מחוויית בניית אפליקציות ב-Node.js?
איזה דירוג מגיע לדעתך לחוויה שלך בפיתוח אפליקציות Go?
2. הגדרה ודרישות
הגדרת סביבה בקצב אישי
- נכנסים אל Cloud Console ויוצרים פרויקט חדש או משתמשים בפרויקט קיים. אם עדיין אין לכם חשבון Gmail או Google Workspace, אתם צריכים ליצור חשבון.



חשוב לזכור את מזהה הפרויקט, שהוא שם ייחודי בכל הפרויקטים ב-Google Cloud (השם שלמעלה כבר תפוס ולא יתאים לכם, מצטערים!). בהמשך ה-codelab הזה נתייחס אליו כאל PROJECT_ID.
- לאחר מכן, תצטרכו להפעיל את החיוב ב-Cloud Console כדי להשתמש במשאבים של Google Cloud.
העלות של התרגול הזה לא אמורה להיות גבוהה, ואולי אפילו לא תצטרכו לשלם בכלל. חשוב לפעול לפי ההוראות בקטע 'ניקוי' כדי להשבית את המשאבים, וכך לא תחויבו אחרי שתסיימו את המדריך הזה. משתמשים חדשים ב-Google Cloud זכאים לתוכנית תקופת ניסיון בחינם בשווי 300$.
Google Cloud Shell
אפשר להשתמש ב-codelab הזה מהמחשב, אבל אנחנו נשתמש ב-Google Cloud Shell, סביבת שורת פקודה שפועלת בענן.
המכונה הווירטואלית הזו מבוססת על Debian, וטעונים בה כל הכלים הדרושים למפתחים. יש בה ספריית בית בנפח מתמיד של 5GB והיא פועלת ב-Google Cloud, מה שמשפר מאוד את הביצועים והאימות ברשת. כלומר, כל מה שצריך כדי לבצע את ההוראות במאמר הזה הוא דפדפן (כן, זה עובד ב-Chromebook).
- כדי להפעיל את Cloud Shell ממסוף Cloud, פשוט לוחצים על הפעלת Cloud Shell
(הקצאת המשאבים והחיבור לסביבה אמורים להימשך רק כמה רגעים).


אחרי שמתחברים ל-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:

ב-Cloud Shell מוגדרים גם כמה משתני סביבה כברירת מחדל, שיכולים להיות שימושיים כשמריצים פקודות בעתיד.
echo $GOOGLE_CLOUD_PROJECT
פלט הפקודה
<PROJECT_ID>
- לבסוף, מגדירים את אזור ברירת המחדל ואת הגדרת הפרויקט.
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 כדי להגדיר את המטען הייעודי (payload) של ההודעות והפעולות. ניצור קובץ 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
אחרי שיש לכם את ההגדרה, אנחנו יכולים ליצור מהקובץ הזה גם את ה-stub בצד השרת וגם את ה-stub בצד הלקוח. צריך להוסיף את יחסי התלות והפלאגינים של gRPC.
קודם כול, מוסיפים את יחסי התלות של 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>
יצירת כרטיסי הכניסה
כשמבצעים build של האפליקציה, הפלאגין ממיר את הגדרות ה-proto לקוד 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. שימוש בשירות
הגנרטור כבר יצר את כל ה-stub בצד הלקוח. כדי לפשט את המעבדה, נשתמש באותו פרויקט Maven, אבל פשוט נוסיף מחלקה חדשה Client עם שיטת main חדשה.
קודם לוחצים על + כדי לפתוח סשן חדש של Cloud Shell, כדי שלא תצטרכו להפסיק את השרת:

בסשן החדש, עוברים לספרייה 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 לקובץ הפרוטו לפרמטר הבקשה או התגובה, למשל:
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 אסינכרוני במקום ב-stub חוסם. מעדכנים את קוד הלקוח ומוודאים שמעדכנים את הסוג 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
השלבים הבאים:
- מידע נוסף על gRPC Java
- דוגמאות נוספות של gRPC Java ב-GitHub
- מידע נוסף על סטרימינג ב-gRPC
- מידע נוסף על המרת קידוד מ-gRPC ל-REST
שליחת משוב
- נשמח אם תקדישו כמה רגעים למילוי הסקר הקצר שלנו.