1. Giới thiệu
Trong lớp học lập trình này, bạn sẽ dùng gRPC để tạo một máy khách và máy chủ tạo thành nền tảng của một ứng dụng lập bản đồ tuyến đường được viết bằng Java.
Khi kết thúc hướng dẫn này, bạn sẽ có một ứng dụng gRPC HelloWorld đơn giản được đo bằng trình bổ trợ gRPC OpenTelemetry và có thể xem các chỉ số quan sát được đã xuất trong Prometheus.
Kiến thức bạn sẽ học được
- Cách thiết lập Trình bổ trợ OpenTelemetry cho ứng dụng Java gRPC hiện có
- Chạy một phiên bản Prometheus cục bộ
- Xuất chỉ số sang Prometheus
- Xem các chỉ số trên trang tổng quan Prometheus
2. Trước khi bắt đầu
Bạn cần có
gitcurlJDKphiên bản 8 trở lên
Cài đặt các điều kiện tiên quyết:
sudo apt-get update -y
sudo apt-get upgrade -y
sudo apt-get install -y git curl
Lấy mã
Để đơn giản hoá quá trình học tập, lớp học lập trình này cung cấp một khung mã nguồn được tạo sẵn để giúp bạn bắt đầu. Các bước sau đây sẽ hướng dẫn bạn cách đo lường bằng Trình bổ trợ OpenTelemetry gRPC trong một ứng dụng.
Mã nguồn của giàn giáo cho lớp học lập trình này có trong thư mục này trên GitHub. Nếu bạn không muốn tự triển khai mã, thì mã nguồn hoàn chỉnh có trong thư mục completed.
Trước tiên, hãy sao chép kho lưu trữ codelab grpc và chuyển đến thư mục grpc-java-opentelemetry:
git clone https://github.com/grpc-ecosystem/grpc-codelabs.git
cd grpc-codelabs/codelabs/grpc-java-opentelemetry/
Ngoài ra, bạn có thể tải tệp .zip chỉ chứa thư mục codelab xuống rồi giải nén theo cách thủ công.
3. Đăng ký trình bổ trợ OpenTelemetry
Chúng ta cần một ứng dụng gRPC để thêm trình bổ trợ gRPC OpenTelemetry. Trong lớp học lập trình này, chúng ta sẽ sử dụng một máy chủ và ứng dụng gRPC HelloWorld đơn giản mà chúng ta sẽ đo bằng trình bổ trợ gRPC OpenTelemetry.
Bước đầu tiên là đăng ký OpenTelemetry Plugin được định cấu hình bằng một trình xuất Prometheus trong ứng dụng. Mở codelabs/grpc-java-opentelemetry/start_here/src/main/java/io/grpc/codelabs/opentelemetry/OpenTelemetryClient.java bằng trình chỉnh sửa mà bạn yêu thích, sau đó sửa đổi main để thêm mã thiết lập API gRPC Java OpenTelemetry.
Thiết lập tính năng đo lường trên ứng dụng
Tạo trình xuất Prometheus
Tạo PrometheusHttpServer để chuyển đổi các chỉ số OpenTelemetry sang định dạng Prometheus và hiển thị các chỉ số này thông qua HttpServer. Đoạn mã sau đây tạo một Prometheus Exporter mới.
// Default prometheus port i.e `prometheusPort` has been initialized to 9465
PrometheusHttpServer prometheusExporter = PrometheusHttpServer.builder()
.setPort(prometheusPort)
.build();
Tạo phiên bản OpenTelemetry SDK
Đăng ký prometheusExporter ở trên dưới dạng MetricReader để đọc các chỉ số từ SdkMeterProvider. SdkMeterProvider được dùng để định cấu hình các chế độ cài đặt chỉ số.
SdkMeterProvider sdkMeterProvider = SdkMeterProvider.builder()
.registerMetricReader(prometheusExporter)
.build();
Tạo một phiên bản OpenTelemetrySdk bằng sdkMeterProvider đã tạo ở trên để triển khai SDK của OpenTelemetry.
OpenTelemetrySdk openTelemetrySdk =OpenTelemetrySdk.builder()
.setMeterProvider(sdkMeterProvider)
.build();
Tạo phiên bản GrpcOpenTelemetry
Sử dụng API GrpcOpenTelemetry để đặt SDK OpenTelemetry sử dụng trình xuất chỉ số Prometheus.
GrpcOpenTelemetry grpcOpenTelmetry = GrpcOpenTelemetry.newBuilder()
.sdk(openTelemetrySdk)
.build();
// Registers gRPC OpenTelemetry globally.
grpcOpenTelmetry.registerGlobal();
Sau khi một phiên bản GrpcOpenTelemetry được đăng ký trên toàn cầu bằng cách sử dụng registerGlobal, tất cả các máy chủ và máy khách gRPC được tạo sau đó sẽ được đo bằng OpenTelemetry.
Tắt OpenTelemetry SDK
Quá trình tắt cần diễn ra trong ShutDownHook. openTelemetrySdk.close() sẽ tắt SDK và cũng gọi lệnh tắt trên SdkMeterProvider.
Thiết lập tính năng đo lường trên máy chủ
Tương tự, hãy thêm GrpcOpenTelemetry vào máy chủ. Mở codelabs/grpc-java-opentelemetry/start_here/src/main/java/io/grpc/codelabs/opentelemetry/OpenTelemetryServer.java rồi thêm mã để khởi động GrpcOpenTelemetry.
Tạo trình xuất Prometheus
Vì lớp học lập trình này có thể chạy trên cùng một máy, nên chúng ta đang sử dụng một cổng khác để lưu trữ các chỉ số phía máy chủ gRPC nhằm tránh xung đột cổng trong khi tạo PrometheusHttpServer.
// Default prometheus port i.e `prometheusPort` has been set to 9464
PrometheusHttpServer prometheusExporter = PrometheusHttpServer.builder()
.setPort(prometheusPort)
.build();
Tạo phiên bản OpenTelemetry SDK
SdkMeterProvider sdkMeterProvider = SdkMeterProvider.builder()
.registerMetricReader(prometheusExporter)
.build();
Khởi chạy GrpcOpenTelemetry bằng OpenTelemetry SDK
OpenTelemetrySdk openTelemetrySdk =OpenTelemetrySdk.builder()
.setMeterProvider(sdkMeterProvider)
.build();
Tạo phiên bản GrpcOpenTelemetry
GrpcOpenTelemetry grpcOpenTelmetry = GrpcOpenTelemetry.newBuilder()
.sdk(openTelemetrySdk)
.build();
// Registers gRPC OpenTelemetry globally.
grpcOpenTelmetry.registerGlobal();
Tắt OpenTelemetry SDK
Sau khi kênh gRPC bị tắt. Việc gọi openTelemetrySdk.close() sẽ tắt SDK và cũng gọi lệnh tắt trên SdkMeterProvider.
4. Chạy ví dụ và xem các chỉ số
Để chạy máy chủ, hãy chạy –
cd start_here
../gradlew installDist
./build/install/start_here/bin/opentelemetry-server
Nếu thiết lập thành công, bạn sẽ thấy kết quả sau cho máy chủ –
[date and time] io.grpc.codelabs.opentelemetry.OpenTelemetryServer start
INFO: Server started, listening on 50051
Trong khi máy chủ đang chạy, trên một thiết bị đầu cuối khác, hãy chạy ứng dụng –
./build/install/start_here/bin/opentelemetry-client world
Một lần chạy thành công sẽ có dạng như sau:
[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
Vì chúng ta đã thiết lập trình bổ trợ gRPC OpenTelemetry để xuất các chỉ số bằng Prometheus. Các chỉ số đó sẽ có trên localhost:9464 cho máy chủ và localhost:9465 cho ứng dụng.
Cách xem các chỉ số về khách hàng:
curl localhost:9465/metrics
Kết quả sẽ có dạng –
# 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
Tương tự, đối với các chỉ số phía máy chủ:
curl localhost:9464/metrics
5. Xem các chỉ số trên Prometheus
Ở đây, chúng ta sẽ thiết lập một phiên bản prometheus để thu thập dữ liệu từ máy chủ và máy khách ví dụ gRPC đang xuất các chỉ số bằng prometheus.
Tải bản phát hành mới nhất của Prometheus xuống cho nền tảng của bạn, sau đó giải nén và chạy bản phát hành đó:
tar xvfz prometheus-*.tar.gz
cd prometheus-*
Tạo một tệp cấu hình prometheus có nội dung sau:
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
Khởi động prometheus bằng cấu hình mới –
./prometheus --config.file=grpc_otel_java_prometheus.yml
Thao tác này sẽ định cấu hình các chỉ số từ quy trình lớp học lập trình máy khách và máy chủ để được thu thập sau mỗi 5 giây.
Truy cập vào http://localhost:9090/graph để xem các chỉ số. Ví dụ: truy vấn –
histogram_quantile(0.5, rate(grpc_client_attempt_duration_seconds_bucket[1m]))
sẽ cho thấy một biểu đồ có độ trễ trung bình của lượt thử bằng cách sử dụng 1 phút làm khung thời gian để tính toán phân vị.
Tỷ lệ truy vấn –
increase(grpc_client_attempt_duration_seconds_bucket[1m])
6. (Không bắt buộc) Bài tập cho người dùng
Trong trang tổng quan prometheus, bạn sẽ nhận thấy QPS thấp. Hãy xem liệu bạn có thể xác định một số mã đáng ngờ trong ví dụ đang giới hạn QPS hay không.
Đối với những người có hứng thú, mã ứng dụng khách chỉ có một RPC đang chờ xử lý tại một thời điểm nhất định. Bạn có thể sửa đổi để máy khách gửi nhiều RPC hơn mà không cần đợi các RPC trước đó hoàn tất. (Chúng tôi chưa cung cấp giải pháp cho vấn đề này.)