1. Einführung
In diesem Codelab erstellen Sie mit gRPC einen Client und einen Server, die die Grundlage für eine in C++ geschriebene Routenplanungsanwendung bilden.
Am Ende des Tutorials haben Sie eine einfache gRPC-HelloWorld-Anwendung, die mit dem gRPC-OpenTelemetry-Plug-in instrumentiert ist, und können die exportierten Beobachtbarkeitsmesswerte in Prometheus sehen.
Lerninhalte
- OpenTelemetry-Plug-in für eine vorhandene gRPC-C++-Anwendung einrichten
- Lokale Prometheus-Instanz ausführen
- Messwerte nach Prometheus exportieren
- Messwerte im Prometheus-Dashboard ansehen
2. Hinweis
Voraussetzungen
gitcurlbuild-essentialclangbazelzum Erstellen von Beispielen in diesem Codelab
Installieren Sie die notwendigen Komponenten:
sudo apt-get update -y
sudo apt-get upgrade -y
sudo apt-get install -y git curl build-essential clang
bazel kann über bazelisk installiert werden. Die neueste Version finden Sie hier.
Eine einfache Möglichkeit, es einzurichten, besteht darin, es wie folgt als binäre Datei von bazel in Ihrem Pfad zu installieren:
sudo cp bazelisk-linux-amd64 /usr/local/bin/bazel
sudo chmod a+x /usr/local/bin/bazel
Alternativ können Sie auch CMake verwenden. Eine Anleitung zur Verwendung von CMake finden Sie hier.
Code abrufen
Um Ihnen das Lernen zu erleichtern, bietet dieses Codelab ein vorgefertigtes Quellcode-Grundgerüst, das Ihnen den Einstieg erleichtert. In den folgenden Schritten erfahren Sie, wie Sie das gRPC-OpenTelemetry-Plug-in in einer Anwendung instrumentieren.
grpc-codelabs
Der Quellcode für das Grundgerüst für dieses Codelab ist in diesem GitHub Verzeichnis verfügbar. Wenn Sie den Code nicht selbst implementieren möchten, finden Sie den vollständigen Quellcode im Verzeichnis „completed“.
Klonen Sie zuerst das gRPC-Codelab-Repository und wechseln Sie zum Ordner „grpc-cpp-opentelemetry“:
git clone -b v1 https://github.com/grpc-ecosystem/grpc-codelabs.git
cd grpc-codelabs/codelabs/grpc-cpp-opentelemetry/
Alternativ können Sie die ZIP-Datei herunterladen, die nur das Codelab-Verzeichnis enthält, und sie manuell entzippen.
Erstellen Sie die gRPC-Bibliothek mit bazel:
bazel build start_here/...
3. OpenTelemetry-Plug-in registrieren
Wir benötigen eine gRPC-Anwendung, um das gRPC-OpenTelemetry-Plug-in hinzuzufügen. In diesem Codelab verwenden wir einen einfachen gRPC-HelloWorld-Client und -Server, die wir mit dem gRPC-OpenTelemetry-Plug-in instrumentieren.
Im ersten Schritt registrieren Sie das OpenTelemetry-Plug-in, das mit einem Prometheus-Exporter im Client konfiguriert wurde. Öffnen Sie codelabs/grpc-cpp-opentelemetry/start_here/greeter_callback_client.cc mit Ihrem bevorzugten Editor und ändern Sie main() so, dass es so aussieht:
int main(int argc, char **argv) {
absl::ParseCommandLine(argc, argv);
// Codelab Solution: Register a global gRPC OpenTelemetry plugin configured
// with a prometheus exporter.
opentelemetry::exporter::metrics::PrometheusExporterOptions opts;
opts.url = absl::GetFlag(FLAGS_prometheus_endpoint);
auto prometheus_exporter =
opentelemetry::exporter::metrics::PrometheusExporterFactory::Create(opts);
auto meter_provider =
std::make_shared<opentelemetry::sdk::metrics::MeterProvider>();
// The default histogram boundaries are not granular enough for RPCs. Override
// the "grpc.client.attempt.duration" view as recommended by
// https://github.com/grpc/proposal/blob/master/A66-otel-stats.md.
AddLatencyView(meter_provider.get(), "grpc.client.attempt.duration", "s");
meter_provider->AddMetricReader(std::move(prometheus_exporter));
auto status = grpc::OpenTelemetryPluginBuilder()
.SetMeterProvider(std::move(meter_provider))
.BuildAndRegisterGlobal();
if (!status.ok()) {
std::cerr << "Failed to register gRPC OpenTelemetry Plugin: "
<< status.ToString() << std::endl;
return static_cast<int>(status.code());
}
// Continuously send RPCs.
RunClient(absl::GetFlag(FLAGS_target));
return 0;
}
Als Nächstes fügen Sie das OpenTelemetry-Plug-in dem Server hinzu. Öffnen Sie codelabs/grpc-cpp-opentelemetry/start_here/greeter_callback_server.cc und ändern Sie „main“ so, dass es so aussieht:
int main(int argc, char** argv) {
absl::ParseCommandLine(argc, argv);
// Register a global gRPC OpenTelemetry plugin configured with a prometheus
// exporter.
opentelemetry::exporter::metrics::PrometheusExporterOptions opts;
opts.url = absl::GetFlag(FLAGS_prometheus_endpoint);
auto prometheus_exporter =
opentelemetry::exporter::metrics::PrometheusExporterFactory::Create(opts);
auto meter_provider =
std::make_shared<opentelemetry::sdk::metrics::MeterProvider>();
// The default histogram boundaries are not granular enough for RPCs. Override
// the "grpc.server.call.duration" view as recommended by
// https://github.com/grpc/proposal/blob/master/A66-otel-stats.md.
AddLatencyView(meter_provider.get(), "grpc.server.call.duration", "s");
meter_provider->AddMetricReader(std::move(prometheus_exporter));
auto status = grpc::OpenTelemetryPluginBuilder()
.SetMeterProvider(std::move(meter_provider))
.BuildAndRegisterGlobal();
if (!status.ok()) {
std::cerr << "Failed to register gRPC OpenTelemetry Plugin: "
<< status.ToString() << std::endl;
return static_cast<int>(status.code());
}
RunServer(absl::GetFlag(FLAGS_port));
return 0;
}
Die erforderlichen Headerdateien und Build-Abhängigkeiten wurden bereits hinzugefügt.
#include "opentelemetry/exporters/prometheus/exporter_factory.h"
#include "opentelemetry/exporters/prometheus/exporter_options.h"
#include "opentelemetry/sdk/metrics/meter_provider.h"
#include <grpcpp/ext/otel_plugin.h>
Build-Abhängigkeiten wurden auch bereits in der Datei BUILD hinzugefügt:
cc_binary(
name = "greeter_callback_client",
srcs = ["greeter_callback_client.cc"],
defines = ["BAZEL_BUILD"],
deps = [
"//util:util",
"@com_github_grpc_grpc//:grpc++",
"@com_github_grpc_grpc//:grpcpp_otel_plugin",
"@com_google_absl//absl/flags:flag",
"@com_google_absl//absl/flags:parse",
"@io_opentelemetry_cpp//exporters/prometheus:prometheus_exporter",
"@io_opentelemetry_cpp//sdk/src/metrics",
],
)
4. Beispiel ausführen und Messwerte ansehen
Führen Sie den Server mit folgendem Befehl aus:
bazel run start_here:greeter_callback_server
Bei einer erfolgreichen Einrichtung wird die folgende Ausgabe für den Server angezeigt:
Server listening on 0.0.0.0:50051
Während der Server ausgeführt wird, führen Sie den Client in einem anderen Terminal aus:
bazel run start_here:greeter_callback_client
Eine erfolgreiche Ausführung sieht so aus:
Greeter received: Hello world
Greeter received: Hello world
Greeter received: Hello world
Greeter received: Hello world
Greeter received: Hello world
Greeter received: Hello world
Greeter received: Hello world
Greeter received: Hello world
Greeter received: Hello world
Greeter received: Hello world
Greeter received: Hello world
Wir haben das gRPC-OpenTelemetry-Plug-in so eingerichtet, dass Messwerte mit Prometheus exportiert werden. Diese Messwerte sind für den Server unter „localhost:9464“ und für den Client unter „localhost:9465“ verfügbar.
So sehen Sie Clientmesswerte:
curl localhost:9465/metrics
Das Ergebnis hat die Form:
# HELP exposer_transferred_bytes_total Transferred bytes to metrics services
# TYPE exposer_transferred_bytes_total counter
exposer_transferred_bytes_total 0
# HELP exposer_scrapes_total Number of times metrics were scraped
# TYPE exposer_scrapes_total counter
exposer_scrapes_total 0
# HELP exposer_request_latencies Latencies of serving scrape requests, in microseconds
# TYPE exposer_request_latencies summary
exposer_request_latencies_count 0
exposer_request_latencies_sum 0
exposer_request_latencies{quantile="0.5"} Nan
exposer_request_latencies{quantile="0.9"} Nan
exposer_request_latencies{quantile="0.99"} Nan
# HELP target Target metadata
# TYPE target gauge
target_info{otel_scope_name="grpc-c++",otel_scope_version="1.67.0-dev",service_name="unknown_service",telemetry_sdk_version="1.13.0",telemetry_sdk_name="opentelemetry",telemetry_sdk_language="cpp"} 1 1721958543107
# 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_count{grpc_method="helloworld.Greeter/SayHello",grpc_status="OK",grpc_target="dns:///localhost:50051",otel_scope_name="grpc-c++",otel_scope_version="1.67.0-dev"} 96 1721958543107
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-c++",otel_scope_version="1.67.0-dev"} 1248 1721958543107
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-c++",otel_scope_version="1.67.0-dev",le="0"} 0 1721958543107
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-c++",otel_scope_version="1.67.0-dev",le="5"} 0 1721958543107
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-c++",otel_scope_version="1.67.0-dev",le="10"} 0 1721958543107
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-c++",otel_scope_version="1.67.0-dev",le="25"} 96 1721958543107
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-c++",otel_scope_version="1.67.0-dev",le="50"} 96 1721958543107
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-c++",otel_scope_version="1.67.0-dev",le="75"} 96 1721958543107
Entsprechend für die serverseitigen Messwerte:
curl localhost:9464/metrics
5. Messwerte in Prometheus ansehen
Hier richten wir eine Prometheus-Instanz ein, die unseren gRPC-Beispielclient und ‑server abruft, die Messwerte mit Prometheus exportieren.
Laden Sie die neueste Version von Prometheus für Ihre Plattform herunter, extrahieren Sie sie und führen Sie sie aus:
tar xvfz prometheus-*.tar.gz
cd prometheus-*
Erstellen Sie eine Prometheus-Konfigurationsdatei mit folgendem Inhalt:
cat > grpc_otel_cpp_prometheus.yml <<EOF
scrape_configs:
- job_name: "prometheus"
scrape_interval: 5s
static_configs:
- targets: ["localhost:9090"]
- job_name: "grpc-otel-cpp"
scrape_interval: 5s
static_configs:
- targets: ["localhost:9464", "localhost:9465"]
EOF
Starten Sie Prometheus mit der neuen Konfiguration:
./prometheus --config.file=grpc_otel_cpp_prometheus.yml
Dadurch werden die Messwerte aus den Codelab-Prozessen für Client und Server alle 5 Sekunden abgerufen.
Rufen Sie http://localhost:9090/graph auf, um die Messwerte anzusehen. Beispiel für eine Abfrage:
histogram_quantile(0.5, rate(grpc_client_attempt_duration_seconds_bucket[1m]))
Dadurch wird ein Diagramm mit der medianen Latenz des Versuchs angezeigt, wobei 1 Minute als Zeitfenster für die Quantilberechnung verwendet wird.
Abfragerate:
increase(grpc_client_attempt_duration_seconds_bucket[1m])
6. (Optional) Übung für Nutzer
In den Prometheus-Dashboards sehen Sie, dass die QPS niedrig ist. Versuchen Sie, verdächtigen Code im Beispiel zu finden, der die QPS begrenzt.
Für Enthusiasten: Der Clientcode ist so begrenzt, dass zu einem bestimmten Zeitpunkt nur ein ausstehender RPC vorhanden ist. Dies kann so geändert werden, dass der Client mehr RPCs sendet, ohne auf den Abschluss der vorherigen zu warten. Die Lösung dafür wird nicht bereitgestellt.