1. Einführung
In diesem Codelab verwenden Sie gRPC, um einen Client und einen Server zu erstellen, die die Grundlage einer in C++ geschriebenen Anwendung zur Routenplanung bilden.
Am Ende der Anleitung 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-essentialclangbazel, um Beispiele in diesem Codelab zu erstellen
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 aktuelle Version finden Sie hier.
Eine einfache Möglichkeit, das Tool einzurichten, besteht darin, es als Bazel-Binärdatei in Ihrem PATH 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 den Einstieg zu erleichtern, wird in diesem Codelab ein vorgefertigtes Quellcode-Gerüst bereitgestellt. In den folgenden Schritten wird beschrieben, wie Sie das gRPC OpenTelemetry-Plug-in in einer Anwendung instrumentieren.
grpc-codelabs
Der Quellcode für das Gerü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 in den Ordner „grpc-cpp-opentelemetry“:
git clone 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 entpacken.
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.
Als Erstes müssen Sie das OpenTelemetry-Plug-in, das mit einem Prometheus-Exporter konfiguriert ist, im Client registrieren. Öffnen Sie codelabs/grpc-cpp-opentelemetry/start_here/greeter_callback_client.cc mit Ihrem bevorzugten Editor und transformieren Sie main() so:
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;
}
Im nächsten Schritt fügen Sie dem Server das OpenTelemetry-Plug-in hinzu. Öffnen Sie codelabs/grpc-cpp-opentelemetry/start_here/greeter_callback_server.cc und transformieren 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 sind auch bereits in der Datei BUILD enthalten:
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
So führen Sie den Server aus:
bazel run start_here:greeter_callback_server
Bei einer erfolgreichen Einrichtung wird für den Server die folgende Ausgabe angezeigt:
Server listening on 0.0.0.0:50051
Führen Sie den Client in einem anderen Terminal aus, während der Server ausgeführt wird:
bazel run start_here:greeter_callback_client
Ein erfolgreicher Lauf 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 auf localhost:9464 für den Server und auf localhost:9465 für den Client verfügbar.
So rufen Sie Clientmesswerte auf:
curl localhost:9465/metrics
Das Ergebnis würde so aussehen:
# 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
Ähnlich verhält es sich bei den serverseitigen Messwerten:
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 aktuelle Version von Prometheus für Ihre Plattform herunter, entpacken Sie sie und führen Sie sie aus:
tar xvfz prometheus-*.tar.gz
cd prometheus-*
Erstellen Sie eine Prometheus-Konfigurationsdatei mit den folgenden Inhalten:
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 Client- und Server-Codelab-Prozessen alle 5 Sekunden erfasst.
Rufen Sie http://localhost:9090/graph auf, um die Messwerte anzusehen. Beispiel:
histogram_quantile(0.5, rate(grpc_client_attempt_duration_seconds_bucket[1m]))
wird ein Diagramm mit der medianen Latenz für Versuche angezeigt, wobei für die Quantilberechnung ein Zeitfenster von einer Minute verwendet wird.
Anzahl der Anfragen –
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. Sehen Sie nach, ob Sie im Beispielcode verdächtigen Code finden, der die QPS begrenzt.
Für den Enthusiasten beschränkt sich der Clientcode darauf, zu einem bestimmten Zeitpunkt nur einen ausstehenden RPC zu haben. Dies kann so geändert werden, dass der Client mehr RPCs sendet, ohne auf den Abschluss der vorherigen zu warten. (Die Lösung hierfür wurde nicht bereitgestellt.)