En las canalizaciones de transmisión distribuidas, puede ser difícil identificar qué etapa específica, llamada a un servicio externo o combinación de trabajadores causa picos de latencia solo con métricas agregadas. Si usas el registro de seguimiento distribuido de OpenTelemetry en Dataflow, puedes hacer un seguimiento de los elementos individuales de extremo a extremo en las transformaciones de canalizaciones, los límites de red y los servicios integrados con un solo ID de seguimiento. Esta visibilidad te ayuda a identificar cuellos de botella en el rendimiento, optimizar los costos de ejecución de la canalización y solucionar problemas de cargas de trabajo de transmisión complejas.
Usa la siguiente información para habilitar, configurar y usar el seguimiento distribuido de OpenTelemetry en tus canalizaciones de Apache Beam.
Casos de uso
El registro de seguimiento distribuido en Dataflow es particularmente útil en las siguientes situaciones:
- Cargas de trabajo de transmisión: Realiza un seguimiento del tiempo de procesamiento por elemento y, luego, identifica las etapas que introducen retrasos o picos de latencia.
- Seguimiento de llamadas a servicios externos en el código del usuario: Mide las duraciones de ejecución cuando tu canalización llama a bases de datos externas, microservicios o APIs de IA generativa dentro del código del usuario (por ejemplo, en un
DoFn). Por ejemplo, puedes medir el tiempo de las llamadas a bases de datos externas (como Spanner o Bigtable), microservicios (con HTTP o gRPC) o APIs de IA generativa (como Gemini). Para obtener más información, consulta Cómo escribir registros personalizados en DoFns y Cómo realizar la integración con bibliotecas cliente. - Optimización del costo y el rendimiento: Expone las duraciones de operaciones específicas en instancias de
PTransformbajo carga del mundo real para identificar la serialización ineficiente, las consultas lentas o la contención de subprocesos de trabajadores. - Canalizaciones complejas de agentes y flujos de trabajo: Obtén visibilidad de las canalizaciones con varias ramas, bucles de agentes iterativos y uniones para determinar qué transformación o rama tarda más.
Limitaciones
El seguimiento distribuido en Dataflow tiene las siguientes limitaciones:
- Esta función se diseñó y verificó solo para las canalizaciones de transmisión.
- Para usar esta función, debes usar el SDK de Beam para Java (versión 2.76.0 o posterior).
- La propagación del contexto entre etapas requiere el Streaming Java Runner (anteriormente llamado Runner v1). El ejecutor portátil (anteriormente llamado Runner v2) restablece el contexto de seguimiento en los límites de la aleatorización.
- El seguimiento de OpenTelemetry integrado en los conectores de E/S de Beam solo se admite para los siguientes conectores: Pub/Sub, Apache Kafka y flujos de cambios de Spanner. En el caso de Apache Kafka, el seguimiento solo se admite cuando usas el conector
KafkaIOdirectamente. No se admite cuando usas E/S administrada para Kafka. Otros conectores de E/S (comoBigtableIO) no tienen un registro de seguimiento de conectores integrado. Para hacer un seguimiento de las operaciones con estos servicios, instrumenta tus llamadas dentro del código del usuario (por ejemplo, en unDoFn). - Las operaciones que combinan varios elementos en uno no propagan un solo contexto de seguimiento. Esto incluye operaciones como
GroupByKey,CoGroupByKeyyCombine. - El contexto no se propaga entre el establecimiento de un temporizador (
Timer.set()) y la ejecución del método de devolución de llamada@OnTimer.
Requisitos previos
Para usar el registro de seguimiento distribuido en Dataflow, asegúrate de que tu entorno cumpla con los siguientes requisitos:
- Tu trabajo debe cumplir con los siguientes requisitos:
- Es una canalización de transmisión
- Usa Streaming Java Runner (antes llamado Runner v1).
- Usa la versión 2.76.0 o posterior del SDK de Apache Beam para Java.
Si exportas seguimientos a Cloud Trace, habilita la API de Telemetry (
telemetry.googleapis.com) en tu proyecto de Google Cloud .Roles necesarios para habilitar las APIs
Para habilitar APIs, necesitas el permiso
serviceusage.services.enable. Si creaste el proyecto, es probable que ya tengas este permiso a través del rol de propietario (roles/owner). De lo contrario, puedes obtener este permiso a través del rol de administrador de Service Usage (roles/serviceusage.serviceUsageAdmin). Obtén más información para otorgar roles.La cuenta de servicio del trabajador debe tener el rol de Agente de Cloud Trace (
roles/cloudtrace.agent), que incluye el permisocloudtrace.traces.patch.
Conceptos básicos
El seguimiento distribuido se basa en los siguientes conceptos de OpenTelemetry:
- Seguimiento
- Representación de una transacción o flujo de trabajo completo a medida que fluye a través de un sistema distribuido. Un seguimiento consta de uno o más intervalos.
- Intervalo
- Es el componente básico de un registro, que representa una sola unidad de trabajo. Por ejemplo, una ejecución de transformación, una llamada de método o una solicitud de RPC.
- Contexto
- Es el estado que se propaga entre subprocesos y límites de la API. Esto incluye el ID de seguimiento y el ID de intervalo.
- Propagador
- Es el mecanismo que se usa para insertar y extraer la representación del contexto a través de los límites de la red. Por ejemplo, el contexto de seguimiento de W3C.
- Exportador
- Un componente que envía los datos de intervalo recopilados a un backend de seguimiento, como Cloud Trace o un recopilador de OpenTelemetry autohospedado.
- Sampler
- Es un mecanismo que controla el volumen de registros determinando qué registros se graban y exportan. Por ejemplo, una tasa de muestreo del 1%.
Habilita el seguimiento de OpenTelemetry
Para habilitar el seguimiento de OpenTelemetry con la configuración predeterminada, configura las opciones de canalización y los experimentos necesarios cuando envíes tu trabajo. El parámetro de configuración predeterminado exporta a Cloud Trace con un muestreo del 1%.
Para modificar los valores predeterminados, consulta Cómo establecer y modificar propiedades de seguimiento.
Configura las opciones y los experimentos de la canalización cuando ejecutes tu trabajo.
Trabajo sin plantilla de Flex
Pasa las siguientes marcas de experimentos cuando envíes un trabajo:
--experiments=enable_otel_defaults,element_metadata_supported,disable_portable_worker
Trabajo de plantilla de Flex
Pasa los experimentos con la marca
--additional-experimentsen el comandogcloud:gcloud dataflow flex-template run JOB_NAME \ --template-file-gcs-location=gs://BUCKET_NAME/templates/TEMPLATE_NAME.json \ --additional-experiments="enable_otel_defaults,element_metadata_supported,disable_portable_worker" \ --region=REGIONReemplaza lo siguiente:
- JOB_NAME: Es el nombre de tu trabajo de Dataflow.
- BUCKET_NAME: Es el bucket de Cloud Storage que contiene tu plantilla.
- TEMPLATE_NAME: Es el nombre de tu archivo de plantilla de Flex.
- REGION: Es la Google Cloud región en la que deseas ejecutar el trabajo.
Estos experimentos configuran los siguientes comportamientos:
enable_otel_defaults: Configura los valores predeterminados estándar de OpenTelemetry, incluido el exportador de Cloud Trace y el muestreo del 1%.element_metadata_supported: Permite la serialización y la propagación de metadatos (como el contexto de seguimiento) en las etapas de la canalización.disable_portable_worker: Fuerza el uso del Runner de Java de transmisión de Dataflow (anteriormente llamado Runner v1).
Si usas las versiones 2.76.0 o 2.77.0 del SDK de Beam para Java, agrega las dependencias de OpenTelemetry requeridas a tu configuración de compilación.
Debido a un problema en las versiones 2.76.0 y 2.77.0, debes agregar las siguientes dependencias a tu archivo
pom.xmlpara que se exporten los registros. Para obtener más información, consulta Administra dependencias de canalizaciones.<dependency> <groupId>io.opentelemetry</groupId> <artifactId>opentelemetry-sdk-extension-autoconfigure</artifactId> <scope>compile</scope> </dependency> <dependency> <groupId>io.opentelemetry</groupId> <artifactId>opentelemetry-exporter-otlp</artifactId> <version>1.62.0</version> <scope>compile</scope> </dependency> <dependency> <groupId>org.apache.beam</groupId> <artifactId>beam-sdks-java-extensions-opentelemetry-gcp-auth-extension</artifactId> <scope>compile</scope> </dependency>Habilita de forma explícita el seguimiento de OpenTelemetry en los conectores de E/S compatibles en el código de tu canalización:
Pub/Sub
Para habilitar el registro de seguimiento cuando lees o escribes en Pub/Sub, haz lo siguiente:
// Reading from Pub/Sub pipeline.apply("ReadFromPubSub", PubsubIO.readMessages() .withEnableOpenTelemetryTracing() .fromSubscription("projects/PROJECT_ID/subscriptions/SUBSCRIPTION_ID")); // Writing to Pub/Sub pipeline.apply("WriteToPubSub", PubsubIO.writeStrings() .withEnableOpenTelemetryTracing() .to("projects/PROJECT_ID/topics/TOPIC_ID"));
Reemplaza lo siguiente:
- PROJECT_ID: Es el ID de tu proyecto de Google Cloud .
- SUBSCRIPTION_ID: Es el nombre de tu suscripción a Pub/Sub.
- TOPIC_ID: Es el nombre de tu tema de Pub/Sub.
Detalles de la propagación del contexto:
- Publicador upstream: Cuando publiques mensajes desde una aplicación externa, inserta el contexto de seguimiento de W3C en los atributos del mensaje de Pub/Sub. Para obtener más información, consulta Registro de OpenTelemetry de Pub/Sub.
- Atributos: Beam espera y completa los siguientes atributos:
googclient_traceparent: Lleva el encabezadotraceparentde W3C.googclient_tracestate: Lleva el encabezadotracestatede W3C.
- Para obtener información sobre el formato de los encabezados, consulta la especificación de contexto de seguimiento de W3C.
Apache Kafka
Para habilitar el registro de seguimiento cuando se lee o escribe en Apache Kafka, haz lo siguiente:
// Reading from Kafka pipeline.apply("ReadFromKafka", KafkaIO.<String, String>read() .withEnableOpenTelemetryTracing() // ... additional configuration ); // Writing to Kafka pipeline.apply("WriteToKafka", KafkaIO.<String, String>write() .withEnableOpenTelemetryTracing() // ... additional configuration );
Detalles de la propagación del contexto:
KafkaIOusa encabezados de registros estándar de Kafka para propagar el contexto.- Espera y, luego, inyecta encabezados que cumplen con la especificación de contexto de seguimiento de W3C:
traceparent: Identifica el contexto de seguimiento entrante.tracestate: Proporciona metadatos adicionales de filtrado y enrutamiento específicos del proveedor.
Spanner
Para habilitar el registro de seguimiento cuando se lee desde flujos de cambios de Spanner, haz lo siguiente:
pipeline.apply("ReadChangeStream", SpannerIO.readChangeStream() .withSpannerConfig(spannerConfig) .withEnableOpenTelemetryTracing(true) .withChangeStreamName("CHANGE_STREAM_NAME"));
Reemplaza lo siguiente:
- CHANGE_STREAM_NAME: Es el nombre del flujo de cambios de Spanner.
Detalles de la creación del intervalo:
- Habilitar el registro de seguimiento inicia un nuevo registro de seguimiento y un nuevo intervalo para cada registro de mutación de la base de datos que lee el lector de captura de datos modificados (CDC).
- Los ciclos de sondeo del lector de Spanner que no devuelven registros nuevos también pueden producir intervalos de seguimiento que se pueden filtrar en la IU de Cloud Trace.
Cómo establecer y modificar propiedades de seguimiento
Cuando especificas enable_otel_defaults, Dataflow aplica las siguientes propiedades predeterminadas:
| Propiedad | Valor predeterminado | Descripción |
|---|---|---|
otel.traces.exporter |
otlp |
Exporta seguimientos con el protocolo OpenTelemetry (OTLP). |
otel.exporter.otlp.endpoint |
https://telemetry.googleapis.com |
Se orienta al receptor de OTLP de Cloud Trace. |
google.cloud.project |
Tu ID del proyecto | Es el Google Cloud proyecto en el que se almacenan los registros. |
otel.traces.sampler.arg |
0.01 (1%) |
Registra 1 de cada 100 registros. |
otel.service.name |
options.getAppName() |
Es el nombre del servicio asociado con los intervalos, que se deriva de la opción de canalización appName. |
Para personalizar la configuración de OpenTelemetry, pasa una lista de propiedades separadas por punto y coma a la opción de canalización --openTelemetryProperties.
En el siguiente ejemplo, se configuran todas las propiedades predeterminadas de forma explícita:
--openTelemetryProperties="otel.traces.exporter=otlp;otel.exporter.otlp.endpoint=https://telemetry.googleapis.com;google.cloud.project=PROJECT_ID;otel.traces.sampler.arg=0.01;otel.service.name=CUSTOM_SERVICE_NAME;otel.java.global-autoconfigure.enabled=true"
Cómo establecer un nombre de servicio personalizado
De forma predeterminada, el nombre del servicio de seguimiento se deriva de la opción appName de la canalización (--appName=YourPipelineName). Puedes anular este valor configurando la propiedad otel.service.name:
--openTelemetryProperties="otel.service.name=CUSTOM_SERVICE_NAME"
Cómo cambiar la tasa y las propiedades de muestreo
Establecer una tasa de muestreo más alta te brinda información de registro más sólida.
Sin embargo, las frecuencias de muestreo altas (como 1.0 o always_on) aumentan significativamente el volumen de datos de seguimiento que se envían a Cloud Trace, lo que puede incrementar tus costos de Google Cloud . Usa tasas de muestreo altas solo para la depuración a corto plazo y redúcelas para las cargas de trabajo de producción.
En el siguiente ejemplo, se configura la frecuencia de muestreo de forma explícita. En este caso, debes proporcionar una lista completa de argumentos:
--openTelemetryProperties="otel.traces.exporter=otlp;otel.exporter.otlp.endpoint=https://telemetry.googleapis.com;google.cloud.project=PROJECT_ID;otel.traces.sampler.arg=0.02;otel.service.name=CUSTOM_SERVICE_NAME;otel.java.global-autoconfigure.enabled=true"
Exporta a back-ends de terceros
Para enviar seguimientos a un backend de seguimiento administrado externo o a un recopilador de OpenTelemetry autohospedado en lugar de Cloud Trace, haz lo siguiente:
- Omite el siguiente experimento:
--experiments=enable_otel_defaults. Configura las propiedades del exportador de forma manual con
--openTelemetryProperties:--openTelemetryProperties="otel.traces.exporter=otlp;otel.exporter.otlp.endpoint=http://COLLECTOR_HOST:4317;otel.traces.sampler=parentbased_always_on"
Extensión de autenticación deGoogle Cloud
El entorno de ejecución de Beam incluye una extensión de autenticación Google Cloud que autentica automáticamente las solicitudes del Protocolo de OpenTelemetry (OTLP) que se envían a las APIs de Google, como telemetry.googleapis.com.
- Cuando se usan los valores predeterminados: Google Cloud La autenticación se habilita automáticamente.
- Cuando se exporta a extremos que no son de Google: Si se omite
enable_otel_defaults, Beam inhabilita la extensión de autenticación Google Cloud estableciendo la propiedad del sistemagoogle.otel.auth.target.signals=none. - Configuración manual: Puedes establecer la propiedad del sistema
google.otel.auth.target.signalsennone(inhabilitada) otrace(habilitada solo para los registros).
Escribe seguimientos personalizados en DoFns
Puedes crear intervalos personalizados dentro del código del usuario, por ejemplo, dentro de un DoFn, para medir operaciones específicas. Esto incluye llamadas a APIs externas o lógica que requiere mucha capacidad de procesamiento.
Ejemplo de implementación de DoFn
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.api.trace.StatusCode;
import io.opentelemetry.api.trace.Tracer;
import io.opentelemetry.context.Scope;
import org.apache.beam.sdk.options.PipelineOptions;
import org.apache.beam.sdk.options.SdkHarnessOptions;
import org.apache.beam.sdk.transforms.DoFn;
public class InvestigateTransactionDoFn extends DoFn<Transaction, RiskAssessment> {
private transient Tracer tracer;
@Setup
public void setup(PipelineOptions options) {
// Obtain the Tracer instance from SdkHarnessOptions
this.tracer = options
.as(SdkHarnessOptions.class)
.getOpenTelemetry()
.getTracer("org.apache.beam.examples.adk.aml");
}
@ProcessElement
public void processElement(@Element Transaction tx, OutputReceiver<RiskAssessment> out) {
// Create and start a custom span as a child of the active context
Span span = tracer.spanBuilder("InvestigateTransactionDoFn:Analyze")
.setAttribute("transaction.id", tx.getId())
.setAttribute("transaction.amount", tx.getAmount())
.startSpan();
// Make the span current in the execution thread
try (Scope scope = span.makeCurrent()) {
// Perform your logic (such as calling an external service)
RiskAssessment assessment = analyzeTransactionWithLLM(tx);
out.output(assessment);
} catch (Exception e) {
// Record exception details and set error status on the span
span.recordException(e);
span.setStatus(StatusCode.ERROR, e.getMessage());
throw e;
} finally {
// Always end the span
span.end();
}
}
private RiskAssessment analyzeTransactionWithLLM(Transaction tx) {
// Application analysis logic
return new RiskAssessment();
}
}
Integración con bibliotecas cliente
Cuando un DoFn invoca bibliotecas externas que también admiten OpenTelemetry, como las bibliotecas cliente de Google Cloud , configura el cliente para que use la instancia de OpenTelemetry de la canalización, de modo que los intervalos secundarios se vinculen directamente al registro de la canalización.
Ejemplo de cliente de Spanner en Java
Para ejecutar consultas manuales de Spanner dentro de un DoFn y vincular esos intervalos al registro de la canalización activa, inicializa SpannerOptions con la instancia de OpenTelemetry de la canalización:
import com.google.cloud.spanner.DatabaseClient;
import com.google.cloud.spanner.DatabaseId;
import com.google.cloud.spanner.ResultSet;
import com.google.cloud.spanner.Spanner;
import com.google.cloud.spanner.SpannerOptions;
import com.google.cloud.spanner.Statement;
import org.apache.beam.sdk.options.PipelineOptions;
import org.apache.beam.sdk.options.SdkHarnessOptions;
import org.apache.beam.sdk.transforms.DoFn;
public class SpannerEnrichmentDoFn extends DoFn<String, String> {
private transient Spanner spanner;
private transient DatabaseClient dbClient;
private final String instanceId;
private final String databaseId;
public SpannerEnrichmentDoFn(String instanceId, String databaseId) {
this.instanceId = instanceId;
this.databaseId = databaseId;
}
@Setup
public void setup(PipelineOptions pipelineOptions) {
// Build SpannerOptions leveraging the pipeline's active OpenTelemetry instance
SpannerOptions options =
SpannerOptions.newBuilder()
.setOpenTelemetry(pipelineOptions
.as(SdkHarnessOptions.class)
.getOpenTelemetry())
.setEnableEndToEndTracing(true)
.setEnableExtendedTracing(true)
.build();
this.spanner = options.getService();
DatabaseId db = DatabaseId.of(options.getProjectId(), instanceId, databaseId);
this.dbClient = spanner.getDatabaseClient(db);
}
@ProcessElement
public void processElement(@Element String inputId, OutputReceiver<String> out) {
Statement statement = Statement.newBuilder(
"SELECT Details FROM AccountTable WHERE AccountId = @id")
.bind("id").to(inputId)
.build();
// Spanner queries automatically generate child spans linked to the active trace
try (ResultSet rs = dbClient.singleUse().executeQuery(statement)) {
while (rs.next()) {
out.output(rs.getString("Details"));
}
}
}
@Teardown
public void tearDown() {
if (spanner != null) {
spanner.close();
}
}
}
Propagación del contexto en las diferentes etapas
En las canalizaciones de datos distribuidas, es fundamental llevar el contexto de seguimiento a través de los límites de los trabajadores y las operaciones de Shuffle para obtener visibilidad de extremo a extremo.
Cuando insertas Redistribute.arbitrarily() en tu canalización, el contexto de seguimiento activo se serializa en los metadatos del elemento, se transmite a través de la red y se deserializa en la VM de trabajador receptora. Esto garantiza la continuación ininterrumpida del registro en todas las etapas.
En el siguiente ejemplo, se ilustra cómo se propaga el contexto de seguimiento en las etapas de la canalización:
- Extraer contexto:
KafkaIO.read()lee un registro entrante y extrae el contexto de seguimiento de los encabezados del mensaje. - Procesa y crea intervalos:
DoFn Aprocesa el elemento dentro de un intervalo de seguimiento activo. - Propagación entre trabajadores:
Redistribute.arbitrarily()serializa el contexto de seguimiento activo en los metadatos del elemento y lo aleatoriza en la red. - Continuar el seguimiento:
DoFn Brecibe el elemento en una VM de trabajador, deserializa el contexto de seguimiento y continúa el procesamiento con el mismo ID de seguimiento.
Visualiza seguimientos en Cloud Trace
Después de habilitar el registro de seguimiento, consulta los registros de seguimiento de la canalización en la consola de Google Cloud :
En la Google Cloud consola, ve a la página Explorador de seguimiento.
En el cuadro de filtro, filtra por
Service: SERVICE_NAME. Este SERVICE_NAME coincide con tu canalizaciónappNameo con elotel.service.nameconfigurado.Como alternativa, busca un ID de seguimiento específico.
Selecciona un registro de la lista de resultados para ver su cronograma detallado.
En el gráfico de la línea de tiempo, se muestra lo siguiente:
- Intervalos del ejecutor: Son los intervalos que genera el entorno de ejecución de Beam.
Por ejemplo,
PubSubIO.ReadyProcessElement. - Intervalos personalizados: Son los intervalos creados dentro de tus implementaciones de
DoFn. Por ejemplo:InvestigateTransactionDoFn:Analyze. Intervalos de la biblioteca cliente: Son los intervalos secundarios generados por las bibliotecas cliente integradas. Por ejemplo, las consultas de RPC de Spanner.

- Intervalos del ejecutor: Son los intervalos que genera el entorno de ejecución de Beam.
Por ejemplo,
¿Qué sigue?
- Obtén más información para explorar y analizar seguimientos distribuidos en la documentación de Cloud Trace.
- Realiza un seguimiento de los mensajes desde la transferencia hasta el procesamiento con el seguimiento de OpenTelemetry de Pub/Sub.
- Supervisa la capacidad de procesamiento de tu canalización, el uso de la CPU y los detalles de ejecución con la interfaz de supervisión de Dataflow.
- Visualiza los registros operativos y diagnostica errores con los registros de canalización de Dataflow.
- Investiga y resuelve problemas de rendimiento con Soluciona problemas de trabajos lentos o atascados y Detecta y resuelve cuellos de botella en la canalización.