How RocketMQ and DDMQ Achieve Ordered Message Consumption – Deep Dive with Code

This article explores the sequential consumption mechanisms of RocketMQ and its derivative DDMQ, detailing the underlying source‑code implementation, differences in producer ordering, broker handling, consumer locking, and how DDMQ simplifies ordering with a single‑node proxy, complete with code examples and diagrams.

Cognitive Technology Team
Cognitive Technology Team
Cognitive Technology Team
How RocketMQ and DDMQ Achieve Ordered Message Consumption – Deep Dive with Code

Introduction

This article provides an in‑depth analysis of RocketMQ and the DDMQ implementation of ordered consumption, covering source‑code principles, differences between ordered sending and receiving, and the lock mechanisms required for strict message ordering.

RocketMQ Model

RocketMQ consists of NameServer (routing provider), Broker (message storage and delivery), and client components. Topics contain queues; each queue holds messages of a single topic.

Ordered Sending

Messages are sent to the same queue using a MessageQueueSelector. The SDK provides selectors such as SelectMessageQueueByHash and SelectMessageQueueByRandom. The key code is:

public static void main(String[] args) throws Exception {
    DefaultMQProducer producer = new DefaultMQProducer("producer_group_name");
    producer.setNamesrvAddr("127.0.0.1:9876");
    producer.start();
    Message message = new Message("test_topic", "test_tag", "Hello, Rocketmq!".getBytes());
    SendResult sendResult = producer.send(message, new SelectMessageQueueByHash(), "test_arg");
    System.out.println(sendResult);
    producer.shutdown();
}

The three parameters of send are the Message, a MessageQueueSelector, and a user argument that must remain constant for ordered delivery.

Ordered Consumption

In cluster mode, only one consumer in a group pulls and processes messages from a given queue. The consumer runs a single thread per queue, and the broker locks the queue for the consumer.

@Override
public ConsumeOrderlyStatus consumeMessage(List<MessageExt> msgs, ConsumeOrderlyContext context) {
    for (MessageExt msg : msgs) {
        System.out.println(new String(msg.getBody()));
    }
    return ConsumeOrderlyStatus.SUCCESS;
}

Locks are applied both to the MessageQueue (to ensure a single thread consumes) and to the ProcessQueue (to avoid rebalance removal during consumption).

DDMQ Sequential Consumption

DDMQ builds on RocketMQ but introduces a proxy layer that handles ordering with only local thread locks, eliminating the need for broker‑side distributed locks.

Client Pull & Ack

The client pulls messages from the proxy, records success/failure locally, and batches the result back to the proxy on the next pull.

public synchronized void ack(Context context, long offset) {
    getResult(context).getSuccessOffsets().add(offset);
}
public synchronized void fail(Context context, long offset) {
    getResult(context).getFailOffsets().add(offset);
}

Proxy Ordering Logic

Messages are placed into a main queue. If a message carries an ordering key (QID, message key, or JSON path), the proxy obtains a lock for that key, inserts the message into a per‑key linked list, and releases the main‑queue lock so other threads can continue processing.

orderLock.lock();
try {
    UpstreamJob dependentJob = jobOrderMap.putIfAbsent(orderId, job);
    if (dependentJob == null) {
        // first in order, process immediately
    } else {
        dependentJob.setNextIfNull(job); // chain
        jobOrderMap.put(orderId, job);
    }
} finally {
    orderLock.unlock();
}

When a job finishes, the proxy releases the lock and enqueues the next job in the chain:

orderLock.lock();
try {
    UpstreamJob nextJob = job.getNext();
    if (nextJob != null) {
        reActivationQueue.offer(nextJob);
        readyJobs.release();
    }
} finally {
    orderLock.unlock();
}

Comparison

RocketMQ requires broker‑side distributed locks plus client‑side thread locks to guarantee ordering across multiple brokers, while DDMQ’s single‑node proxy only needs local thread locks, simplifying the design.

RocketMQDDMQOrdered Consumption
Cognitive Technology Team
Written by

Cognitive Technology Team

Cognitive Technology Team regularly delivers the latest IT news, original content, programming tutorials and experience sharing, with daily perks awaiting you.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.