NoSQL hesapları için API ile Azure Cosmos DB Async Java SDK v2 kullanırken karşılaşılan sorunları giderme

UYGULANANLAR: NoSQL

Önemli

Bu, Azure Cosmos DB için en son Java SDK'sı değildir ! Projenizi Azure Cosmos DB Java SDK v4'e yükseltmeniz ve ardından Azure Cosmos DB Java SDK v4 sorun giderme kılavuzunu okumanız gerekir. Yükseltmek için Azure Cosmos DB Java SDK v4'e geçiş kılavuzu ve Reactor vs RxJava kılavuzundaki yönergeleri izleyin.

Bu makalede yalnızca Azure Cosmos DB Async Java SDK v2 ile ilgili sorun giderme işlemleri yer alır. Daha fazla bilgi için bkz. Azure Cosmos DB Async Java SDK v2 Sürüm Notları, Maven deposu ve performans ipuçları .

Önemli

31 Ağustos 2024'te Azure Cosmos DB Zaman Uyumsuz Java SDK'sı v2.x kullanımdan kaldırılacak; SDK ve SDK kullanan tüm uygulamalar çalışmaya devam eder; Azure Cosmos DB, bu SDK için daha fazla bakım ve destek sağlamayı durduracaktır. Azure Cosmos DB Java SDK v4'e geçiş yapmak için yukarıdaki yönergelerin izlenmesini öneririz.

Bu makalede NoSQL için Azure Cosmos DB hesaplarıyla Java Async SDK'sını kullanırken karşılaşılan yaygın sorunlar, geçici çözümler, tanılama adımları ve araçlar ele alınıyor. Java Async SDK'sı, NoSQL için Azure Cosmos DB'ye erişmek için istemci tarafı mantıksal gösterimi sağlar. Bu makalede, sorunla karşılaştığınızda size yardımcı olacak araçlar ve yaklaşımlar açıklanır.

Şu listeyle başlayın:

Yaygın sorunlar ve geçici çözümler

Ağ sorunları, Netty okuma zaman aşımı hatası, düşük aktarım hızı, yüksek gecikme süresi

Genel öneriler

  • Uygulamanın Azure Cosmos DB hesabınızla aynı bölgede çalıştığından emin olun.
  • Uygulamanın çalıştığı konakta CPU kullanımını denetleyin. CPU kullanımı yüzde 90 veya daha fazlaysa uygulamanızı daha yüksek yapılandırmaya sahip bir konakta çalıştırın. Veya yükü daha fazla makineye dağıtabilirsiniz.

Bağlan azaltma

Bağlan azaltma, konak makinedeki bağlantı sınırı veya Azure SNAT (PAT) bağlantı noktası tükenmesi nedeniyle oluşabilir.

Konak makinede Bağlan ion sınırı

Red Hat gibi bazı Linux sistemlerinin toplam açık dosya sayısı üst sınırı vardır. Linux'taki yuvalar dosya olarak uygulandığından, bu sayı toplam bağlantı sayısını da sınırlar. Aşağıdaki komutu çalıştırın.

ulimit -a

"Nofile" olarak tanımlanan izin verilen en fazla açık dosya sayısı, bağlantı havuzu boyutunuzun en az iki katı olmalıdır. Daha fazla bilgi için bkz . Performans ipuçları.

Azure SNAT (PAT) bağlantı noktası tükenmesi

Uygulamanız azure Sanal Makineler genel IP adresi olmadan dağıtılıyorsa, varsayılan olarak Azure SNAT bağlantı noktaları VM'nizin dışındaki herhangi bir uç noktaya bağlantı kurar. VM'den Azure Cosmos DB uç noktasına izin verilen bağlantı sayısı, Azure SNAT yapılandırmasıyla sınırlıdır.

Azure SNAT bağlantı noktaları yalnızca VM'nizin özel ip adresi olduğunda ve VM'den bir işlem genel IP adresine bağlanmaya çalıştığında kullanılır. Azure SNAT sınırlamasını önlemeye yönelik iki geçici çözüm vardır:

  • Azure Cosmos DB hizmet uç noktanızı Azure Sanal Makineler sanal ağınızın alt ağına ekleyin. Daha fazla bilgi için bkz. Azure Sanal Ağ hizmet uç noktaları.

    Hizmet uç noktası etkinleştirildiğinde, istekler artık genel IP'den Azure Cosmos DB'ye gönderilmez. Bunun yerine sanal ağ ve alt ağ kimliği gönderilir. Bu değişiklik, yalnızca genel IP'lere izin veriliyorsa güvenlik duvarının düşmesine neden olabilir. Güvenlik duvarı kullanıyorsanız, hizmet uç noktasını etkinleştirdiğinizde Sanal Ağ ACL'leri kullanarak güvenlik duvarına bir alt ağ ekleyin.

  • Azure VM'nize genel IP atayın.

Hizmete ulaşılamıyor - güvenlik duvarı

ConnectTimeoutException SDK'nın hizmete ulaşamadığını gösterir. Doğrudan modu kullanırken aşağıdakine benzer bir hata alabilirsiniz:

GoneException{error=null, resourceAddress='https://cdb-ms-prod-westus-fd4.documents.azure.com:14940/apps/e41242a5-2d71-5acb-2e00-5e5f744b12de/services/d8aa21a5-340b-21d4-b1a2-4a5333e7ed8a/partitions/ed028254-b613-4c2a-bf3c-14bd5eb64500/replicas/131298754052060051p//', statusCode=410, message=Message: The requested resource is no longer available at the server., getCauseInfo=[class: class io.netty.channel.ConnectTimeoutException, message: connection timed out: cdb-ms-prod-westus-fd4.documents.azure.com/101.13.12.5:14940]

Uygulama makinenizde çalışan bir güvenlik duvarı varsa doğrudan mod için gerekli olan 10.000 ile 20.000 arasındaki bağlantı noktalarını açın. Ayrıca bir konak makinede Bağlan ion sınırını izleyin.

HTTP proxy'si

HTTP ara sunucusu kullanıyorsanız, SDK'da ConnectionPolicyyapılandırılan bağlantı sayısını destekleyebilendiğinden emin olun. Aksi takdirde bağlantı sorunlarıyla karşılaşırsınız.

Geçersiz kodlama düzeni: Netty GÇ iş parçacığını engelleme

SDK, Azure Cosmos DB ile iletişim kurmak için Netty GÇ kitaplığını kullanır. SDK zaman uyumsuz API'lere sahiptir ve Netty'nin engelleyici olmayan GÇ API'lerini kullanır. SDK'nın GÇ çalışması GÇ Netty iş parçacıklarında gerçekleştirilir. GÇ Netty iş parçacığı sayısı, uygulama makinesinin CPU çekirdek sayısıyla aynı olacak şekilde yapılandırılır.

Netty GÇ iş parçacıklarının yalnızca engelleyici olmayan Netty GÇ işleri için kullanılması amaçlanıyor. SDK, Uygulamanın koduna Netty GÇ iş parçacıklarından birinde API çağırma sonucunu döndürür. Uygulama, Netty iş parçacığında sonuçları aldıktan sonra uzun süreli bir işlem gerçekleştirirse, SDK'nın iç GÇ işini gerçekleştirmek için yeterli GÇ iş parçacığı olmayabilir. Bu tür uygulama kodlaması düşük aktarım hızına, yüksek gecikme süresine ve io.netty.handler.timeout.ReadTimeoutException hatalara neden olabilir. Geçici çözüm, işlemin zaman aldığını bildiğinizde iş parçacığını değiştirmektir.

Örneğin, aşağıdaki kod parçacığına göz atın. Netty iş parçacığında birkaç milisaniyeden uzun süren uzun süreli çalışmalar gerçekleştirebilirsiniz. Öyleyse, sonunda GÇ işini işlemek için Netty GÇ iş parçacığının mevcut olmadığı bir duruma geçebilirsiniz. Sonuç olarak ReadTimeoutException hatası alırsınız.

Zaman uyumsuz Java SDK V2 (Maven com.microsoft.azure::azure-cosmosdb)

@Test
public void badCodeWithReadTimeoutException() throws Exception {
    int requestTimeoutInSeconds = 10;

    ConnectionPolicy policy = new ConnectionPolicy();
    policy.setRequestTimeoutInMillis(requestTimeoutInSeconds * 1000);

    AsyncDocumentClient testClient = new AsyncDocumentClient.Builder()
            .withServiceEndpoint(TestConfigurations.HOST)
            .withMasterKeyOrResourceToken(TestConfigurations.MASTER_KEY)
            .withConnectionPolicy(policy)
            .build();

    int numberOfCpuCores = Runtime.getRuntime().availableProcessors();
    int numberOfConcurrentWork = numberOfCpuCores + 1;
    CountDownLatch latch = new CountDownLatch(numberOfConcurrentWork);
    AtomicInteger failureCount = new AtomicInteger();

    for (int i = 0; i < numberOfConcurrentWork; i++) {
        Document docDefinition = getDocumentDefinition();
        Observable<ResourceResponse<Document>> createObservable = testClient
                .createDocument(getCollectionLink(), docDefinition, null, false);
        createObservable.subscribe(r -> {
                    try {
                        // Time-consuming work is, for example,
                        // writing to a file, computationally heavy work, or just sleep.
                        // Basically, it's anything that takes more than a few milliseconds.
                        // Doing such operations on the IO Netty thread
                        // without a proper scheduler will cause problems.
                        // The subscriber will get a ReadTimeoutException failure.
                        TimeUnit.SECONDS.sleep(2 * requestTimeoutInSeconds);
                    } catch (Exception e) {
                    }
                },

                exception -> {
                    //It will be io.netty.handler.timeout.ReadTimeoutException.
                    exception.printStackTrace();
                    failureCount.incrementAndGet();
                    latch.countDown();
                },
                () -> {
                    latch.countDown();
                });
    }

    latch.await();
    assertThat(failureCount.get()).isGreaterThan(0);
}

Geçici çözüm, üzerinde zaman alan iş parçacığını değiştirmektir. Uygulamanız için zamanlayıcının tek bir örneğini tanımlayın.

Zaman uyumsuz Java SDK V2 (Maven com.microsoft.azure::azure-cosmosdb)

// Have a singleton instance of an executor and a scheduler.
ExecutorService ex  = Executors.newFixedThreadPool(30);
Scheduler customScheduler = rx.schedulers.Schedulers.from(ex);

İşlem açısından ağır iş veya GÇ'yi engelleme gibi zaman alan işler yapmanız gerekebilir. Bu durumda iş parçacığını API'yi kullanarak sizin customScheduler tarafınızdan sağlanan bir çalışana .observeOn(customScheduler) geçirin.

Zaman uyumsuz Java SDK V2 (Maven com.microsoft.azure::azure-cosmosdb)

Observable<ResourceResponse<Document>> createObservable = client
        .createDocument(getCollectionLink(), docDefinition, null, false);

createObservable
        .observeOn(customScheduler) // Switches the thread.
        .subscribe(
            // ...
        );

kullanarak observeOn(customScheduler)Netty GÇ iş parçacığını serbest bırakır ve özel zamanlayıcı tarafından sağlanan kendi özel iş parçacığınıza geçersiniz. Bu değişiklik sorunu çözer. Artık başarısızlıkla sonuçlanmayacaksınız io.netty.handler.timeout.ReadTimeoutException .

Bağlan havuzu tükenmiş sorunu

PoolExhaustedException bir istemci tarafı hatasıdır. Bu hata, uygulama iş yükünüzün SDK bağlantı havuzunun hizmetlerinden daha yüksek olduğunu gösterir. Bağlantı havuzu boyutunu artırın veya yükü birden çok uygulamada dağıtın.

İstek oranı fazla yüksek

Bu hata, sunucu tarafı hatasıdır. Sağlanan aktarım hızınızı kullandığınızı gösterir. Daha sonra yeniden deneyin. Bu hatayı sık sık alırsanız, koleksiyon aktarım hızındaki artışı göz önünde bulundurun.

Azure Cosmos DB Öykünücüsü'ne bağlanma hatası

Azure Cosmos DB Öykünücüsü HTTPS sertifikası otomatik olarak imzalanır. SDK'nın öykünücüyle çalışması için öykünücü sertifikasını bir Java TrustStore'na aktarın. Daha fazla bilgi için bkz . Azure Cosmos DB Öykünücüsü sertifikalarını dışarı aktarma.

Bağımlılık Çakışması Sorunları

Exception in thread "main" java.lang.NoSuchMethodError: rx.Observable.toSingle()Lrx/Single;

Yukarıdaki özel durum, RxJava lib'in eski bir sürümüne (örneğin, 1.2.2) bağımlılığınız olduğunu gösterir. SDK'mız, RxJava'nın önceki sürümlerinde kullanılamayan API'lere sahip RxJava 1.3.8'i kullanır.

Bu tür sorunların geçici çözümü, RxJava-1.2.2'de başka hangi bağımlılığın getireceğini belirlemek ve RxJava-1.2.2'deki geçişli bağımlılığı dışlamak ve CosmosDB SDK'sının daha yeni sürümü getirmesine izin vermektir.

RxJava-1.2.2'de hangi kitaplığın getirebileceğini belirlemek için proje pom.xml dosyanızın yanında aşağıdaki komutu çalıştırın:

mvn dependency:tree

Daha fazla bilgi için maven bağımlılık ağacı kılavuzuna bakın.

RxJava-1.2.2'nin projenizin diğer bağımlılığının geçişli bağımlılığı olduğunu belirledikten sonra, pom dosyanızdaki bu lib'e bağımlılığı değiştirebilir ve RxJava geçişli bağımlılığını hariç tutabilirsiniz:

<dependency>
  <groupId>${groupid-of-lib-which-brings-in-rxjava1.2.2}</groupId>
  <artifactId>${artifactId-of-lib-which-brings-in-rxjava1.2.2}</artifactId>
  <version>${version-of-lib-which-brings-in-rxjava1.2.2}</version>
  <exclusions>
    <exclusion>
      <groupId>io.reactivex</groupId>
      <artifactId>rxjava</artifactId>
    </exclusion>
  </exclusions>
</dependency>

Daha fazla bilgi için geçişli bağımlılıkları dışlama kılavuzuna bakın.

İstemci SDK günlüğünü etkinleştirme

Java Async SDK'sı, log4j ve logback gibi popüler günlük çerçevelerinde oturum açmayı destekleyen günlüğe kaydetme cephesi olarak SLF4j kullanır.

Örneğin günlük çerçevesi olarak log4j kullanmak istiyorsanız Java sınıf yolunuzda aşağıdaki kitaplıkları ekleyin.

<dependency>
  <groupId>org.slf4j</groupId>
  <artifactId>slf4j-log4j12</artifactId>
  <version>${slf4j.version}</version>
</dependency>
<dependency>
  <groupId>log4j</groupId>
  <artifactId>log4j</artifactId>
  <version>${log4j.version}</version>
</dependency>

Ayrıca log4j yapılandırması da ekleyin.

# this is a sample log4j configuration

# Set root logger level to DEBUG and its only appender to A1.
log4j.rootLogger=INFO, A1

log4j.category.com.microsoft.azure.cosmosdb=DEBUG
#log4j.category.io.netty=INFO
#log4j.category.io.reactivex=INFO
# A1 is set to be a ConsoleAppender.
log4j.appender.A1=org.apache.log4j.ConsoleAppender

# A1 uses PatternLayout.
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%d %5X{pid} [%t] %-5p %c - %m%n

Daha fazla bilgi için sfl4j günlüğe kaydetme kılavuzuna bakın.

İşletim sistemi ağ istatistikleri

ve CLOSE_WAITgibi ESTABLISHED durumlarda kaç bağlantı olduğunu öğrenmek için netstat komutunu çalıştırın.

Linux'ta aşağıdaki komutu çalıştırabilirsiniz.

netstat -nap

Sonucu yalnızca Azure Cosmos DB uç noktasına yönelik bağlantılara göre filtreleyin.

Durumdaki Azure Cosmos DB uç noktasına ESTABLISHED bağlantı sayısı, yapılandırılan bağlantı havuzu boyutunuzdan büyük olamaz.

Azure Cosmos DB uç noktasına yapılan birçok bağlantı şu durumda CLOSE_WAIT olabilir. 1000'den fazla olabilir. Yüksek olan bir sayı, bağlantıların hızlı bir şekilde kurulduğunu ve kesildiğini gösterir. Bu durum sorunlara neden olabilir. Daha fazla bilgi için Yaygın sorunlar ve geçici çözümler bölümüne bakın.