1. บทนำ
ในโค้ดแล็บนี้ คุณจะได้ใช้ gRPC เพื่อสร้างไคลเอ็นต์และเซิร์ฟเวอร์ซึ่งเป็นรากฐานของแอปพลิเคชันการแมปเส้นทางที่เขียนด้วยภาษา Java
เมื่อสิ้นสุดบทแนะนำนี้ คุณจะมีแอปพลิเคชัน gRPC HelloWorld แบบง่ายๆ ที่ติดตั้งปลั๊กอิน gRPC OpenTelemetry และจะดูเมตริกการสังเกตการณ์ที่ส่งออกใน Prometheus ได้
สิ่งที่คุณจะได้เรียนรู้
- วิธีตั้งค่าปลั๊กอิน OpenTelemetry สำหรับแอปพลิเคชัน gRPC Java ที่มีอยู่
- การเรียกใช้อินสแตนซ์ Prometheus ในเครื่อง
- ส่งออกเมตริกไปยัง Prometheus
- ดูเมตริกจากแดชบอร์ด Prometheus
2. ก่อนเริ่มต้น
สิ่งที่คุณต้องมี
gitcurlJDKv8 ขึ้นไป
ติดตั้งข้อกำหนดเบื้องต้น
sudo apt-get update -y
sudo apt-get upgrade -y
sudo apt-get install -y git curl
รับโค้ด
Codelab นี้มีโครงร่างซอร์สโค้ดที่สร้างไว้ล่วงหน้าเพื่อช่วยให้คุณเริ่มต้นใช้งานได้ง่ายขึ้น ขั้นตอนต่อไปนี้จะแนะนําคุณตลอดการติดตั้งใช้งานปลั๊กอิน gRPC OpenTelemetry ในแอปพลิเคชัน
ซอร์สโค้ดโครงร่างสำหรับ Codelab นี้อยู่ในไดเรกทอรีนี้ใน GitHub หากไม่ต้องการติดตั้งใช้งานโค้ดด้วยตนเอง คุณจะดูซอร์สโค้ดที่เสร็จสมบูรณ์ได้ในไดเรกทอรี completed
ก่อนอื่น ให้โคลนที่เก็บโค้ดแล็บ grpc แล้ว cd ไปยังโฟลเดอร์ grpc-java-opentelemetry
git clone https://github.com/grpc-ecosystem/grpc-codelabs.git
cd grpc-codelabs/codelabs/grpc-java-opentelemetry/
หรือคุณจะดาวน์โหลดไฟล์ .zip ที่มีเฉพาะไดเรกทอรี Codelab แล้วแตกไฟล์ด้วยตนเองก็ได้
3. ลงทะเบียนปลั๊กอิน OpenTelemetry
เราต้องมีแอปพลิเคชัน gRPC เพื่อเพิ่มปลั๊กอิน gRPC OpenTelemetry ในโค้ดแล็บนี้ เราจะใช้ไคลเอ็นต์และเซิร์ฟเวอร์ gRPC HelloWorld แบบง่ายๆ ซึ่งเราจะติดตั้งเครื่องมือด้วยปลั๊กอิน OpenTelemetry ของ gRPC
ขั้นตอนแรกคือการลงทะเบียนปลั๊กอิน 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 ที่สร้างขึ้นข้างต้นสำหรับการใช้งาน SDK ของ OpenTelemetry
OpenTelemetrySdk openTelemetrySdk =OpenTelemetrySdk.builder()
.setMeterProvider(sdkMeterProvider)
.build();
สร้างอินสแตนซ์ GrpcOpenTelemetry
ใช้ API ของ GrpcOpenTelemetry เพื่อตั้งค่า OpenTelemetry SDK ซึ่งใช้ตัวส่งออกเมตริกของ Prometheus
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
สร้างตัวส่งออก Prometheus
เนื่องจาก 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 และเรียกใช้การปิดใน 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]))
จะแสดงกราฟที่มีเวลาในการตอบสนองของความพยายามที่ค่ามัธยฐานโดยใช้ 1 นาทีเป็นกรอบเวลาสำหรับการคำนวณควอนไทล์
อัตราการค้นหา -
increase(grpc_client_attempt_duration_seconds_bucket[1m])
6. (ไม่บังคับ) แบบฝึกหัดสำหรับผู้ใช้
ในแดชบอร์ด Prometheus คุณจะเห็นว่า QPS ต่ำ ดูว่าคุณสามารถระบุโค้ดที่น่าสงสัยในตัวอย่างที่จำกัด QPS ได้หรือไม่
สำหรับผู้ที่กระตือรือร้น รหัสไคลเอ็นต์จะจำกัดตัวเองให้มี RPC ที่รอดำเนินการเพียงรายการเดียวในขณะใดก็ตาม ซึ่งสามารถแก้ไขเพื่อให้ไคลเอ็นต์ส่ง RPC เพิ่มเติมได้โดยไม่ต้องรอให้ RPC ก่อนหน้าเสร็จสมบูรณ์ (ยังไม่มีวิธีแก้ปัญหานี้)