Volver al inicio

Retrasos reintento Spring Kafka: cómo solucionarlo

Artículo analiza la causa de retrasos en tópicos de reintento Spring Kafka con @RetryableTopic: sobrecarga del TaskScheduler por defecto. Diagnóstico vía métricas y threaddump, solución — aumentar pool a 10. Recomendaciones de monitoreo.

Solución de retrasos en tópicos de reintento Spring Kafka
Advertisement 728x90

Reintentos No Bloqueantes en Spring Kafka: Diagnóstico y Solución de Retrasos

Al implementar reintentos asíncronos para Kafka usando @RetryableTopic en Spring Boot 3.2 y Spring Kafka 3.1, se acumulan retrasos en los temas de reintento bajo carga. El tema principal procesa mensajes de manera uniforme, pero retry-0 acumula mensajes durante 10–12 minutos, luego se limpia parcialmente y se vuelve a estancar. Esto provoca un procesamiento desigual.

Las métricas muestran picos esporádicos de solicitudes de fetch en lugar de sondeos consistentes. El consumidor sondea periódicamente al broker para latidos, pero la lectura real ocurre de forma esporádica con alta latencia.

Métricas Clave para el Análisis

Para el diagnóstico, recopile estas métricas de Spring Kafka:

Google AdInline article slot
  • kafka_consumer_time_between_poll_avg / max — intervalos entre sondeos.
  • kafka_consumer_last_poll_seconds_ago — tiempo desde el último sondeo.
  • kafka_consumer_poll_idle_ratio_avg — proporción de sondeos inactivos.
  • kafka_consumer_fetch_manager_fetch_rate / fetch_latency_avg — velocidad y latencia del fetch.
  • spring_kafka_listener_seconds_count / sum — tiempo de procesamiento del listener.

Los gráficos de fetch-rate e invocaciones del listener confirman: el procesamiento se activa en ráfagas, el sondeo inactivo es alto.

Diagnóstico mediante Volcado de Hilos

El volcado de hilos reveló ~180 hilos en TIMED_WAITING en ScheduledThreadPoolExecutor$DelayedWorkQueue.take. Esto indica sobrecarga del programador, utilizado para reanudar particiones retrasadas.

Mecanismo de Pausa en RetryableTopic

@RetryableTopic usa ContainerPartitionPausingBackOffManager: al procesar el primer mensaje de reintento, verifica el backoff, pausa la partición para now() + delay, y programa la reanudación mediante ListenerContainerPauseService.

Google AdInline article slot

Código de pausa:

private final TaskScheduler scheduler;

public void pausePartition(MessageListenerContainer messageListenerContainer, 
                           TopicPartition partition,
                           Duration pauseDuration) {
    Instant resumeAt = Instant.now().plusMillis(pauseDuration.toMillis());
    messageListenerContainer.pausePartition(partition);
    this.scheduler.schedule(() -> {
        messageListenerContainer.resumePartition(partition);
    }, resumeAt);
}

Bajo alta carga, la cola de tareas del programador se desborda. Por defecto, spring.task.scheduling.pool.size=1, creando un cuello de botella: las tareas de reanudación se acumulan, el fetch no comienza a tiempo.

Solución: Aumentar el Pool del Programador

Configure spring.task.scheduling.pool.size=10 en application.properties.

Google AdInline article slot

Resultados:

  • El retraso en Retry-0 se estabilizó en un nivel aceptable (no cae a 0 debido al backoff).
  • Los intervalos de sondeo se acortaron, el fetch-rate aumentó.
  • Las invocaciones del listener se volvieron consistentes.

Gráfico de retraso después de la corrección: permanece plano sin crecimiento. La latencia del fetch disminuyó, los sondeos son más frecuentes.

Conclusiones Clave

  • Programador limitado: el pool predeterminado de 1 hilo no puede manejar pausas/reanudaciones masivas bajo carga de reintentos.
  • Métricas primero: monitoree fetch-rate, poll-idle, listener-time antes del volcado de hilos.
  • Transacciones secundarias: ack-mode=record, max.poll.records=1 no afectan el retraso.
  • Concurrencia correcta: Spring Kafka escala correctamente por particiones, incluso con temas multiplicados.
  • Alternativa: para alta carga, considere reintentos personalizados con verificaciones de timestamp en un bucle en lugar de pausas.

Recomendaciones de Monitoreo

Agregue paneles para:

  • Tasa de commit/rollback para exactamente una vez.
  • Tamaño de la cola del programador (métrica personalizada).
  • Eventos de pausa/reanudación de particiones.
  • Delta entre timestamp de backoff y tiempo actual.

Pruebe bajo carga antes de producción. El código fuente de Spring Kafka proporciona información completa sobre la mecánica.

— Editorial Team

Advertisement 728x90

Leer después