۱. مقدمه
در این آزمایشگاه کد، شما از gRPC برای ایجاد یک کلاینت و سرور استفاده خواهید کرد که پایه و اساس یک برنامه مسیریابی نوشته شده در جاوا را تشکیل میدهند.
در پایان این آموزش، شما یک برنامه ساده gRPC HelloWorld مجهز به افزونه gRPC OpenTelemetry خواهید داشت و میتوانید معیارهای مشاهدهپذیری خروجی گرفته شده را در Prometheus مشاهده کنید.
آنچه یاد خواهید گرفت
- نحوه تنظیم افزونه OpenTelemetry برای برنامه جاوا gRPC موجود
- اجرای یک نمونه محلی پرومتئوس
- خروجی گرفتن از معیارها به پرومتئوس
- مشاهده معیارها از داشبورد پرومتئوس
۲. قبل از شروع
آنچه نیاز دارید
-
git -
curl -
JDKنسخه ۸ یا بالاتر
پیشنیازها را نصب کنید:
sudo apt-get update -y
sudo apt-get upgrade -y
sudo apt-get install -y git curl
کد را دریافت کنید
برای سادهسازی یادگیری شما، این codelab یک چارچوب کد منبع از پیش ساخته شده ارائه میدهد تا به شما در شروع کار کمک کند. مراحل زیر شما را در استفاده از افزونه gRPC OpenTelemetry در یک برنامه راهنمایی میکند.
کد منبع scaffold برای این codelab در این دایرکتوری github موجود است. اگر ترجیح میدهید کد را خودتان پیادهسازی نکنید، کد منبع تکمیلشده در دایرکتوری completed موجود است.
ابتدا، مخزن grpc codelab را کلون کنید و با دستور cd به پوشه grpc-java-opentelemetry بروید:
git clone https://github.com/grpc-ecosystem/grpc-codelabs.git
cd grpc-codelabs/codelabs/grpc-java-opentelemetry/
روش دیگر این است که فایل .zip که فقط شامل دایرکتوری codelab است را دانلود کرده و به صورت دستی آن را از حالت فشرده خارج کنید.
۳. افزونه OpenTelemetry را ثبت کنید
برای اضافه کردن افزونه gRPC OpenTelemetry به یک برنامه gRPC نیاز داریم. در این آزمایشگاه کد، از یک کلاینت و سرور ساده gRPC HelloWorld استفاده خواهیم کرد که آن را با افزونه gRPC OpenTelemetry تجهیز خواهیم کرد.
اولین قدم شما ثبت افزونه OpenTelemetry پیکربندی شده با یک صادرکننده Prometheus در کلاینت است. codelabs/grpc-java-opentelemetry/start_here/src/main/java/io/grpc/codelabs/opentelemetry/OpenTelemetryClient.java با ویرایشگر مورد علاقه خود باز کنید، سپس main را برای اضافه کردن کد برای تنظیم API gRPC Java OpenTelemetry تغییر دهید.
نصب ابزار دقیق روی کلاینت
ایجاد صادرکننده پرومتئوس
یک PrometheusHttpServer ایجاد کنید تا معیارهای OpenTelemetry را به فرمت Prometheus تبدیل کرده و آنها را از طریق HttpServer نمایش دهد. قطعه کد زیر یک Prometheus Exporter جدید ایجاد میکند.
// Default prometheus port i.e `prometheusPort` has been initialized to 9465
PrometheusHttpServer prometheusExporter = PrometheusHttpServer.builder()
.setPort(prometheusPort)
.build();
ایجاد نمونه OpenTelemetry SDK
در بالا، prometheusExporter به عنوان MetricReader ثبت کنید تا معیارها را از SdkMeterProvider بخواند. SdkMeterProvider برای پیکربندی تنظیمات معیارها استفاده میشود.
SdkMeterProvider sdkMeterProvider = SdkMeterProvider.builder()
.registerMetricReader(prometheusExporter)
.build();
یک نمونه از OpenTelemetrySdk با sdkMeterProvider ایجاد شده در بالا برای پیادهسازی SDK از OpenTelemetry ایجاد کنید.
OpenTelemetrySdk openTelemetrySdk =OpenTelemetrySdk.builder()
.setMeterProvider(sdkMeterProvider)
.build();
ایجاد نمونه GrpcOpenTelemetry
با استفاده از GrpcOpenTelemetry API ، OpenTelemetry SDK را که از Prometheus Metric export استفاده میکند، تنظیم کنید.
GrpcOpenTelemetry grpcOpenTelmetry = GrpcOpenTelemetry.newBuilder()
.sdk(openTelemetrySdk)
.build();
// Registers gRPC OpenTelemetry globally.
grpcOpenTelmetry.registerGlobal();
زمانی که یک نمونه GrpcOpenTelemetry با استفاده از registerGlobal به صورت سراسری ثبت شود، تمام کلاینتها و سرورهای gRPC که متعاقباً ایجاد میشوند، با OpenTelemetry تجهیز خواهند شد.
خاموش کردن SDK مربوط به OpenTelemetry
خاموش کردن باید درون ShutDownHook اتفاق بیفتد. openTelemetrySdk.close() SDK را خاموش میکند و همچنین خاموش کردن را در SdkMeterProvider فراخوانی میکند.
نصب ابزار دقیق روی سرور
به همین ترتیب، بیایید GrpcOpenTelemetry را نیز به سرور اضافه کنیم. codelabs/grpc-java-opentelemetry/start_here/src/main/java/io/grpc/codelabs/opentelemetry/OpenTelemetryServer.java را باز کنید و کد لازم برای راهاندازی GrpcOpenTelemetry را اضافه کنید.
ایجاد صادرکننده پرومتئوس
از آنجایی که این codelab ممکن است از همان دستگاه اجرا شود، ما از پورت متفاوتی برای میزبانی معیارهای سمت سرور gRPC استفاده میکنیم تا از تداخل پورتها هنگام ایجاد PrometheusHttpServer جلوگیری کنیم.
// Default prometheus port i.e `prometheusPort` has been set to 9464
PrometheusHttpServer prometheusExporter = PrometheusHttpServer.builder()
.setPort(prometheusPort)
.build();
ایجاد نمونه OpenTelemetry SDK
SdkMeterProvider sdkMeterProvider = SdkMeterProvider.builder()
.registerMetricReader(prometheusExporter)
.build();
مقداردهی اولیه GrpcOpenTelemetry با OpenTelemetry SDK
OpenTelemetrySdk openTelemetrySdk =OpenTelemetrySdk.builder()
.setMeterProvider(sdkMeterProvider)
.build();
ایجاد نمونه GrpcOpenTelemetry
GrpcOpenTelemetry grpcOpenTelmetry = GrpcOpenTelemetry.newBuilder()
.sdk(openTelemetrySdk)
.build();
// Registers gRPC OpenTelemetry globally.
grpcOpenTelmetry.registerGlobal();
خاموش کردن SDK مربوط به OpenTelemetry
بعد از اینکه کانال gRPC خاموش شد، فراخوانی openTelemetrySdk.close() باعث خاموش شدن SDK و همچنین فراخوانی shutdown در SdkMeterProvider میشود.
۴. اجرای مثال و مشاهده معیارها
برای اجرای سرور، دستور زیر را اجرا کنید -
cd start_here
../gradlew installDist
./build/install/start_here/bin/opentelemetry-server
با راهاندازی موفقیتآمیز، خروجی زیر را برای سرور مشاهده خواهید کرد -
[date and time] io.grpc.codelabs.opentelemetry.OpenTelemetryServer start
INFO: Server started, listening on 50051
در حالی که سرور در حال اجرا است، در یک ترمینال دیگر، کلاینت را اجرا کنید -
./build/install/start_here/bin/opentelemetry-client world
یک اجرای موفق به این شکل خواهد بود -
[date and time]io.grpc.codelabs.opentelemetry.OpenTelemetryClient greet
INFO: Greeting: Hello world
[date and time] io.grpc.codelabs.opentelemetry.OpenTelemetryClient greet
INFO: Will try to greet world ...
[date and time]io.grpc.codelabs.opentelemetry.OpenTelemetryClient greet
INFO: Greeting: Hello world
از آنجایی که افزونه gRPC OpenTelemetry را برای خروجی گرفتن از معیارها با استفاده از Prometheus تنظیم کردهایم، این معیارها برای سرور در localhost:9464 و برای کلاینت در localhost:9465 در دسترس خواهند بود.
برای دیدن معیارهای مشتری -
curl localhost:9465/metrics
نتیجه به شکل زیر خواهد بود -
# HELP grpc_client_attempt_duration_seconds Time taken to complete a client call attempt
# TYPE grpc_client_attempt_duration_seconds histogram
grpc_client_attempt_duration_seconds_bucket{grpc_method="helloworld.Greeter/SayHello",grpc_status="OK",grpc_target="dns:///localhost:50051",otel_scope_name="grpc-java",otel_scope_version="1.66.0",le="0.002"} 0
grpc_client_attempt_duration_seconds_bucket{grpc_method="helloworld.Greeter/SayHello",grpc_status="OK",grpc_target="dns:///localhost:50051",otel_scope_name="grpc-java",otel_scope_version="1.66.0",le="0.003"} 2
grpc_client_attempt_duration_seconds_bucket{grpc_method="helloworld.Greeter/SayHello",grpc_status="OK",grpc_target="dns:///localhost:50051",otel_scope_name="grpc-java",otel_scope_version="1.66.0",le="0.004"} 14
grpc_client_attempt_duration_seconds_bucket{grpc_method="helloworld.Greeter/SayHello",grpc_status="OK",grpc_target="dns:///localhost:50051",otel_scope_name="grpc-java",otel_scope_version="1.66.0",le="0.005"} 29
grpc_client_attempt_duration_seconds_bucket{grpc_method="helloworld.Greeter/SayHello",grpc_status="OK",grpc_target="dns:///localhost:50051",otel_scope_name="grpc-java",otel_scope_version="1.66.0",le="0.1"} 33
grpc_client_attempt_duration_seconds_bucket{grpc_method="helloworld.Greeter/SayHello",grpc_status="OK",grpc_target="dns:///localhost:50051",otel_scope_name="grpc-java",otel_scope_version="1.66.0",le="+Inf"} 34
grpc_client_attempt_duration_seconds_count{grpc_method="helloworld.Greeter/SayHello",grpc_status="OK",grpc_target="dns:///localhost:50051",otel_scope_name="grpc-java",otel_scope_version="1.66.0"} 34
grpc_client_attempt_duration_seconds_sum{grpc_method="helloworld.Greeter/SayHello",grpc_status="OK",grpc_target="dns:///localhost:50051",otel_scope_name="grpc-java",otel_scope_version="1.66.0"} 0.46512665300000006
# HELP grpc_client_attempt_rcvd_total_compressed_message_size_bytes Compressed message bytes received per call attempt
# TYPE grpc_client_attempt_rcvd_total_compressed_message_size_bytes histogram
grpc_client_attempt_rcvd_total_compressed_message_size_bytes_bucket{grpc_method="helloworld.Greeter/SayHello",grpc_status="OK",grpc_target="dns:///localhost:50051",otel_scope_name="grpc-java",otel_scope_version="1.66.0",le="0.0"} 0
grpc_client_attempt_rcvd_total_compressed_message_size_bytes_sum{grpc_method="helloworld.Greeter/SayHello",grpc_status="OK",grpc_target="dns:///localhost:50051",otel_scope_name="grpc-java",otel_scope_version="1.66.0"} 442.0
# HELP grpc_client_attempt_sent_total_compressed_message_size_bytes Compressed message bytes sent per client call attempt
# TYPE grpc_client_attempt_sent_total_compressed_message_size_bytes histogram
grpc_client_attempt_sent_total_compressed_message_size_bytes_bucket{grpc_method="helloworld.Greeter/SayHello",grpc_status="OK",grpc_target="dns:///localhost:50051",otel_scope_name="grpc-java",otel_scope_version="1.66.0",le="0.0"} 0
grpc_client_attempt_sent_total_compressed_message_size_bytes_bucket{grpc_method="helloworld.Greeter/SayHello",grpc_status="OK",grpc_target="dns:///localhost:50051",otel_scope_name="grpc-java",otel_scope_version="1.66.0",le="1024.0"} 34
grpc_client_attempt_sent_total_compressed_message_size_bytes_sum{grpc_method="helloworld.Greeter/SayHello",grpc_status="OK",grpc_target="dns:///localhost:50051",otel_scope_name="grpc-java",otel_scope_version="1.66.0"} 238.0
# HELP grpc_client_attempt_started_total Number of client call attempts started
# TYPE grpc_client_attempt_started_total counter
grpc_client_attempt_started_total{grpc_method="helloworld.Greeter/SayHello",grpc_target="dns:///localhost:50051",otel_scope_name="grpc-java",otel_scope_version="1.66.0"} 34.0
# HELP grpc_client_call_duration_seconds Time taken by gRPC to complete an RPC from application's perspective
# TYPE grpc_client_call_duration_seconds histogram
grpc_client_call_duration_seconds_bucket{grpc_method="helloworld.Greeter/SayHello",grpc_status="OK",grpc_target="dns:///localhost:50051",otel_scope_name="grpc-java",otel_scope_version="1.66.0",le="0.0"} 0
grpc_client_call_duration_seconds_bucket{grpc_method="helloworld.Greeter/SayHello",grpc_status="OK",grpc_target="dns:///localhost:50051",otel_scope_name="grpc-java",otel_scope_version="1.66.0",le="0.003"} 2
grpc_client_call_duration_seconds_bucket{grpc_method="helloworld.Greeter/SayHello",grpc_status="OK",grpc_target="dns:///localhost:50051",otel_scope_name="grpc-java",otel_scope_version="1.66.0",le="+Inf"} 34
grpc_client_call_duration_seconds_count{grpc_method="helloworld.Greeter/SayHello",grpc_status="OK",grpc_target="dns:///localhost:50051",otel_scope_name="grpc-java",otel_scope_version="1.66.0"} 34
grpc_client_call_duration_seconds_sum{grpc_method="helloworld.Greeter/SayHello",grpc_status="OK",grpc_target="dns:///localhost:50051",otel_scope_name="grpc-java",otel_scope_version="1.66.0"} 0.512708707
# TYPE target_info gauge
target_info{service_name="unknown_service:java",telemetry_sdk_language="java",telemetry_sdk_name="opentelemetry",telemetry_sdk_version="1.40.0"} 1
به طور مشابه، برای معیارهای سمت سرور -
curl localhost:9464/metrics
۵. مشاهده معیارها در پرومتئوس
در اینجا، ما یک نمونه پرومتئوس راهاندازی خواهیم کرد که کلاینت و سرور نمونه gRPC ما را که معیارها را با استفاده از پرومتئوس صادر میکنند، scrap میکند.
آخرین نسخه Prometheus را برای پلتفرم خود دانلود کنید ، سپس آن را استخراج و اجرا کنید:
tar xvfz prometheus-*.tar.gz
cd prometheus-*
یک فایل پیکربندی پرومتئوس با موارد زیر ایجاد کنید -
cat > grpc_otel_java_prometheus.yml <<EOF
scrape_configs:
- job_name: "prometheus"
scrape_interval: 5s
static_configs:
- targets: ["localhost:9090"]
- job_name: "grpc-otel-java"
scrape_interval: 5s
static_configs:
- targets: ["localhost:9464", "localhost:9465"]
EOF
پرومتئوس را با پیکربندی جدید شروع کنید -
./prometheus --config.file=grpc_otel_java_prometheus.yml
این کار باعث میشود معیارهای مربوط به فرآیندهای codelab کلاینت و سرور هر ۵ ثانیه یکبار scrap شوند.
برای مشاهده معیارها به آدرس http://localhost:9090/graph بروید. برای مثال، عبارت زیر
histogram_quantile(0.5, rate(grpc_client_attempt_duration_seconds_bucket[1m]))
نموداری با میانه تأخیر تلاش با استفاده از ۱ دقیقه به عنوان بازه زمانی برای محاسبه چندک نشان میدهد.
نرخ درخواستها -
increase(grpc_client_attempt_duration_seconds_bucket[1m])
۶. (اختیاری) تمرین برای کاربر
در داشبوردهای پرومتئوس، متوجه خواهید شد که QPS پایین است. ببینید آیا میتوانید کد مشکوکی را در مثال شناسایی کنید که QPS را محدود میکند یا خیر.
برای علاقهمندان، کد کلاینت خود را به داشتن تنها یک RPC در حال انتظار در یک لحظه معین محدود میکند. این میتواند به گونهای تغییر کند که کلاینت RPC های بیشتری را بدون انتظار برای تکمیل RPC های قبلی ارسال کند. (راه حلی برای این مشکل ارائه نشده است.)