Tüm Ürünler
Search
Belge Merkezi

ApsaraMQ for RocketMQ:Send and receive ordered messages

Son Güncelleme:Oct 04, 2026

ApsaraMQ for RocketMQ'deki sıralı mesajlar, bir konu veya bölüm içinde katı ilk giren ilk çıkar (FIFO) teslimatı garanti eder. İşleme sırasının iş mantığınızı etkilediği durumlarda sıralı mesajları kullanın; örneğin, belirli bir fiyattaki ilk teklifin kazanması gereken işlem eşleştirme veya ekleme, güncelleme ve silme işlemlerinin sırayla uygulanması gereken veritabanı değişikliği senkronizasyonu gibi senaryolarda bu mesaj türünü tercih edin.

Aşağıdaki C++ örnekleri, HTTP istemci SDK'sı aracılığıyla sıralı mesajların nasıl gönderileceğini ve alınacağını gösterir.

Sıralama nasıl çalışır?

ApsaraMQ for RocketMQ iki sıralama kapsamını destekler:

  • Genel olarak sıralanmış mesajlar -- Bir konudaki tüm mesajlar FIFO düzeninde teslim edilir. Her mesajın sırayla işlenmesi gerektiğinde bu kapsamı kullanın.

  • Bölümlere göre sıralanmış mesajlar -- Mesajlar, parçalama anahtarına göre bölümlere dağıtılır. Her bölüm içinde mesajlar FIFO düzeninde teslim edilir. Yalnızca ilgili mesajların sıralanması gerektiğinde, örneğin sipariş kimliği veya kullanıcı kimliğine göre gruplandırma yaparken daha yüksek aktarım hızı sağlamak için bu kapsamı kullanın.

Parçalama anahtarı, hangi bölümün mesajı alacağını belirler. Aynı parçalama anahtarına sahip mesajlar her zaman aynı bölüme gider ve gönderim sırasına göre tüketilir. Parçalama anahtarı, mesaj anahtarından farklıdır.

Daha fazla bilgi için bkz. Sıralı mesajlar.

Üretim sırası

Broker, tek bir üreticinin veya iş parçacığının mesajları gönderdiği sıraya göre mesaj sırasını belirler. Sıralamayı korumak için:

  • İlgili mesajları tek bir iş parçacığındaki tek bir üreticiden gönderin.

  • Birden çok üretici veya iş parçacığı eşzamanlı olarak gönderim yaparsa broker mesajları varış zamanına göre sıralar; bu sıra, amaçlanan iş sırasından farklı olabilir.

Tüketim sırası

Tüketici, bölümlere göre sıralanmış mesajları bir veya daha fazla bölümden çeker ve her bölümün mesajlarını gönderim sırasına göre işler. Sıralama garantisi uygun onaya bağlıdır:

  • Tüketici, aynı bölümden sonraki toplu işi çekmeden önce bir toplu işteki tüm mesajları onaylamalıdır.

  • Broker, zaman aşımından önce bir mesaj için onay (ACK) almazsa bu mesajı yeniden teslim eder.

  • Her yeniden teslim, benzersiz bir zaman damgası içeren yeni bir makbuz tanıtıcısı oluşturur.

Ön koşullar

Başlamadan önce şunlara sahip olduğunuzdan emin olun:

Sıralı mesaj gönderme

Önemli

Broker, tek bir üreticiden veya iş parçacığından gelen mesajları varış sırasına göre sıralar. Birden çok üretici veya iş parçacığı eşzamanlı olarak gönderim yaparsa broker tarafındaki sıra, iş tarafındaki gönderim sırasından farklı olabilir.

Aşağıdaki yer tutucuları gerçek değerlerinizle değiştirin:

Yer Tutucu Açıklama Nerede Bulunur
${HTTP_ENDPOINT} Örneğinizin HTTP uç noktası ApsaraMQ for RocketMQ konsolunda Instance Details sayfası > HTTP Endpoint
${TOPIC} Konu adı Konsolda oluşturduğunuz konu
${INSTANCE_ID} Örnek Kimliği Konsoldaki Instance Details sayfası. Örneğin ad alanı yoksa boş bir dize olarak ayarlayın
//#include <iostream>
#include <fstream>
#include <time.h>
#include "mq_http_sdk/mq_client.h"

using namespace std;
using namespace mq::http::sdk;

int main() {

    MQClient mqClient(
            // The HTTP endpoint. You can obtain the endpoint in the HTTP Endpoint section of the Instance Details page in the ApsaraMQ for RocketMQ console.
            "${HTTP_ENDPOINT}",
            // Make sure that the environment variables ALIBABA_CLOUD_ACCESS_KEY_ID and ALIBABA_CLOUD_ACCESS_KEY_SECRET are configured.
	          // The AccessKey ID that is used for authentication.
	          System.getenv("ALIBABA_CLOUD_ACCESS_KEY_ID"),
	          // The AccessKey secret that is used for authentication.
	          System.getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET")
            );

    // The topic in which the message is produced. You must create the topic in the ApsaraMQ for RocketMQ console.
    string topic = "${TOPIC}";
    // The ID of the instance to which the topic belongs. You must create the instance in the ApsaraMQ for RocketMQ console.
    // If the instance has a namespace, specify the ID of the instance. If the instance does not have a namespace, set the instanceID parameter to null or an empty string. You can obtain the namespace of the instance on the Instance Details page in the ApsaraMQ for RocketMQ console.
    string instanceId = "${INSTANCE_ID}";

    MQProducerPtr producer;
    if (instanceId == "") {
        producer = mqClient.getProducerRef(topic);
    } else {
        producer = mqClient.getProducerRef(instanceId, topic);
    }

    try {
        // Cyclically send four messages.
        for (int i = 0; i < 8; i++)
        {
            PublishMessageResponse pmResp;
            // The message content.
            TopicMessage pubMsg("Hello, mq!order msg!");
            // The sharding key that is used to distribute ordered messages to a specific partition. Sharding keys can be used to identify partitions. A sharding key is different from a message key.
            pubMsg.setShardingKey(std::to_string(i % 2));
            // The custom attributes of the message.
            pubMsg.putProperty("a",std::to_string(i));
            producer->publishMessage(pubMsg, pmResp);
            cout << "Publish mq message success. Topic is: " << topic
                << ", msgId is:" << pmResp.getMessageId()
                << ", bodyMD5 is:" << pmResp.getMessageBodyMD5() << endl;
        }
    } catch (MQServerException& me) {
        cout << "Request Failed: " + me.GetErrorCode() << ", requestId is:" << me.GetRequestId() << endl;
        return -1;
    } catch (MQExceptionBase& mb) {
        cout << "Request Failed: " + mb.ToString() << endl;
        return -2;
    }

    return 0;
}

Bu örnek, iki parçalama anahtarı (0 ve 1 aracılığıyla i % 2) kullanarak sekiz mesaj gönderir. Aynı parçalama anahtarına sahip mesajlar, gönderim sırasına göre aynı bölüme teslim edilir. putProperty çağrısı, izleme amacıyla her mesaja özel bir nitelik ekler.

Sıralı mesaj alma

Bölüm düzeyinde sıralamayı korumak için standart tüketim yöntemi yerine consumeMessageOrderly yöntemini çağırın. Uzun oylama modunda broker, mesaj mevcut değilse isteği belirtilen süre boyunca açık tutar ve bir mesaj geldiğinde hemen yanıt verir.

Yukarıda listelenen yer tutuculara ek olarak aşağıdakileri de değiştirin:

Yer Tutucu Açıklama Nerede Bulunur
${GROUP_ID} Tüketici grubu kimliği ApsaraMQ for RocketMQ konsolunda oluşturduğunuz tüketici grubu
#include <vector>
#include <fstream>
#include "mq_http_sdk/mq_client.h"

#ifdef _WIN32
#include <windows.h>
#else
#include <unistd.h>
#endif

using namespace std;
using namespace mq::http::sdk;

int main() {

    MQClient mqClient(
            // The HTTP endpoint. You can obtain the endpoint in the HTTP Endpoint section of the Instance Details page in the ApsaraMQ for RocketMQ console.
            "${HTTP_ENDPOINT}",
            // Make sure that the environment variables ALIBABA_CLOUD_ACCESS_KEY_ID and ALIBABA_CLOUD_ACCESS_KEY_SECRET are configured.
	          // The AccessKey ID that is used for authentication.
	          System.getenv("ALIBABA_CLOUD_ACCESS_KEY_ID"),
	          // The AccessKey secret that is used for authentication.
	          System.getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET")
            );

    // The topic in which the message is produced. You must create the topic in the ApsaraMQ for RocketMQ console.
    string topic = "${TOPIC}";
    // The ID of the consumer group that you created in the ApsaraMQ for RocketMQ console.
    string groupId = "${GROUP_ID}";
    // The ID of the instance to which the topic belongs. You must create the instance in the ApsaraMQ for RocketMQ console.
    // If the instance has a namespace, specify the ID of the instance. If the instance does not have a namespace, set the instanceID parameter to null or an empty string. You can obtain the namespace of the instance on the Instance Details page in the ApsaraMQ for RocketMQ console.
    string instanceId = "${INSTANCE_ID}";

    MQConsumerPtr consumer;
    if (instanceId == "") {
        consumer = mqClient.getConsumerRef(topic, groupId);
    } else {
        consumer = mqClient.getConsumerRef(instanceId, topic, groupId, "");
    }

    do {
        try {
            std::vector<Message> messages;
            // Consume messages in long polling mode. The consumer may pull partitionally ordered messages from multiple partitions. The consumer consumes messages from the same partition in the order in which the messages are sent.
            // Assume that a consumer pulls partitionally ordered messages from one partition. If the broker fails to receive an acknowledgement (ACK) for a message from the consumer, the broker delivers the message in the partition to the consumer again.
            // The consumer can consume the next batch of messages from a partition only after all messages that are pulled from the partition in the previous batch are acknowledged as consumed.
            // In long polling mode, if no message in the topic is available for consumption, the request is suspended on the broker for the specified period of time. If a message becomes available for consumption within the specified period of time, the broker immediately sends a response to the consumer. In this example, the value is specified as 3 seconds.
            consumer->consumeMessageOrderly(
                    3, // The maximum number of messages that can be consumed at a time. In this example, the value is specified as 3. The maximum value that you can specify is 16.
                    3, // The duration of a long polling cycle. Unit: seconds. In this example, the value is specified as 3. The maximum value that you can specify is 30.
                    messages
            );
            cout << "Consume: " << messages.size() << " Messages!" << endl;

            // The message consumption logic.
            std::vector<std::string> receiptHandles;
            for (std::vector<Message>::iterator iter = messages.begin();
                    iter != messages.end(); ++iter)
            {
                cout << "MessageId: " << iter->getMessageId()
                    << " PublishTime: " << iter->getPublishTime()
                    << " Tag: " << iter->getMessageTag()
                    << " Body: " << iter->getMessageBody()
                    << " FirstConsumeTime: " << iter->getFirstConsumeTime()
                    << " NextConsumeTime: " << iter->getNextConsumeTime()
                    << " ConsumedTimes: " << iter->getConsumedTimes()
                    << " Properties: " << iter->getPropertiesAsString()
                    << " ShardingKey: " << iter->getShardingKey() << endl;
                receiptHandles.push_back(iter->getReceiptHandle());
            }

            // Obtain an ACK from the consumer.
            // If the broker fails to receive an ACK for a message from the consumer before the period of time that is specified by the Message.NextConsumeTime parameter elapses, the broker delivers the message for consumption again.
            // A unique timestamp is specified for the handle of a message each time the message is consumed.
            AckMessageResponse bdmResp;
            consumer->ackMessage(receiptHandles, bdmResp);
            if (!bdmResp.isSuccess()) {
                // If the handle of a message times out, the broker cannot receive an ACK for the message from the consumer.
                const std::vector<AckMessageFailedItem>& failedItems =
                    bdmResp.getAckMessageFailedItem();
                for (std::vector<AckMessageFailedItem>::const_iterator iter = failedItems.begin();
                        iter != failedItems.end(); ++iter)
                {
                    cout << "AckFailedItem: " << iter->errorCode
                        << "  " << iter->receiptHandle << endl;
                }
            } else {
                cout << "Ack: " << messages.size() << " messages suc!" << endl;
            }
        } catch (MQServerException& me) {
            if (me.GetErrorCode() == "MessageNotExist") {
                cout << "No message to consume! RequestId: " + me.GetRequestId() << endl;
                continue;
            }
            cout << "Request Failed: " + me.GetErrorCode() + ".RequestId: " + me.GetRequestId() << endl;
#ifdef _WIN32
            Sleep(2000);
#else
            usleep(2000 * 1000);
#endif
        } catch (MQExceptionBase& mb) {
            cout << "Request Failed: " + mb.ToString() << endl;
#ifdef _WIN32
            Sleep(2000);
#else
            usleep(2000 * 1000);
#endif
        }

    } while(true);
}

consumeMessageOrderly parametreleri

Parametre Açıklama Aralık
Toplu iş boyutu Çekme başına maksimum mesaj sayısı Maksimum: 16
Uzun oylama süresi Mesaj olmadığında broker'ın isteği beklettiği saniye cinsinden süre Maksimum: 30

Onay davranışı

Her toplu işi işledikten sonra, işlenen tüm mesajların makbuz tanıtıcılarıyla ackMessage yöntemini çağırın.

  • Toplu iş kapısı: Tüketici, mevcut toplu işteki her mesaj onaylanana kadar bir bölümden sonraki toplu işi çekemez.

  • Zaman aşımında yeniden teslim: Broker, NextConsumeTime öncesinde bir ACK almazsa mesajı benzersiz bir zaman damgası içeren yeni bir makbuz tanıtıcısıyla yeniden teslim eder.

  • **MessageNotExist yönetimi:** Bu hata kodu, kullanılabilir mesaj olmadığını gösterir. Örnek, bunu gecikme olmadan oylama döngüsünü sürdürerek ele alır.

  • Hata kurtarma: Diğer özel durumlar durumunda örnek, sık hata döngülerinden kaçınmak için yeniden denemeden önce 2 saniye bekler.

Kullanım notları

  • Sıralama kapsamı başına tek üretici. Göreceli sıralama gerektiren tüm mesajları tek bir iş parçacığındaki tek bir üreticiden gönderin. Çoklu üretici veya çoklu iş parçacığı gönderimleri amaçlanan sırayı bozabilir.

  • Parçalama anahtarlarını doğru granülerlikte tasarlayın. Sipariş kimlikleri veya kullanıcı kimlikleri gibi iş anlamı taşıyan anahtarlar kullanın. Tek bir parçalama anahtarı altında çok fazla mesaj toplamaktan kaçının; bu, bir bölümü aşırı yükler ve aktarım hızını sınırlar.

  • Hızlı onaylayın. Geciken onay, aynı bölümdeki sonraki mesajların tüketimini engeller ve uçtan uca gecikme süresini artırır.

  • Sıralamayı bozmadan hataları yönetin. Mesaj işleme başarısız olursa mesajın zaman aşımına uğramasına ve yeniden teslim edilmesine izin verin; onaylayıp atlamak sıralama garantisini bozar.