Tüm Ürünler
Search
Belge Merkezi

ApsaraMQ for RocketMQ:Ordered messages

Son Güncelleme:Oct 04, 2026

Sıralı mesajlar, tüketicilerin mesajları tam olarak gönderildikleri sırayla işlemesine olanak tanır. ApsaraMQ for RocketMQ, sıralamayı kapsamak için mesaj gruplarını kullanır: aynı gruptaki mesajlar her zaman ardışık olarak iletilirken, farklı gruplardaki mesajlar bağımsız olarak işlenir.

Kullanım senaryoları

Aşağı akış sistemlerinin olayları, yukarı akışta gerçekleştiği tam sırayla işlemesi gerektiğinde sıralı mesajları kullanın:

  • Alım-satım eşleştirme -- Menkul kıymet ticaretinde, birden fazla teklif aynı fiyata sahip olduğunda ilk teklif ilk işlem kuralı geçerlidir. Sipariş işleme sistemi, teklifleri verildikleri tam sırayla ele almalıdır.

    Trade matchmaking

  • Artımlı veri senkronizasyonu -- Veritabanı değişikliklerini (eklemeler, güncellemeler, silmeler) bir mesaj kuyruğu aracılığıyla bir arama sistemine çoğaltırken, işlemler orijinal sırayla yeniden oynatılmalıdır. Sıra dışı yeniden oynatma tutarsız bir duruma yol açar.

    Normal message -- out-of-order risk

    Ordered messages -- consistent replay

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

Uçtan uca mesaj sıralaması iki bölümden oluşur: üretim sırası (gönderen taraf) ve tüketim sırası (alan taraf). Katı first in, first out (FIFO) işleme için her ikisinin de sağlanması gerekir.

Üretim sırası

Üretim sırasını garanti altına almak için aşağıdaki üç koşulu da karşılayın:

  1. Aynı mesaj grubu -- Birbirine göre sıralanması gereken tüm mesajlar için aynı mesaj grubunu ayarlayın. Farklı gruplardaki mesajların arasında herhangi bir sıralama ilişkisi yoktur.

  2. Tek üretici -- İlgili tüm mesajları tek bir üreticiden gönderin. Aynı mesaj grubu kullanılsa bile, farklı sistemlerdeki farklı üreticilerden gelen mesajların kesin bir sırası yoktur.

  3. Seri gönderim -- Mesajları tek bir iş parçacığından ardışık olarak gönderin. Üretici istemcisi çoklu iş parçacığı erişimini destekler ancak farklı iş parçacıklarından paralel olarak gönderilen mesajların kesin bir sırası yoktur.

Bu koşullar karşılandığında, aynı mesaj grubuna sahip mesajlar gönderim sırasına göre aynı kuyrukta depolanır.

Storage logic for ordered messages

Depolama davranışı:

  • Aynı gruptan gelen mesajlar, aynı kuyrukta ardışık olarak depolanır.

  • Farklı gruplardan gelen mesajlar aynı kuyrukta birlikte bulunabilir ancak bunların birbirine göre sırası garanti edilmez.

Yukarıdaki diyagramda, Mesaj Grubu 1 (G1-M1, G1-M2, G1-M3) ve Mesaj Grubu 4 (G4-M1, G4-M2) Kuyruk 1'i paylaşır. ApsaraMQ for RocketMQ, her bir grup içindeki sırayı garanti eder ancak gruplar arasındaki sırayı garanti etmez.

Tüketim sırası

Tüketim sırasını garanti etmek için iki mekanizma birlikte çalışır:

  1. İletim sırası -- SDK ve sunucu protokolü, mesajları depolama sırasına göre iletir. Al-işle-onayla desenini sıkı bir şekilde izleyin. Eşzamanlı olmayan işleme, sıralama garantisini bozabilir.

    Önemli

    PushConsumer ile mesajlar, depolama sırasına göre tek tek iletilir. SimpleConsumer ile tek bir çekmede birden fazla mesaj gelebilir; uygulamanız bunları ardışık olarak işlemeli ve aynı grup için tekrar receive çağrısı yapmadan önce her birini onaylamalıdır. Ayrıntılar için bkz. Tüketici türleri.

  2. Sınırlı yeniden denemeler -- Sıralı bir mesaj maksimum yeniden deneme sayısından sonra başarısız olursa, sonraki mesajların engellenmemesi için atlanır. Tüm grubu engelleme riski ile güvenilirlik arasında denge kuran bir yeniden deneme sayısı seçin. Bir mesaj grubu içindeki yeniden denemeler:

    • Sıralama garantisini bozmaz.

    • Diğer mesaj gruplarındaki mesajları etkilemez.

    • Geçerli mesaj çözümlenene kadar aynı gruptaki sonraki mesajları engeller.

    Önemli

    Başarısız bir sıralı mesaj yeniden denenirken, aynı gruptaki sonraki mesajlar engellenir. Bu mesajlar yalnızca geçerli mesaj başarılı olduktan veya yeniden denemelerini tükettikten sonra iletilir.

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

Katı FIFO, hem üretim hem de tüketim sırası gerektirir. Ancak her tüketicinin sıralı iletime ihtiyacı yoktur. Aktarım hızı ve sıralama gereksinimlerine göre karıştırıp eşleştirin:

Üretim sırası Tüketim sırası Sonuç
Mesaj grubu ayarlandı; seri gönderim Sıralı Her mesaj grubu içinde katı FIFO
Mesaj grubu ayarlandı; seri gönderim Eşzamanlı En iyi çaba kronolojik sıra; daha yüksek aktarım hızı
Mesaj grubu yok; sırasız gönderim Sıralı Kuyruk düzeyinde katı sıralama (depolama sırasıyla eşleşir, gönderim sırasıyla değil)
Mesaj grubu yok; sırasız gönderim Eşzamanlı En iyi çaba kronolojik sıra

Mesaj yaşam döngüsü

Sıralı bir mesaj beş durumdan geçer:

Message lifecycle

  1. Başlatıldı -- Üretici mesajı oluşturur ve göndermeye hazırlanır.

  2. Hazır -- Mesaj aracıya ulaşır ve tüketiciler tarafından görünür hale gelir.

  3. Aktif -- Bir tüketici mesajı alır ve işler. Aracı, zaman aşımı içinde herhangi bir onay almazsa iletimi yeniden dener. Ayrıntılar için bkz. Tüketim yeniden denemesi.

  4. Onaylandı -- Tüketici sonucu taahhüt eder. Varsayılan olarak, ApsaraMQ for RocketMQ tüm mesajları saklar. Aracı, mesajı tüketildi olarak işaretler ancak hemen silmez.

  5. Silindi -- Saklama süresi dolduktan veya depolama alanı azaldıktan sonra, aracı en eski mesajları yuvarlak temelli siler. Silme işleminden önce mesajlar yeniden tüketilebilir. Ayrıntılar için bkz. Mesaj depolama ve temizleme.

Önemli
  • Yeniden denenmiş bir mesaj, yeni bir mesaj olarak değerlendirilir. Orijinal mesajın yaşam döngüsü sona erer.

  • Sıralı bir mesaj yeniden denenirken, aynı gruptaki sonraki mesajlar, geçerli mesaj başarılı olana kadar engellenir.

Sınırlamalar

  • Sıralı mesajlar yalnızca MessageType değeri FIFO olarak ayarlanmış konulara gönderilebilir. Mesaj türü, konu türüyle eşleşmelidir.

Önemli

Bir tüketici grubu sıralı iletim için ayarlanırsa, bu grup tarafından tüketilen tüm mesajlar gerçek türlerinden bağımsız olarak sıralı mesajlar olarak faturalandırılır. Katı sıralama gerekmiyorsa, maliyetleri azaltmak için grubu eşzamanlı iletim olarak ayarlayın.

Ön koşullar

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

  • MessageType değeri FIFO olarak ayarlanmış bir konu, ApsaraMQ for RocketMQ konsolu içinde oluşturuldu

  • Sıralı iletim için yapılandırılmış bir tüketici grubu (yalnızca sıralı tüketime ihtiyacınız varsa gereklidir)

  • Projenizde kurulu olan RocketMQ 5.x gRPC SDK

Önemli

Sıralı mesajlar yalnızca MessageType değeri FIFO olarak ayarlanmış konulara gönderilebilir. Sıralı iletim moduna ayarlanmamış bir tüketici grubu, mesajları eşzamanlı olarak iletir. Herhangi bir kod yazmadan önce hem konu türünü hem de tüketici grubu iletim modunu doğrulayın.

Tüketim eşzamanlılığını optimize edin

RocketMQ 5.x gRPC SDK ile PushConsumer, aynı MessageQueue'deki mesajları mesaj gruplarına göre farklı iş parçacıklarına dağıtabilir. Mesaj grubu değerleriniz ne kadar çeşitli olursa, aktarım hızı kazancı o kadar büyük olur.

Desteklenen SDK sürümleri:

SDK Minimum sürüm
Java 5.0.8
C++ 5.0.3
Diğer SDK'lar Desteklenmiyor

Sıralı mesajları gönderin ve tüketin

Sıralı mesajlar, her gönderim çağrısında bir mesaj grubu gerektirir. Mesaj gruplarını işletmenizin izin verdiği en ince granülerlikle tasarlayın; örneğin, sipariş kimliği veya kullanıcı kimliği kullanın. Bu, varlık başına sıralamayı etkinleştirirken varlıklar arasındaki paralelliği en üst düzeye çıkarır.

Aşağıdaki tüm örnekler Java kullanır. Diğer dillerdeki eksiksiz SDK örnekleri için bkz. RocketMQ 5.x gRPC SDK.

Örnek kod

Sıralı mesajları gönderin

import org.apache.rocketmq.client.apis.*;
import org.apache.rocketmq.client.apis.message.Message;
import org.apache.rocketmq.client.apis.producer.Producer;
import org.apache.rocketmq.client.apis.producer.SendReceipt;

public class ProducerExample {
    public static void main(String[] args) throws ClientException {
        // Instance endpoint. Get it from the Endpoints tab on the instance details page.
        // Use the VPC endpoint for access from ECS over the internal network.
        // Use the public endpoint for access from a local machine or on-premises data center.
        String endpoints = "<your-endpoint>";
        // Topic name. Create the topic in the console first.
        String topic = "<your-fifo-topic>";
        ClientServiceProvider provider = ClientServiceProvider.loadService();
        ClientConfigurationBuilder builder = ClientConfiguration.newBuilder().setEndpoints(endpoints);
        // For public network access, set the instance username and password.
        // Get them from the Intelligent Authentication tab on the Access Control page.
        // For internal network access from ECS, skip this -- the server authenticates via VPC.
        // For Serverless instances, set credentials for public access.
        // If authentication-free internal access is enabled, skip this for internal access.
        // builder.setCredentialProvider(new StaticSessionCredentialsProvider("<instance-username>", "<instance-password>"));
        ClientConfiguration configuration = builder.build();
        Producer producer = provider.newProducerBuilder()
                .setTopics(topic)
                .setClientConfiguration(configuration)
                .build();
        // Build an ordered message with a message group.
        Message message = provider.newMessageBuilder()
                .setTopic(topic)
                .setKeys("messageKey")         // Message key for lookup
                .setTag("messageTag")          // Tag for consumer-side filtering
                .setMessageGroup("fifoGroup001") // Message group -- keep values discrete to avoid hot spots
                .setBody("messageBody".getBytes())
                .build();
        try {
            SendReceipt sendReceipt = producer.send(message);
            System.out.println(sendReceipt.getMessageId());
        } catch (ClientException e) {
            e.printStackTrace();
        }
    }
}

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

Yer Tutucu Açıklama Örnek
<your-endpoint> Konsoldan alınan örnek uç noktası rmq-cn-xxx.cn-hangzhou.rmq.aliyuncs.com:8080
<your-fifo-topic> FIFO konu adı order-events
<instance-username> Örnek kullanıcı adı (yalnızca genel erişim) LTAI5tXxx
<instance-password> Örnek parolası (yalnızca genel erişim) xXxXxXx

PushConsumer ile tüketin

PushConsumer, sıralı mesajları depolama sırasına göre tek tek iletir. Tüketiciyi başlatmadan önce konsolda tüketici grubunu sıralı iletim moduna ayarlayın. Aksi takdirde, mesajlar eşzamanlı olarak iletilir.

import org.apache.rocketmq.client.apis.*;
import org.apache.rocketmq.client.apis.consumer.ConsumeResult;
import org.apache.rocketmq.client.apis.consumer.FilterExpression;
import org.apache.rocketmq.client.apis.consumer.FilterExpressionType;
import org.apache.rocketmq.client.apis.consumer.PushConsumer;
import org.apache.rocketmq.shaded.org.slf4j.Logger;
import org.apache.rocketmq.shaded.org.slf4j.LoggerFactory;

import java.io.IOException;
import java.util.Collections;

public class PushConsumerExample {
    private static final Logger LOGGER = LoggerFactory.getLogger(PushConsumerExample.class);

    private PushConsumerExample() {
    }

    public static void main(String[] args) throws ClientException, IOException, InterruptedException {
        // Instance endpoint. Get it from the Endpoints tab on the instance details page.
        String endpoints = "<your-endpoint>";
        // Topic and consumer group. Create both in the console first.
        String topic = "<your-fifo-topic>";
        String consumerGroup = "<your-consumer-group>";
        final ClientServiceProvider provider = ClientServiceProvider.loadService();
        ClientConfigurationBuilder builder = ClientConfiguration.newBuilder().setEndpoints(endpoints);
        // For public network access, set credentials.
        // builder.setCredentialProvider(new StaticSessionCredentialsProvider("<instance-username>", "<instance-password>"));
        ClientConfiguration clientConfiguration = builder.build();
        // Subscribe to all tags.
        String tag = "*";
        FilterExpression filterExpression = new FilterExpression(tag, FilterExpressionType.TAG);
        PushConsumer pushConsumer = provider.newPushConsumerBuilder()
                .setClientConfiguration(clientConfiguration)
                .setConsumerGroup(consumerGroup)
                .setSubscriptionExpressions(Collections.singletonMap(topic, filterExpression))
                .setMessageListener(messageView -> {
                    // Process the message and return the result.
                    System.out.println("Consume Message: " + messageView);
                    return ConsumeResult.SUCCESS;
                })
                .build();
        Thread.sleep(Long.MAX_VALUE);
        // Close the consumer when no longer needed.
        // pushConsumer.close();
    }
}

SimpleConsumer ile tüketin

SimpleConsumer, mesajları toplu halde çeker. Her bir toplamdaki mesajları ardışık olarak işleyin ve her birini ayrı ayrı onaylayın.

Önemli

Aynı mesaj grubundaki mesajlar için, önceki bir mesaj onaylanmadıysa tekrar receive çağrısı yapmak, o gruptan sonraki mesajları döndürmez. Bu kilitleme mekanizması, sıra dışı işlemeyi önler. Diğer mesaj gruplarından gelen mesajlar etkilenmez ve yine de eşzamanlı olarak alınabilir.

import org.apache.rocketmq.client.apis.ClientConfiguration;
import org.apache.rocketmq.client.apis.ClientConfigurationBuilder;
import org.apache.rocketmq.client.apis.ClientException;
import org.apache.rocketmq.client.apis.ClientServiceProvider;
import org.apache.rocketmq.client.apis.consumer.FilterExpression;
import org.apache.rocketmq.client.apis.consumer.FilterExpressionType;
import org.apache.rocketmq.client.apis.consumer.SimpleConsumer;
import org.apache.rocketmq.client.apis.message.MessageView;
import org.apache.rocketmq.shaded.org.slf4j.Logger;
import org.apache.rocketmq.shaded.org.slf4j.LoggerFactory;

import java.io.IOException;
import java.time.Duration;
import java.util.Collections;
import java.util.List;

public class SimpleConsumerExample {
    private static final Logger LOGGER = LoggerFactory.getLogger(SimpleConsumerExample.class);

    private SimpleConsumerExample() {
    }

    public static void main(String[] args) throws ClientException, IOException {
        // Instance endpoint. Get it from the Endpoints tab on the instance details page.
        String endpoints = "<your-endpoint>";
        // Topic and consumer group. Create both in the console first.
        String topic = "<your-fifo-topic>";
        String consumerGroup = "<your-consumer-group>";
        final ClientServiceProvider provider = ClientServiceProvider.loadService();
        ClientConfigurationBuilder builder = ClientConfiguration.newBuilder().setEndpoints(endpoints);
        // For public network access, set credentials.
        // builder.setCredentialProvider(new StaticSessionCredentialsProvider("<instance-username>", "<instance-password>"));
        ClientConfiguration clientConfiguration = builder.build();

        Duration awaitDuration = Duration.ofSeconds(10);
        // Subscribe to all tags.
        String tag = "*";
        FilterExpression filterExpression = new FilterExpression(tag, FilterExpressionType.TAG);
        SimpleConsumer consumer = provider.newSimpleConsumerBuilder()
                .setClientConfiguration(clientConfiguration)
                .setConsumerGroup(consumerGroup)
                .setAwaitDuration(awaitDuration)                    // Long polling timeout
                .setSubscriptionExpressions(Collections.singletonMap(topic, filterExpression))
                .build();
        int maxMessageNum = 16;
        Duration invisibleDuration = Duration.ofSeconds(10);       // Invisibility window for processing
        // Poll for messages in a loop. Use multiple threads for higher throughput.
        while (true) {
            final List<MessageView> messageViewList = consumer.receive(maxMessageNum, invisibleDuration);
            messageViewList.forEach(messageView -> {
                System.out.println(messageView);
                // Acknowledge each message after processing.
                try {
                    consumer.ack(messageView);
                } catch (ClientException e) {
                    e.printStackTrace();
                }
            });
        }
        // Close the consumer when no longer needed.
        // consumer.close();
    }
}

Tüketim yeniden denemelerini sorun giderin

PushConsumer için sıralı tüketim yeniden denemeleri istemci tarafında gerçekleşir; sunucu yeniden deneme ayrıntılarını günlüğe kaydetmez. Bir mesaj izlemesi failed teslimat sonucu gösteriyorsa, tüketici istemci günlüklerini kontrol edin.

İstemci günlük yolu için bkz. Günlük yapılandırması.

İstemci günlüklerinde şu anahtar sözcükleri arayın:

Message listener raised an exception while consuming messages
Failed to consume fifo message finally, run out of attempt times

En iyi uygulamalar

Mesajları toplu halde değil, seri olarak işleyin

Mesajları tek tek tüketin. Toplu tüketim, sıralamayı bozabilir.

Örnek: Mesajlar 1 -> 2 -> 3 -> 4 sırasıyla gönderilir. Toplu tüketim sırasında, 2 ve 3 numaralı mesajlar birlikte işlenir ve başarısız olur. Yeniden denemede, hem 2 hem de 3 yeniden teslim edilir; ancak 3 numaralı mesaj başka bir denemede zaten başarılı olmuşsa, 2 numaralı mesaj ondan sonra işlenebilir ve bu da sıra dışı tüketime neden olabilir.

Sıcak noktaları önlemek için mesaj gruplarını dağıtın

ApsaraMQ for RocketMQ, hangi sunucu tarafı kuyruğunun her mesajı depolayacağını belirlemek için mesaj grubu değerini kullanır. Aynı gruptaki tüm mesajlar aynı kuyruğa yönlendirilir. Çok sayıda mesajı birkaç grupta yoğunlaştırmak, bu kuyrukları aşırı yükleyerek depolama sıcak noktaları oluşturur ve ölçeklenebilirliği sınırlar.

Mesaj grupları olarak ince taneli anahtarlar kullanın; örneğin, sipariş kimlikleri veya kullanıcı kimlikleri. Mesaj grubu değerleriniz ne kadar çeşitli olursa, mesajlar kuyruklar arasında o kadar eşit dağıtılır. Bu, aynı varlık için mesajların sırasını korurken farklı varlıklar için yükü kuyruklara yayar.