SpringBoot + Disruptor: Achieving 6 Million Orders per Second with Ultra‑Fast Concurrency
This article explains why Disruptor—a lock‑free, high‑throughput Java queue from LMAX—was chosen over traditional brokers, details its core concepts such as RingBuffer, Sequence, and WaitStrategy, and provides a step‑by‑step SpringBoot demo that can handle up to six million orders per second without pressure.
Background
Project required an ultra‑low latency message queue; Disruptor was chosen because it can handle up to 6 million TPS on a single thread.
Disruptor Overview
Open‑source Java framework from LMAX designed for the producer‑consumer problem, providing higher throughput and lower latency than traditional I/O queues. Implements a bounded lock‑free queue.
Core Concepts
RingBuffer – circular buffer that stores events; since version 3.0 its role is limited to storage and update.
Sequence – tracks consumer progress and avoids false sharing of CPU caches.
Sequencer – core component; implementations SingleProducerSequencer and MultiProducerSequencer define the concurrent algorithm.
SequenceBarrier – holds references to the main published sequence and dependent consumer sequences to determine event availability.
WaitStrategy – defines how a consumer waits for the next event; multiple strategies offer different performance characteristics.
Event – user‑defined data exchanged between producer and consumer.
EventProcessor – holds a consumer’s Sequence and runs the event‑loop.
EventHandler – user‑implemented interface that processes events.
Producer – user code that publishes events; Disruptor does not define a specific interface.
Demo – Step‑by‑Step Implementation (Spring Boot)
Add Maven dependency
<dependency>
<groupId>com.lmax</groupId>
<artifactId>disruptor</artifactId>
<version>3.3.4</version>
</dependency>Message model
@Data
public class MessageModel {
private String message;
}EventFactory
public class HelloEventFactory implements EventFactory<MessageModel> {
@Override
public MessageModel newInstance() {
return new MessageModel();
}
}EventHandler (consumer)
@Slf4j
public class HelloEventHandler implements EventHandler<MessageModel> {
@Override
public void onEvent(MessageModel event, long sequence, boolean endOfBatch) {
try {
Thread.sleep(1000); // simulate async processing
log.info("Consumer start");
if (event != null) {
log.info("Consumed: {}", event);
}
} catch (Exception e) {
log.info("Consumer failed");
}
log.info("Consumer end");
}
}BeanManager (utility)
@Component
public class BeanManager implements ApplicationContextAware {
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext ctx) throws BeansException {
applicationContext = ctx;
}
public static ApplicationContext getApplicationContext() { return applicationContext; }
public static Object getBean(String name) { return applicationContext.getBean(name); }
public static <T> T getBean(Class<T> clazz) { return applicationContext.getBean(clazz); }
}MQManager (RingBuffer bean)
@Configuration
public class MQManager {
@Bean("messageModel")
public RingBuffer<MessageModel> messageModelRingBuffer() {
ExecutorService executor = Executors.newFixedThreadPool(2);
HelloEventFactory factory = new HelloEventFactory();
int bufferSize = 1024 * 256; // must be power of two
Disruptor<MessageModel> disruptor = new Disruptor<>(factory, bufferSize, executor,
ProducerType.SINGLE, new BlockingWaitStrategy());
disruptor.handleEventsWith(new HelloEventHandler());
disruptor.start();
return disruptor.getRingBuffer();
}
}Service interface
public interface DisruptorMqService {
void sayHelloMq(String message);
}Service implementation (producer)
@Service
public class DisruptorMqServiceImpl implements DisruptorMqService {
@Autowired
private RingBuffer<MessageModel> messageModelRingBuffer;
@Override
public void sayHelloMq(String message) {
log.info("record the message: {}", message);
long sequence = messageModelRingBuffer.next();
try {
MessageModel event = messageModelRingBuffer.get(sequence);
event.setMessage(message);
log.info("Add to queue: {}", event);
} catch (Exception e) {
log.error("failed to add event", e);
} finally {
messageModelRingBuffer.publish(sequence);
}
}
}Test class
@RunWith(SpringRunner.class)
@SpringBootTest(classes = DemoApplication.class)
public class DemoApplicationTests {
@Autowired
private DisruptorMqService disruptorMqService;
@Test
public void sayHelloMqTest() throws Exception {
disruptorMqService.sayHelloMq("Message arrived, Hello world!");
log.info("Message queue sent");
Thread.sleep(2000); // verify async consumption
}
}Test Output
2020-04-05 14:31:18.543 INFO DisruptorMqServiceImpl : record the message: 消息到了,Hello world!
2020-04-05 14:31:18.545 INFO DisruptorMqServiceImpl : 往消息队列中添加消息:MessageModel(message=消息到了,Hello world!)
2020-04-05 14:31:18.545 INFO DemoApplicationTests : 消息队列已发送完毕
2020-04-05 14:31:19.547 INFO HelloEventHandler : 消费者处理消息开始
2020-04-05 14:31:19.547 INFO HelloEventHandler : 消费者消费的信息是:MessageModel(message=消息到了,Hello world!)
2020-04-05 14:31:19.547 INFO HelloEventHandler : 消费者处理消息结束Conclusion
The producer‑consumer pattern is common; many message‑queue products can achieve similar functionality, but Disruptor implements the queue entirely in memory and without locks, which explains its superior performance.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Java Architect Handbook
Focused on Java interview questions and practical article sharing, covering algorithms, databases, Spring Boot, microservices, high concurrency, JVM, Docker containers, and ELK-related knowledge. Looking forward to progressing together with you.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
