Versi 4 (V4) AWS SDK untuk .NET telah dirilis!
Untuk informasi tentang mengubah perubahan dan memigrasikan aplikasi Anda, lihat topik https://docs.aws.amazon.com/sdk-for-net/v4/developer-guide/net-dg-v4.html migrasi.
Terjemahan disediakan oleh mesin penerjemah. Jika konten terjemahan yang diberikan bertentangan dengan versi bahasa Inggris aslinya, utamakan versi bahasa Inggris.
Praktik terbaik kinerja untuk AWS SDK untuk .NET
Cara Anda membuat klien, menangani respons, dan mengonfigurasi aplikasi Anda memiliki efek besar pada throughput, latensi, dan penggunaan memori. Topik ini menjelaskan pola penggunaan dan konfigurasi yang membantu aplikasi Anda berjalan secara efisien dan andal. Pola-pola ini paling penting di bawah beban tinggi atau di lingkungan yang terbatas sumber daya seperti wadah dan fungsi tanpa server. Mengikuti praktik ini dapat meningkatkan kinerja dan mencegah masalah umum seperti respons lambat, hang, dan penggunaan memori yang tinggi.
Praktik yang paling berdampak adalah sebagai berikut:
-
Gunakan kembali satu klien layanan berumur panjang al ih-alih membuat satu per permintaan.
-
Buang respons dan aliran sehingga koneksi jaringan dilepaskan kembali ke kumpulan koneksi.
-
Gunakanasync/awaitdengan benar dan jangan pernah memblokir panggilan SDK asinkron.
-
Konfigurasikan pengumpulan sampah .NET untuk lingkungan terbatas seperti AWS Lambda dan Amazon ECS.
-
Kelola koneksi HTTP dan batas koneksi di bawah throughput tinggi.
Sebelum Anda mulai, pastikan Anda telah mengatur lingkungan Anda dan meng konfigurasi proyek Anda.
Gunakan kembali satu klien layanan yang berumur panjang
Layanan klien seperti Amazons3Client dan aman untuk ut AmazonDynamoDBClient as, relatif mahal untuk dibangun, dan berumur panjang. Membangun klien menyelesaikan informasi Wilayah dan titik akhir dan menetapkan infrastruktur HTTP yang mendasarinya. Buat satu klien per layanan dan gunakan kembali selama masa pakai aplikasi Anda. Jika Anda memanggil lebih dari satu Wilayah, buat klien terpisah untuk setiap Wilayah.
Awas
Jangan membuat klien layanan baru untuk setiap permintaan atau di dalam loop. Membuat klien berulang kali mengubah infrastruktur HTTP yang mendasarinya, yang menambahkan latensi terukur. Ini juga dapat mengeluarkan soket atau pegangan dan menyebabkan permintaan gagal atau menggantung di bawah beban.
Dalam aplikasi yang menggunakan injeksi ketergantungan, daftarkan klien sebagai singleton. Metode AddAWSService ekstensi dari AWSSDK.Extensions.NETCore.Setup NuGet paket mendaftarkan klien dengan masa pakai defaultServiceLifetime.Singleton. Klien dibuat saat pertama kali diminta, dan instance yang sama digunakan kembali selama masa proses. Untuk informasi selengkapnya tentang mendaftar AWS
kan layanan dengan injeksi ketergantungan dan opsi membaca dari konfigurasi, lihatAWSSDK.Extensions.NETCore.Setup dan IConfiguration.
Anda juga dapat mendaftarkan klien sebagai singleton secara manual.
builder.Services.AddSingleton<IAmazonS3>(_ => new AmazonS3Client());
catatan
Karena AddAWSService mendaftarkan klien sebagai singleton secara default, jangan buang klien yang disediakannya. Jika Anda memerlukan masa pakai non-default, berikan ServiceLifetime nilai yang berbeda ke lifetime parameter opsional. AddAWSService
Menggunakan kembali klien tidak berarti Anda harus berhenti membuang respons per operasi. Gunakan kembali klien selama masa pakai aplikasi, tetapi terus buang respons dan aliran yang dikembalikan oleh operasi individual, seperti yang dijelaskan dalamBuang tanggapan dan aliran.
Buang respons dan aliran untuk melepaskan koneksi
Beberapa objek respons SDK membawa aliran jaringan langsung. Contoh yang paling umum adalah GetObjectResponse, yang mengimplementasikan IDisposable dan mengekspos konten objek melalui ResponseStream propertinya. Respons menahan koneksi HTTP terbuka sampai aliran dibaca sepenuhnya atau respons dibuang. Jika Anda membocorkan respons ini (misalnya, dengan memanggil GetObject dalam satu loop tanpa membuang setiap hasil), koneksi terbuka terakumulasi hingga kumpulan koneksi habis, dan panggilan berikutnya diblokir. Ini adalah penyebab di balik laporan unduhan yang “hang secara acak” atau terhenti pada objek ke-N.
Selalu bungkus respons streaming dalam using pernyataan dan baca atau salin streamingnya segera.
using Amazon.S3; using Amazon.S3.Model; // s3Client is a reused, long-lived client. var request = new GetObjectRequest { BucketName = bucketName, Key = key }; using var response = await s3Client.GetObjectAsync(request); await response.WriteResponseStreamToFileAsync(filePath, append: false, CancellationToken.None);
Membuang respons dan membuangnya ResponseStream setara; salah satu menutup aliran jaringan yang mendasarinya dan mengembalikan koneksi ke pool.
Tip
Jika Anda hanya memerlukan metadata objek, seperti ukuran, waktu modifikasi terakhir, jenis konten, atau ETag, panggil atau alih-alihGetObjectMetadata. GetObjectMetadataAsync GetObject Operasi metadata mengeluarkan HEAD permintaan HTTP dan tidak mentransfer badan objek, jadi tidak ada aliran konten untuk dikelola.
var metadata = await s3Client.GetObjectMetadataAsync(bucketName, key); Console.WriteLine($"Size: {metadata.ContentLength} bytes");
Awas
Jenis respons dan aliran seperti GetObjectResponse tidak menerapkan finalizer, jadi Anda tidak dapat mengandalkan pengumpulan sampah untuk melepaskan koneksi mereka untuk Anda. Anda harus membuang respons dan aliran secara deterministik dengan using atau panggilan eksplisitDispose.
Gunakan async/await dengan benar
Pada .NET modern, operasi layanan di dalamnya asinkron dan mengembalikan a. AWS SDK untuk .NET Task Pada .NET Framework, metode sinkron juga ada, tetapi panggilan asinkron berskala lebih baik dan direkomendasikan. Gunakan operasi denganawait, dan async sebarkan melalui setiap lapisan kode Anda hingga titik masuk. Untuk informasi selengkapnya tentang pemrograman asinkron dengan SDK, lihat. Pemrograman asinkron
Awas
Jangan memblokir panggilan SDK asinkron dengan.Result,.Wait(), atau. .GetAwaiter().GetResult() Pola sinkronisasi over-async ini adalah penyebab umum aplikasi yang hang:
-
Di bawah beban, pemblokiran panggilan menghabiskan utas lebih cepat daripada yang dapat tumbuh kumpulan utas, sehingga kelanjutan tidak dapat berjalan. Kelap aran kumpulan utas ini muncul sebagai hang yang tidak terbatas dan merupakan mode kegagalan dominan di .NET modern (di mana tidak ASP.NET Core memiliki default).
SynchronizationContext -
Beberapa konteks menangkap
SynchronizationContext, seperti aplikasi klasikASP.NET,,Windows Forms,WPF,Blazor WebAssembly, dan .NET Framework. Dalam konteks ini, memblokir utas panggilan sementara kelanjutan membutuhkan utas yang sama menghasilkan kebun tuan. Operasi di SDK digunakanConfigureAwait(false)secara internal, sehingga mereka tidak memposting kelanjutannya kembali ke konteks yang diambil. Kebuntuan muncul dariasynckode di tempat lain dalam rantai panggilan Anda yang menangkapnya. Mengkonsumsi panggilan SDK denganawaitseluruhnya menghindari masalah sepenuhnya.
Metode berikut memblokir panggilan asinkron dan dapat menemui jalan buntu atau membuat kumpulan thread kelaparan.
// Anti-pattern: do not do this. public GetObjectResponse Get(GetObjectRequest request) { return s3Client.GetObjectAsync(request).Result; }
Sebaliknya, buat metode async dan await panggilan.
public async Task<GetObjectResponse> GetAsync(GetObjectRequest request) { return await s3Client.GetObjectAsync(request); }
Rekomendasi tambahan untuk kode asinkron:
-
Berikan a
CancellationTokenke setiap operasi sehingga panggilan yang lambat atau terhenti dapat dibatalkan alih-alih digantung. Untuk informasi selengkapnya, lihat Menggunakan CancellationToken parameter untuk batas waktu. -
Jangan menelan pengecualian di
catchblok kosong. Melakukannya menyembunyikan kegagalan yang sebenarnya dan membuat hang tidak dapat dibedakan dari kesalahan. Tangkap pengecualian tertentu dan catat. -
Saat mengembalikan pengecualian yang tertangkap, gunakan alih-
throw;throw ex;alih agar jejak tumpukan asli dipertahankan. -
Jika Anda harus memanggil dari batas sinkron, perlakukan itu sebagai upaya terakhir dan isolasi pekerjaan dari konteks yang ditangkap daripada menjadikan panggilan pemblokiran sebagai pola default.
Konfigurasikan pengumpulan sampah .NET untuk AWS Lambda dan Amazon ECS
Ketika sebuah wadah tampaknya memiliki “kebocoran memori,” .NET sampah kolektor (GC) mungkin mempertahankan memori yang direklamasi untuk digunakan kembali. Akibatnya, memori proses dapat tampak tinggi dan stabil bahkan ketika heap yang dikelola tidak tumbuh. Selain itu, GC tidak secara otomatis mendeteksi batas memori wadah (batas cgroup-nya). Dalam lingkungan yang terbatas, tumpukan kemudian dapat tumbuh ke arah memori host daripada batas wadah. Hal ini dapat menyebabkan OutOfMemoryException atau wadah dihentikan.
Untuk membantu GC bekerja dengan baik di lingkungan terbatas:
-
Tetapkan batas memori eksplisit pada wadah sehingga GC menghormati batas cgroup, and/or atur
DOTNET_GCHeapHardLimit(nilai byte absolut, dalam heksadesimal) atau variabelDOTNET_GCHeapHardLimitPercentlingkungan untuk menutup heap yang dikelola. Dalam beberapa kasus kehabisan memori Amazon ECS yang dilaporkan, pengaturan batas memori keras menyelesaikan crash. -
Pada host ECS kecil AWS Lambda dan Amazon, pertimbangkan untuk menonaktifkan pengumpulan sampah (latar belakang) bersamaan sehingga kolektor tidak mencadangkan memori tambahan; misalnya, atur variabel
DOTNET_gcConcurrentlingkungan ke0, atau disetel<ConcurrentGarbageCollection>false</ConcurrentGarbageCollection>dalam file proyek. -
Ikat konkurensi Anda. Meluncurkan banyak operasi sekaligus, seperti memanggil
Task.WhenAllkoleksi besar, meningkatkan memori proses dan dapat membuat kumpulan koneksi kelaparan. Tutup tingkat paralelisme sebagai gantinya. Misalnya, hindari pola tak terbatas ini:// Anti-pattern: starts one task per item with no limit. await Task.WhenAll(keys.Select(key => s3Client.GetObjectMetadataAsync(bucket, key)));Sebagai gantinya, batasi konkurensi dengan:
Parallel.ForEachAsyncvar options = new ParallelOptions { MaxDegreeOfParallelism = 10 }; await Parallel.ForEachAsync(keys, options, async (key, token) => { await s3Client.GetObjectMetadataAsync(bucket, key, token); });
Untuk informasi selengkapnya tentang pengaturan ini, lihat Opsi konfigurasi Runtime untuk pengumpulan sampah
Kelola koneksi HTTP dan batas koneksi
Di bawah throughput tinggi, dua masalah terkait koneksi umum terjadi. Yang pertama adalah membuka terlalu banyak koneksi berumur pendek. Ini menghabiskan port sementara, meninggalkan soket, dan menambahkan latensi jabat tangan TIME_WAIT TCP dan TLS. Yang kedua adalah memiliki terlalu sedikit koneksi yang tersedia, yang menghambat paralelisme. Menggunakan kembali satu klien berumur panjang (lihatGunakan kembali klien layanan) adalah dasar untuk pengumpulan koneksi yang sehat, karena pengumpulan tergantung pada klien yang digunakan kembali.
Untuk menyetel jumlah koneksi bersamaan per titik akhir, atur MaxConnectionsPerServer properti pada konfigurasi klien. Ketika properti ini adalah null (default), default yang mendasarinya HttpClientHandler berlaku, yang secara efektif tidak terbatas di.NET modern. Naikkan hanya ketika banyak permintaan bersamaan ke titik akhir yang sama mengalami hambatan pada koneksi. Titik awal yang baik adalah jumlah puncak permintaan bersamaan yang Anda harapkan per titik akhir. Mengaturnya jauh lebih tinggi dari kebutuhan beban kerja Anda membuang soket tanpa meningkatkan throughput.
using Amazon.S3; var config = new AmazonS3Config { MaxConnectionsPerServer = 50 }; var s3Client = new AmazonS3Client(config);
Jika Anda sudah menggunakan injeksi ketergantungan, konfigurasikan klien Anda melaluiAWSSDK.Extensions.NETCore.Setup. Ini adalah pendekatan yang disarankan ketika Anda menggunakan DI atau mendaftarkan beberapa klien layanan. Ini memusatkan konfigurasi dan membuat klien mudah disuntikkan dan diuji. Anda dapat mengatur nilai konfigurasi dari konfigurasi aplikasi Anda, bukan dalam kode. Untuk informasi selengkapnya, lihat AWSSDK.Extensions.NETCore.Setup dan IConfiguration.
Terakhir, ikat paralelisme Anda sendiri sehingga Anda tidak memulai lebih banyak operasi bersamaan daripada yang diizinkan batas koneksi Anda. Misalnya, panggilan gerbang dengan SemaphoreSlim ukuran batas koneksi Anda:
var throttle = new SemaphoreSlim(50); // match MaxConnectionsPerServer await throttle.WaitAsync(token); try { await s3Client.GetObjectAsync(request, token); } finally { throttle.Release(); }
Konfigurasikan batas waktu dan percobaan ulang
Batas waktu dan percobaan ulang memiliki efek langsung pada kinerja yang dirasakan. TimeoutNilai yang terlalu tinggi memungkinkan permintaan yang terhenti memblokir untuk waktu yang lama. Ketika layanan sudah mengembalikan kesalahan pelambatan, kebijakan coba ulang yang agresif menambahkan lebih banyak permintaan dan dapat memperburuk pelambatan. Pilih kebijakan coba ulang yang sesuai dengan toleransi aplikasi Anda untuk latensi versus kegagalan, dan biarkan pengecualian asli menyebar daripada mencoba lagi dengan cara yang menutupi hang.
catatan
Pro Timeout perti tidak mempengaruhi panggilan asinkron. Jika Anda menggunakan panggilan asinkron, lihat Menggunakan CancellationToken parameter untuk batas waktu sebagai gantinya.
Untuk informasi selengkapnya tentang mode coba lagiMaxErrorRetry,, dan Timeout properti (hanya ReadWriteTimeout berlaku untuk.NET Framework), bersama dengan contoh cara mengaturnya, lihatPercobaan ulang dan batas waktu.
Mengoptimalkan streaming dan transfer objek besar (Amazon S3)
Untuk mengunggah dan mengunduh objek besar, atau banyak objek, gunakan TransferUtility kelas di Amazon.S3.Transfer namespace. Ini mengunggah dan mengunduh secara paralel menggunakan transfer multipart, dan mengelola aliran, bagian, dan koneksi untuk Anda. Ini lebih cepat daripada transfer aliran tunggal dan merupakan cara yang disarankan untuk memindahkan objek besar.
-
Unduhan multibagian paralel. Versi SDK sebelumnya mengunduh objek sebagai aliran tunggal, daripada mengunduh bagian secara paralel. Dimulai dengan
AWSSDK.S3versi 4.0.17,TransferUtilitymenyediakan unduhan multibagian (paralel) melalui metodeDownloadWithResponseAsync,OpenStreamWithResponseAsync, dan.DownloadDirectoryWithResponseAsyncSaat Anda menggunakanOpenStreamWithResponseAsync, bagian-bagian objek akan di-buffer dalam memori saat Anda menggunakan aliran yang dikembalikan. Kontrol berapa banyak bagian yang disangga denganMaxInMemoryPartsproperti dari TransferUtilityOpenStreamRequest. Untuk sebagian besar transfer, lebih sukaTransferUtility. Unduh rentang byte sendiri denganByteRangeproperti GetObjectRequest hanya ketika Anda memerlukan rentang tertentu atau skema paralelisme khusus. Untuk informasi selengkapnya, lihat Memperkenalkan dukungan unduhan multibagian untuk AWS SDK untuk .NET Transfer Managerdi Blog AWS Alat Pengembang. -
Panjang konten untuk unggahan. Amazon S3
PUTmemerlukan panjang konten yang diketahui, dan secara default SDK menghitung checksum atas isi permintaan. Ketika panjangnya diketahui dan aliran dapat dicari, SDK dapat melakukan ini tanpa menyangga seluruh objek dalam memori. MenanganiTransferUtilityaliran yang tidak dapat dicari untuk Anda dengan melakukan buffering sesuai kebutuhan. Jika Anda menelepPutObjectAsyncon langsung dengan aliran yang tidak dapat dicari (seperti isi permintaan mentahASP.NET Core), permintaan dapat gagal. Menyediakan aliran yang dapat dicari, atur panjang konten secara eksplisit, atau konfigurasikan cara SDK menghitung checksum. Untuk informasi selengkapnya, lihat Perlindungan integritas data di Panduan Refer AWS ensi SDK dan Alat. -
Ukuran bagian. Amazon S3 memungkinkan maksimum 10.000 bagian per unggahan multipart. Ketika panjang total diketahui, SDK menghitung ukuran bagian yang tetap dalam batas ini secara otomatis. Anda terutama perlu mengatur
PartSizesendiri untuk streaming yang panjangnya tidak diketahui sebelumnya. Jika tidak, bagian default kecil dapat melebihi batas pada unggahan yang sangat besar. Ukuran bagian yang lebih besar juga mengurangi overhead per bagian, dengan mengorbankan lebih banyak memori per bagian.
Mendiagnosis masalah kinerja
Saat Anda menyelidiki perlambatan, hang, atau kebocoran yang tampak jelas, sinyal berikut membantu Anda menemukan penyebabnya dengan cepat:
-
Semakin banyak soket di
TIME_WAITstatusCLOSE_WAITatau (terlihat dengannetstat) adalah sidik jari tanggapan yang tidak diinginkan atau klien yang dibuat dan dibuang per permintaan. Lihat Buang tanggapan dan aliran dan Gunakan kembali klien layanan. -
Aktifkan metrik permintaan dan pencatatan respons untuk mengonfirmasi bahwa permintaan benar-benar dikirim dan untuk mengukur latensi. Tetapkan properti LoggingConfig objek pada AWSConfig sebelum Anda membuat klien layanan Anda. Klien menangkap pengaturan seperti
LogMetricssaat dibangun.using Amazon; AWSConfigs.LoggingConfig.LogMetrics = true; AWSConfigs.LoggingConfig.LogResponses = ResponseLoggingOption.OnError; -
Saat menyelidiki memori, bedakan memori seluruh proses dari tumpukan terkelola. Memori proses yang tinggi namun stabil seringkali merupakan GC yang menyimpan memori reklamasi daripada kebocoran. Lihat Konfigurasikan pengumpulan sampah.