kafka sink accumulates sarama Broker responseReceiver goroutines as broker connections expand
Nobody has claimed this yet.
- Dominant language
- Go
- Stars
- 56
- Forks
- 63
- Avg merge
- 2d 20h
- Merged PRs (30d)
- 34
Description
Background
We are seeing the goroutine count continuously increase on one TiCDC node for more than a day in a customer environment. This does not happen on every cluster.
I correlated two goroutine dumps (around 2026-03-20 19:00 and 2026-03-20 20:00 UTC) with the node-local TiCDC log from the same node.
Raw goroutine dumps:
- see files
What grows
Between the two dumps:
- total goroutines:
23584 -> 23602(+18) github.com/IBM/sarama.(*Broker).responseReceiver:914 -> 932(+18)- logpuller worker goroutines stayed flat:
logservice/logpuller.(*regionRequestWorker).receiveAndDispatchChangeEvents:1824 -> 1824logservice/logpuller.(*regionRequestWorker).processRegionSendTask:1824 -> 1824
So the growth is concentrated in Sarama broker receiver goroutines, not in logpuller workers.
Correlated log evidence from the same node
In the 2026-03-20 19:* window:
Connected to broker:24Closed connection to broker:7- net broker connection growth:
+17
This matches the responseReceiver goroutine delta (+18) very closely.
I did not find sink close/rebuild logs in the 19:* or 20:* window:
- no
Sink manager closing sink factory - no
Close kafka async producer client success - no
Close kafka async producer success - no
Kafka DDL producer closed - no
async producer exit since context is done
So in this one-hour window, this does not currently look like sink recreation.
Observed pattern
The Sarama logs show periodic metadata refresh batches roughly every 9 minutes:
19:07 / 19:16 / 19:25 / 19:34 / 19:43 / 19:5220:01 / 20:10 / 20:19 / 20:28 / 20:37
During some refreshes we see broken pipes, deregistration, and immediate re-registration of brokers in the same refresh cycle.
Example around 19:36:24:
- brokers
#91,#8,#50hitwrite: broken pipe - the connections are closed and deregistered
- the same brokers are registered again immediately in that refresh cycle
Example around 20:12:24:
- brokers
#59,#64,#44,#2hitwrite: broken pipe - the connections are closed and deregistered
- the same brokers are registered again immediately in that refresh cycle
Relevant code paths
TiCDC Kafka sink creates three long-lived Sarama clients per sink:
- admin client:
pkg/sink/kafka/sarama_factory.go - sync producer client:
pkg/sink/kafka/sarama_factory.go - async producer client:
pkg/sink/kafka/sarama_factory.go
TiCDC also configures and drives them like this:
pkg/sink/kafka/sarama_config.go:config.Metadata.RefreshFrequency = 9 * time.Minutedownstreamadapter/sink/kafka/sink.go: DML producer heartbeat every5sdownstreamadapter/sink/kafka/sink.go: DDL producer heartbeat every5sdownstreamadapter/sink/topicmanager/kafka_topic_manager.go: admin heartbeat every5s- all three
Heartbeat()implementations iterate overclient.Brokers()and callApiVersions(...)
On the Sarama side:
client.LeastLoadedBroker()opens the selected brokerBroker.Open()starts aresponseReceivergoroutine
Suspected problem
From the operator side this looks like a goroutine leak, but the current evidence suggests a narrower issue:
- long-lived Kafka clients gradually expand the set of connected brokers
- once a broker connection is opened, the 5-second heartbeat keeps it active
responseReceivergoroutines therefore grow monotonically until the per-client broker set reaches a plateau
So I am not claiming that this is already proven to be an infinite leak. The current claim is narrower:
- the goroutine growth is real
- it is driven by Kafka/Sarama broker connection growth inside long-lived clients
- it is not explained by sink recreation in the analyzed one-hour window
- the steady-state goroutine count can still become very high and look like a leak operationally
Questions
Is this considered expected behavior, or should TiCDC avoid keeping so many broker connections alive per sink/client?
Possible directions that seem relevant:
- reduce the heartbeat scope
- allow more broker connections to age out instead of keeping them alive every
5s - avoid expanding the broker connection set so aggressively during metadata refresh
- provide a documented limit/workaround for large-broker-count Kafka clusters
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with pkg/sink/kafka/sarama_factory.go and pkg/sink/kafka/sarama_config.go, then trace the heartbeat paths in downstreamadapter/sink/kafka/sink.go and downstreamadapter/sink/topicmanager/kafka_topic_manager.go into Sarama's Broker.Open and responseReceiver. Compare broker connection and goroutine behavior across metadata refreshes; done requires an agreed expected connection policy and evidence that the selected behavior is bounded or otherwise documented.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- go, kafka
- Domain
- backend, distributed-systems
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Needs clarification
- Newbie friendliness
- 35/100