Udostępnij za pośrednictwem


Rozwiązywanie problemów podczas korzystania z asynchronicznego zestawu Java SDK usługi Azure Cosmos DB w wersji 2 z interfejsem API dla kont NoSQL

DOTYCZY: NoSQL

Ważne

Nie jest to najnowszy zestaw Java SDK dla usługi Azure Cosmos DB! Należy uaktualnić projekt do zestawu Java SDK usługi Azure Cosmos DB w wersji 4, a następnie przeczytać przewodnik rozwiązywania problemów z zestawem Java SDK usługi Azure Cosmos DB w wersji 4. Postępuj zgodnie z instrukcjami w przewodniku Migrate to Azure Cosmos DB Java SDK v4 (Migrowanie do zestawu Java SDK usługi Azure Cosmos DB w wersji 4 ) i przewodniku Reactor vs RxJava w celu uaktualnienia.

W tym artykule opisano rozwiązywanie problemów tylko z zestawem Java SDK asynchronicznego zestawu Java SDK usługi Azure Cosmos DB w wersji 2. Aby uzyskać więcej informacji, zobacz Informacje o wersji zestawu Java SDK asynchronicznego zestawu Java SDK w wersji 2, repozytorium Maven i porady dotyczące wydajności usługi Azure Cosmos DB.

Ważne

31 sierpnia 2024 r. zestaw JAVA SDK asynchroniczny usługi Azure Cosmos DB w wersji 2.x zostanie wycofany; zestaw SDK i wszystkie aplikacje korzystające z zestawu SDK będą nadal działać; Usługa Azure Cosmos DB po prostu przestanie zapewniać dalszą konserwację i obsługę tego zestawu SDK. Zalecamy wykonanie powyższych instrukcji, aby przeprowadzić migrację do zestawu Java SDK usługi Azure Cosmos DB w wersji 4.

W tym artykule opisano typowe problemy, obejścia, kroki diagnostyczne i narzędzia podczas korzystania z zestawu JAVA Async SDK z kontami usługi Azure Cosmos DB for NoSQL. Zestaw JAVA Async SDK zapewnia logiczną reprezentację po stronie klienta w celu uzyskania dostępu do usługi Azure Cosmos DB for NoSQL. W tym artykule opisano narzędzia i podejścia pomocne w przypadku napotkania jakichkolwiek problemów.

Zacznij od tej listy:

  • Zapoznaj się z sekcją Typowe problemy i obejścia w tym artykule.
  • Zapoznaj się z zestawem SDK, który jest dostępny w usłudze GitHub. Zawiera sekcję problemów, która jest aktywnie monitorowana. Sprawdź, czy wystąpił już podobny problem z obejściem.
  • Zapoznaj się z poradami dotyczącymi wydajności i postępuj zgodnie z sugerowanymi rozwiązaniami.
  • Przeczytaj resztę tego artykułu, jeśli nie znajdziesz rozwiązania. Następnie zgłoś problem z usługą GitHub.

Typowe problemy i ich rozwiązania

Problemy z siecią, błąd limitu czasu odczytu netty, niska przepływność, duże opóźnienie

Sugestie ogólne

  • Upewnij się, że aplikacja działa w tym samym regionie co konto usługi Azure Cosmos DB.
  • Sprawdź użycie procesora CPU na hoście, na którym działa aplikacja. Jeśli użycie procesora CPU wynosi co najmniej 90 procent, uruchom aplikację na hoście z wyższą konfiguracją. Możesz też rozłożyć obciążenie na więcej maszyn.

Ograniczanie połączeń

Ograniczanie połączeń może wystąpić z powodu limitu połączenia na maszynie hosta lub wyczerpaniu portów SNAT (PAT).

Limit połączeń na maszynie hosta

Niektóre systemy Linux, takie jak Red Hat, mają górny limit całkowitej liczby otwartych plików. Gniazda w systemie Linux są implementowane jako pliki, więc ta liczba ogranicza łączną liczbę połączeń. Uruchom następujące polecenie.

ulimit -a

Liczba maksymalnych dozwolonych otwartych plików, które są identyfikowane jako "nofile", musi być co najmniej dwukrotnie większy niż rozmiar puli połączeń. Aby uzyskać więcej informacji, zobacz Porady dotyczące wydajności.

Wyczerpanie portów SNAT (PAT) platformy Azure

Jeśli aplikacja jest wdrażana na maszynach wirtualnych platformy Azure bez publicznego adresu IP, domyślnie porty SNAT platformy Azure nawiązują połączenia z dowolnym punktem końcowym poza maszyną wirtualną. Liczba połączeń dozwolonych z maszyny wirtualnej do punktu końcowego usługi Azure Cosmos DB jest ograniczona przez konfigurację protokołu SNAT platformy Azure.

Porty SNAT platformy Azure są używane tylko wtedy, gdy maszyna wirtualna ma prywatny adres IP i proces z maszyny wirtualnej próbuje nawiązać połączenie z publicznym adresem IP. Istnieją dwa obejścia, aby uniknąć ograniczenia usługi Azure SNAT:

  • Dodaj punkt końcowy usługi Azure Cosmos DB do podsieci sieci wirtualnej usługi Azure Virtual Machines. Aby uzyskać więcej informacji, zobacz Punkty końcowe usługi Azure Virtual Network.

    Po włączeniu punktu końcowego usługi żądania nie są już wysyłane z publicznego adresu IP do usługi Azure Cosmos DB. Zamiast tego są wysyłane tożsamości sieci wirtualnej i podsieci. Ta zmiana może spowodować porzucenie zapory, jeśli dozwolone są tylko publiczne adresy IP. Jeśli używasz zapory, po włączeniu punktu końcowego usługi dodaj podsieć do zapory przy użyciu list ACL sieci wirtualnej.

  • Przypisz publiczny adres IP do maszyny wirtualnej platformy Azure.

Nie można nawiązać połączenia z usługą — zapora

ConnectTimeoutException wskazuje, że zestaw SDK nie może nawiązać połączenia z usługą. Podczas korzystania z trybu bezpośredniego może wystąpić błąd podobny do następującego:

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]

Jeśli na maszynie aplikacji jest uruchomiona zapora, otwórz zakres portów od 10 000 do 20 000, które są używane przez tryb bezpośredni. Należy również przestrzegać limitu połączeń na maszynie hosta.

Serwer proxy HTTP

Jeśli używasz serwera proxy HTTP, upewnij się, że może obsługiwać liczbę połączeń skonfigurowanych w zestawie SDK ConnectionPolicy. W przeciwnym razie występują problemy z połączeniem.

Nieprawidłowy wzorzec kodowania: Blokowanie wątku we/wy netty

Zestaw SDK używa biblioteki we/wy netty do komunikowania się z usługą Azure Cosmos DB. Zestaw SDK ma asynchroniczne interfejsy API i używa nieblokujących interfejsów API we/wy netty. Praca we/wy zestawu SDK jest wykonywana w wątkach IO Netty. Liczba wątków netty we/wy jest skonfigurowana tak samo jak liczba rdzeni procesora CPU maszyny aplikacji.

Wątki we/wy Netty mają być używane tylko w przypadku pracy we/wy netty nieblokujących. Zestaw SDK zwraca wynik wywołania interfejsu API dla jednego z wątków operacji we/wy netty do kodu aplikacji. Jeśli aplikacja wykonuje długotrwałą operację po otrzymaniu wyników w wątku Netty, zestaw SDK może nie mieć wystarczającej liczby wątków we/wy, aby wykonać wewnętrzną pracę we/wy. Takie kodowanie aplikacji może spowodować niską przepływność, duże opóźnienia i io.netty.handler.timeout.ReadTimeoutException błędy. Obejście polega na przełączeniu wątku, gdy wiadomo, że operacja zajmuje trochę czasu.

Zapoznaj się na przykład z poniższym fragmentem kodu. Możesz wykonać długotrwałą pracę, która zajmuje więcej niż kilka milisekund w wątku Netty. Jeśli tak, w końcu możesz dostać się do stanu, w którym żaden wątek we/wy netty nie jest obecny do przetwarzania operacji we/wy. W rezultacie otrzymasz błąd 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);
}

Obejście polega na zmianie wątku, na którym wykonujesz pracę, która zajmuje trochę czasu. Zdefiniuj pojedyncze wystąpienie harmonogramu dla aplikacji.

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

Może być konieczne wykonywanie pracy, która wymaga czasu, na przykład obliczeniowej ciężkiej pracy lub blokowania operacji we/wy. W takim przypadku przełącz wątek do procesu roboczego dostarczonego przez użytkownika customScheduler przy użyciu interfejsu .observeOn(customScheduler) API.

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

Za pomocą polecenia observeOn(customScheduler)wydasz wątek Netty we/wy i przełączysz się do własnego niestandardowego wątku udostępnionego przez niestandardowy harmonogram. Ta modyfikacja rozwiązuje problem. Nie otrzymasz już błędu io.netty.handler.timeout.ReadTimeoutException .

Problem z wyczerpaną pulą połączeń

PoolExhaustedException jest błędem po stronie klienta. Ten błąd wskazuje, że obciążenie aplikacji jest wyższe niż może obsłużyć pula połączeń zestawu SDK. Zwiększ rozmiar puli połączeń lub rozłóż obciążenie dla wielu aplikacji.

Zbyt duża liczba żądań

Ten błąd jest awarią po stronie serwera. Wskazuje ona, że zużyliśmy aprowizowaną przepływność. Ponów próbę później. Jeśli ten błąd występuje często, rozważ zwiększenie przepływności kolekcji.

Niepowodzenie nawiązywania połączenia z emulatorem usługi Azure Cosmos DB

Certyfikat HTTPS emulatora usługi Azure Cosmos DB jest z podpisem własnym. Aby zestaw SDK działał z emulatorem, zaimportuj certyfikat emulatora do magazynu zaufania Java. Aby uzyskać więcej informacji, zobacz Eksportowanie certyfikatów emulatora usługi Azure Cosmos DB.

Problemy z konfliktem zależności

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

Powyższy wyjątek sugeruje, że masz zależność od starszej wersji biblioteki RxJava (np. 1.2.2). Nasz zestaw SDK opiera się na wersji RxJava 1.3.8, która ma interfejsy API niedostępne we wcześniejszej wersji oprogramowania RxJava.

Obejściem takich problemów jest zidentyfikowanie, która inna zależność powoduje wywołanie biblioteki RxJava-1.2.2 i wykluczenie zależności przechodniej z biblioteki RxJava-1.2.2 i zezwolenie zestawowi CosmosDB SDK na wprowadzenie nowszej wersji.

Aby zidentyfikować, która biblioteka wprowadza plik RxJava-1.2.2, uruchom następujące polecenie obok pliku pom.xml projektu:

mvn dependency:tree

Aby uzyskać więcej informacji, zobacz przewodnik drzewa zależności maven.

Po zidentyfikowaniu pliku RxJava-1.2.2 zależność przechodnia innej zależności projektu można zmodyfikować zależność od tej biblioteki w pliku pom i wykluczyć zależność przechodnią 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>

Aby uzyskać więcej informacji, zobacz przewodnik po zależnościach przejściowych wykluczania.

Włączanie rejestrowania zestawu SDK klienta

Zestaw JAVA Async SDK używa biblioteki SLF4j jako fasady rejestrowania, która obsługuje logowanie się do popularnych struktur rejestrowania, takich jak log4j i logback.

Jeśli na przykład chcesz użyć log4j jako struktury rejestrowania, dodaj następujące biblioteki w ścieżce klas Języka Java.

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

Dodaj również konfigurację 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

Aby uzyskać więcej informacji, zobacz podręcznik rejestrowania sfl4j.

Statystyki sieci systemu operacyjnego

Uruchom polecenie netstat, aby uzyskać informacje o liczbie połączeń w stanach, takich jak ESTABLISHED i CLOSE_WAIT.

W systemie Linux możesz uruchomić następujące polecenie.

netstat -nap

Filtruj wynik tylko do połączeń z punktem końcowym usługi Azure Cosmos DB.

Liczba połączeń z punktem końcowym usługi Azure Cosmos DB w ESTABLISHED stanie nie może być większa niż skonfigurowany rozmiar puli połączeń.

Wiele połączeń z punktem końcowym usługi Azure Cosmos DB może być w CLOSE_WAIT stanie . Może istnieć więcej niż 1000. Liczba, która wysoka wskazuje, że połączenia są ustanawiane i szybko się rozwiązywane. Ta sytuacja potencjalnie powoduje problemy. Aby uzyskać więcej informacji, zobacz sekcję Typowe problemy i obejścia .