次の方法で共有


NoSQL アカウント用 API で Azure Cosmos DB Async Java SDK v2 を使用する場合の問題のトラブルシューティング

Important

これは Azure Cosmos DB 用の最新の Java SDK では "ありません"。 プロジェクトを Azure Cosmos DB Java SDK v4 にアップグレードしてから、Azure Cosmos DB Java SDK v4 トラブルシューティング ガイドをお読みください。 アップグレードするには、 Azure Cosmos DB Java SDK v4 への移行 ガイドと Reactor vs RxJava ガイドの手順に従ってください。

この記事では、Azure Cosmos DB Async Java SDK v2 のみのトラブルシューティングについて説明します。 詳細については、Azure Cosmos DB Async Java SDK v2 リリース ノートMaven リポジトリおよびパフォーマンス に関するヒントを参照してください。

Important

2024 年 8 月 31 日に、Azure Cosmos DB Async Java SDK v2.x は廃止されます。SDK と SDK を使用するすべてのアプリケーション は引き続き機能します。Azure Cosmos DB では、この SDK の追加のメンテナンスとサポートが提供されなくなります。 上記の手順に従って Azure Cosmos DB Java SDK v4 に移行することをお勧めします。

この記事では、Azure Cosmos DB for NoSQL アカウントで Java Async SDK を使用する場合の一般的な問題、回避策、診断手順、およびツールについて説明します。 Java Async SDK は、Azure Cosmos DB for NoSQL にアクセスするためのクライアント側の論理表現を提供します。 この記事では、問題が発生した場合に役立つツールとアプローチについて説明します。

次の一覧から始めます。

一般的な問題と対処法

ネットワークの問題、Netty 読み取りタイムアウトエラー、低スループット、高待機時間

一般的な推奨事項

  • アプリが Azure Cosmos DB アカウントと同じリージョンで実行されていることを確認します。
  • アプリが実行されているホストの CPU 使用率を確認します。 CPU 使用率が 90% 以上の場合は、より高い構成でホストでアプリを実行します。 または、より多くのマシンに負荷を分散させることができます。

接続の調整

接続の調整は、 ホスト コンピューターの接続制限 または Azure SNAT (PAT) ポートの枯渇が原因で発生する可能性があります。

ホスト コンピューターの接続制限

Red Hat などの一部の Linux システムでは、開いているファイルの合計数に上限があります。 Linux のソケットはファイルとして実装されるため、この数によって接続の合計数も制限されます。 次のコマンドを実行します。

ulimit -a

"nofile" として識別される、許可される最大開いているファイルの数は、接続プールのサイズの少なくとも 2 倍である必要があります。 詳細については、「パフォーマンスの ヒント」を参照してください。

Azure SNAT (PAT) ポート不足

アプリがパブリック IP アドレスなしで Azure Virtual Machines にデプロイされている場合、既定では 、Azure SNAT ポート は VM の外部にある任意のエンドポイントへの接続を確立します。 VM から Azure Cosmos DB エンドポイントへの許可される接続の数は、Azure SNAT 構成によって制限されます。

Azure SNAT ポートは、VM にプライベート IP アドレスがあり、VM からのプロセスがパブリック IP アドレスへの接続を試みる場合にのみ使用されます。 Azure SNAT の制限を回避するには、次の 2 つの回避策があります。

  • Azure Virtual Machines 仮想ネットワークのサブネットに Azure Cosmos DB サービス エンドポイントを追加します。 詳細については、Azure 仮想ネットワーク サービス エンドポイントに関するページを参照してください。

    サービス エンドポイントが有効になると、要求はパブリック IP から Azure Cosmos DB に送信されなくなります。 代わりに、仮想ネットワークとサブネット ID が送信されます。 この変更により、パブリック IP のみが許可された場合はファイアウォール ドロップが発生することがあります。 ファイアウォールを使用している場合、サービス エンドポイントを有効にするときに、Virtual Network ACL を使用してファイアウォールにサブネットを追加します。

  • Azure VM にパブリック IP を割り当てます。

サービスに到達できない - ファイアウォール

ConnectTimeoutException は、SDK がサービスに到達できないことを示します。 ダイレクト モードを使用すると、次のようなエラーが発生する場合があります。

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]

アプリ コンピューターでファイアウォールが実行されている場合は、直接モードで使用されるポート範囲 10,000 ~ 20,000 を開きます。 また、 ホスト コンピューターの接続制限に従います

HTTP プロキシ

HTTP プロキシを使用する場合は、SDK ConnectionPolicyで構成されている接続の数をサポートできることを確認します。 そうしないと、接続の問題が発生します。

無効なコーディング パターン: Netty IO スレッドのブロック

SDK では 、Netty IO ライブラリを使用して Azure Cosmos DB と通信します。 SDK には非同期 API があり、Netty の非ブロッキング IO API を使用します。 SDK の IO 作業は、IO Netty スレッドで実行されます。 IO Netty スレッドの数は、アプリ コンピューターの CPU コア数と同じに構成されます。

Netty IO スレッドは、非ブロッキング Netty IO 作業にのみ使用されます。 SDK は、Netty IO スレッドの 1 つで API 呼び出しの結果をアプリのコードに返します。 Netty スレッドで結果を受け取った後にアプリが長時間の操作を実行する場合、SDK には内部 IO 処理を実行するのに十分な IO スレッドがない可能性があります。 このようなアプリのコーディングにより、スループットが低く、待機時間が長く、 io.netty.handler.timeout.ReadTimeoutException エラーが発生する可能性があります。 回避策は、操作に時間がかかることがわかっているときにスレッドを切り替える方法です。

たとえば、次のコード スニペットを見てみましょう。 Netty スレッドでは、数ミリ秒以上かかる長期的な作業を実行できます。 その場合、最終的には、IO 処理を処理するために Netty IO スレッドが存在しない状態になる可能性があります。 その結果、ReadTimeoutException エラーが発生します。

Async 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);
}

回避策は、時間がかかる作業を実行するスレッドを変更することです。 アプリのスケジューラのシングルトン インスタンスを定義します。

Async 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);

計算負荷の高い作業や IO のブロックなど、時間がかかる作業が必要な場合があります。 この場合は、customScheduler API を使用して、.observeOn(customScheduler)によって提供されるワーカーにスレッドを切り替えます。

Async 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(
            // ...
        );

observeOn(customScheduler)を使用すると、Netty IO スレッドを解放し、カスタム スケジューラによって提供される独自のカスタム スレッドに切り替えます。 この変更により、問題が解決されます。 io.netty.handler.timeout.ReadTimeoutExceptionエラーは発生しなくなります。

接続プールの枯渇に関する問題

PoolExhaustedException はクライアント側の障害です。 このエラーは、アプリのワークロードが SDK 接続プールが提供できるものよりも高いことを示します。 接続プールのサイズを増やすか、複数のアプリに負荷を分散します。

要求率が大きすぎる

このエラーは、サーバー側の障害です。 これは、プロビジョニングされたスループットを使用したことを示します。 後で再試行してください。 このエラーが頻繁に発生する場合は、コレクションのスループットの増加を検討してください。

Azure Cosmos DB Emulator への接続に失敗する

Azure Cosmos DB Emulator HTTPS 証明書は自己署名されています。 SDK でエミュレーターを操作するには、エミュレーター証明書を Java TrustStore にインポートします。 詳細については、「 Azure Cosmos DB Emulator 証明書のエクスポート」を参照してください。

依存関係の競合の問題

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

上記の例外は、古いバージョンの RxJava lib (1.2.2 など) に依存している可能性があることを示しています。 この SDK は、以前のバージョンの RxJava では使用できない API を持つ RxJava 1.3.8 に依存しています。

このような問題の回避策は、RxJava-1.2.2 で他のどの依存関係をもたらすかを特定し、RxJava-1.2.2 の推移的な依存関係を除外し、CosmosDB SDK で新しいバージョンを使用できるようにすることです。

RxJava-1.2.2 でどのライブラリを取り込むかを特定するには、プロジェクト pom.xml ファイルの横にある次のコマンドを実行します。

mvn dependency:tree

詳細については、 Maven 依存関係ツリー ガイドを参照してください。

RxJava-1.2.2 がプロジェクトの他の依存関係の推移的な依存関係であることを特定したら、pom ファイル内のその lib への依存関係を変更し、RxJava 推移的な依存関係を除外できます。

<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>

詳細については、 推移的な依存関係の除外に関するガイドを参照してください。

クライアント SDK のログ記録を有効にする

Java Async SDK では、log4j や logback などの一般的なログ 記録フレームワークへのログ記録をサポートするログ ファサードとして SLF4j が使用されます。

たとえば、ログ記録フレームワークとして log4j を使用する場合は、Java クラスパスに次の lib を追加します。

<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>

log4j 構成も追加します。

# 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

詳細については、 sfl4j ログマニュアルを参照してください。

OS ネットワークの統計情報

netstat コマンドを実行して、 ESTABLISHEDCLOSE_WAITなどの状態にある接続の数を把握します。

Linux では、次のコマンドを実行できます。

netstat -nap

結果をフィルター処理して、Azure Cosmos DB エンドポイントへの接続のみにします。

ESTABLISHED状態の Azure Cosmos DB エンドポイントへの接続の数は、構成された接続プール のサイズを超えることはできません。

Azure Cosmos DB エンドポイントへの多くの接続が CLOSE_WAIT 状態である可能性があります。 1,000 を超える可能性があります。 高い数値は、接続が確立され、迅速に切断されることを示します。 この状況により、問題が発生する可能性があります。 詳細については、「 一般的な問題と回避策 」セクションを参照してください。