1. مقدمة
في هذا الدرس التطبيقي حول الترميز، ستستخدم gRPC لإنشاء عميل وخادم يشكّلان الأساس لتطبيق يحدّد المسارات مكتوب بلغة Java.
في نهاية هذا البرنامج التعليمي، سيكون لديك تطبيق gRPC HelloWorld بسيط مزوّد بالمكوّن الإضافي gRPC OpenTelemetry، وستتمكّن من الاطّلاع على مقاييس إمكانية تتبّع البيانات التي تم تصديرها في Prometheus.
أهداف الدورة التعليمية
- كيفية إعداد المكوّن الإضافي OpenTelemetry لتطبيق gRPC Java حالي
- تشغيل نسخة Prometheus محلية
- تصدير المقاييس إلى Prometheus
- عرض المقاييس من لوحة بيانات Prometheus
2. قبل البدء
المتطلبات
gitcurl- الإصدار 8 من
JDKأو الإصدارات الأحدث
ثبِّت المتطلبات الأساسية:
sudo apt-get update -y
sudo apt-get upgrade -y
sudo apt-get install -y git curl
الحصول على الشفرة
لتبسيط عملية التعلّم، يوفّر لك هذا الدرس التطبيقي حول الترميز بنية أساسية مُعدّة مسبقًا لرمز المصدر لمساعدتك على البدء. ستوضّح لك الخطوات التالية كيفية تزويد المكوّن الإضافي gRPC OpenTelemetry بأدوات في أحد التطبيقات.
يتوفّر رمز المصدر الخاص بهذا الدرس التطبيقي حول الترميز في هذا الدليل على GitHub. إذا كنت تفضّل عدم تنفيذ الرمز بنفسك، يتوفّر الرمز المصدر المكتمل في الدليل completed.
أولاً، استنسِخ مستودع دروس الترميز في grpc وانتقِل إلى المجلد grpc-java-opentelemetry:
git clone -b v1 https://github.com/grpc-ecosystem/grpc-codelabs.git
cd grpc-codelabs/codelabs/grpc-java-opentelemetry/
بدلاً من ذلك، يمكنك تنزيل ملف .zip الذي يحتوي على دليل الدرس العملي فقط وفك ضغطه يدويًا.
3- تسجيل المكوّن الإضافي 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 لإضافة رمز لإعداد واجهة برمجة التطبيقات gRPC Java OpenTelemetry.
إعداد أدوات القياس على العميل
إنشاء أداة تصدير Prometheus
أنشئ PrometheusHttpServer لتحويل مقاييس OpenTelemetry إلى تنسيق Prometheus وعرضها من خلال HttpServer. ينشئ مقتطف الرمز البرمجي التالي أداة تصدير Prometheus جديدة.
// Default prometheus port i.e `prometheusPort` has been initialized to 9465
PrometheusHttpServer prometheusExporter = PrometheusHttpServer.builder()
.setPort(prometheusPort)
.build();
إنشاء مثيل OpenTelemetry SDK
يتم تسجيل الدالة البرمجية أعلاه create prometheusExporter كـ MetricReader لقراءة المقاييس من SdkMeterProvider. يتم استخدام SdkMeterProvider لضبط إعدادات المقاييس.
SdkMeterProvider sdkMeterProvider = SdkMeterProvider.builder()
.registerMetricReader(prometheusExporter)
.build();
أنشئ مثيلاً من OpenTelemetrySdk باستخدام sdkMeterProvider الذي تم إنشاؤه أعلاه لتنفيذ حزمة تطوير البرامج (SDK) الخاصة بـ OpenTelemetry.
OpenTelemetrySdk openTelemetrySdk =OpenTelemetrySdk.builder()
.setMeterProvider(sdkMeterProvider)
.build();
إنشاء مثيل GrpcOpenTelemetry
باستخدام واجهة برمجة التطبيقات GrpcOpenTelemetry، اضبط حزمة تطوير البرامج OpenTelemetry التي تستخدم أداة تصدير مقاييس Prometheus.
GrpcOpenTelemetry grpcOpenTelmetry = GrpcOpenTelemetry.newBuilder()
.sdk(openTelemetrySdk)
.build();
// Registers gRPC OpenTelemetry globally.
grpcOpenTelmetry.registerGlobal();
بعد تسجيل مثيل GrpcOpenTelemetry على مستوى العالم باستخدام registerGlobal، سيتم تزويد جميع عملاء وخوادم gRPC التي تم إنشاؤها لاحقًا بأدوات OpenTelemetry.
إيقاف حزمة تطوير البرامج (SDK) الخاصة بمنصة OpenTelemetry
يجب أن يتم الإيقاف النهائي داخل ShutDownHook. تؤدي الدالة openTelemetrySdk.close() إلى إيقاف حزمة SDK، كما تستدعي الدالة shutdown في SdkMeterProvider.
إعداد أدوات القياس على الخادم
وبالمثل، لنضِف GrpcOpenTelemetry إلى الخادم أيضًا. افتح codelabs/grpc-java-opentelemetry/start_here/src/main/java/io/grpc/codelabs/opentelemetry/OpenTelemetryServer.java وأضِف الرمز لبدء GrpcOpenTelemetry.
إنشاء أداة تصدير Prometheus
بما أنّ هذا الدرس التطبيقي حول الترميز قد يتم تنفيذه من الجهاز نفسه، سنستخدم منفذًا مختلفًا لاستضافة مقاييس جهة خادم 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 باستخدام حزمة تطوير البرامج (SDK) OpenTelemetry
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 وإيقاف SdkMeterProvider أيضًا.
4. تشغيل المثال وعرض المقاييس
لتشغيل الخادم، نفِّذ الأمر التالي:
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
5- عرض المقاييس على Prometheus
سنعمل هنا على إعداد نسخة من Prometheus ستزحف إلى مثال عميل وخادم gRPC اللذين يصدّران المقاييس باستخدام Prometheus.
نزِّل أحدث إصدار من Prometheus لمنصتك، ثم استخرِجه وشغِّله:
tar xvfz prometheus-*.tar.gz
cd prometheus-*
أنشئ ملف إعداد 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 بالإعداد الجديد -
./prometheus --config.file=grpc_otel_java_prometheus.yml
سيؤدي ذلك إلى ضبط المقاييس من عمليات الدرس التطبيقي حول الترميز من جهة العميل والخادم ليتم جمعها كل 5 ثوانٍ.
انتقِل إلى http://localhost:9090/graph للاطّلاع على المقاييس. على سبيل المثال، طلب البحث -
histogram_quantile(0.5, rate(grpc_client_attempt_duration_seconds_bucket[1m]))
سيعرض الرسم البياني متوسط وقت استجابة المحاولة باستخدام دقيقة واحدة كإطار زمني لاحتساب الكمية.
معدّل طلبات البحث -
increase(grpc_client_attempt_duration_seconds_bucket[1m])
6. (اختياري) تمرين للمستخدم
في لوحات بيانات Prometheus، ستلاحظ أنّ عدد الطلبات في الثانية منخفض. تحقَّق مما إذا كان بإمكانك تحديد بعض الرموز المشبوهة في المثال التي تحدّ من عدد الطلبات في الثانية.
بالنسبة إلى المستخدمين المتحمّسين، يقتصر رمز العميل على طلب إجراء واحد فقط في انتظار المراجعة في لحظة معيّنة. ويمكن تعديل ذلك لكي يرسل العميل المزيد من طلبات RPC بدون انتظار اكتمال الطلبات السابقة. (لم يتم تقديم الحلّ لهذه المشكلة).