Tips performa untuk Azure Cosmos DB dan .NET

BERLAKU UNTUK: NoSQL

Azure Cosmos DB adalah database terdistribusi yang cepat dan fleksibel yang menskalakan dengan mulus dengan tingkat latensi dan throughput terjamin. Anda tidak perlu membuat perubahan arsitektur besar atau menulis kode kompleks untuk menskalakan database dengan Azure Cosmos DB. Penskalaan naik dan turun semudah melakukan satu panggilan API. Untuk mempelajari lebih lanjut, lihat sediakan throughput kontainer atau sediakan throughput database.

Karena Azure Cosmos DB diakses melalui panggilan jaringan, Anda dapat membuat pengoptimalan sisi klien untuk mencapai kinerja puncak saat menggunakan SQL .NET SDK.

Jika Anda mencoba meningkatkan kinerja database, pertimbangkan opsi yang disajikan di bagian berikut ini.

Rekomendasi hosting

Mengaktifkan pengumpulan sampah sisi server

Mengurangi frekuensi pengumpulan sampah dapat membantu beberapa kasus. Dalam .NET, atur gcServer ke true.

Meluaskan skala beban kerja klien Anda

Jika Anda menguji pada tingkat throughput tinggi, atau pada tingkat yang lebih besar dari 50.000 Unit Permintaan per detik (RU/s), aplikasi klien bisa menjadi hambatan beban kerja. Ini karena mesin mungkin menutup pada CPU atau pemanfaatan jaringan. Jika mencapai titik ini, Anda dapat terus mendorong akun Azure Cosmos DB lebih lanjut dengan meluaskan skala aplikasi klien di beberapa server.

Catatan

Penggunaan CPU yang tinggi dapat menyebabkan peningkatan latensi dan timeout permintaan pengecualian.

Operasi metadata

Jangan memverifikasi Database dan/atau Kontainer yang ada dengan menelepon Create...IfNotExistsAsync dan/atau Read...Async di jalur panas dan/atau sebelum melakukan operasi item. Validasi hanya boleh dilakukan pada startup aplikasi bila diperlukan, jika Anda mengharapkannya dihapus (jika tidak, itu tidak diperlukan). Operasi metadata ini akan menghasilkan latensi end-to-end tambahan, tidak memiliki SLA, dan keterbatasan terpisah mereka sendiri yang tidak berskala seperti operasi data.

Pencatatan dan pelacakan

Beberapa lingkungan mengaktifkan .NET DefaultTraceListener. DefaultTraceListener menimbulkan masalah performa pada lingkungan produksi yang menyebabkan penyempitan CPU dan I/O yang tinggi. Periksa dan pastikan bahwa DefaultTraceListener dinonaktifkan untuk aplikasi Anda dengan menghapusnya dari TraceListeners di lingkungan produksi.

Versi SDK terbaru (lebih besar dari 3.23.0) secara otomatis menghapusnya saat mendeteksinya, dengan versi yang lebih lama, Anda dapat menghapusnya dengan:

if (!Debugger.IsAttached)
{
    Type defaultTrace = Type.GetType("Microsoft.Azure.Cosmos.Core.Trace.DefaultTrace,Microsoft.Azure.Cosmos.Direct");
    TraceSource traceSource = (TraceSource)defaultTrace.GetProperty("TraceSource").GetValue(null);
    traceSource.Listeners.Remove("Default");
    // Add your own trace listeners
}

Jaringan

Kebijakan koneksi: Gunakan mode koneksi langsung

Mode koneksi default .NET V3 SDK bersifat langsung dengan protokol TCP. Konfigurasikan mode koneksi saat Anda membuat instans CosmosClient di CosmosClientOptions. Untuk mempelajari selengkapnya tentang berbagai opsi konektivitas, lihat artikel mode konektivitas.

string connectionString = "<your-account-connection-string>";
CosmosClient client = new CosmosClient(connectionString,
new CosmosClientOptions
{
    ConnectionMode = ConnectionMode.Gateway // ConnectionMode.Direct is the default
});

Kelelahan port sementara

Jika menghadapi volume koneksi tinggi atau penggunaan port tinggi pada instans, pertama-tama pastikan bahwa instans klien Anda adalah database tunggal. Dengan kata lain, instans klien harus unik untuk seumur hidup aplikasi.

Saat berjalan di protokol TCP, klien mengoptimalkan latensi dengan menggunakan koneksi umur-panjang. Ini berbeda dengan protokol HTTPS, yang mengakhiri koneksi setelah inaktif dua menit.

Ketika aksesnya jarang, dan jika jumlah koneksi lebih tinggi dibanding mode Gateway, Anda dapat:

  • Mengonfigurasi properti CosmosClientOptions.PortReuseMode ke PrivatePortPool (berlaku dengan versi kerangka kerja 4.6.1 ke atas dan .NET Core versi 2.0 ke atas). Properti ini memungkinkan SDK untuk menggunakan kumpulan kecil port sementara untuk berbagai titik akhir tujuan Azure Cosmos DB.
  • Konfigurasikan properti CosmosClientOptions.IdleConnectionTimeout lebih besar dari atau sama dengan 10 menit. Nilai yang disarankan adalah dari 20 menit hingga 24 jam.

Untuk performa, kolokasikan klien di wilayah Azure yang sama

Jika memungkinkan, tempatkan aplikasi apa pun yang memanggil Azure Cosmos DB di wilayah yang sama dengan database Azure Cosmos DB. Berikut adalah perkiraan perbandingan: panggilan ke Azure Cosmos DB dalam wilayah yang sama selesai dalam 1 milidetik (ms) hingga 2 ms, tetapi latensi antara pantai Barat dan Timur AS lebih dari 50 ms. Latensi ini dapat bervariasi dari permintaan ke permintaan, tergantung pada rute yang diambil oleh permintaan saat melewati klien ke batas pusat data Azure.

Anda bisa mendapatkan latensi serendah mungkin dengan memastikan bahwa aplikasi panggilan terletak di wilayah Azure yang sama dengan titik akhir Azure Cosmos DB yang disediakan. Untuk daftar wilayah yang tersedia, lihat Wilayah Azure.

Kolokasikan klien di wilayah yang sama.

Menambah jumlah utas/tugas

Karena panggilan ke Azure Cosmos DB dilakukan melalui jaringan, Anda mungkin perlu variasi tingkat konkurensi permintaan sehingga aplikasi klien menghabiskan waktu tunggu minimal di antara permintaan. Misalnya, jika Anda menggunakan .NET Task Parallel Library, buatlah ratusan tugas yang dibaca dari atau ditulis ke Azure Cosmos DB.

Aktifkan jaringan terakselerasi

Untuk mengurangi latensi dan jitter CPU, kami sarankan Anda mengaktifkan jaringan terakselerasi pada komputer virtual klien. Untuk informasi selengkapnya, lihat Buat komputer virtual Windows dengan jaringan terakselerasi atau Buat komputer virtual Linux dengan jaringan terakselerasi.

Penggunaan SDK

Menginstal SDK terbaru

Azure Cosmos DB SDK terus ditingkatkan untuk memberikan performa terbaik. Untuk menentukan SDK terbaru dan meninjau peningkatan, lihat Azure Cosmos DB SDK.

Gunakan API stream

.NET SDK V3 berisi API stream yang dapat menerima dan mengembalikan data tanpa serialisasi.

Aplikasi tingkat menengah yang tidak mengonsumsi respons langsung dari SDK tetapi menyampaikannya ke tingkat aplikasi lain dapat memperoleh manfaat dari API stream. Untuk contoh penanganan stream, lihat sampel manajemen item.

Gunakan klien database tunggal Azure Cosmos DB selama masa pakai aplikasi Anda

Setiap instans CosmosClient aman untuk utas dan melakukan manajemen koneksi dan caching alamat yang efisien saat beroperasi dalam mode Direct. Untuk memungkinkan manajemen koneksi efisien dan kinerja klien SDK lebih baik, kami sarankan Anda menggunakan satu instans per AppDomain untuk masa pakai aplikasi.

Saat Anda mengerjakan Azure Functions, instans juga harus mengikuti panduan yang ada dan mempertahankan satu instans.

Hindari memblokir panggilan

Azure Cosmos DB SDK harus dirancang untuk memproses banyak permintaan secara bersamaan. API asinkron memungkinkan kumpulan kecil utas untuk menangani ribuan permintaan bersamaan dengan tidak menunggu pemblokiran panggilan. Alih-alih menunggu tugas sinkron yang sudah berjalan lama untuk diselesaikan, utas dapat bekerja pada permintaan lain.

Masalah performa umum dalam aplikasi yang menggunakan Azure Cosmos DB SDK adalah memblokir panggilan yang bisa asinkron. Banyak panggilan pemblokiran sinkron menyebabkan kurangnya Kumpulan Utas dan waktu respons yang menurun.

Jangan:

  • Blokir eksekusi asinkron dengan memanggil Task.Wait atau Task.Result.
  • Gunakan Task.Run untuk membuat API sinkron menjadi asinkron.
  • Dapatkan kunci di jalur kode umum. Azure Cosmos DB .NET SDK paling berkinerja ketika dirancang untuk menjalankan kode secara paralel.
  • Panggil Task.Run dan segera tunggu. ASP.NET Core sudah menjalankan kode aplikasi pada rangkaian Kumpulan Utas normal, jadi memanggil Task.Run hanya menghasilkan penjadwalan Kumpulan Utas yang tidak perlu. Bahkan jika kode yang dijadwalkan akan memblokir utas, Task.Run tidak mencegahnya.
  • Jangan gunakan ToList() di Container.GetItemLinqQueryable<T>() yang menggunakan panggilan pemblokiran untuk menguras kueri secara sinkron. Gunakan ToFeedIterator() untuk mengosongkan kueri secara asinkron.

Lakukan:

  • Panggil AZURE Cosmos DB .NET API secara asinkron.
  • Seluruh tumpukan panggilan adalah asinkron untuk mendapatkan keuntungan dari pola async/await.

Profiler, seperti PerfView, dapat digunakan untuk menemukan utas yang sering ditambahkan ke Kumpulan Utas. Acara Microsoft-Windows-DotNETRuntime/ThreadPoolWorkerThread/Start tersebut menunjukkan utas yang ditambahkan ke kumpulan utas.

Menonaktifkan respons konten pada operasi tulis

Untuk beban kerja yang memiliki muatan buat berat, atur opsi permintaan EnableContentResponseOnWrite ke false. Layanan tidak akan lagi mengembalikan sumber daya yang dibuat atau diperbarui ke SDK. Biasanya, karena aplikasi memiliki objek yang sedang dibuat, layanan tidak perlu mengembalikannya. Nilai header masih dapat diakses, seperti biaya permintaan. Menonaktifkan respons konten dapat membantu meningkatkan performa, karena SDK tidak lagi perlu mengalokasikan memori atau serialisasi isi respons. Ini juga mengurangi penggunaan bandwidth jaringan untuk lebih membantu performa.

ItemRequestOptions requestOptions = new ItemRequestOptions() { EnableContentResponseOnWrite = false };
ItemResponse<Book> itemResponse = await this.container.CreateItemAsync<Book>(book, new PartitionKey(book.pk), requestOptions);
// Resource will be null
itemResponse.Resource

Aktifkan Bulk untuk mengoptimalkan throughput alih-alih latensi

Aktifkan Bulk ketika beban kerja memerlukan sejumlah besar throughput, dan latensi tidak penting. Untuk informasi selengkapnya tentang cara mengaktifkan fitur Bulk, dan untuk mempelajari skenario mana yang harus digunakan, lihat Pengantar dukungan Bulk.

Meningkatkan System.Net MaxConnections per host saat Anda menggunakan mode Gateway

Permintaan Azure Cosmos DB dibuat melalui HTTPS/REST saat Anda menggunakan mode Gateway. Mereka tunduk pada batas koneksi default per nama host atau alamat IP. Anda mungkin perlu mengatur MaxConnections ke nilai yang lebih tinggi (dari 100 hingga 1.000) sehingga pustaka klien dapat menggunakan beberapa koneksi simultan ke Azure Cosmos DB. Dalam .NET SDK 1.8.0 dan yang lebih baru, nilai default untuk ServicePointManager.DefaultConnectionLimit adalah 50. Untuk mengubah nilai, Anda bisa mengatur Documents.Client.ConnectionPolicy.MaxConnectionLimit ke nilai yang lebih tinggi.

Menambah jumlah utas/tugas

Lihat Menambah jumlah utas/tugas di bagian Jaringan di artikel ini.

Operasi kueri

Untuk operasi kueri, buka tips performa untuk kueri.

Kebijakan pengindeksan

Mengecualikan jalur yang tidak digunakan dari pengindeksan untuk penulisan yang lebih cepat

Kebijakan pengindeksan Azure Cosmos DB juga memungkinkan Anda menentukan jalur dokumen mana yang akan disertakan atau dikecualikan dari pengindeksan dengan menggunakan jalur pengindeksan (IndexingPolicy.IncludedPaths dan IndexingPolicy.ExcludedPaths).

Hanya mengindeks jalur yang Anda butuhkan dapat meningkatkan performa tulis, mengurangi biaya RU pada operasi tulis, dan mengurangi penyimpanan indeks ketika pola kueri telah diketahui. Ini karena biaya pengindeksan berkorelasi langsung dengan jumlah jalur unik yang diindeks. Misalnya, kode berikut menunjukkan cara mengecualikan seluruh bagian dokumen (subtree) dari pengindeksan dengan menggunakan wildcard "*":

var containerProperties = new ContainerProperties(id: "excludedPathCollection", partitionKeyPath: "/pk" );
containerProperties.IndexingPolicy.IncludedPaths.Add(new IncludedPath { Path = "/*" });
containerProperties.IndexingPolicy.ExcludedPaths.Add(new ExcludedPath { Path = "/nonIndexedContent/*");
Container container = await this.cosmosDatabase.CreateContainerAsync(containerProperties);

Untuk informasi selengkapnya, lihat kebijakan pengindeksan Azure Cosmos DB.

Throughput

Ukur dan setel untuk penggunaan RU/s lebih rendah

Azure Cosmos DB menawarkan serangkaian operasi database yang kaya. Operasi ini mencakup kueri relasional dan hierarkis dengan file Universal Disk Format (UDF), prosedur tersimpan, dan pemicu, semua beroperasi pada dokumen dalam koleksi database.

Biaya yang terkait dengan masing-masing operasi ini bervariasi berdasarkan CPU, IO, dan memori yang dibutuhkan untuk menyelesaikan operasi. Alih-alih memikirkan dan mengelola sumber daya perangkat keras, Anda dapat menganggap request unit (RU) sebagai ukuran tunggal untuk sumber daya yang diperlukan untuk melakukan berbagai operasi database untuk melayani permintaan.

Throughput disediakan berdasarkan jumlah Unit Permintaan yang ditetapkan untuk setiap kontainer. Konsumsi Unit Permintaan dievaluasi sebagai tarif unit per detik. Aplikasi yang melebihi tarif Unit Permintaan yang disediakan untuk kontainer dibatasi hingga tarif turun di bawah tingkat yang disediakan untuk kontainer. Jika aplikasi Anda memerlukan tingkat throughput yang lebih tinggi, Anda dapat meningkatkan throughput dengan menyediakan Unit Permintaan tambahan.

Kompleksitas sebuah kueri memengaruhi jumlah Unit Permintaan yang digunakan pada sebuah operasi. Jumlah predikat, sifat predikat, jumlah file UDF, dan ukuran set data sumber memengaruhi biaya operasi kueri.

Untuk mengukur overhead operasi apa pun (buat, perbarui, atau hapus), periksa header x-ms-request-charge (atau properti RequestCharge yang setara di ResourceResponse<T> atau FeedResponse<T> di .NET SDK) untuk mengukur jumlah Unit Permintaan yang digunakan oleh operasi:

// Measure the performance (Request Units) of writes
ItemResponse<Book> response = await container.CreateItemAsync<Book>(myBook, new PartitionKey(myBook.PkValue));
Console.WriteLine("Insert of item consumed {0} request units", response.RequestCharge);
// Measure the performance (Request Units) of queries
FeedIterator<Book> queryable = container.GetItemQueryIterator<ToDoActivity>(queryString);
while (queryable.HasMoreResults)
    {
        FeedResponse<Book> queryResponse = await queryable.ExecuteNextAsync<Book>();
        Console.WriteLine("Query batch consumed {0} request units", queryResponse.RequestCharge);
    }

Biaya permintaan yang dikembalikan di header ini adalah sebagian kecil dari throughput yang Anda sediakan (yaitu, 2.000 RU/s). Misalnya, jika kueri sebelumnya mengembalikan 1.000 dokumen 1-KB, biaya operasinya adalah 1.000. Jadi, dalam satu detik, server hanya mengindahkan dua permintaan tersebut sebelum membatasi tarif permintaan selanjutnya. Untuk informasi selengkapnya, lihat Unit Permintaan dan kalkulator Unit Permintaan.

Menangani tarif pembatasan/permintaan yang terlalu besar

Ketika klien mencoba melebihi throughput yang dipesan untuk akun, tidak ada penurunan kinerja di server dan tidak ada penggunaan kapasitas throughput di luar tingkat yang dipesan. Server secara mandiri mengakhiri permintaan dengan RequestRateTooLarge (kode status HTTP 429). Ini mengembalikan header x-ms-retry-after-ms yang menunjukkan jumlah waktu, dalam milidetik, bahwa pengguna harus menunggu sebelum mencoba permintaan lagi.

    HTTP Status 429,
    Status Line: RequestRateTooLarge
    x-ms-retry-after-ms :100

SDK secara implisit menangkap respons ini, mengindahkan header coba-lagi yang ditentukan server, dan mengulang permintaan. Kecuali akun Anda diakses secara bersamaan oleh beberapa klien, coba lagi berikutnya akan berhasil.

Jika Anda memiliki lebih dari satu klien yang secara kumulatif beroperasi secara konsisten di atas tingkat permintaan, jumlah coba lagi default yang saat ini diatur ke 9 mungkin tidak cukup. Dalam hal ini, klien melempar CosmosException dengan kode status 429 ke aplikasi.

Anda dapat mengubah jumlah coba lagi default dengan mengatur RetryOptions pada instans CosmosClientOptions. Secara default, CosmosException dengan kode status 429 dikembalikan setelah waktu tunggu kumulatif 30 detik jika permintaan terus beroperasi di atas tingkat permintaan. Galat ini dikembalikan bahkan ketika jumlah coba lagi saat ini kurang dari jumlah coba lagi maksimum, meski nilai saat ini adalah default 9 atau nilai yang ditentukan pengguna.

Perilaku coba lagi otomatis membantu meningkatkan ketahanan dan kegunaan untuk sebagian besar aplikasi. Tapi itu mungkin bukan perilaku terbaik untuk melakukan tolok ukur kinerja, terutama ketika Anda mengukur latensi. Latensi yang diamati klien akan meningkat jika eksperimen mengenai pembatasan server dan menyebabkan SDK klien diam-diam mencoba kembali. Untuk menghindari lonjakan latensi selama eksperimen kinerja, ukur biaya yang dikembalikan oleh setiap operasi, dan pastikan bahwa permintaan beroperasi di bawah tingkat permintaan yang dipesan.

Untuk informasi selengkapnya, lihat Unit Permintaan.

Desain dokumen yang lebih kecil untuk throughput lebih tinggi

Biaya permintaan (yaitu, biaya pemrosesan permintaan) dari operasi tertentu berkorelasi langsung dengan ukuran dokumen. Operasi pada dokumen besar lebih mahal daripada operasi pada dokumen kecil.

Langkah berikutnya

Untuk contoh aplikasi yang digunakan untuk mengevaluasi Azure Cosmos DB untuk skenario kinerja tinggi pada beberapa mesin klien, lihat Pengujian kinerja dan skala dengan Azure Cosmos DB.

Untuk mempelajari selengkapnya tentang perancangan aplikasi Anda untuk skala dan kinerja tinggi, lihat Pemartisian dan penyekalaan di Azure Cosmos DB.