Tüm Ürünler
Search
Belge Merkezi

ApsaraMQ for RocketMQ:Send and receive ordered messages

Son Güncelleme:Oct 04, 2026

ApsaraMQ for RocketMQ, sıralı mesajları katı bir ilk giren ilk çıkar (FIFO) diziliminde iletir. Uygulamanızın mesajların gönderildikleri sırayla işlenmesini gerektirdiği durumlarda, örneğin ticari siparişlerin gönderilme zamanına göre işlenmesi veya veritabanı değişikliklerinin ardışık olarak senkronize edilmesi gibi senaryolarda sıralı mesajları kullanın.

Bu konu, Java için HTTP istemci SDK'sını kullanarak sıralı mesaj gönderip almanıza ilişkin örnek kodlar sunar.

Çalışma biçimi

Sıralı mesajlar iki kategoriye ayrılır:

  • Genel olarak sıralı mesajlar: Bir konudaki tüm mesajlar tek bir FIFO dizilimini takip eder. Bu yaklaşım en güçlü sıralama garantisi sağlar ancak aktarım hızını tek bir parçayla sınırlar.

  • Parça bazında sıralı mesajlar: Mesajlar parçalama anahtarına göre parçalara dağıtılır. Her parça içinde mesajlar FIFO sırasını izler. Farklı parçalar bağımsız olarak tüketildiğinden, sıralamanın önemli olduğu yerlerde düzen korunurken daha yüksek aktarım hızı elde edilir.

Bir parçalama anahtarı, bir mesajın hangi parçaya ait olduğunu belirler. Aynı parçalama anahtarına sahip mesajlar her zaman aynı parçaya iletilir ve sırayla tüketilir. Parçalama anahtarı, mesaj anahtarından farklıdır.

Önemli

Bir ApsaraMQ for RocketMQ aracı, mesajların oluşturulma sırasını göndericinin tek bir üretici veya iş parçacığı kullanarak mesajları gönderme sırasına göre belirler. Gönderici birden çok üretici veya iş parçacığı kullanarak eşzamanlı olarak mesaj gönderirse, mesaj sırası ApsaraMQ for RocketMQ aracının mesajları aldığı sıraya göre belirlenir. Bu sıra, iş tarafındaki gönderme sırasından farklı olabilir.

Üretim sırası ve tüketim sırası

Uçtan uca FIFO teslimatı iki bağımsız faktöre bağlıdır:

Üretim sırası Tüketim sırası Sonuç
Tek üretici, seri gönderimler Sıralı tüketim (consumeMessageOrderly) Parçalama anahtarı başına FIFO garantili
Birden çok üretici veya iş parçacığı Sıralı tüketim Sıra, broker varışına göre belirlenir; iş niyetine göre değil
Tek üretici, seri gönderimler Eşzamanlı tüketim Tüketim sırası garantili değildir

Katı sıralama için her iki koşulun da sağlanması gerekir: tek bir üretici iş parçacığından gönderim yapılmalı ve consumeMessageOrderly ile tüketilmelidir.

Ön koşullar

Başlamadan önce aşağıdaki işlemleri tamamladığınızdan emin olun:

  • SDK for Java'yı yükleyin. Daha fazla bilgi için bkz. Java ortamınızı kurma.

  • Kodda belirtmek istediğiniz kaynakları ApsaraMQ for RocketMQ konsolunda oluşturun. Kaynaklar arasında örnekler, konular ve tüketici grupları bulunur. Daha fazla bilgi için bkz. Kaynak oluşturma.

  • Alibaba Cloud hesabınızın AccessKey çiftini edinin. Daha fazla bilgi için bkz. AccessKey oluşturma.

Sıralı mesaj gönderme

Aşağıdaki örnekte, parçalama anahtarları kullanılarak iki parça arasında sekiz sıralı mesaj gönderilmektedir.

Yer tutucuları gerçek değerlerinizle değiştirin:

Yer tutucu Açıklama Örnek
<your-http-endpoint> ApsaraMQ for RocketMQ konsolundaki Instance Details sayfasındaki HTTP uç noktası http://xxx.mqrest.cn-hangzhou.aliyuncs.com
<your-topic> Konu adı OrderTopic
<your-instance-id> Örnek kimliği. Örneğin ad alanı yoksa null veya "" olarak ayarlayın MQ_INST_xxx
import com.aliyun.mq.http.MQClient;
import com.aliyun.mq.http.MQProducer;
import com.aliyun.mq.http.model.TopicMessage;

import java.util.Date;

public class OrderProducer {

    public static void main(String[] args) {
        MQClient mqClient = new MQClient(
                "<your-http-endpoint>",
                // Read credentials from environment variables to avoid hardcoding secrets
                System.getenv("ALIBABA_CLOUD_ACCESS_KEY_ID"),
                System.getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET")
        );

        final String topic = "<your-topic>";
        // Set to null or "" if the instance has no namespace
        final String instanceId = "<your-instance-id>";

        // Get the producer for the specified topic
        MQProducer producer;
        if (instanceId != null && instanceId != "") {
            producer = mqClient.getProducer(instanceId, topic);
        } else {
            producer = mqClient.getProducer(topic);
        }

        try {
            // Send 8 messages, alternating between 2 sharding keys (partitions)
            for (int i = 0; i < 8; i++) {
                TopicMessage pubMsg = new TopicMessage(
                        "hello mq!".getBytes(),   // Message body
                        "A"                        // Message tag for filtering
                );
                // Sharding key determines the partition. Messages with the same
                // sharding key are delivered to the same partition in FIFO order.
                pubMsg.setShardingKey(String.valueOf(i % 2));
                pubMsg.getProperties().put("a", String.valueOf(i));

                // Publish synchronously. No exception means the send succeeded.
                TopicMessage pubResultMsg = producer.publishMessage(pubMsg);

                System.out.println(new Date() + " Send mq message success. Topic is:" + topic
                        + ", msgId is: " + pubResultMsg.getMessageId()
                        + ", bodyMD5 is: " + pubResultMsg.getMessageBodyMD5());
            }
        } catch (Throwable e) {
            // Handle send failure: retry or persist the message for later delivery
            System.out.println(new Date() + " Send mq message failed. Topic is:" + topic);
            e.printStackTrace();
        }

        mqClient.close();
    }
}
Not

Her konu yalnızca bir mesaj türünü destekler. Sıralı mesajlar için oluşturulan bir konu, normal mesajları gönderemez veya alamaz.

Sıralı mesaj alma

Aşağıdaki örnekte, uzun oylama kullanan ve parça düzeyinde FIFO sırasını garanti eden consumeMessageOrderly kullanılarak sıralı mesajlar tüketilmektedir.

Yer tutucuları gerçek değerlerinizle değiştirin:

Yer tutucu Açıklama Örnek
<your-http-endpoint> Instance Details sayfasındaki HTTP uç noktası http://xxx.mqrest.cn-hangzhou.aliyuncs.com
<your-topic> Konu adı OrderTopic
<your-group-id> Tüketici grubu kimliği GID_Order
<your-instance-id> Örnek kimliği. Örneğin ad alanı yoksa null veya "" olarak ayarlayın MQ_INST_xxx
import com.aliyun.mq.http.MQClient;
import com.aliyun.mq.http.MQConsumer;
import com.aliyun.mq.http.common.AckMessageException;
import com.aliyun.mq.http.model.Message;

import java.util.ArrayList;
import java.util.List;

public class OrderConsumer {

    public static void main(String[] args) {
        MQClient mqClient = new MQClient(
                "<your-http-endpoint>",
                System.getenv("ALIBABA_CLOUD_ACCESS_KEY_ID"),
                System.getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET")
        );

        final String topic = "<your-topic>";
        final String groupId = "<your-group-id>";
        // Set to null or "" if the instance has no namespace
        final String instanceId = "<your-instance-id>";

        final MQConsumer consumer;
        if (instanceId != null && instanceId != "") {
            consumer = mqClient.getConsumer(instanceId, topic, groupId, null);
        } else {
            consumer = mqClient.getConsumer(topic, groupId);
        }

        // Continuously poll for messages
        do {
            List<Message> messages = null;

            try {
                // consumeMessageOrderly guarantees partition-level FIFO order.
                // The consumer must ACK all messages in a batch before the broker
                // delivers the next batch from the same partition.
                messages = consumer.consumeMessageOrderly(
                        3,  // Max messages per batch (up to 16)
                        3   // Long polling timeout in seconds (up to 30)
                );
            } catch (Throwable e) {
                e.printStackTrace();
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e1) {
                    e1.printStackTrace();
                }
            }

            if (messages == null || messages.isEmpty()) {
                System.out.println(Thread.currentThread().getName() + ": no new message, continue!");
                continue;
            }

            // Process messages
            System.out.println("Receive " + messages.size() + " messages:");
            for (Message message : messages) {
                System.out.println(message);
                System.out.println("ShardingKey: " + message.getShardingKey()
                        + ", a:" + message.getProperties().get("a"));
            }

            // ACK consumed messages. If the broker does not receive an ACK before
            // the retry timeout, it redelivers the message.
            {
                List<String> handles = new ArrayList<String>();
                for (Message message : messages) {
                    handles.add(message.getReceiptHandle());
                }

                try {
                    consumer.ackMessage(handles);
                } catch (Throwable e) {
                    if (e instanceof AckMessageException) {
                        AckMessageException errors = (AckMessageException) e;
                        System.out.println("Ack message fail, requestId is:"
                                + errors.getRequestId() + ", fail handles:");
                        if (errors.getErrorMessages() != null) {
                            for (String errorHandle : errors.getErrorMessages().keySet()) {
                                System.out.println("Handle:" + errorHandle
                                        + ", ErrorCode:" + errors.getErrorMessages().get(errorHandle).getErrorCode()
                                        + ", ErrorMsg:" + errors.getErrorMessages().get(errorHandle).getErrorMessage());
                            }
                        }
                        continue;
                    }
                    e.printStackTrace();
                }
            }
        } while (true);
    }
}

Sıralı tüketimin çalışma biçimi

consumeMessageOrderly çağrıldığında broker şu davranışları uygular:

  1. Parça düzeyinde kilitleme: Tüketici birden çok parçadan mesaj çekebilir ancak her parça içinde mesajlar gönderilme sırasına göre gelir.

  2. Toplu onaylama kapısı: Tüketici, aynı parçadan sonraki toplu işi almadan önce mevcut toplu işteki tüm mesajları onaylamalıdır (ACK). Broker, yeniden deneme zaman aşımından önce onay almazsa onaylanmamış mesajı yeniden iletir.

  3. Uzun oylama: Kullanılabilir mesaj yoksa broker isteği belirtilen oylama süresi boyunca (en fazla 30 saniye) bekletir ve bir mesaj geldiğinde hemen yanıt verir.

Kullanım notları

  • Tek tür konular: Her konu yalnızca bir mesaj türünü destekler. Aynı konuda sıralı mesajları normal mesajlarla karıştırmayın.

  • Katı sıra için tek üretici: Göreceli sıralama gerektiren tüm mesajları tek bir iş parçacığındaki tek bir üreticiden gönderin. Birden çok üretici veya eşzamanlı iş parçacığı kullanmak sıralama garantisini bozar.

  • Parçalama anahtarı tasarımı: İlgili mesajları gruplayan ancak sıcak parçalar oluşturmayan bir parçalama anahtarı seçin. Örneğin, tek bir parçada çok fazla mesaj yoğunlaşmasına neden olabilecek bir müşteri kimliği yerine, bir siparişe ait tüm olayları sıralı tutmak için bir sipariş kimliği kullanın.

  • Hızlı onaylama: Gecikmeli onaylama, tüm parça için sonraki mesaj teslimatlarını engeller. Her toplu işi mümkün olduğunca hızlı şekilde işleyin ve onaylayın.

  • Alındı tanıtıcısının sona ermesi: Her mesaj alındı tanıtıcısının benzersiz bir zaman damgası vardır. Tanıtıcı onaylamadan önce sona ererse onaylama başarısız olur ve broker mesajı yeniden iletir.

Ayrıca bkz.

  • Sıralı mesajlar: Sıralama garantileri, sıralama türleri ve ayrıntılı kavramlar

  • Kaynak oluşturma: Konsolda örnekleri, konuları ve tüketici gruplarını kurma