Observability באפליקציות gRPC בלי שרת Proxy
כלים לניטור מיקרו-שירותים מאפשרים לכם להטמיע את האפליקציות שלכם כדי לאסוף ולהציג נתוני טלמטריה ב-Cloud Monitoring, ב-Cloud Logging וב-Cloud Trace מעומסי עבודה של gRPC שנפרסו ב- Google Cloud, כולל עומסי עבודה של gRPC ב-Cloud Service Mesh.
לקוחות ושרתים של gRPC משולבים עם OpenCensus כדי לייצא מדדים ועקבות למגוון של מערכות עורפיות, כולל Trace ו-Monitoring. אפשר לעשות את זה בשפות הבאות של gRPC:
- C++
- Go
- Java
מומלץ לקרוא את סקירת הניראות של מיקרו-שירותים, ואז לפעול לפי ההוראות שבמאמר הגדרה של הניראות של מיקרו-שירותים כדי להגדיר את עומסי העבודה של gRPC ל:
- Cloud Monitoring והצגת מדדים.
- Cloud Logging וצפייה ביומנים.
- Cloud Trace וצפייה בנתוני מעקב.
ההוראות במסמך הזה מתייחסות למשימות הבאות:
צפייה בפרטי ההעברה בכלי Trace
אחרי שתשלימו את תהליך ההגדרה, לקוחות ושרתים של gRPC עם מכשור ישלחו עקבות ל-Trace. בדף Trace Overview במסוף Google Cloud מוצגת רשימה של טראסים מהזמן האחרון. אפשר לבחור מעקב ספציפי כדי לראות פירוט של התנועה, בדומה למה שמתואר בקטע הבא.
תאימות של Trace עם שרת ה-proxy של Envoy
ייצוא נתוני מעקב אל Trace באמצעות Cloud Service Mesh ו-Envoy proxy, כפי שמתואר במאמר Observability with Envoy, מתבצע באמצעות הגדרת כלי המעקב OpenCensus של Envoy, שמאפשר תאימות מלאה בין נתוני מעקב שמיוצאים מאפליקציות gRPC בלי שרת Proxy ומ-Envoy proxy בתוך Service mesh. כדי להבטיח תאימות ל-gRPC בלי שרת Proxy, צריך להגדיר את הקשר של המעקב ב-bootstrap של Envoy כך שיכלול את GRPC_TRACE_BIN בפורמט המעקב ב-OpenCensusConfig שלו. לדוגמה:
tracing:
http:
name: envoy.tracers.opencensus
typed_config:
"@type": type.googleapis.com/envoy.config.trace.v2.OpenCensusConfig
stackdriver_exporter_enabled: "true"
stackdriver_project_id: "PROJECT_ID"
incoming_trace_context: ["CLOUD_TRACE_CONTEXT", "GRPC_TRACE_BIN"]
outgoing_trace_context: ["CLOUD_TRACE_CONTEXT", "GRPC_TRACE_BIN"]
חשיפת ממשק האדמין
לפעמים, מדדים ונתוני מעקב לא מספיקים כדי לפתור בעיה. יכול להיות שתצטרכו לבדוק את ההגדרה או את מצב זמן הריצה של ספריית gRPC באפליקציה. המידע הזה כולל פרטים על מפענח ה-DNS, מצב הקישוריות לעמיתים, נתונים סטטיסטיים של RPC בערוץ וההגדרה שהתקבלה מ-Cloud Service Mesh.
כדי לקבל מידע כזה, אפליקציות gRPC יכולות לחשוף את ממשק האדמין ביציאה מסוימת. לאחר מכן תוכלו לשלוח שאילתה לאפליקציה כדי להבין איך השירותים מוגדרים ואיך הם פועלים. בקטע הזה מופיעות הוראות להגדרת ממשק הניהול של אפליקציות שנכתבו בכל אחת מהשפות הנתמכות.
מומלץ ליצור שרת gRPC נפרד באפליקציה, שיאזין ליציאה ששמורה למטרה הזו. כך תוכלו לגשת לאפליקציות gRPC גם כשאי אפשר לגשת ליציאות הנתונים בגלל הגדרה שגויה או בעיות ברשת. מומלץ לחשוף את ממשק האדמין רק ב-localhost או בשקע דומיין של Unix.
בקטעי הקוד הבאים אפשר לראות איך יוצרים ממשק אדמין.
C++
ב-C++, משתמשים בקוד הזה כדי ליצור ממשק אדמין:
#include <grpcpp/ext/admin_services.h>
grpc::ServerBuilder builder;
grpc::AddAdminServices(&builder);
builder.AddListeningPort(":50051", grpc::ServerCredentials(...));
std::unique_ptr<grpc::Server> server(builder.BuildAndStart());
Go
ב-Go, משתמשים בקוד הזה כדי ליצור ממשק אדמין:
import "google.golang.org/grpc/admin"
lis, err := net.Listen("tcp", ":50051")
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
defer lis.Close()
grpcServer := grpc.NewServer(...opts)
cleanup, err := admin.Register(grpcServer)
if err != nil {
log.Fatalf("failed to register admin services: %v", err)
}
defer cleanup()
if err := grpcServer.Serve(lis); err != nil {
log.Fatalf("failed to serve: %v", err)
}
Java
ב-Java, משתמשים בקוד הזה כדי ליצור ממשק אדמין:
import io.grpc.services.AdminInterface;
server = ServerBuilder.forPort(50051)
.useTransportSecurity(certChainFile, privateKeyFile)
.addServices(AdminInterface.getStandardServices())
.build()
.start();
server.awaitTermination();
Python
ב-Python, משתמשים בקוד הזה כדי ליצור ממשק אדמין:
import grpc_admin
server = grpc.server(futures.ThreadPoolExecutor())
grpc_admin.add_admin_servicers(server)
server.add_insecure_port('[::]:50051')
server.start()
server.wait_for_termination()
שימוש ב-SSH כדי להתחבר למכונה וירטואלית
בדוגמה של gRPC Wallet ממשק האדמין כבר מופעל. אפשר לשנות את יציאת ממשק האדמין באמצעות הדגל הבא:
--admin-port=PORT
יציאת האדמין שמוגדרת כברירת מחדל היא localhost:28881.
כדי לנפות באגים באפליקציית gRPC, אפשר להשתמש ב-SSH כדי להתחבר לאחת מהמכונות הווירטואליות שמריצות את wallet-service. כך מקבלים גישה אל localhost.
# List the Wallet VMs $ gcloud compute instances list --filter="zone:(us-central1-a)" --filter="name~'grpcwallet-wallet-v2'" NAME ZONE MACHINE_TYPE PREEMPTIBLE INTERNAL_IP EXTERNAL_IP STATUS grpcwallet-wallet-v2-mig-us-central1-ccl1 us-central1-a n1-standard-1 10.240.0.38 35.223.42.98 RUNNING grpcwallet-wallet-v2-mig-us-central1-k623 us-central1-a n1-standard-1 10.240.0.112 35.188.133.75 RUNNING # Pick one of the Wallet VMs to debug $ gcloud compute ssh grpcwallet-wallet-v2-mig-us-central1-ccl1 --zone=us-central1-a
התקנת הכלי grpcdebug
כדי לגשת לממשק האדמין, צריך לקוח gRPC שיכול לתקשר עם שירותי האדמין באפליקציית gRPC. בדוגמאות הבאות משתמשים בכלי שנקרא grpcdebug שאפשר להוריד ולהתקין במכונה וירטואלית או ב-Pod שבהם פועלת אפליקציית gRPC. המאגר של grpcdebug נמצא בכתובת grpc-ecosystem/grpcdebug.
הגרסה המינימלית של Golang שנתמכת היא 1.12. מדריך ההתקנה הרשמי של Golang זמין באתר Golang.
אם אתם פועלים לפי המדריך ליצירת מכונת VM של Linux עבור wallet-service, אתם יכולים להתקין את Golang 1.16 באמצעות הפקודות הבאות:
sudo apt update && sudo apt install -y wget wget https://golang.org/dl/go1.16.3.linux-amd64.tar.gz sudo rm -rf /usr/local/go sudo tar -C /usr/local -xzf go1.16.3.linux-amd64.tar.gz export PATH=$PATH:/usr/local/go/bin sudo ln -sf /usr/local/go/bin/go /usr/bin/go go version # go version go1.16.3 linux/amd64
כדי להתקין את הכלי grpcdebug, מריצים את הפקודות הבאות:
go install -v github.com/grpc-ecosystem/grpcdebug@latest export PATH=$PATH:$(go env GOPATH)/bin
עכשיו יש לכם גישה לממשק שורת הפקודה grpcdebug. פלט העזרה מכיל מידע על פקודות נתמכות:
$ grpcdebug -h
grpcdebug is a gRPC service admin command-line interface
Usage:
grpcdebug <target address> [flags] <command>
Available Commands:
channelz Display gRPC states in human readable way.
health Check health status of the target service (default "").
help Help about any command
xds Fetch xDS related information.
Flags:
--credential_file string Sets the path of the credential file; used in [tls] mode
-h, --help Help for grpcdebug
--security string Defines the type of credentials to use [tls, google-default, insecure] (default "insecure")
--server_name_override string Overrides the peer server name if non empty; used in [tls] mode
-t, --timestamp Print timestamp as RFC 3339 instead of human readable strings
-v, --verbose Print verbose information for debugging
כדי לקבל מידע נוסף על פקודה מסוימת, משתמשים בפקודה הבאה:
grpcdebug <target address> [command] --help
שימוש בכלי grpcdebug לניפוי באגים באפליקציות
אפשר להשתמש בכלי grpcdebug כדי לנפות באגים באפליקציות.
הכלי grpcdebug מספק הגדרה שדומה ל-ssh_config ותומך בכינויים, בשכתוב של שם המארח ובהגדרת אבטחת החיבור (לא מאובטח/TLS).
מידע נוסף על התכונה המתקדמת הזו זמין במאמר grpcdebug/Connect&Security.
בקטעים הבאים מתוארים השירותים שמוצגים בממשק הניהול ומוסבר איך לגשת אליהם.
שימוש ב-Channelz
שירות Channelz מספק גישה למידע על זמן הריצה לגבי החיבורים ברמות שונות בספריית gRPC של האפליקציה. אפשר להשתמש בזה כדי לבצע ניתוח בזמן אמת של אפליקציות שאולי יש בהן בעיות שקשורות להגדרה או לרשת. בדוגמאות הבאות מניחים שפרסתם את דוגמת הארנק של gRPC באמצעות ההוראות שבמאמר הגדרה של ניהול תנועה מתקדם באמצעות שירותי gRPC בלי שרת Proxy, ושהעברתם את הדגל הבא:
--admin-port=PORT
אחרי ששולחים כמה בקשות RPC מלקוח בדיקה, כמו שמוסבר בקטע אימות ההגדרה, משתמשים בפקודות הבאות כדי לגשת לנתוני Channelz של שירותי gRPC:
- משתמשים ב-SSH כדי להתחבר למכונה וירטואלית שמופעל בה
wallet-service. - מגדירים את
grpcdebugכדי להתחבר לאפליקציית gRPC שפועלת.
פלט ברירת המחדל של grpcdebug הוא בפורמט של טבלה שמתאים למסוף. אם מציינים את הדגל --json, הפלט מקודד כ-JSON.
הפקודה grpcdebug channelz משמשת לאחזור ולהצגה של מידע על ניפוי באגים משירות Channelz. הפקודה פועלת גם בלקוחות gRPC וגם בשרתי gRPC.
במקרה של לקוחות gRPC, הפקודה grpcdebug channelz channels מספקת רשימה של ערוצים קיימים ומידע בסיסי:
$ grpcdebug localhost:28881 channelz channels Channel ID Target State Calls(Started/Succeeded/Failed) Created Time 1 xds:///account.grpcwallet.io:10080 READY 0/0/0 59 seconds ago 2 trafficdirector.googleapis.com:443 READY 2/0/0 59 seconds ago 4 xds:///stats.grpcwallet.io:10080 READY 0/0/0 59 seconds ago
אם אתם צריכים מידע נוסף על ערוץ מסוים, אתם יכולים להשתמש בgrpcdebug channelz channel [CHANNEL_ID] כדי לבדוק מידע מפורט על הערוץ הזה. מזהה הערוץ יכול להיות מזהה הערוץ או כתובת היעד, אם יש רק כתובת יעד אחת. ערוץ gRPC יכול להכיל כמה ערוצי משנה, שהם הפשטה של gRPC מעל חיבור TCP.
$ grpcdebug localhost:28881 channelz channel 2
Channel ID: 2
Target: trafficdirector.googleapis.com:443
State: READY
Calls Started: 2
Calls Succeeded: 0
Calls Failed: 0
Created Time: 10 minutes ago
---
Subchannel ID Target State Calls(Started/Succeeded/Failed) CreatedTime
3 trafficdirector.googleapis.com:443 READY 2/0/0 10 minutes ago
---
Severity Time Child Ref Description
CT_INFO 10 minutes ago Channel Created
CT_INFO 10 minutes ago parsed scheme: ""
CT_INFO 10 minutes ago scheme "" not registered, fallback to default scheme
CT_INFO 10 minutes ago ccResolverWrapper: sending update to cc: {[{trafficdirector.googleapis.com:443 <nil> 0 <nil>}] <nil> <nil>}
CT_INFO 10 minutes ago Resolver state updated: {Addresses:[{Addr:trafficdirector.googleapis.com:443 ServerName: Attributes:<nil> Type:0 Metadata:<nil>}] ServiceConfig:<nil> Attributes:<nil>} (resolver returned new addresses)
CT_INFO 10 minutes ago ClientConn switching balancer to "pick_first"
CT_INFO 10 minutes ago Channel switches to new LB policy "pick_first"
CT_INFO 10 minutes ago subchannel(subchannel_id:3 ) Subchannel(id:3) created
CT_INFO 10 minutes ago Channel Connectivity change to CONNECTING
CT_INFO 10 minutes ago Channel Connectivity change to READY
אפשר גם לבדוק מידע מפורט על ערוץ משני:
$ grpcdebug localhost:28881 channelz subchannel 3 Subchannel ID: 3 Target: trafficdirector.googleapis.com:443 State: READY Calls Started: 2 Calls Succeeded: 0 Calls Failed: 0 Created Time: 12 minutes ago --- Socket ID Local->Remote Streams(Started/Succeeded/Failed) Messages(Sent/Received) 9 10.240.0.38:60338->142.250.125.95:443 2/0/0 214/132
אפשר לאחזר מידע על שקעי TCP:
$ grpcdebug localhost:28881 channelz socket 9
Socket ID: 9
Address: 10.240.0.38:60338->142.250.125.95:443
Streams Started: 2
Streams Succeeded: 0
Streams Failed: 0
Messages Sent: 226
Messages Received: 141
Keep Alives Sent: 0
Last Local Stream Created: 12 minutes ago
Last Remote Stream Created: a long while ago
Last Message Sent Created: 8 seconds ago
Last Message Received Created: 8 seconds ago
Local Flow Control Window: 65535
Remote Flow Control Window: 966515
---
Socket Options Name Value
SO_LINGER [type.googleapis.com/grpc.channelz.v1.SocketOptionLinger]:{duration:{}}
SO_RCVTIMEO [type.googleapis.com/grpc.channelz.v1.SocketOptionTimeout]:{duration:{}}
SO_SNDTIMEO [type.googleapis.com/grpc.channelz.v1.SocketOptionTimeout]:{duration:{}}
TCP_INFO [type.googleapis.com/grpc.channelz.v1.SocketOptionTcpInfo]:{tcpi_state:1 tcpi_options:7 tcpi_rto:204000 tcpi_ato:40000 tcpi_snd_mss:1408 tcpi_rcv_mss:1408 tcpi_last_data_sent:8212 tcpi_last_data_recv:8212 tcpi_last_ack_recv:8212 tcpi_pmtu:1460 tcpi_rcv_ssthresh:88288 tcpi_rtt:2400 tcpi_rttvar:3012 tcpi_snd_ssthresh:2147483647 tcpi_snd_cwnd:10 tcpi_advmss:1408 tcpi_reordering:3}
---
Security Model: TLS
Standard Name: TLS_AES_128_GCM_SHA256
בצד השרת, אפשר להשתמש ב-Channelz כדי לבדוק את הסטטוס של אפליקציית השרת. לדוגמה, אפשר לקבל את רשימת השרתים באמצעות הפקודה grpcdebug
channelz servers:
$ grpcdebug localhost:28881 channelz servers Server ID Listen Addresses Calls(Started/Succeeded/Failed) Last Call Started 5 [127.0.0.1:28881] 9/8/0 now 6 [[::]:50051] 159/159/0 4 seconds ago
כדי לקבל מידע נוסף על שרת ספציפי, משתמשים בפקודה grpcdebug channelz
server. אפשר לבדוק שקעי שרת באותו אופן שבו בודקים שקעי לקוח.
$ grpcdebug localhost:28881 channelz server 6 Server Id: 6 Listen Addresses: [[::]:50051] Calls Started: 174 Calls Succeeded: 174 Calls Failed: 0 Last Call Started: now --- Socket ID Local->Remote Streams(Started/Succeeded/Failed) Messages(Sent/Received) 25 10.240.0.38:50051->130.211.1.39:44904 68/68/0 68/68 26 10.240.0.38:50051->130.211.0.167:32768 54/54/0 54/54 27 10.240.0.38:50051->130.211.0.22:32768 52/52/0 52/52
שימוש בשירות לגילוי סטטוס הלקוח
API של Client Status Discovery Service (CSDS) הוא חלק מ-xDS APIs. באפליקציית gRPC, שירות ה-CSDS מספק גישה להגדרה (שנקראת גם הגדרת xDS) שהוא מקבל מ-Cloud Service Mesh. כך תוכלו לזהות ולפתור בעיות שקשורות להגדרות ברשת ה-Mesh.
בדוגמאות הבאות מניחים שפרסתם את דוגמת gRPC Wallet באמצעות ההוראות שבמאמר הגדרת ניהול תעבורה מתקדם באמצעות שירותי gRPC בלי שרת Proxy.
כדי להשתמש ב-CSDS לבדיקת ההגדרה:
- משתמשים ב-SSH כדי להתחבר למכונה וירטואלית שמופעל בה
wallet-service. פועלים לפי ההוראות במאמר שימוש ב-SSH כדי להתחבר למכונה וירטואלית. - מריצים את לקוח
grpcdebug.
כדי לקבל סקירה כללית של סטטוס ההגדרה, מריצים את הפקודה הבאה:
grpcdebug localhost:28881 xds status
התוצאות אמורות להיראות כך:
Name Status Version Type LastUpdated account.grpcwallet.io:10080 ACKED 1618529574783547920 type.googleapis.com/envoy.config.listener.v3.Listener 3 seconds ago stats.grpcwallet.io:10080 ACKED 1618529574783547920 type.googleapis.com/envoy.config.listener.v3.Listener 3 seconds ago URL_MAP/830293263384_grpcwallet-url-map_0_account.grpcwallet.io:10080 ACKED 1618529574783547920 type.googleapis.com/envoy.config.route.v3.RouteConfiguration 3 seconds ago URL_MAP/830293263384_grpcwallet-url-map_1_stats.grpcwallet.io:10080 ACKED 1618529574783547920 type.googleapis.com/envoy.config.route.v3.RouteConfiguration 3 seconds ago cloud-internal-istio:cloud_mp_830293263384_3566964729007423588 ACKED 1618529574783547920 type.googleapis.com/envoy.config.cluster.v3.Cluster 3 seconds ago cloud-internal-istio:cloud_mp_830293263384_7383783194368524341 ACKED 1618529574783547920 type.googleapis.com/envoy.config.cluster.v3.Cluster 3 seconds ago cloud-internal-istio:cloud_mp_830293263384_3363366193797120473 ACKED 1618529574783547920 type.googleapis.com/envoy.config.cluster.v3.Cluster 3 seconds ago cloud-internal-istio:cloud_mp_830293263384_3566964729007423588 ACKED 86 type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment 2 seconds ago cloud-internal-istio:cloud_mp_830293263384_3363366193797120473 ACKED 86 type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment 2 seconds ago cloud-internal-istio:cloud_mp_830293263384_7383783194368524341 ACKED 86 type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment 2 seconds ago
ההגדרה של סטטוס ההגדרה מופיעה במסמכי התיעוד של Envoy proxy.
בקצרה, הסטטוס של משאב xDS הוא אחד מהערכים REQUESTED, DOES_NOT_EXIST, ACKED או NACKED.
כדי לקבל dump של הגדרות xDS גולמיות, מריצים את הפקודה הבאה:
grpcdebug localhost:28881 xds config
מוצגת רשימה של JSON אובייקטים של PerXdsConfig:
{
"config": [
{
"node": {
"id": "projects/830293263384/networks/default/nodes/6e98b038-6d75-4a4c-8d35-b0c7a8c9cdde",
"cluster": "cluster",
"metadata": {
"INSTANCE_IP": "10.240.0.38",
"TRAFFICDIRECTOR_GCP_PROJECT_NUMBER": "830293263384",
"TRAFFICDIRECTOR_NETWORK_NAME": "default"
},
"locality": {
"zone": "us-central1-a"
},
"userAgentName": "gRPC Go",
"userAgentVersion": "1.37.0",
"clientFeatures": [
"envoy.lb.does_not_support_overprovisioning"
]
},
"xdsConfig": [
{
"listenerConfig": {
"versionInfo": "1618529930989701137",
"dynamicListeners": [
{
...
אם פלט ההגדרה הגולמי מפורט מדי, אפשר להשתמש ב-grpcdebug כדי לסנן לפי סוגים ספציפיים של xDS. לדוגמה:
$ grpcdebug localhost:28881 xds config --type=cds
{
"versionInfo": "1618530076226619310",
"dynamicActiveClusters": [
{
"versionInfo": "1618530076226619310",
"cluster": {
"@type": "type.googleapis.com/envoy.config.cluster.v3.Cluster",
"name": "cloud-internal-istio:cloud_mp_830293263384_7383783194368524341",
"altStatName": "/projects/830293263384/global/backendServices/grpcwallet-stats-service",
"type": "EDS",
"edsClusterConfig": {
"edsConfig": {
"ads": {},
"initialFetchTimeout": "15s",
...
אפשר גם להציג את ההגדרות של כמה סוגי xDS בו-זמנית:
$ grpcdebug localhost:28881 xds config --type=lds,eds
{
"versionInfo": "1618530076226619310",
"dynamicListeners": [...]
}
{
"dynamicEndpointConfigs": [...]
}
המאמרים הבאים
- מידע נוסף זמין במאמר בנושא יכולת צפייה (Observability) באמצעות Envoy.
- כדי לפתור בעיות בהגדרות כשפורסים שירותי gRPC בלי שרת Proxy, אפשר לעיין במאמר פתרון בעיות בפריסות שמשתמשות ב-gRPC בלי שרת Proxy.