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) düzeninde iletir ve tüketir. Aşağıdaki örnek kod, Go için HTTP istemcisi SDK'sı kullanarak sıralı mesajların nasıl gönderileceğini ve tüketileceğini gösterir.

Sıralama türleri

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

Tür Davranış Ne zaman kullanılır
Genel olarak sıralı Bir konudaki tüm mesajlar tek bir FIFO dizisini takip eder. Her mesajın tam gönderim sırasına göre işlenmesi gerektiğinde; örneğin, ardışık komut yürütme senaryolarında.
Bölümlere ayrılmış şekilde sıralı Mesajlar, parçalama anahtarı kullanılarak bölümler arasında dağıtılır. Her bölüm kendi FIFO sırasını korur. Yalnızca aynı mantıksal grubu paylaşan mesajların (örneğin aynı sipariş kimliği veya kullanıcı kimliği) katı sıralamaya ihtiyacı olduğu durumlarda.

Bir parçalama anahtarı, bir mesajın hangi bölüme ait olduğunu belirler. Bu, mesaj anahtarından farklıdır; mesaj anahtarı izleme amacıyla kullanılan bir iş tanımlayıcısıyken parçalama anahtarı sıralamayı kontrol eder.

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

Sıralamanın çalışma şekli

Sıralama, üretici ile tüketicinin koordinasyonuna bağlıdır.

Gönderen taraf: Mesajları göndermek için tek bir üretici ve tek bir iş parçacığı kullanın. Aracı (broker), o üreticiden aldığı mesajların tam sırasını korur.

Tüketen taraf: Mesajları bölüm bölüm çekmek için ConsumeMessageOrderly yöntemini çağırın. Her bölümde, mevcut toplu işteki her mesaj onaylanana kadar sonraki toplu iş teslim edilmez. Aracı, NextConsumeTime son tarihinden önce bir onay almazsa onaylanmamış mesajı yeniden iletir.

Ön koşullar

Örnek kodu çalıştırmadan önce aşağıdaki kurulumları tamamlayın:

Sıralı mesajları gönderme

Önemli

Aracı, tek bir üreticinin veya iş parçacığının mesajları gönderdiği sıraya göre mesaj sırasını belirler. Birden çok üretici veya iş parçacığı eşzamanlı olarak gönderim yaparsa aracıya varış sırası amaçlanan iş sırasından farklı olabilir. Sıralamayı garanti altına almak için tek bir üretici ve tek bir iş parçacığı kullanarak gönderim yapın.

Aşağıdaki kod, bölümlere ayrılmış şekilde sıralı sekiz mesaj gönderir. Parçalama anahtarı i % 2 mesajları iki bölüm arasında dağıtır; bu sayede çift indeksli mesajlar bir bölüme, tek indeksli mesajlar ise diğerine gider.

Kodu çalıştırmadan önce yer tutucuları değiştirin:

Yer Tutucu Açıklama Örnek
${HTTP_ENDPOINT} ApsaraMQ for RocketMQ konsolundaki Instance Details sayfasındaki HTTP uç noktası http://xxx.mqrest.cn-hangzhou.aliyuncs.com
${TOPIC} Konsolda oluşturulan konu OrderedTestTopic
${INSTANCE_ID} Örnek kimliği. Örneğin bir ad alanı varsa kimliği belirtin. Yoksa bunu boş bir dize olarak ayarlayın. Ad alanı bilgileri için Instance Details sayfasını kontrol edin. MQ_INST_xxx
package main

import (
    "fmt"
    "time"
    "strconv"
    "os"

    "github.com/aliyunmq/mq-http-go-sdk"
)

func main() {
    // HTTP endpoint from the Instance Details page in the ApsaraMQ for RocketMQ console.
    endpoint := "${HTTP_ENDPOINT}"
    // Set the ALIBABA_CLOUD_ACCESS_KEY_ID and ALIBABA_CLOUD_ACCESS_KEY_SECRET
    // environment variables before running this code.
    accessKey := os.Getenv("ALIBABA_CLOUD_ACCESS_KEY_ID")
    secretKey := os.Getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET")
    // Topic created in the ApsaraMQ for RocketMQ console.
    topic := "${TOPIC}"
    // Instance ID. If the instance has a namespace, specify the ID.
    // If not, set this to an empty string.
    instanceId := "${INSTANCE_ID}"

    client := mq_http_sdk.NewAliyunMQClient(endpoint, accessKey, secretKey, "")

    mqProducer := client.GetProducer(instanceId, topic)
    // Send 8 messages across 2 partitions.
    for i := 0; i < 8; i++ {
        msg := mq_http_sdk.PublishMessageRequest{
            MessageBody: "hello mq!",
            MessageTag:  "",
            Properties:  map[string]string{},
        }
        msg.MessageKey = "MessageKey"
        msg.Properties["a"] = strconv.Itoa(i)
        // Sharding key determines the partition.
        // Messages with the same sharding key are delivered in FIFO order.
        msg.ShardingKey = strconv.Itoa(i % 2)
        ret, err := mqProducer.PublishMessage(msg)

        if err != nil {
            fmt.Println(err)
            return
        } else {
            fmt.Printf("Publish ---->\n\tMessageId:%s, BodyMD5:%s, \n", ret.MessageId, ret.MessageBodyMD5)
        }
        time.Sleep(time.Duration(100) * time.Millisecond)
    }
}

Sıralı mesajları tüketme

Bu kod, uzun yoklama kullanarak sıralı mesajları tüketir. Tüketici, mesajları bölüm bölüm çeker ve sonraki isteği yapmadan önce her toplu işi onaylar.

Yer tutucuları gerçek değerlerinizle değiştirin. Sıralı mesajları gönderme bölümünde listelenenlere ek olarak aşağıdakileri de belirtin:

Yer Tutucu Açıklama Örnek
${GROUP_ID} ApsaraMQ for RocketMQ konsolunda oluşturulan tüketici grubu GID_OrderedTest
package main

import (
    "fmt"
    "github.com/gogap/errors"
    "strings"
    "time"
    "os"

    "github.com/aliyunmq/mq-http-go-sdk"
)

func main() {
    // HTTP endpoint from the Instance Details page in the ApsaraMQ for RocketMQ console.
    endpoint := "${HTTP_ENDPOINT}"
    // Set the ALIBABA_CLOUD_ACCESS_KEY_ID and ALIBABA_CLOUD_ACCESS_KEY_SECRET
    // environment variables before running this code.
    accessKey := os.Getenv("ALIBABA_CLOUD_ACCESS_KEY_ID")
    secretKey := os.Getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET")
    // Topic created in the ApsaraMQ for RocketMQ console.
    topic := "${TOPIC}"
    // Instance ID. If the instance has a namespace, specify the ID.
    // If not, set this to an empty string.
    instanceId := "${INSTANCE_ID}"
    // Consumer group created in the ApsaraMQ for RocketMQ console.
    groupId := "${GROUP_ID}"

    client := mq_http_sdk.NewAliyunMQClient(endpoint, accessKey, secretKey, "")

    mqConsumer := client.GetConsumer(instanceId, topic, groupId, "")

    for {
        endChan := make(chan int)
        respChan := make(chan mq_http_sdk.ConsumeMessageResponse)
        errChan := make(chan error)
        go func() {
            select {
            case resp := <-respChan:
                {
                    var handles []string
                    fmt.Printf("Consume %d messages---->\n", len(resp.Messages))
                    for _, v := range resp.Messages {
                        handles = append(handles, v.ReceiptHandle)
                        fmt.Printf("\tMessageID: %s, PublishTime: %d, MessageTag: %s\n"+
                            "\tConsumedTimes: %d, FirstConsumeTime: %d, NextConsumeTime: %d\n"+
                            "\tBody: %s\n"+
                            "\tProps: %s\n"+
                            "\tShardingKey: %s\n",
                            v.MessageId, v.PublishTime, v.MessageTag, v.ConsumedTimes,
                            v.FirstConsumeTime, v.NextConsumeTime, v.MessageBody, v.Properties, v.ShardingKey)
                    }

                    // Acknowledge all messages in this batch.
                    // If the broker does not receive an ACK before NextConsumeTime,
                    // it redelivers the message.
                    ackerr := mqConsumer.AckMessage(handles)
                    if ackerr != nil {
                        fmt.Println(ackerr)
                        if errAckItems, ok := ackerr.(errors.ErrCode).Context()["Detail"].([]mq_http_sdk.ErrAckItem); ok {
                           for _, errAckItem := range errAckItems {
                              fmt.Printf("\tErrorHandle:%s, ErrorCode:%s, ErrorMsg:%s\n",
                                 errAckItem.ErrorHandle, errAckItem.ErrorCode, errAckItem.ErrorMsg)
                           }
                        } else {
                           fmt.Println("ack err =", ackerr)
                        }
                        time.Sleep(time.Duration(3) * time.Second)
                    } else {
                        fmt.Printf("Ack ---->\n\t%s\n", handles)
                    }

                    endChan <- 1
                }
            case err := <-errChan:
                {
                    if strings.Contains(err.(errors.ErrCode).Error(), "MessageNotExist") {
                        fmt.Println("\nNo new message, continue!")
                    } else {
                        fmt.Println(err)
                        time.Sleep(time.Duration(3) * time.Second)
                    }
                    endChan <- 1
                }
            case <-time.After(35 * time.Second):
                {
                    fmt.Println("Timeout of consumer message ??")
                    endChan <- 1
                }
            }
        }()

        // The consumer pulls partitionally ordered messages partition by partition.
        // Within each partition, the next batch is delivered only after all messages
        // in the current batch are acknowledged.
        // Long polling: if no message is available, the request is held on the broker
        // for up to the specified polling duration. The network timeout is 35 seconds.
        mqConsumer.ConsumeMessageOrderly(respChan, errChan,
            3, // Max messages per batch (up to 16).
            3, // Long polling duration in seconds (up to 30).
        )
        <-endChan
    }
}

Temel tüketim davranışları

Davranış Ayrıntı
Bölüm düzeyinde sıralama Tüketici aynı anda birden çok bölümden çekim yapabilir ancak her bölümdeki mesajlar her zaman gönderim sırasına göre teslim edilir.
Toplu iş onay kapısı Bir bölümden sonraki toplu iş, önceki toplu işteki her mesaj onaylanana kadar teslim edilmez.
Otomatik yeniden iletme Aracı, NextConsumeTime süresinden önce herhangi bir onay almazsa mesajı yeniden iletir. Her yeniden iletme işlemi, benzersiz bir zaman damgasına sahip yeni bir makbuz tanıtıcısı atar.
Uzun yoklama Mesaj mevcut olmadığında aracı, boş bir yanıt döndürmeden önce belirtilen yoklama süresi (bu örnekte 3 saniye) boyunca isteği bekletir. Ağ zaman aşımı 35 saniyedir.

Sonraki adımlar

  • Sıralı mesajlar: Sıralama türleri, garantiler ve tasarım hususları

  • Go HTTP SDK'sını kullanarak diğer mesaj türlerini gönderme ve alma

  • Ortamı hazırlama: Go geliştirme ortamını kurma