3.3 – Task Parallelism & Scaling
Overview
This module is the authoritative explanation of Kafka Connect's scaling model. By the end, you will understand:
- The relationship between connectors and tasks.
- How task parallelism works.
- Partition-to-task mapping for source and sink connectors.
- Task rebalancing behavior.
- Scaling limits and best practices.
All concepts about scaling and parallelism live here. Other modules (e.g., performance tuning) will reference this module, not re-explain these mechanics.
Connectors vs. Tasks: The Relationship
Conceptual Model
Connector (Logical Job)
│
├── Task 1 (Execution Unit)
├── Task 2 (Execution Unit)
├── Task 3 (Execution Unit)
└── Task N (Execution Unit)
Key Insight: A connector is a job definition that doesn't process data itself. Instead, it spawns tasks that do the actual work.
Connector Responsibilities
- Define Configuration: Connection details, table names, topics, etc.
- Split Work: Determine how to divide work into tasks.
- Monitor Tasks: Track task health and request restarts if needed.
Task Responsibilities
- Execute Work: Read from external systems (source) or write to external systems (sink).
- Report Progress: Commit offsets, report status to the Connect runtime.
Analogy: A connector is like a project manager that defines a job and breaks it into subtasks. Tasks are the workers who execute those subtasks.
Task Parallelism
What is Task Parallelism?
Task parallelism is the ability to run multiple tasks concurrently to increase throughput.
Configured via tasks.max
The maximum number of tasks a connector can create is controlled by the tasks.max configuration:
{
"name": "jdbc-source",
"config": {
"connector.class": "io.confluent.connect.jdbc.JdbcSourceConnector",
"tasks.max": "5",
...
}
}
Important: tasks.max is a maximum, not a guarantee. The actual number of tasks created depends on:
- Connector Logic: The connector plugin determines how to split work.
- Available Work: For example, a JDBC source with 3 tables can only create 3 tasks, even if
tasks.max=10.
Example: JDBC Source with 3 Tables
Configuration:
{
"tasks.max": "5",
"table.whitelist": "users,orders,products"
}
Result: Only 3 tasks are created (one per table), even though tasks.max=5.
| Task | Table |
|---|---|
| Task 0 | users |
| Task 1 | orders |
| Task 2 | products |
Partition-to-Task Mapping
Source Connectors
For source connectors, the connector plugin determines how to partition work. Common strategies:
1. Per-Table Partitioning (JDBC Source)
Each task reads from one or more database tables.
Example: tasks.max=2, table.whitelist=users,orders,products
| Task | Tables |
|---|---|
| Task 0 | users, orders |
| Task 1 | products |
2. Per-File Partitioning (File Source)
Each task reads from one or more files.
Example: tasks.max=3, monitoring directory with 5 files.
| Task | Files |
|---|---|
| Task 0 | file1, file2 |
| Task 1 | file3, file4 |
| Task 2 | file5 |
3. Range Partitioning (Custom Source)
Tasks read different ranges of data (e.g., user IDs 1-1000, 1001-2000, etc.).
Sink Connectors
For sink connectors, tasks are typically assigned based on Kafka partition assignment.
Kafka Partition Assignment
Each sink task consumes from one or more Kafka partitions.
Example: Topic orders with 6 partitions, tasks.max=3
| Task | Kafka Partitions |
|---|---|
| Task 0 | Partition 0, Partition 1 |
| Task 1 | Partition 2, Partition 3 |
| Task 2 | Partition 4, Partition 5 |
Key Rule: The number of sink tasks cannot exceed the number of Kafka partitions. If tasks.max=10 but the topic has only 3 partitions, only 3 tasks will be created.
Task Distribution Across Workers
In Distributed Mode
Tasks are distributed across workers in a Connect cluster.
Example: 3 workers, 6 tasks
| Worker | Tasks |
|---|---|
| Worker 1 | Task 0, Task 1 |
| Worker 2 | Task 2, Task 3 |
| Worker 3 | Task 4, Task 5 |
Rebalancing: If a worker fails, its tasks are reassigned to surviving workers.
In Standalone Mode
All tasks run on the single worker.
Task Rebalancing
When Does Rebalancing Happen?
Rebalancing is triggered by:
- Worker Joins: New worker added to the cluster.
- Worker Leaves: Worker crashes or is shut down.
- Connector Reconfiguration:
tasks.maxis changed. - Task Failure: A task crashes and needs reassignment.
Rebalance Process
- Detection: Workers detect membership changes via Kafka's group coordination protocol.
- Leader Election: The group leader computes a new task assignment.
- Task Stop: Workers stop tasks that are no longer assigned to them.
- Task Start: Workers start newly assigned tasks.
Duration: Typically 5-10 seconds in a healthy cluster. During this time, affected tasks are paused.
Example: Worker Failure
Before Failure:
| Worker | Tasks |
|---|---|
| Worker 1 | Task 0, Task 1 |
| Worker 2 | Task 2, Task 3 |
| Worker 3 | Task 4, Task 5 |
After Worker 2 Fails:
| Worker | Tasks |
|---|---|
| Worker 1 | Task 0, Task 1, Task 2 |
| Worker 3 | Task 3, Task 4, Task 5 |
Impact: Tasks 2 and 3 are briefly paused during reassignment, then resume on Worker 1 and Worker 3.
Scaling Strategies
Horizontal Scaling (Add More Tasks)
How: Increase tasks.max in connector configuration.
When to Use:
- Connector throughput is bottlenecked by task processing speed.
- External system can handle more concurrent connections (e.g., database has available connection pool capacity).
Example: JDBC source reading from a large table.
{
"tasks.max": "10" // Increase from 3 to 10
}
Limitation: Cannot exceed the number of logical partitions (e.g., database tables, Kafka partitions).
Vertical Scaling (Add More Workers)
How: Add more workers to the Connect cluster.
When to Use:
- Existing workers are CPU/memory-saturated.
- You want higher fault tolerance (more workers = more redundancy).
Example: Scale from 3 workers to 5 workers.
Benefit: Tasks are redistributed across more workers, reducing per-worker load.
Combined Scaling
Best Practice: Scale both tasks and workers together for maximum throughput.
Example: Increase tasks.max from 3 to 12 and add 2 more workers.
| Before | After |
|---|---|
| 3 workers, 3 tasks | 5 workers, 12 tasks |
| Each worker runs 1 task | Each worker runs ~2-3 tasks |
Scaling Limits
1. Connector-Defined Limits
Some connectors cannot create more tasks than logical partitions:
- JDBC Source: Max tasks = number of tables.
- File Source: Max tasks = number of files.
- Kafka Sink: Max tasks = number of Kafka partitions.
2. External System Limits
- Database Connection Pools: If a database allows 10 concurrent connections, creating 20 tasks may cause connection errors.
- API Rate Limits: REST API-based sources may throttle requests, limiting effective parallelism.
3. Worker Capacity
Each worker has finite CPU/memory. Too many tasks on one worker can degrade performance.
Rule of Thumb: Aim for 5-10 tasks per worker, depending on task complexity.
4. Kafka Partition Count
For sink connectors, the number of tasks is capped by the number of Kafka partitions.
Example: Topic with 3 partitions → max 3 sink tasks, even if tasks.max=10.
Practical Scaling Examples
Example 1: Scaling a JDBC Source
Scenario: Ingest data from 10 database tables.
Configuration:
{
"tasks.max": "10",
"table.whitelist": "users,orders,products,..."
}
Result: 10 tasks (1 per table), distributed across workers.
Bottleneck: Database connection pool (ensure pool size ≥ 10).
Example 2: Scaling a Kafka Sink
Scenario: Write data to Elasticsearch from a Kafka topic with 12 partitions.
Configuration:
{
"tasks.max": "12",
"topics": "logs"
}
Result: 12 tasks (1 per partition), distributed across workers.
Bottleneck: Elasticsearch indexing throughput (tune batch.size and max.buffered.records).
Example 3: Over-Provisioning
Scenario: Set tasks.max=20 but only 5 tables exist.
Result: Only 5 tasks are created (connector logic limits task count).
Lesson: Setting tasks.max too high has no negative effect (but no benefit either).
Task Affinity and Stickiness
What is Task Affinity?
Task affinity is the preference to assign a task to the same worker it previously ran on.
Benefits:
- Faster Startup: If state stores or cached data exist on the worker, tasks start faster.
- Reduced Data Transfer: For stateful connectors, local state avoids network overhead.
Implementation: Connect uses a "sticky" assignment strategy where tasks prefer their previous worker during rebalancing.
When Affinity is Broken
Affinity is broken when:
- The previous worker is no longer available (crash, decommission).
- The cluster is rebalanced due to worker additions.
Impact: Tasks may take slightly longer to start due to state reconstruction or cache misses.
Monitoring Task Parallelism
JMX Metrics
Connector-Level Metrics:
kafka.connect:type=connector-metrics,connector="{connector-name}"→connector-task-count
Task-Level Metrics:
kafka.connect:type=task-metrics,connector="{connector-name}",task="{task-id}"→batch-size-avg,offset-commit-completion-rate
REST API
Check Task Assignment:
curl http://localhost:8083/connectors/jdbc-source/status
Response:
{
"name": "jdbc-source",
"connector": {"state": "RUNNING", "worker_id": "worker1:8083"},
"tasks": [
{"id": 0, "state": "RUNNING", "worker_id": "worker1:8083"},
{"id": 1, "state": "RUNNING", "worker_id": "worker2:8083"},
{"id": 2, "state": "RUNNING", "worker_id": "worker3:8083"}
]
}
Interpretation: 3 tasks running across 3 workers.
Best Practices for Scaling
1. Start Small, Scale Gradually
Begin with tasks.max=1, verify functionality, then increase incrementally.
2. Match Tasks to Logical Partitions
For JDBC sources, set tasks.max equal to the number of tables (if feasible).
3. Monitor External System Load
Ensure the external system (database, API, etc.) can handle the increased concurrency.
4. Use Multiple Workers for Fault Tolerance
Even if tasks.max=1, use ≥3 workers for high availability.
5. Tune Kafka Partition Count
For sink connectors, ensure the Kafka topic has enough partitions to support desired parallelism.
Example: If you want 10 sink tasks, the topic should have ≥10 partitions.
6. Avoid Over-Scaling
More tasks ≠ always better. Too many tasks can:
- Overwhelm external systems.
- Increase coordination overhead.
- Degrade per-task throughput.
Common Scaling Pitfalls
Pitfall 1: tasks.max Exceeds Logical Partitions
Symptom: tasks.max=10, but only 3 tasks are created.
Cause: Connector can only create tasks for available work (e.g., 3 tables, 3 files).
Fix: Align tasks.max with the actual number of partitions.
Pitfall 2: Database Connection Pool Exhaustion
Symptom: Tasks fail with "Too many connections" errors.
Cause: tasks.max exceeds database connection pool size.
Fix: Increase database connection pool or reduce tasks.max.
Pitfall 3: Kafka Partition Bottleneck
Symptom: Sink connector with tasks.max=10, but throughput doesn't increase.
Cause: Kafka topic has only 3 partitions → only 3 tasks are created.
Fix: Increase Kafka partition count (requires topic reconfiguration or new topic).
Pitfall 4: Unbalanced Task Distribution
Symptom: Some workers are idle while others are overloaded.
Cause: Connector logic creates uneven task assignments.
Fix: Ensure logical partitions (tables, files, etc.) are balanced in size.
Key Takeaways
- Connectors define jobs; tasks execute them. Tasks are units of parallelism.
tasks.maxcontrols maximum task count, but actual count depends on connector logic.- Source connectors partition by logical units (tables, files); sink connectors partition by Kafka partitions.
- Rebalancing redistributes tasks when workers join/leave or connectors are reconfigured.
- Scaling strategies: Increase
tasks.max(horizontal), add workers (vertical), or both. - Scaling limits: Logical partitions, external system capacity, worker capacity, Kafka partitions.
- Best practice: Start small, scale gradually, and monitor external system load.
What's Next?
- Module 4.1 covers Single Message Transforms (SMTs) for record-level transformations.
- Module 5.1 discusses performance tuning and throughput optimization.
- Module 8.1 explains monitoring task and worker metrics.
Further Reading
End of Module 3.3