Tüm Ürünler
Search
Belge Merkezi

DataHub:Abonelik oluşturun

Son Güncelleme:Oct 07, 2026

Abonelik özelliği

Bir DataHub konusundan veri tükettiğinizde, uygulama hatası sonrası işlemeye devam etmek için tüketim ofsetlerini kendiniz yönetmeniz gerekir. Bu durum, ilerlemenizi kaydetmenizi ve ofset depolama hizmetinizin yüksek düzeyde kullanılabilir olmasını sağlamanızı gerektirir; bu da uygulamanızın karmaşıklığını artırır. Bu süreci basitleştirmek için DataHub, tüketim ofsetlerinizi sunucu tarafında saklayan bir abonelik hizmeti sunar. Birkaç basit yapılandırma adımı ve minimum kod ile, uygulamanıza şeffaf bir şekilde çalışan yüksek kullanılabilirliğe sahip bir ofset yönetimi hizmetine sahip olursunuz. Abonelik hizmeti ayrıca en az bir kez (at-least-once) tüketim semantiğini destekleyen esnek ofset sıfırlama yetenekleri sağlar. Örneğin, belirli bir zaman aralığındaki verileri etkileyen bir işleme hatası bulursanız ve verileri yeniden tüketmek isterseniz, ofseti ilgili zamana sıfırlayabilirsiniz. Uygulamanız bu değişikliği otomatik olarak algılar ve yeniden başlatmaya gerek kalmadan verileri yeniden işler.

Abonelik oluşturun

Hesabınızın belirtilen projede bir konu için abonelik oluşturma iznine sahip olduğundan emin olun. Ayrıntılar için İzin Kontrolü belgelerine. Aşağıdaki adımları izleyin:

  • Konu sayfasını açın, sağ üst köşedeki + Subscription seçeneğine tıklayın, abonelik ayrıntılarını doldurun ve Create seçeneğine tıklayın.

    • Subscription Application: Bu aboneliği kullanan uygulamanın adı.

    • Description: Aboneliğin ayrıntılı açıklaması.

  • Tüketim Kontrol Noktası altındaki arama düğmesine tıklayarak tüm parçaların tüketim durumunu görüntüleyin.

Kullanım örneği

Abonelik özelliği ofsetleri depolar. Abonelik özelliği DataHub'ın okuma ve yazma işlevlerinden bağımsız olsa da (ayrıntılar için Java SDK belgelerine), verileri okuduktan sonra tüketim ofsetlerini depolamanız gerektiğinde genellikle bu işlevlerle birlikte kullanılır.

// Example of consuming data and committing offsets during the process.
public void offset_consumption(int maxRetry) {
    String endpoint = "<YourEndPoint>";
    String accessId = "<YourAccessId>";
    String accessKey = "<YourAccessKey>";
    String projectName = "<YourProjectName>";
    String topicName = "<YourTopicName>";
    String subId = "<YourSubId>";
    String shardId = "0";
    List<String> shardIds = Arrays.asList(shardId);
    // Create a DatahubClient instance.
    DatahubClient datahubClient = DatahubClientBuilder.newBuilder()
            .setDatahubConfig(
                    new DatahubConfig(endpoint,
                            // Whether to enable binary transfer. This feature is supported by the server since version 2.12.
                            new AliyunAccount(accessId, accessKey), true))
            .build();
    RecordSchema schema = datahubClient.getTopic(projectName, topicName).getRecordSchema();
    OpenSubscriptionSessionResult openSubscriptionSessionResult = datahubClient.openSubscriptionSession(projectName, topicName, subId, shardIds);
    SubscriptionOffset subscriptionOffset = openSubscriptionSessionResult.getOffsets().get(shardId);
    // 1. Get the cursor for the current offset. If the current offset has expired or has never been consumed, get the cursor for the first record within the lifecycle.
    String cursor = "";
    // A sequence number less than 0 indicates that the shard has not been consumed.
    if (subscriptionOffset.getSequence() < 0) {
        // Get the cursor for the first record within the lifecycle.
        cursor = datahubClient.getCursor(projectName, topicName, shardId, CursorType.OLDEST).getCursor();
    } else {
        // Get the cursor for the next record.
        long nextSequence = subscriptionOffset.getSequence() + 1;
        try {
            // Getting a cursor using SEQUENCE may throw a SeekOutOfRangeException, which indicates that the data at the current cursor has expired.
            cursor = datahubClient.getCursor(projectName, topicName, shardId, CursorType.SEQUENCE, nextSequence).getCursor();
        } catch (SeekOutOfRangeException e) {
            // Get the cursor for the first record within the lifecycle.
            cursor = datahubClient.getCursor(projectName, topicName, shardId, CursorType.OLDEST).getCursor();
        }
    }
    // 2. Read records and save the offset. This example demonstrates reading tuple data and committing the offset every 1,000 records.
    long recordCount = 0L;
    // Read 1,000 records at a time.
    int fetchNum = 1000;
    int retryNum = 0;
    int commitNum = 1000;
    while (retryNum < maxRetry) {
        try {
            GetRecordsResult getRecordsResult = datahubClient.getRecords(projectName, topicName, shardId, schema, cursor, fetchNum);
            if (getRecordsResult.getRecordCount() <= 0) {
                // No data. Sleep and try again.
                System.out.println("no data, sleep 1 second");
                Thread.sleep(1000);
                continue;
            }
            for (RecordEntry recordEntry : getRecordsResult.getRecords()) {
                // Process the data.
                TupleRecordData data = (TupleRecordData) recordEntry.getRecordData();
                System.out.println("field1:" + data.getField("field1") + "\t"
                        + "field2:" + data.getField("field2"));
                // After processing the data, update the offset.
                recordCount++;
                subscriptionOffset.setSequence(recordEntry.getSequence());
                subscriptionOffset.setTimestamp(recordEntry.getSystemTime());
                // Commit the offset every 1000 records.
                if (recordCount % commitNum == 0) {
                    // Commit the offset.
                    Map<String, SubscriptionOffset> offsetMap = new HashMap<>();
                    offsetMap.put(shardId, subscriptionOffset);
                    datahubClient.commitSubscriptionOffset(projectName, topicName, subId, offsetMap);
                    System.out.println("commit offset successful");
                }
            }
            cursor = getRecordsResult.getNextCursor();
        } catch (SubscriptionOfflineException | SubscriptionSessionInvalidException e) {
            // Exit. SubscriptionOfflineException: The subscription is offline. SubscriptionSessionInvalidException: Another client is consuming the same subscription.
            e.printStackTrace();
            throw e;
        } catch (SubscriptionOffsetResetException e) {
            // The offset was reset. You need to get the latest version of the SubscriptionOffset.
            SubscriptionOffset offset = datahubClient.getSubscriptionOffset(projectName, topicName, subId, shardIds).getOffsets().get(shardId);
            subscriptionOffset.setVersionId(offset.getVersionId());
            // After an offset is reset, you must get the new cursor. The method you use to get the cursor should match how the offset was reset.
            // If both sequence and timestamp were set during the reset, you can get the cursor by using either SEQUENCE or SYSTEM_TIME.
            // If only the sequence was set, you must use SEQUENCE.
            // If only the timestamp was set, you must use SYSTEM_TIME.
            // As a general rule, try to get the cursor using SEQUENCE first, then SYSTEM_TIME. If both fail, use OLDEST.
            cursor = null;
            if (cursor == null) {
                try {
                    long nextSequence = offset.getSequence() + 1;
                    cursor = datahubClient.getCursor(projectName, topicName, shardId, CursorType.SEQUENCE, nextSequence).getCursor();
                    System.out.println("get cursor successful");
                } catch (DatahubClientException exception) {
                    System.out.println("get cursor by SEQUENCE failed, try to get cursor by SYSTEM_TIME");
                }
            }
            if (cursor == null) {
                try {
                    cursor = datahubClient.getCursor(projectName, topicName, shardId, CursorType.SYSTEM_TIME, offset.getTimestamp()).getCursor();
                    System.out.println("get cursor successful");
                } catch (DatahubClientException exception) {
                    System.out.println("get cursor by SYSTEM_TIME failed, try to get cursor by OLDEST");
                }
            }
            if (cursor == null) {
                try {
                    cursor = datahubClient.getCursor(projectName, topicName, shardId, CursorType.OLDEST).getCursor();
                    System.out.println("get cursor successful");
                } catch (DatahubClientException exception) {
                    System.out.println("get cursor by OLDEST failed");
                    System.out.println("get cursor failed!!");
                    throw e;
                }
            }
        } catch (LimitExceededException e) {
            // Limit exceeded, retry.
            e.printStackTrace();
            retryNum++;
        } catch (DatahubClientException e) {
            // Other error, retry.
            e.printStackTrace();
            retryNum++;
        } catch (Exception e) {
            e.printStackTrace();
            System.exit(-1);
        }
    }
}
  • Uygulama ilk kez başlatıldığında, mevcut en eski kayıttan itibaren veri tüketmeye başlar. Uygulama çalışırken, web konsolundaki abonelik sayfasını yenileyerek parçanın tüketim ofsetinin ilerlediğini görebilirsiniz.

  • Tüketici çalışırken web konsolundaki Reset Checkpoint özelliğini kullanarak ofseti manuel olarak değiştirirseniz, uygulama değişikliği otomatik olarak algılar ve yeni ofsetten tüketmeye devam eder. Bunu yapmak için istemci bir SubscriptionOffsetResetException yakalar ve sunucudan en güncel SubscriptionOffset nesnesini almak için getSubscriptionOffset yöntemini çağırır.

  • Aynı aboneliğin aynı parçasını tüketmek için birden fazla tüketici iş parçacığı veya işlemi aynı anda kullanmayın. Bu durum, ofsetin farklı tüketiciler tarafından üzerine yazılmasına neden olur ve depolanan ofseti tanımsız bir durumda bırakır. Bu senaryoda sunucu bir SubscriptionSessionInvalidException özel durumu oluşturur. Bu özel durumu yakalayın, uygulamadan çıkın ve yinelenen tüketiciler için tasarımınızı kontrol edin.