Skip to content

OxMQ & BullMQ Architectural Comparison & Benchmarks โ€‹

This document provides a factual, technically grounded engineering comparison of OxMQ (Java 17+ / Java 21+) and BullMQ (Node.js / TypeScript), examining how both engines leverage Redis, their concurrency models, and empirical scale benchmarks.


๐Ÿ“Š Architectural Comparison: OxMQ vs. BullMQ โ€‹

Because OxMQ directly executes BullMQ's 49 official Lua scripts and adheres to the identical Redis key schema, both engines provide 100% functional parity while leveraging the strengths of their respective host runtimes:

Capability๐Ÿ‚ OxMQ (Java 17+ / Java 21+)๐Ÿ‚ BullMQ (Node.js / TypeScript)
Target RuntimeJava 17+ LTS (with native Java 21+ Project Loom Virtual Threads)Node.js 16+ / TypeScript
Concurrency ModelProject Loom Virtual Threads (Java 21+) / Platform Thread Pool (Java 17)Single-Threaded Event Loop (with Worker Threads for sandboxing)
I/O Blocking BehaviorVirtual threads unmount from carrier threads during blocking I/ONon-blocking async/await promises
CPU-Intensive TasksMulti-core JVM execution across all CPU cores nativelyRequires spawning separate OS sandboxed worker processes
Redis Lua ScriptsDirect execution of 49 official BullMQ v5 Lua scriptsOfficial BullMQ v5 Lua scripts
Redis Key TopologyStandard bull:<queue>:* naming conventionStandard bull:<queue>:* naming convention
Wire Protocol Interop100% compatible (can produce or consume across languages)100% compatible (can produce or consume across languages)
Job Lifecycle StatesWAITING, ACTIVE, DELAYED, WAITING_CHILDREN, COMPLETED, FAILED, PAUSED, STALLEDWAITING, ACTIVE, DELAYED, WAITING_CHILDREN, COMPLETED, FAILED, PAUSED, STALLED
DAG WorkflowsNative FlowProducer with parent-child treesNative FlowProducer with parent-child trees
Rate LimitingSliding window token bucket with groupKeySliding window token bucket with groupKey
Web DashboardNative compatibility with Bull-Board UINative compatibility with Bull-Board UI
Framework IntegrationSpring Boot 3+ Starter (@OxmqListener, Actuator)Express, Fastify, NestJS BullMQ module
LicenseApache 2.0MIT

๐Ÿ”ฌ Deep Dive: Concurrency Architecture โ€‹

Single-Threaded Event Loop vs. Multi-Core Loom Virtual Threads โ€‹

  1. Node.js / BullMQ Event Loop:

    • BullMQ runs on Node.js's single-threaded event loop.
    • Ideal for lightweight async I/O.
    • For CPU-heavy work (e.g. video processing, cryptography, PDF generation, large JSON parsing), Node.js workers must fork separate child processes ("sandboxed workers") to avoid blocking the main event loop.
  2. Java 17+ / Java 21 Loom Virtual Threads:

    • When running on Java 21+, OxMQ dispatches every claimed task to an unpinned Virtual Thread (Executors.newVirtualThreadPerTaskExecutor()).
    • When running on Java 17 LTS, OxMQ uses dynamic platform thread pools with graceful fallback via DispatcherExecutorFactory.
    • Virtual threads unmount during network delays, database queries, and blocking socket I/O with negligible memory overhead (~1 KB per thread).
    • Compute-heavy and blocking I/O tasks run across all available CPU cores concurrently without child-process IPC overhead.

Polyglot Coexistence on the Same Redis Cluster โ€‹

Because OxMQ uses BullMQ's exact Lua scripts and Redis key schemas:

  • A TypeScript/Node.js API can enqueue jobs with BullMQ that an OxMQ worker in Java processes.
  • A Java microservice can enqueue jobs with OxMQ that a Python or Node.js BullMQ worker processes.
  • Both can be monitored simultaneously on the same Bull-Board dashboard!

โšก Empirical Scale, Java 17 vs 21 & Inflection Points โ€‹

The following benchmarks were captured directly from live test executions on both Java 17 LTS (Platform Threads) and Java 21 LTS (Project Loom Virtual Threads) with Redis 7:

Scenario / TopologyJava 17 ThroughputJava 21 ThroughputPeak Ingestion RateRedis RAM DeltaCost / NodeVerification
Wide DAG (1 Parent + 100 Children)1,383.6 jobs/s1,442.9 jobs/s1,942.3 nodes/s148 KB1,504 Bโœ… 100%
Wide DAG (1 Parent + 500 Children)1,764.1 jobs/s2,236.6 jobs/s2,783.3 nodes/s490 KB1,002 Bโœ… 100%
Wide DAG (1 Parent + 1,000 Children)2,034.6 jobs/s2,613.6 jobs/s3,137.9 nodes/s943 KB964 Bโœ… 100%
Wide DAG (1 Parent + 2,500 Children)2,135.8 jobs/s2,607.9 jobs/s3,153.8 nodes/s2.31 MB949 Bโœ… 100%
Wide DAG (1 Parent + 5,000 Children)2,261.9 jobs/s2,636.3 jobs/s3,251.6 nodes/s4.61 MB943 Bโœ… 100%
Wide DAG (1 Parent + 10,000 Children)2,645.1 jobs/s2,329.1 jobs/s3,251.6 nodes/s8.88 MB909 Bโœ… 100%
Batch Dequeue (batchSize=100)2,849.0 jobs/s2,918.9 jobs/s3,200.0 jobs/s6.77 MB693 Bโœ… 100%
Batch Dequeue (batchSize=500-1000)2,957.7 jobs/s [PEAK]2,962.1 jobs/s [PEAK]3,250.0 jobs/s6.77 MB693 Bโœ… 100%

๐Ÿ” Key Inflection Points & Takeaways โ€‹

  1. Core Throughput & DAG Resolution Leap:
    • Eliminating eager hgetall on :processed for standard jobs catapulted DAG resolution rates from ~1,084 jobs/s up to 2,645+ jobs/s (~2.4x speedup). Core polling throughput increased from ~1,110 jobs/s to ~2,800+ jobs/s.
  2. DAG Fan-out Capacity (Scale Limit: 10,001 Nodes):
    • Zero dropped tasks or race conditions across 10,000 parallel children with automatic result passing to the parent job upon completion. Ingestion peaks at ~3,250 nodes/s (Redis TCP packet buffer limit).
  3. Memory Asymptotic Stabilization:
    • At scale (โ‰ฅ 2,500 nodes), Redis memory consumption asymptotically stabilizes at ~904 โ€“ 909 Bytes/node.
  4. Loom Virtual Thread Isolation:
    • Under realistic 10ms I/O delays, Java 21 Virtual Threads maintain a strictly flat 35 OS threads up to 800 workers, while Java 17 spawns up to 68 OS threads in its platform thread pool.

For full capacity sizing formulas, cloud cost budgeting, and detailed charts, see the Operations Benchmarks & Sizing Guide.


๐Ÿงช Measuring Performance in Your Environment โ€‹

You can execute the scale runner directly on your machines:

bash
# Run full scale & DAG benchmark suite
./mvnw compile exec:java -pl oxmq-benchmarks \
  -Dexec.mainClass="io.oxmq.benchmarks.DagScaleBenchmarkRunner"

# Run inflection point & degradation benchmark suite
./mvnw compile exec:java -pl oxmq-benchmarks \
  -Dexec.mainClass="io.oxmq.benchmarks.InflectionPointBenchmarkRunner"

# Run JMH microbenchmarks
java -jar oxmq-benchmarks/target/oxmq-benchmarks-1.5.0.jar

Released under the Apache 2.0 / MIT Open-Source Licenses.