Tips performa untuk Azure Cosmos DB dan .NET

BERLAKU UNTUK: API SQL

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

Untuk beban kerja intensif kueri, gunakan Windows 64-bit dan bukan pemrosesan hos Linux atau Windows 32-bit

Kami merekomendasikan pemrosesan hos Windows 64-bit untuk meningkatkan kinerja. SQL SDK mencakup ServiceInterop.dll asli untuk memilah dan mengoptimalkan kueri secara lokal. ServiceInterop.dll hanya didukung pada platform Windows x64.

Untuk Linux dan platform lain yang tidak menyediakan ServiceInterop.dll, panggilan jaringan tambahan dilakukan ke gateway untuk mendapatkan kueri optimal.

Empat jenis aplikasi yang tercantum di sini menggunakan pemrosesan host 32-bit secara default. Untuk mengubah pemrosesan host menjadi pemrosesan 64-bit untuk jenis aplikasi Anda, lakukan hal berikut:

  • Untuk aplikasi yang dapat dieksekusi: Di jendela Properti Proyek, pada panel Build, atur target platform ke x64.

  • Untuk proyek pengujian berbasis VSTest: Pada menu Uji Visual Studio, pilih Uji > Pengaturan Uji, lalu atur Arsitektur Prosesor Default ke X64.

  • Untuk aplikasi web ASP.NET yang disebarkan secara lokal: Pilih Alat > Opsi > Proyek dan Solusi > Proyek Web, lalu pilih Gunakan versi 64-bit IIS Express untuk situs web dan proyek.

  • Untuk aplikasi web ASP.NET yang disebarkan di Azure: Di portal Azure, di Pengaturan aplikasi, pilih platform 64-bit.

Catatan

Secara default, proyek Visual Studio baru diatur ke CPU mana pun. Kami menyarankan agar Anda mengatur proyek ke x64 sehingga tidak beralih ke x86. Proyek yang diatur ke CPU mana pun dapat dengan mudah beralih ke x86 jika dependensi hanya x86 ditambahkan.
File ServiceInterop.dll perlu berada di folder tempat DLL SDK dijalankan. Ini harus menjadi perhatian hanya jika Anda menyalin DLL secara manual atau memiliki sistem build atau penerapan kustom.

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.

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

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 Cosmos DB SDK adalah pemblokiran panggilan yang bisa jadi asinkron. Banyak pemblokiran panggilan 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. 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 pemblokiran panggilan untuk mengosongkan kueri secara sinkron. Gunakan ToFeedIterator() untuk mengosongkan kueri secara asinkron.

Lakukan:

  • Panggil 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.

Setel kueri paralel untuk koleksi yang dipartisi

SQL .NET SDK mendukung kueri paralel, yang memungkinkan Anda untuk mengueri kontainer yang dipartisi secara paralel. Untuk informasi selengkapnya, lihat sampel kode yang bekerja dengan SDK. Kueri paralel dirancang untuk memberikan latensi dan throughput kueri yang lebih baik daripada imbangan seri mereka.

Kueri paralel menyediakan dua parameter yang dapat Anda selaraskan agar sesuai kebutuhan:

  • MaxConcurrency: Mengontrol jumlah maksimum partisi yang dapat dikueri secara paralel.

    Kueri paralel bekerja dengan mengueri beberapa partisi secara paralel. Tetapi data dari tiap partisi diambil secara serial sehubungan dengan kueri. Mengatur MaxConcurrency di SDK V3 ke jumlah partisi memiliki peluang terbaik untuk mencapai kueri paling berkinerja, asalkan semua kondisi sistem lainnya tetap sama. Jika tidak tahu jumlah partisi, Anda dapat mengatur tingkat paralelisme ke angka tinggi. Sistem akan memilih minimum (jumlah partisi, input yang disediakan pengguna) sebagai derajat paralelisme.

    Kueri paralel menghasilkan manfaat paling besar jika data didistribusikan secara merata di semua partisi sehubungan dengan kueri. Jika koleksi dipartisi sehingga semua atau sebagian besar data yang dikembalikan oleh kueri terkonsentrasi dalam beberapa partisi (satu partisi adalah kasus terburuk), partisi tersebut akan menghambat performa kueri.

  • MaxBufferedItemCount: Mengontrol jumlah hasil pra-ambil.

    Kueri paralel dirancang untuk pra-ambil hasil saat batch hasil saat ini sedang diproses oleh klien. Pra-pengambilan ini membantu meningkatkan latensi keseluruhan kueri. Parameter MaxBufferedItemCount membatasi jumlah hasil pra-pengambilan. Atur MaxBufferedItemCount ke jumlah hasil yang ingin dikembalikan (atau angka yang lebih tinggi) agar kueri menerima manfaat maksimum dari pra-pengambilan.

    Pra-pengambilan bekerja dengan cara yang sama terlepas dari derajat paralelisme, dan ada satu buffer untuk data dari semua partisi.

Menerapkan backoff pada interval RetryAfter

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

Untuk informasi selengkapnya, lihat RetryAfter.

Ada mekanisme untuk mencatat informasi diagnostik tambahan dan memecahkan masalah latensi, seperti yang ditunjukkan dalam sampel berikut. Anda dapat mencatat untai diagnostik untuk permintaan yang memiliki latensi baca lebih tinggi. Untai diagnostik yang ditangkap akan membantu Anda memahami berapa kali Anda menerima galat 429 untuk permintaan tertentu.

ItemResponse<Book> readItemResponse = await this.cosmosContainer.ReadItemAsync<Book>("ItemId", new PartitionKey("PartitionKeyValue"));
readItemResponse.Diagnostics.ToString(); 

Menambah jumlah utas/tugas

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

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.