High-throughput Kafka parallel consumer for asyncio + multiprocessing
Project description
Pyrallel Consumer
High-performance Kafka Parallel Processing Library
Pyrallel Consumer is a Python Kafka parallel consumer for high-throughput stream processing.
If you are looking for a parallel consumer for Kafka in Python, this project provides key-ordered processing, robust offset commit semantics, and runtime-selectable execution engines (asyncio / multiprocessing).
Inspired by Java's confluentinc/parallel-consumer, it is designed to maximize parallelism while preserving ordering guarantees and data consistency.
🌟 Key Features
- High parallelism: Process messages in parallel without being tightly limited by Kafka partition count.
- Ordering guarantees: Preserve processing order per message key.
- Data consistency: Gap-based offset commit strategy to minimize duplicate processing during rebalances/restarts.
- Stability & visibility: Epoch-based fencing and rich operational metrics.
- Flexible execution model: Runtime-selectable hybrid architecture (
AsyncExecutionEngine/ProcessExecutionEngine).
📈 Observability
You can expose Prometheus metrics via KafkaConfig.metrics.
Metrics are disabled by default (enabled=False).
from pyrallel_consumer.config import KafkaConfig
config = KafkaConfig()
config.metrics.enabled = True
config.metrics.port = 9095
consumer = PyrallelConsumer(config, worker, topic="demo")
Core Metrics
| Metric | Type | Labels | Description |
|---|---|---|---|
consumer_processed_total |
Counter | topic, partition, status |
Number of completed messages (success/failure) |
consumer_processing_latency_seconds |
Histogram | topic, partition |
End-to-end processing latency (WorkManager submit → completion) |
consumer_in_flight_count |
Gauge | – | Current in-flight message count |
consumer_parallel_lag |
Gauge | topic, partition |
True lag (last_fetched - last_committed) |
consumer_gap_count |
Gauge | topic, partition |
Number of commit-blocking gaps |
consumer_internal_queue_depth |
Gauge | topic, partition |
Messages waiting in virtual partition queue |
consumer_oldest_task_duration_seconds |
Gauge | topic, partition |
Time blocked by oldest offset/task |
consumer_backpressure_active |
Gauge | – | Backpressure status (1=paused) |
consumer_metadata_size_bytes |
Gauge | topic |
Kafka commit metadata payload size |
These metrics are based on the same values returned by BrokerPoller.get_metrics().
📊 Benchmark Snapshot (profiling OFF)
Recent run (4 partitions, 2000 messages, 100 keys, profiling off):
Workload semantics (what each option actually does)
-
sleepworkload (--worker-sleep-ms N)- Simulates blocking latency by calling
time.sleep(N/1000)per message. - Useful for modeling external blocking work with minimal CPU usage.
- Simulates blocking latency by calling
-
ioworkload (--worker-io-sleep-ms N)- Simulates async I/O latency by awaiting
asyncio.sleep(N/1000)per message. - Useful for network/DB-like I/O-bound behavior.
- Simulates async I/O latency by awaiting
-
cpuworkload (--worker-cpu-iterations K)- Simulates CPU-bound work by repeatedly applying hash computation (
sha256)Ktimes per message. - Higher
Kmeans more CPU pressure per message.
- Simulates CPU-bound work by repeatedly applying hash computation (
These options are implemented in the benchmark workers and directly control per-message work cost.
| Workload | Setting | baseline TPS | async TPS | process TPS |
|---|---|---|---|---|
| sleep | --workloads sleep --order key_hash --worker-sleep-ms 5 |
159.69 | 2206.35 | 910.04 |
| cpu | --workloads cpu --order key_hash --worker-cpu-iterations 500 |
2598.79 | 1403.07 | 2072.26 |
| io | --workloads io --order key_hash --worker-io-sleep-ms 5 |
159.89 | 2797.18 | 916.60 |
Note: process mode benchmarks were run with profiling disabled for stability.
🚀 Architecture Overview
Pyrallel Consumer is organized into three layers: Control Plane, Execution Plane, and Worker Layer.
The Control Plane manages Kafka communication and offsets independently from execution mode.
The Execution Plane runs user workers via asyncio tasks or multiprocessing.
graph TD
subgraph "Ingress Layer (Kafka Client)"
A["Kafka Broker"] --> B["BrokerPoller"]
end
subgraph "Routing Layer (Dispatcher)"
B --> C{"Key Extractor"}
C --> D["Virtual Partition 1"]
C --> E["Virtual Partition 2"]
end
subgraph "Execution Layer (Execution Engine)"
D --> G["ExecutionEngine.submit"]
E --> G
G --> H["AsyncExecutionEngine"]
G --> I["ProcessExecutionEngine"]
H --> J["Async Worker Task"]
I --> K["Process Worker"]
J & K --> L["Completion Channel"]
end
subgraph "Management & Control (Control Plane)"
L --> M["WorkManager"]
M --> N["Offset Tracker"]
N --> O["Commit Encoder"]
end
🛠️ Installation & Setup
Dependency Management (uv)
pip install uv
uv pip install -r requirements.txt
uv pip install -r dev-requirements.txt # optional
Package Build / Distribution
pip install .
python -m pip install build
python -m build
# artifacts: dist/*.tar.gz, dist/*.whl
Security / Config Notes
- Grafana admin password is expected via
GF_SECURITY_ADMIN_PASSWORDin.env. - For DLQ payload minimization, set
KAFKA_DLQ_PAYLOAD_MODE=metadata_only. - License: Apache-2.0
Env-based Config (pydantic-settings)
KAFKA_BOOTSTRAP_SERVERS=localhost:9092
KAFKA_CONSUMER_GROUP=my-consumer-group
EXECUTION_MODE=async # or process
🔁 Retry & DLQ
Pyrallel Consumer supports automatic retries and DLQ publishing.
Retry (ExecutionConfig)
| Env | Default | Description |
|---|---|---|
EXECUTION_MAX_RETRIES |
3 |
Max retry count |
EXECUTION_RETRY_BACKOFF_MS |
1000 |
Initial backoff (ms) |
EXECUTION_EXPONENTIAL_BACKOFF |
true |
Exponential backoff toggle |
EXECUTION_MAX_RETRY_BACKOFF_MS |
30000 |
Max backoff cap (ms) |
EXECUTION_RETRY_JITTER_MS |
200 |
Random jitter range (ms) |
DLQ (KafkaConfig)
| Env | Default | Description |
|---|---|---|
KAFKA_DLQ_ENABLED |
true |
Enable DLQ publish |
KAFKA_DLQ_TOPIC_SUFFIX |
.dlq |
DLQ topic suffix |
DLQ headers include:
x-error-reasonx-retry-attemptsource-topicpartitionoffsetepoch
💡 Usage
from pyrallel_consumer.consumer import PyrallelConsumer
from pyrallel_consumer.config import KafkaConfig, ExecutionConfig
from pyrallel_consumer.dto import ExecutionMode, WorkItem
config = KafkaConfig()
config.dlq_enabled = True
config.DLQ_TOPIC_SUFFIX = ".failed"
exec_conf = ExecutionConfig()
exec_conf.mode = ExecutionMode.ASYNC
exec_conf.max_retries = 5
exec_conf.retry_backoff_ms = 2000
async def worker(item: WorkItem):
...
consumer = PyrallelConsumer(config=config, worker=worker, topic="orders")
For detailed runnable patterns, see examples/.
🧪 Run Benchmarks
uv run python -m benchmarks.run_parallel_benchmark
# or pass flags directly for the existing CLI flow
uv run python benchmarks/run_parallel_benchmark.py \
--bootstrap-servers localhost:9092 \
--num-messages 50000 \
--num-keys 200 \
--num-partitions 8
- JSON report is saved to
benchmarks/results/<UTC timestamp>.json. - No flags: launches a Textual TUI so you can configure the benchmark interactively.
- You can skip rounds with
--skip-baseline,--skip-async,--skip-process. - Use
--workloads sleep,cputo run any subset of workloads and--order key_hash,partitionto run multiple ordering modes in one invocation. - Use
--strict-completion-monitor on,offto compare the completion monitor modes in benchmark output. - Topic/group reset is enabled by default; disable with
--skip-resetif needed.
📖 Documentation
prd_dev.md: concise developer-oriented summaryprd.md: full design rationale and architecture detailsdocs/ops_playbooks.md: ops playbook, tuning guide, incident response
📊 Monitoring Stack (Prometheus + Grafana)
Included stack (via docker-compose.yml):
- Prometheus (9090)
- Grafana (3000)
- Kafka Exporter (9308)
- Kafka UI (8080)
- Kafka (9092)
Usage:
- Enable metrics in app:
config.metrics.enabled = True
config.metrics.port = 9091
- Start stack:
docker compose up -d
- Verify:
- Prometheus: http://localhost:9090
- Grafana: http://localhost:3000 (default
admin/admin)
- Add Grafana datasource:
- Type: Prometheus
- URL:
http://prometheus:9090 - Access: Server
- Example queries:
consumer_processed_totalconsumer_processing_latency_seconds_bucketconsumer_in_flight_count
🤝 Contributing
All commit messages follow Conventional Commits.
© 2026 Pyrallel Consumer Project
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pyrallel_consumer-0.1.2a1.tar.gz.
File metadata
- Download URL: pyrallel_consumer-0.1.2a1.tar.gz
- Upload date:
- Size: 42.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
193b8cf49a13ba0136cd67772332fc6c2826e4101a0a42c11d1c6e98142cb37d
|
|
| MD5 |
b17da56d65b5cbc6c48327906affcb55
|
|
| BLAKE2b-256 |
f9244d461abe04af496a21d7b2ea6e884f8d376675a5971d0591512e38ea189e
|
File details
Details for the file pyrallel_consumer-0.1.2a1-py3-none-any.whl.
File metadata
- Download URL: pyrallel_consumer-0.1.2a1-py3-none-any.whl
- Upload date:
- Size: 46.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
01c6b9e0c5611b51b60be9d01d137ba45d4de5ad9d6bb4d77807b507542e6faa
|
|
| MD5 |
457e6d77b9696922d49dbf698ef81cce
|
|
| BLAKE2b-256 |
32630385a08a075ebeabe324b502100c0d055688e0c453175c20eadf5eef7ae1
|