Memecahkan masalah saat Anda menggunakan Azure Cosmos DB Java SDK v4 dengan akun SQL API

BERLAKU UNTUK: API SQL

Penting

Artikel ini hanya membahas pemecahan masalah untuk Azure Cosmos DB Java SDK v4. Silakan lihat catatan Rilis, repositori Maven, dan tips performa Azure Cosmos DB Java SDK v4 untuk informasi selengkapnya. Jika saat ini Anda menggunakan versi yang lebih lama dari v4, lihat panduan Migrasi ke Azure Cosmos DB Java SDK v4 untuk bantuan peningkatan ke v4.

Artikel ini membahas masalah umum, solusi, langkah diagnostik, dan alat saat Anda menggunakan Azure Cosmos DB Java SDK v4 dengan akun Azure Cosmos DB SQL API. Azure Cosmos DB Java SDK v4 menyediakan representasi logis sisi klien untuk mengakses Azure Cosmos DB SQL API. Artikel ini menjelaskan alat dan pendekatan untuk membantu Anda jika mengalami masalah.

Mulai dengan daftar ini:

  • Lihatlah bagian Masalah umum dan solusi dalam artikel ini.
  • Lihatlah Java SDK di repo pusat Azure Cosmos DB, yang tersedia open source di GitHub. Ini memiliki bagian masalah yang dipantau secara aktif. Periksa untuk melihat apakah ada masalah serupa dengan solusi yang sudah diajukan. Salah satu tips bermanfaat adalah memfilter masalah dengan tag cosmos:v4-item.
  • Tinjau tips performa untuk Azure Cosmos DB Java SDK v4, dan ikuti praktik yang disarankan.
  • Baca artikel lainnya, jika Anda tidak menemukan solusi. Kemudian mengajukan masalah GitHub. Jika ada opsi untuk menambahkan tag ke masalah GitHub Anda, tambahkan label cosmos:v4-item.

Coba Lagi Logika

Cosmos DB SDK pada setiap kegagalan IO akan mencoba kembali operasi yang gagal jika mencoba kembali di SDK dapat dilakukan. Mencoba lagi untuk kegagalan apa pun adalah praktik yang baik, tetapi menangani/ mencoba kembali kegagalan penulisan harus dilakukan. Disarankan untuk menggunakan SDK terbaru karena logika coba lagi terus ditingkatkan.

  1. Kegagalan IO baca dan kueri akan dicoba kembali oleh SDK tanpa memunculkannya ke pengguna akhir.
  2. Menulis (Buat, Upsert, Ganti, Hapus) "tidakā€ idempoten dan karenanya SDK tidak selalu dapat mencoba kembali operasi penulisan yang gagal. Diperlukan logika aplikasi pengguna untuk menangani kegagalan dan mencoba lagi.
  3. Trouble shooting sdk availability menjelaskan pencobaan kembali untuk akun Cosmos DB multiwilayah.

Rancangan percobaan ulang

Aplikasi harus dirancang untuk mencoba kembali tanpa pengecualian, kecuali ini adalah masalah umum yang tidak dapat diatasi dengan percobaan kembali. Misalnya, aplikasi harus mencoba kembali saat 408 waktu tunggu permintaan habis. Timeout ini mungkin bersifat sementara sehingga percobaan ulang mungkin akan berhasil mengatasinya. Aplikasi tidak boleh mencoba kembali jika terjadi kesalahan 400, hal ini biasanya berarti bahwa ada masalah dengan permintaan yang harus diselesaikan terlebih dahulu. Mencoba kembali pada kesalahan 400 tidak akan memperbaiki masalah dan akan mengakibatkan kegagalan yang sama jika dicoba kembali. Tabel di bawah ini menunjukkan kegagalan umum dan mana yang memerlukan percobaan kembali.

Kode status kesalahan umum

Kode Status Dapat Dicoba Lagi Deskripsi
400 Tidak Permintaan buruk (yaitu, json tidak valid, header salah, tombol partisi salah di header)
401 Tidak Tidak berwenang
403 Tidak Terlarang
404 Tidak Sumber daya tidak ditemukan
408 Ya Waktu permintaan berakhir
409 Tidak Kegagalan konflik adalah ketika ID yang disediakan untuk sumber daya pada operasi tulis telah diambil oleh sumber daya yang ada. Gunakan ID lain untuk sumber daya untuk menyelesaikan masalah ini mengingat ID harus unik dalam semua dokumen dengan nilai kunci partisi yang sama.
410 Ya Pengecualian hilang (kegagalan sementara yang seharusnya tidak melanggar SLA)
412 Tidak Kegagalan prakondisi adalah tempat operasi menentukan eTag yang berbeda dari versi yang tersedia di server. Ini adalah kesalahan konkurensi yang optimis. Coba lagi permintaan setelah membaca versi terbaru sumber daya dan memperbarui eTag pada permintaan.
413 Tidak Entitas Permintaan Terlalu Besar
429 Ya Aman untuk mencoba kembali jika ditampilkan 429. Hal ini dapat dihindari dengan mengikuti tautan untuk terlalu banyak permintaan.
449 Ya Kesalahan sementara yang hanya terjadi pada operasi tulis, dan aman untuk mencoba kembali. Kesalahan ini dapat mengarah ke masalah desain saat terlalu banyak operasi bersamaan yang mencoba memperbarui objek yang sama di Cosmos DB.
500 Ya Operasi gagal karena kesalahan layanan yang tak terduga. Hubungi dukungan dengan mengisi Masalah dukungan Azure.
503 Ya Layanan tidak tersedia

Masalah umum dan solusi

Masalah jaringan, kegagalan waktu habis baca Netty, throughput rendah, latensi tinggi

Saran umum

Untuk performa terbaik:

  • Pastikan aplikasi berjalan di wilayah yang sama dengan akun Azure Cosmos DB Anda.
  • Periksa penggunaan CPU di host tempat aplikasi berjalan. Jika penggunaan CPU 50 persen atau lebih, jalankan aplikasi Anda di host dengan konfigurasi yang lebih tinggi. Atau Anda dapat mendistribusikan beban pada lebih banyak komputer.

Pembatasan koneksi

Pembatasan koneksi dapat terjadi karena batas koneksi pada komputer host atau kelelahan port Azure SNAT (PAT).

Batas koneksi pada komputer host

Beberapa sistem Linux, seperti Red Hat, memiliki batas atas jumlah total file terbuka. Soket di Linux diimplementasikan sebagai file, sehingga angka ini membatasi jumlah total koneksi juga. Jalankan perintah berikut.

ulimit -a

Jumlah file terbuka maksimum yang diizinkan, yang diidentifikasi sebagai "nofile," harus setidaknya dua kali lipat ukuran kumpulan koneksi Anda. Untuk informasi selengkapnya, lihat tips performa Azure Cosmos DB Java SDK v4.

Kelelahan port Azure SNAT (PAT)

Jika aplikasi Anda diterapkan di Azure Virtual Machines tanpa alamat IP publik, secara default port Azure SNAT membangun koneksi ke titik akhir di luar VM Anda. Jumlah koneksi yang diizinkan dari VM ke titik akhir Azure Cosmos DB dibatasi oleh konfigurasi Azure SNAT.

Port Azure SNAT hanya digunakan saat VM Anda memiliki alamat IP pribadi dan proses dari VM mencoba menyambungkan ke alamat IP publik. Ada dua solusi untuk menghindari batasan Azure SNAT:

  • Menambahkan titik akhir layanan Azure Cosmos DB Anda ke subnet jaringan virtual Azure Virtual Machines Anda. Untuk informasi selengkapnya, lihat Titik akhir layanan Microsoft Azure Virtual Network.

    Ketika titik akhir layanan diaktifkan, permintaan tidak lagi dikirimkan dari IP publik ke Azure Cosmos DB. Sebagai gantinya, jaringan virtual dan identitas subnet dikirim. Perubahan ini dapat mengakibatkan firewall turun jika hanya IP publik yang diizinkan. Jika Anda menggunakan firewall, saat Anda mengaktifkan titik akhir layanan, tambahkan subnet ke firewall menggunakan Virtual Network ACL.

  • Tetapkan IP publik ke Azure VM Anda.

Tidak dapat menjangkau Layanan - firewall

ConnectTimeoutException menunjukkan bahwa SDK tidak dapat menjangkau layanan. Anda mungkin mengalami kegagalan yang mirip dengan yang berikut ini saat menggunakan mode langsung:

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]

Jika Anda memiliki firewall yang berjalan di komputer aplikasi Anda, buka rentang port 10.000 hingga 20.000 yang digunakan oleh mode langsung. Ikuti juga Batas koneksi pada komputer host.

Proksi HTTP

Jika Anda menggunakan proksi HTTP, pastikan dapat mendukung jumlah koneksi yang dikonfigurasi di SDK ConnectionPolicy. Jika tidak, Anda akan menghadapi masalah koneksi.

Pola pengkodean tidak valid: Memblokir utas IO Netty

SDK menggunakan pustaka IO Netty untuk berkomunikasi dengan Azure Cosmos DB. SDK memiliki Async API dan menggunakan IO API non-blokir Netty. Fungsi IO SDK dilakukan pada utas IO Netty. Jumlah utas IO Netty dikonfigurasi agar sama dengan jumlah core CPU komputer aplikasi.

Utas IO Netty dimaksudkan untuk digunakan hanya untuk pekerjaan IO non-blokir Netty. SDK mengembalikan hasil pemanggilan API pada salah satu utas IO Netty ke kode aplikasi. Jika aplikasi melakukan operasi jangka panjang setelah menerima hasil pada utas Netty, SDK mungkin tidak memiliki cukup thread IO untuk melakukan pekerjaan IO internalnya. Pengodean aplikasi tersebut dapat mengakibatkan throughput rendah, latensi tinggi, dan kegagalan io.netty.handler.timeout.ReadTimeoutException. Solusinya adalah mengganti utas ketika Anda tahu operasi membutuhkan waktu.

Misalnya, lihat cuplikan kode berikut yang menambahkan item ke kontainer (lihat di sini untuk panduan tentang pengaturan database dan kontainer.) Anda mungkin melakukan pekerjaan jangka panjang yang membutuhkan lebih dari beberapa milidetik pada utas Netty. Jika demikian, Anda akhirnya bisa masuk ke status di mana tidak ada thread IO Netty yang hadir untuk memproses pekerjaan IO. Akibatnya, Anda mendapatkan kegagalan ReadTimeoutException.

Java SDK V4 (Maven com.azure::azure-cosmos) Async API


//Bad code with read timeout exception

int requestTimeoutInSeconds = 10;

/* ... */

AtomicInteger failureCount = new AtomicInteger();
// Max number of concurrent item inserts is # CPU cores + 1
Flux<Family> familyPub =
        Flux.just(Families.getAndersenFamilyItem(), Families.getAndersenFamilyItem(), Families.getJohnsonFamilyItem());
familyPub.flatMap(family -> {
    return container.createItem(family);
}).flatMap(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) {
    }
    return Mono.empty();
}).doOnError(Exception.class, exception -> {
    failureCount.incrementAndGet();
}).blockLast();
assert(failureCount.get() > 0);

Solusinya adalah mengubah utas tempat Anda melakukan pekerjaan yang membutuhkan waktu. Tentukan instans singleton penjadwal untuk aplikasi Anda.

Java SDK V4 (Maven com.azure::azure-cosmos) Async API

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

Anda mungkin perlu melakukan pekerjaan yang membutuhkan waktu, misalnya, pekerjaan berat secara komputasi atau memblokir IO. Dalam hal ini, alihkan untuk ke pekerja yang disediakan oleh customScheduler Anda menggunakan .publishOn(customScheduler) API.

Java SDK V4 (Maven com.azure::azure-cosmos) Async API

container.createItem(family)
        .publishOn(customScheduler) // Switches the thread.
        .subscribe(
                // ...
        );

Dengan menggunakan publishOn(customScheduler), Anda merilis thread IO Netty dan beralih ke utas kustom Anda sendiri yang disediakan oleh penjadwal kustom. Modifikasi ini memecahkan masalah. Anda tidak akan mendapatkan kegagalan io.netty.handler.timeout.ReadTimeoutException lagi.

Rentang permintaan terlalu besar

Kegagalan ini adalah kegagalan sisi server. Ini menunjukkan bahwa Anda mengonsumsi throughput yang disediakan. Coba lagi nanti. Jika Anda sering mengalami kegagalan ini, pertimbangkan melakukan peningkatan throughput koleksi.

  • Menerapkan backoff di interval getRetryAfterInMilliseconds

    Selama pengujian performa, Anda harus meningkatkan beban sampai tingkat permintaan yang kecil dibatasi. Jika dibatasi, aplikasi klien harus melakukan backoff untuk interval coba lagi yang ditentukan server. Memperhatikan backoff akan memastikan bahwa Anda menghabiskan sedikit waktu menunggu di antara upaya ulang.

Penanganan kesalahan dari Java SDK Reactive Chain

Penanganan kesalahan dari Cosmos DB Java SDK penting dalam hal logika aplikasi klien. Ada mekanisme penanganan kesalahan yang berbeda yang disediakan oleh kerangka kerja inti reaktor yang dapat digunakan dalam skenario yang berbeda. Sebaiknya pelanggan memahami operator penanganan kesalahan ini secara mendetail dan menggunakan operator yang paling sesuai dengan skenario logika percobaan ulang mereka.

Penting

Kami tidak merekomendasikan penggunaan operator onErrorContinue(), karena tidak didukung di semua skenario. Perhatikan bahwa onErrorContinue() adalah operator spesialis yang dapat membuat perilaku rantai reaktif Anda menjadi tidak jelas. Operator ini beroperasi pada operator hulu, bukan hilir, memerlukan dukungan operator khusus untuk berfungsi, dan ruang lingkup dapat dengan mudah menyebar ke hulu ke kode pustaka yang tidak mengantisipasinya (menghasilkan perilaku yang tidak diinginkan.). Lihat dokumentasi dari onErrorContinue() untuk mengetahui detail selengkapnya tentang operator khusus ini.

Kegagalan menyambungkan ke Azure Cosmos DB Emulator

Sertifikat HTTPS Azure Cosmos DB Emulator ditandatangani sendiri. Agar SDK dapat digunakan dengan emulator, impor sertifikat emulator ke Java TrustStore. Untuk informasi selengkapnya, lihat Mengekspor sertifikat Azure Cosmos DB Emulator.

Masalah Konflik Dependensi

Azure Cosmos DB Java SDK menarik sejumlah dependensi; secara umum, jika pohon dependensi proyek Anda menyertakan versi artefak yang lebih lama yang bergantung pada Azure Cosmos DB Java SDK, ini dapat mengakibatkan kesalahan tak terduga yang dihasilkan saat Anda menjalankan aplikasi Anda. Jika Anda men-debug mengapa aplikasi Anda secara tak terduga melemparkan pengecualian, ada baiknya untuk memeriksa ulang bahwa pohon dependensi Anda tidak secara tidak sengaja menarik versi lama dari satu atau lebih dependensi Azure Cosmos DB Java SDK.

Solusi untuk masalah tersebut adalah mengidentifikasi dependensi proyek mana yang membawa versi lama dan mengecualikan dependensi transitif pada versi lama tersebut, dan memungkinkan Azure Cosmos DB Java SDK untuk membawa versi yang lebih baru.

Untuk mengidentifikasi dependensi proyek mana yang membawa versi lama dari sesuatu yang menjadi bergantungnya Azure Cosmos DB Java SDK, jalankan perintah berikut terhadap file pom.xml proyek Anda:

mvn dependency:tree

Untuk informasi selengkapnya, lihat panduan pohon ketergantungan maven.

Setelah mengetahui dependensi proyek mana yang bergantung pada versi yang lebih lama, Anda dapat memodifikasi dependensi pada lib tersebut dalam file pom Anda dan mengecualikan dependensi transitif, dengan mengikuti contoh di bawah ini (yang mengasumsikan bahwa reactor-core adalah dependensi yang sudah usang):

<dependency>
  <groupId>${groupid-of-lib-which-brings-in-reactor}</groupId>
  <artifactId>${artifactId-of-lib-which-brings-in-reactor}</artifactId>
  <version>${version-of-lib-which-brings-in-reactor}</version>
  <exclusions>
    <exclusion>
      <groupId>io.projectreactor</groupId>
      <artifactId>reactor-core</artifactId>
    </exclusion>
  </exclusions>
</dependency>

Untuk informasi selengkapnya, lihat panduan dependensi transitif yang dikecualikan.

Mengaktifkan pencatatan SDK klien

Azure Cosmos DB Java SDK v4 menggunakan SLF4j sebagai fasad logging yang mendukung pencatatan ke kerangka kerja pencatatan populer seperti log4j dan logback.

Misalnya, jika Anda ingin menggunakan log4j sebagai kerangka kerja pengelogan, tambahkan libs berikut di classpath Java Anda.

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

Tambahkan juga konfigurasi log4j.

# this is a sample log4j configuration

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

log4j.category.com.azure.cosmos=INFO
#log4j.category.io.netty=OFF
#log4j.category.io.projectreactor=OFF
# 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

Untuk informasi selengkapnya, lihat manual pengelogan sfl4j.

Statistik jaringan OS

Jalankan perintah netstat untuk merasakan berapa banyak koneksi dalam status seperti ESTABLISHED dan CLOSE_WAIT.

Di Linux, Anda dapat menjalankan perintah berikut.

netstat -nap

Di Windows, Anda bisa menjalankan perintah yang sama dengan bendera argumen yang berbeda:

netstat -abn

Filter hasilnya hanya ke koneksi ke titik akhir Azure Cosmos DB.

Jumlah koneksi ke titik akhir Azure Cosmos DB dalam status ESTABLISHED tidak boleh lebih besar dari ukuran kumpulan koneksi yang telah dikonfigurasi.

Banyak koneksi ke titik akhir Azure Cosmos DB mungkin berada dalam status CLOSE_WAIT. Mungkin ada lebih dari 1.000. Angka yang tinggi menunjukkan bahwa koneksi dibuat dan dihentikan dengan cepat. Situasi ini berpotensi menimbulkan masalah. Untuk informasi selengkapnya, lihat bagian Masalah umum dan solusi.