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 codelab وانتقِل إلى المجلد grpc-java-opentelemetry:
git clone https://github.com/grpc-ecosystem/grpc-codelabs.git
cd grpc-codelabs/codelabs/grpc-java-opentelemetry/
بدلاً من ذلك، يمكنك تنزيل ملف .zip الذي يحتوي على دليل الدرس العملي فقط وفك ضغطه يدويًا.
3- تسجيل مكوّن OpenTelemetry الإضافي
نحتاج إلى تطبيق gRPC لإضافة المكوّن الإضافي gRPC OpenTelemetry. في هذا الدرس التطبيقي حول الترميز، سنستخدم عميل وخادم بسيطَين من 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 API.
إعداد أدوات قياس حالة التطبيق على العميل
إنشاء أداة تصدير Prometheus
أنشئ 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 الذي تم إنشاؤه أعلاه لتنفيذ OpenTelemetry في حزمة SDK.
OpenTelemetrySdk openTelemetrySdk =OpenTelemetrySdk.builder()
.setMeterProvider(sdkMeterProvider)
.build();
إنشاء مثيل GrpcOpenTelemetry
باستخدام واجهة برمجة التطبيقات GrpcOpenTelemetry API، اضبط حزمة تطوير البرامج (SDK) الخاصة بـ OpenTelemetry التي تستخدم أداة تصدير مقاييس Prometheus.
GrpcOpenTelemetry grpcOpenTelmetry = GrpcOpenTelemetry.newBuilder()
.sdk(openTelemetrySdk)
.build();
// Registers gRPC OpenTelemetry globally.
grpcOpenTelmetry.registerGlobal();
بعد تسجيل مثيل GrpcOpenTelemetry على مستوى العالم باستخدام registerGlobal، سيتم تزويد جميع عملاء وخوادم gRPC التي تم إنشاؤها بعد ذلك بأدوات OpenTelemetry.
Shutdown OpenTelemetry Sdk
يجب أن يتم الإيقاف داخل 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();
Shutdown OpenTelemetry Sdk
بعد إيقاف قناة 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
سيؤدي ذلك إلى ضبط المقاييس من عمليات codelab الخاصة بالعميل والخادم ليتم جمعها كل 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 بدون انتظار اكتمال الطلبات السابقة. (لم يتم تقديم الحلّ لهذه المشكلة).