1. סקירה כללית
gRPC הוא framework וערכת כלים של Google לניהול מרחוק (RPC) ללא שפה. היא מאפשרת להגדיר שירות באמצעות מאגרי פרוטוקולים, ערכה של כלים ושפה בינאריים במיוחד לביצוע סריאליזציה. לאחר מכן ניתן ליצור stubs אידיומטיים של לקוח ושרת מהגדרת השירות במגוון שפות.
ב-Codelab הזה תלמדו איך לפתח שירות מבוסס Java שחושף API באמצעות framework של gRPC, ואז לכתוב לקוח שישתמש ב-stub בצד הלקוח שנוצר על ידי gRPC.
מה תלמדו
- שפת מאגר הנתונים הזמני של הפרוטוקולים
- איך מטמיעים שירות gRPC באמצעות Java
- איך מטמיעים לקוח gRPC באמצעות Java
איך תשתמשו במדריך הזה?
איזה דירוג מגיע לחוויה שלך עם בניית אפליקציות של Node.js?
איזה דירוג מגיע לחוויה שלך עם הפיתוח של אפליקציות Go?
2. הגדרה ודרישות
הגדרת סביבה בקצב עצמאי
- נכנסים למסוף Cloud ויוצרים פרויקט חדש או עושים שימוש חוזר בפרויקט קיים. אם אין לכם עדיין חשבון Gmail או חשבון Google Workspace, עליכם ליצור חשבון.
חשוב לזכור את מזהה הפרויקט, שם ייחודי לכל הפרויקטים ב-Google Cloud (השם שלמעלה כבר תפוס ולא מתאים לכם, סליחה). בהמשך ב-Codelab הזה, היא תיקרא PROJECT_ID
.
- בשלב הבא צריך להפעיל את החיוב במסוף Cloud כדי להשתמש במשאבים של Google Cloud.
מעבר ב-Codelab הזה לא אמור לעלות הרבה, אם בכלל. חשוב לבצע את כל ההוראות בקטע 'ניקוי' שמסביר איך להשבית משאבים כדי שלא תצברו חיובים מעבר למדריך הזה. משתמשים חדשים ב-Google Cloud זכאים להצטרף לתוכנית תקופת ניסיון בחינם בשווי 1,200 ש"ח.
Google Cloud Shell
אומנם אפשר להפעיל את ה-Codelab הזה מהמחשב, אבל ב-Codelab הזה נשתמש ב-Google Cloud Shell, סביבת שורת הפקודה (CLI) שפועלת ב-Cloud.
המכונה הווירטואלית הזו שמבוססת על Debian נטענת עם כל הכלים למפתחים שדרושים לכם. יש בה ספריית בית בנפח מתמיד של 5GB והיא פועלת ב-Google Cloud, מה שמשפר משמעותית את ביצועי הרשת והאימות. כלומר, כל מה שדרוש ל-Codelab הזה הוא דפדפן (כן, הוא פועל ב-Chromebook).
- כדי להפעיל את Cloud Shell ממסוף Cloud, לוחצים על Activate 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:
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, יש לתעד את מטענים ייעודיים (payloads) של שירות (בקשה ותגובה) ואת פעולות השירות ב-IDL (שפת הגדרת ממשק). ב-gRPC משתמשים בתחביר Protobuffer 3 כדי להגדיר מטענים ייעודיים של הודעות ופעולות. ניצור קובץ פרוטו לשירות ברכה פשוט עם בקשת שלום ותשובה שלום.
קודם כול, יוצרים ספריית Proto חדשה שתכיל את קובץ ה-proto החדש:
$ mkdir -p src/main/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>
יצירת ה-Stubs
כשיוצרים את האפליקציה, הפלאגין ממיר את הגדרות הפרוטו לקוד 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. צריכת השירות
המחולל כבר יצר את כל ה-stubs בצד הלקוח. כדי לפשט את שיעור ה-Lab, נשתמש באותו פרויקט של Maven, אבל פשוט נוסיף מחלקה חדשה של Client
בשיטה ראשית חדשה.
קודם לוחצים על + כדי לפתוח סשן חדש ב-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
בקובץ ה-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 אסינכרוני במקום ב-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
נשמח לקבל ממך משוב
- כדאי למלא את הסקר הקצר מאוד שלנו