1. Introdução
Neste codelab, você vai usar o gRPC para criar um cliente e um servidor que formam a base de um aplicativo de mapeamento de rotas escrito em Python.
Ao final do tutorial, você terá um aplicativo gRPC HelloWorld simples instrumentado com o plug-in gRPC OpenTelemetry e poderá conferir as métricas de observabilidade exportadas no Prometheus.
O que você vai aprender
- Como configurar o plug-in OpenTelemetry para um aplicativo Python gRPC atual
- Executar uma instância local do Prometheus
- Exportar métricas para o Prometheus
- Conferir métricas no painel do Prometheus
2. Antes de começar
O que é necessário
- git
- curl
- build-essential
- Python 3.9 ou mais recente. Para instruções de instalação do Python específicas da plataforma, consulte Configuração e uso do Python. Se preferir, instale um Python não sistêmico usando ferramentas como uv ou pyenv.
- A versão 9.0.1 ou mais recente do pip para instalar pacotes Python.
- venv para criar ambientes virtuais em Python.
Instale os pré-requisitos:
sudo apt-get update -y
sudo apt-get upgrade -y
sudo apt-get install -y git curl build-essential clang
sudo apt install python3
sudo apt install python3-pip python3-venv
Acessar o código
Para facilitar o aprendizado, este codelab oferece um scaffold de código-fonte pré-criado para ajudar você a começar. As etapas a seguir explicam como instrumentar o plug-in gRPC do OpenTelemetry em um aplicativo.
grpc-codelabs
O código-fonte do scaffold para este codelab está disponível neste diretório do GitHub. Se preferir não implementar o código por conta própria, o código-fonte concluído está disponível no diretório completed.
Primeiro, clone o repositório do codelab do gRPC e acesse a pasta grpc-python-opentelemetry:
git clone https://github.com/grpc-ecosystem/grpc-codelabs.git
cd grpc-codelabs/codelabs/grpc-python-opentelemetry/
Como alternativa, baixe o arquivo .zip que contém apenas o diretório do codelab e descompacte-o manualmente.
Primeiro, crie um novo ambiente virtual Python (venv) para isolar as dependências do projeto dos pacotes do sistema:
python3 -m venv --upgrade-deps .venv
Para ativar o ambiente virtual no shell bash/zsh:
source .venv/bin/activate
Para Windows e shells não padrão, consulte a tabela em https://docs.python.org/3/library/venv.html#how-venvs-work.
Em seguida, instale as dependências no ambiente usando:
python -m pip install -r requirements.txt
3. Registrar o plug-in do OpenTelemetry
Precisamos de um aplicativo gRPC para adicionar o plug-in gRPC OpenTelemetry. Neste codelab, vamos usar um cliente e um servidor gRPC HelloWorld simples que vamos instrumentar com o plug-in gRPC OpenTelemetry.
A primeira etapa é registrar o plug-in do OpenTelemetry configurado com um exportador do Prometheus no cliente. Abra start_here/observability_greeter_client.py com seu editor favorito. Primeiro, adicione dependências e macros relacionadas para que fiquem assim:
import logging
import time
import grpc
import grpc_observability
import helloworld_pb2
import helloworld_pb2_grpc
from opentelemetry.exporter.prometheus import PrometheusMetricReader
from opentelemetry.sdk.metrics import MeterProvider
from prometheus_client import start_http_server
_SERVER_PORT = "50051"
_PROMETHEUS_PORT = 9465
Em seguida, transforme run() para que fique assim:
def run():
# Start Prometheus client
start_http_server(port=_PROMETHEUS_PORT, addr="0.0.0.0")
meter_provider = MeterProvider(metric_readers=[PrometheusMetricReader()])
otel_plugin = grpc_observability.OpenTelemetryPlugin(
meter_provider=meter_provider
)
otel_plugin.register_global()
with grpc.insecure_channel(target=f"localhost:{_SERVER_PORT}") as channel:
stub = helloworld_pb2_grpc.GreeterStub(channel)
# Continuously send RPCs every second.
while True:
try:
response = stub.SayHello(helloworld_pb2.HelloRequest(name="You"))
print(f"Greeter client received: {response.message}")
time.sleep(1)
except grpc.RpcError as rpc_error:
print("Call failed with code: ", rpc_error.code())
# Deregister is not called in this example, but this is required to clean up.
otel_plugin.deregister_global()
A próxima etapa é adicionar o plug-in OpenTelemetry ao servidor. Abra start_here/observability_greeter_server.py e adicione dependências e macros relacionadas para ficar assim:
from concurrent import futures
import logging
import time
import grpc
import grpc_observability
import helloworld_pb2
import helloworld_pb2_grpc
from opentelemetry.sdk.metrics import MeterProvider
from opentelemetry.exporter.prometheus import PrometheusMetricReader
from prometheus_client import start_http_server
_SERVER_PORT = "50051"
_PROMETHEUS_PORT = 9464
Em seguida, transforme run() para que fique assim:
def serve():
# Start Prometheus client
start_http_server(port=_PROMETHEUS_PORT, addr="0.0.0.0")
meter_provider = MeterProvider(metric_readers=[PrometheusMetricReader()])
otel_plugin = grpc_observability.OpenTelemetryPlugin(
meter_provider=meter_provider
)
otel_plugin.register_global()
server = grpc.server(
thread_pool=futures.ThreadPoolExecutor(max_workers=10),
)
helloworld_pb2_grpc.add_GreeterServicer_to_server(Greeter(), server)
server.add_insecure_port("[::]:" + _SERVER_PORT)
server.start()
print("Server started, listening on " + _SERVER_PORT)
server.wait_for_termination()
# Deregister is not called in this example, but this is required to clean up.
otel_plugin.deregister_global()
4. Executar o exemplo e conferir as métricas
Para executar o servidor, execute:
cd start_here
python -m observability_greeter_server
Com uma configuração bem-sucedida, você verá a seguinte saída para o servidor:
Server started, listening on 50051
Enquanto o servidor estiver em execução, execute o cliente em outro terminal:
# Run the below commands to cd to the working directory and activate virtual environment in the new terminal
cd grpc-codelabs/codelabs/grpc-python-opentelemetry/
source .venv/bin/activate
cd start_here
python -m observability_greeter_client
Uma execução bem-sucedida será semelhante a esta:
Greeter client received: Hello You
Greeter client received: Hello You
Greeter client received: Hello You
Como configuramos o plug-in gRPC OpenTelemetry para exportar métricas usando o Prometheus. Essas métricas estarão disponíveis em localhost:9464 para o servidor e localhost:9465 para o cliente.
Para ver as métricas do cliente:
curl localhost:9465/metrics
O resultado seria assim:
# HELP python_gc_objects_collected_total Objects collected during gc
# TYPE python_gc_objects_collected_total counter
python_gc_objects_collected_total{generation="0"} 241.0
python_gc_objects_collected_total{generation="1"} 163.0
python_gc_objects_collected_total{generation="2"} 0.0
# HELP python_gc_objects_uncollectable_total Uncollectable objects found during GC
# TYPE python_gc_objects_uncollectable_total counter
python_gc_objects_uncollectable_total{generation="0"} 0.0
python_gc_objects_uncollectable_total{generation="1"} 0.0
python_gc_objects_uncollectable_total{generation="2"} 0.0
# HELP python_gc_collections_total Number of times this generation was collected
# TYPE python_gc_collections_total counter
python_gc_collections_total{generation="0"} 78.0
python_gc_collections_total{generation="1"} 7.0
python_gc_collections_total{generation="2"} 0.0
# HELP python_info Python platform information
# TYPE python_info gauge
python_info{implementation="CPython",major="3",minor="10",patchlevel="9",version="3.10.9"} 1.0
# HELP process_virtual_memory_bytes Virtual memory size in bytes.
# TYPE process_virtual_memory_bytes gauge
process_virtual_memory_bytes 1.868988416e+09
# HELP process_resident_memory_bytes Resident memory size in bytes.
# TYPE process_resident_memory_bytes gauge
process_resident_memory_bytes 4.1680896e+07
# TYPE process_resident_memory_bytes gauge 21:20:16 [154/966]
process_resident_memory_bytes 4.1680896e+07
# HELP process_start_time_seconds Start time of the process since unix epoch in seconds.
# TYPE process_start_time_seconds gauge
process_start_time_seconds 1.72375679833e+09
# HELP process_cpu_seconds_total Total user and system CPU time spent in seconds.
# TYPE process_cpu_seconds_total counter
process_cpu_seconds_total 0.38
# HELP process_open_fds Number of open file descriptors.
# TYPE process_open_fds gauge
process_open_fds 9.0
# HELP process_max_fds Maximum number of open file descriptors.
# TYPE process_max_fds gauge
process_max_fds 4096.0
# HELP target_info Target metadata
# TYPE target_info gauge
target_info{service_name="unknown_service",telemetry_sdk_language="python",telemetry_sdk_name="opentelemetry",telemetry_sdk_version="1.26.0"} 1.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="other",grpc_target="localhost:50051"} 18.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="other",grpc_status="OK",grpc_target="localhost:50051",le="0.0"} 0.0
grpc_client_attempt_sent_total_compressed_message_size_bytes_bucket{grpc_method="other",grpc_status="OK",grpc_target="localhost:50051",le="5.0"} 18.0
grpc_client_attempt_sent_total_compressed_message_size_bytes_bucket{grpc_method="other",grpc_status="OK",grpc_target="localhost:50051",le="10.0"} 18.0
grpc_client_attempt_sent_total_compressed_message_size_bytes_bucket{grpc_method="other",grpc_status="OK",grpc_target="localhost:50051",le="25.0"} 18.0
grpc_client_attempt_sent_total_compressed_message_size_bytes_bucket{grpc_method="other",grpc_status="OK",grpc_target="localhost:50051",le="50.0"} 18.0
grpc_client_attempt_sent_total_compressed_message_size_bytes_bucket{grpc_method="other",grpc_status="OK",grpc_target="localhost:50051",le="75.0"} 18.0
grpc_client_attempt_sent_total_compressed_message_size_bytes_bucket{grpc_method="other",grpc_status="OK",grpc_target="localhost:50051",le="100.0"} 18.0
grpc_client_attempt_sent_total_compressed_message_size_bytes_bucket{grpc_method="other",grpc_status="OK",grpc_target="localhost:50051",le="250.0"} 18.0
Da mesma forma, para as métricas do lado do servidor:
curl localhost:9464/metrics
5. Como visualizar métricas no Prometheus
Aqui, vamos configurar uma instância do Prometheus que vai extrair nosso exemplo de cliente e servidor gRPC que estão exportando métricas usando o Prometheus.
Faça o download da versão mais recente do Prometheus para sua plataforma usando o link fornecido ou o seguinte comando:
curl -sLO https://github.com/prometheus/prometheus/releases/download/v3.7.3/prometheus-3.7.3.linux-amd64.tar.gz
Em seguida, extraia e execute usando o seguinte comando:
tar xvfz prometheus-*.tar.gz
cd prometheus-*
Crie um arquivo de configuração do Prometheus com o seguinte:
cat > grpc_otel_python_prometheus.yml <<EOF
scrape_configs:
- job_name: "prometheus"
scrape_interval: 5s
static_configs:
- targets: ["localhost:9090"]
- job_name: "grpc-otel-python"
scrape_interval: 5s
static_configs:
- targets: ["localhost:9464", "localhost:9465"]
EOF
Inicie o Prometheus com a nova configuração:
./prometheus --config.file=grpc_otel_python_prometheus.yml
Isso vai configurar as métricas dos processos do codelab do cliente e do servidor para serem coletadas a cada 5 segundos.
Acesse http://localhost:9090/graph para conferir as métricas. Por exemplo, a consulta:
histogram_quantile(0.5, rate(grpc_client_attempt_duration_seconds_bucket[1m]))
vai mostrar um gráfico com a latência mediana da tentativa usando 1 minuto como janela de tempo para o cálculo do quantil.
Taxa de consultas:
increase(grpc_client_attempt_duration_seconds_bucket[1m])
6. (Opcional) Exercício para o usuário
Nos painéis do Prometheus, você vai notar que o QPS está baixo. Veja se você consegue identificar um código suspeito no exemplo que está limitando o QPS.
Para os entusiastas, o código do cliente se limita a ter apenas uma RPC pendente em um determinado momento. Isso pode ser modificado para que o cliente envie mais RPCs sem esperar que os anteriores sejam concluídos. (A solução para isso não foi fornecida.)