Runtime: Singleton HttpClient tidak menghargai perubahan DNS

Dibuat pada 29 Agu 2016  ·  77Komentar  ·  Sumber: dotnet/runtime

Seperti yang dijelaskan dalam posting berikut: http://byterot.blogspot.co.uk/2016/07/singleton-httpclient-dns.html , setelah Anda mulai menyimpan instance HttpClient untuk meningkatkan kinerja, Anda akan akan mengalami masalah di mana klien tidak akan menghormati pembaruan catatan DNS jika terjadi skenario failover.

Masalah mendasarnya adalah bahwa nilai default ConnectionLeaseTimeout diatur ke -1 , tak terbatas. Itu hanya akan ditutup saat membuang klien, yang sangat tidak efisien.

Cara mengatasinya adalah memperbarui nilai pada titik layanan seperti ini:

var sp = ServicePointManager.FindServicePoint(new Uri("http://foo.bar/baz/123?a=ab"));
sp.ConnectionLeaseTimeout = 60*1000; // 1 minute

Sayangnya, tidak ada cara untuk melakukan ini dengan .NET Core hari ini.

ServicePointManager harus dibawa ke .NET Core atau fungsi serupa yang serupa harus diaktifkan dengan cara lain.

area-System.Net.Http enhancement

Komentar yang paling membantu

Ini benar-benar masalah. Solusi yang diusulkan oleh @darrelmiller tampaknya menunjukkan kurangnya pemahaman tentang kasus penggunaan.

Kami menggunakan Manajer Lalu Lintas Azure untuk mengevaluasi kesehatan instans. Mereka bekerja di atas DNS dengan TTL pendek. Sebuah host tidak secara ajaib mengetahui bahwa itu tidak sehat dan mulai mengeluarkan C connection:close header. Manajer lalu lintas hanya mendeteksi keadaan tidak sehat dan menyesuaikan resolusi DNS yang sesuai. Dengan desain ini SEPENUHNYA TRANSPARAN untuk klien dan host... sebagaimana adanya, aplikasi dengan HttpClient statis yang menyelesaikan DNS (tanpa disadari) oleh manajer lalu lintas tidak akan pernah menerima host baru ketika host yang diselesaikan sebelumnya menjadi tidak sehat.

Pada netcore 1.1 saat ini saya sedang mencari resolusi untuk masalah yang tepat ini. Saya tidak melihatnya, secara alami.

Semua 77 komentar

Saya tidak berpikir itu properti yang sama. Itu batas waktu koneksi, bukan ConnectionLeaseTimeout.

Seperti yang didokumentasikan di https://msdn.microsoft.com/en-us/library/system.net.servicepoint.connectionleasetimeout.aspx , itu harus dihapus secara berkala dalam beberapa skenario. Tetapi tidak ada cara yang jelas untuk mengubah perilaku di .NET Core.

@onovotny Ya itu hal aneh yang tampaknya melakukan koneksi eksplisit : tutup setelah jangka waktu tertentu. Tidak ada alasan yang tidak dapat diimplementasikan sebagai bagian dari middleware jika Anda benar-benar menginginkannya. Itu hanya tajuk HTTP.

@darrelmiller jadi itu keluar dari area saya, tidak yakin ... tetapi jika ada solusi terdokumentasi yang mengatasi masalah aslinya, itu akan menjadi manfaat besar.

@onovotny , tidak ada kelas ServicePointManager di .NET Core. Ini terdengar seperti masalah .NET Framework (Desktop). Silakan buka masalah di UserVoice atau Connect.

@onovotny Masalah aslinya, seperti yang saya pahami adalah, di sisi server, seseorang ingin memperbarui entri DNS sehingga semua permintaan di masa mendatang untuk Host A pergi ke alamat IP baru. Solusi terbaik menurut saya adalah ketika entri DNS itu diubah, aplikasi pada Host A harus diberitahu untuk mengembalikan header C connection:close ke klien pada semua respons di masa mendatang. Itu akan memaksa semua klien untuk memutuskan koneksi dan membuat yang baru. Solusinya adalah tidak memiliki nilai batas waktu pada klien sehingga klien mengirimkan koneksi C

Ini cocok dengan pertanyaan di Stackoverflow Unit yang menguji failover DNS, menggunakan resolver DNS khusus dan dapat memberikan konteks lebih lanjut seputar masalah ini, jadi saya akan menautkan silang (saya akan menghapus di sini jika tidak pantas).

Ini benar-benar masalah. Solusi yang diusulkan oleh @darrelmiller tampaknya menunjukkan kurangnya pemahaman tentang kasus penggunaan.

Kami menggunakan Manajer Lalu Lintas Azure untuk mengevaluasi kesehatan instans. Mereka bekerja di atas DNS dengan TTL pendek. Sebuah host tidak secara ajaib mengetahui bahwa itu tidak sehat dan mulai mengeluarkan C connection:close header. Manajer lalu lintas hanya mendeteksi keadaan tidak sehat dan menyesuaikan resolusi DNS yang sesuai. Dengan desain ini SEPENUHNYA TRANSPARAN untuk klien dan host... sebagaimana adanya, aplikasi dengan HttpClient statis yang menyelesaikan DNS (tanpa disadari) oleh manajer lalu lintas tidak akan pernah menerima host baru ketika host yang diselesaikan sebelumnya menjadi tidak sehat.

Pada netcore 1.1 saat ini saya sedang mencari resolusi untuk masalah yang tepat ini. Saya tidak melihatnya, secara alami.

@kudoz83 Anda benar, tuan rumah tidak secara ajaib mengetahui kapan manajer lalu lintas telah menyesuaikan resolusi DNS, oleh karena itu mengapa saya katakan

ketika entri DNS itu diubah, aplikasi pada host A harus diberi tahu

Jika Anda tidak percaya bahwa praktis untuk memberi tahu server asal bahwa server tersebut harus mengembalikan header c connection:close maka Anda hanya memiliki beberapa pilihan:

  • Tutup koneksi secara berkala dari klien atau middleware dan bayar biaya pembukaan kembali koneksi tersebut secara berlebihan
  • Minta klien melakukan polling layanan untuk mengetahui kapan harus mengatur ulang koneksi.
  • Gunakan bagian dari middleware yang cukup pintar untuk mengetahui kapan DNS telah diaktifkan.

Dan tentang saya yang tidak memahami use case. Masalah aslinya didasarkan pada posting blog di mana kasus penggunaan terkait dengan peralihan antara slot produksi dan pementasan dan tidak ada hubungannya dengan pemantauan kesehatan. Meskipun kedua skenario dapat memperoleh manfaat dari dapat menerima pemberitahuan tentang sakelar DNS/slot.

AFAIK tidak ada cara untuk memberi tahu Host yang gagal bahwa itu gagal? Umumnya ini berarti itu dalam beberapa jenis keadaan kesalahan. Posting asli berbicara tentang skenario failover.

Azure Traffic Manager dijelaskan di sini https://docs.microsoft.com/en-us/azure/traffic-manager/traffic-manager-monitoring

Ini beroperasi pada tingkat DNS dan transparan untuk klien dan host - sesuai desain. Instans Azure yang berkomunikasi satu sama lain melalui Pengelola Lalu Lintas untuk resolusi DNS berada dalam masalah tanpa dapat menyetel TTL pada penyegaran DNS untuk HttpClient.

Cara HttpClient saat ini beroperasi tampaknya bertentangan dengan penawaran layanan Azure Microsoft sendiri - yang merupakan intinya. Belum lagi, layanan serupa (EG Amazon Route 53) bekerja dengan cara yang persis sama, dan memiliki dependensi DNS TTL pendek yang sama persis.

Jelas saya menemukan utas ini karena saya terpengaruh oleh masalah ini. Saya hanya mencoba mengklarifikasi bahwa tampaknya tidak ada solusi yang ideal saat ini selain hanya membuat ulang HttpClients secara sewenang-wenang (dengan mengorbankan kinerja dan kompleksitas) demi memastikan failover DNS berhasil.

AFAIK tidak ada cara untuk memberi tahu Host yang gagal bahwa itu gagal?

Jika host "gagal" tidak dapat mengeksekusi kode apa pun, maka kami tidak memerlukan kode status HTTP 503 karena server asal tidak akan pernah dapat mengembalikannya. Ada skenario di mana host yang gagal mungkin tidak dapat memproses pemberitahuan, tetapi dalam kasus tersebut mungkin juga tidak akan menahan koneksi TCP/IP aktif untuk waktu yang lama.

Ketika Ali awalnya mengangkat topik ini di Twitter, sebelum dia menulis posting blog, dia sepakat tentang fakta bahwa klien akan terus membuat permintaan dan mendapatkan tanggapan dari server yang telah ditukar.

Saya memahami situasi Anda berbeda dan Anda tidak dapat mengandalkan server asal yang dapat menutup koneksi dengan andal. Apa yang saya tidak yakin saya mengerti adalah mengapa untuk situasi Anda, Anda tidak dapat menggunakan HttpMessageHandler untuk mendeteksi respons 5XX, tutup koneksi dan coba lagi permintaan. Atau bahkan lebih sederhana, cukup yakinkan server web Anda untuk mengembalikan koneksi: tutup setiap kali mengembalikan kode status 5XX.

Perlu juga dicatat bahwa perilaku yang Anda khawatirkan tidak ada di HttpClient. Itu ada di HttpHandler yang mendasarinya atau bahkan di bawahnya, dan ada sejumlah implementasi berbeda dari HttpHandler yang digunakan. Menurut pendapat saya, perilaku saat ini konsisten dengan cara kerja HTTP. Saya setuju ada tantangan ketika pengaturan DNS diperbarui saat koneksi terbuka, tetapi ini bukan masalah .net. Ini adalah masalah arsitektur HTTP. Itu tidak berarti .net tidak bisa melakukan sesuatu untuk mengurangi masalah ini.

Saya ingin tahu seperti apa solusi yang menurut Anda seharusnya. Apakah menurut Anda sesuatu seperti ConnectionLeaseTimeout harus diimplementasikan kembali yang hanya memutuskan koneksi secara berkala terlepas dari apakah telah terjadi failover atau tidak? Atau apakah Anda punya solusi yang lebih baik?

Maaf,

Seharusnya aku tidak tampil agresif seperti yang terdengar kemarin. Sedang mengalami hari yang buruk.

Sejujurnya saya tidak tahu bagaimana ConnectionLeaseTimeout bekerja di bawah selimut. Fungsionalitas yang diinginkan adalah agar HttpClient dapat dikonfigurasi untuk melakukan pencarian DNS baru, sebelum membuat koneksi baru sebagai lawan dari cache pencarian DNS sebelumnya sampai klien dibuang. Saya tidak percaya ini membutuhkan mematikan koneksi yang ada ...

@kudoz83 Jangan khawatir, kita semua memiliki hari-hari seperti itu :-)

Dari apa yang saya pahami ConnectionLeaseTimeout secara harfiah adalah pengatur waktu yang secara berkala menutup koneksi idle dari sisi klien. Ini diimplementasikan di ServicePointManager, yang tidak ada di core. Ini berbeda dengan timeout "idle connection" yang hanya menutup koneksi setelah tidak digunakan dalam jangka waktu tertentu.

Kemungkinan ada panggilan Win32 yang memungkinkan pembersihan cache klien DNS. Itu akan memastikan koneksi baru melakukan pencarian DNS. Saya mencarinya dengan cepat tetapi tidak menemukannya, tetapi saya yakin itu ada di suatu tempat.

Di .net core di Windows, pengelolaan koneksi HTTP sebenarnya diserahkan kepada OS. Yang paling dekat Anda dapatkan adalah panggilan ke Win32 API WinHttpOpen https://github.com/dotnet/corefx/blob/master/src/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpHandler.cs# L718 Tidak ada API publik yang dapat saya temukan untuk melakukan apa pun dengan _sessionHandle. Untuk mendapatkan jenis perubahan perilaku yang Anda cari akan memerlukan orang-orang OS untuk membuat perubahan. Setidaknya begitulah saya memahaminya.

Bukankah lebih mudah untuk mendapatkan Azure Traffic Manager hanya dengan menetapkan TTL yang sangat rendah pada entri DNS? Jika Anda tidak khawatir tentang koneksi yang berumur panjang, maka TTL yang rendah akan meminimalkan kemungkinan koneksi baru disiapkan untuk server yang mati.

Keuntungan dari cara WinHttpHandler dibangun adalah kami mendapatkan hal-hal seperti HTTP/2 secara gratis dengan pembaruan OS. Kelemahannya adalah kita tidak mendapatkan banyak kendali dalam kode terkelola.

@darrelmiller

[ConnectionLeaseTimeout] diimplementasikan di ServicePointManager, yang tidak ada di core.

Tampaknya ServicePoint.ConnectionLeaseTimeout akan kembali di .Net Standard 2.0/.Net Core 1.2. (Meskipun saya tidak tahu apakah misalnya koneksi WinHttpHandler akan mematuhinya.)

Saya pikir ada beberapa miskomunikasi di sini: DNS TTL sama sekali tidak terkait dengan masa pakai koneksi HTTP/TCP.

Koneksi HTTP baru melakukan pencarian DNS dan terhubung ke alamat host yang dikembalikan. Beberapa permintaan HTTP dapat dibuat melalui koneksi tunggal yang sama tetapi setelah membuka koneksi HTTP (dan koneksi TCP yang mendasarinya) tidak melakukan pencarian DNS lagi.

Ini adalah perilaku yang benar sehingga meskipun Anda membuat 1000 permintaan melalui koneksi yang berlangsung selama berhari-hari, resolusi DNS tidak masalah karena koneksi tidak berubah. Jika Anda membuat permintaan HTTP baru melalui koneksi HTTP baru, Anda akan melihat pencarian DNS untuk koneksi baru.

Penyegaran DNS ini tidak ada hubungannya dengan HttpClient , yang hanya menggunakan HttpClientHandler secara default (yang dengan sendirinya menggunakan tumpukan soket HttpWebRequest ) dan resolusi DNS apa pun ditangani oleh tumpukan itu. ServicePointManager mengelola objek ServicePoint di tumpukan itu yang merupakan koneksi ke host tertentu. ServicePointManager memang memiliki beberapa cache pencarian DNS sisi klien minimum yang dapat Anda atur.

Pengaturan default dimaksudkan agar koneksi tetap terbuka tanpa batas untuk efisiensi. Jika host yang terhubung menjadi tidak tersedia maka koneksi akan terputus secara otomatis, menyebabkan koneksi baru dengan pencarian DNS baru, namun TTL DNS tidak akan menyebabkan koneksi baru. Jika Anda membutuhkannya, Anda harus mengkodekannya ke dalam aplikasi Anda.

Jika Anda ingin pencarian DNS lain dilakukan, Anda perlu mengatur ulang koneksi pada klien. Anda dapat memaksa koneksi TCP seumur hidup maksimal, mengirim header connection: close atau membuang HttpClient atau ServicePoint mendasarinya. Anda juga dapat melakukan resolusi DNS dengan Dns.GetHostAddresses dan menggunakan alamat IP sebagai gantinya untuk permintaan HTTP Anda.

Semoga itu bisa membantu, jika saya tidak setuju dengan ini, beri tahu saya.

@manigandham

Saya pikir ada beberapa miskomunikasi di sini: DNS TTL sama sekali tidak terkait dengan masa pakai koneksi HTTP/TCP.

Ya DNS TTL cukup tidak berhubungan, tetapi tidak sepenuhnya.

Koneksi HTTP baru melakukan pencarian DNS dan terhubung ke alamat host yang dikembalikan.

Ya itu benar. Tetapi Windows memiliki cache DNS lokal yang menghormati TTL. Jika TTL tinggi dan server DNS telah mengubah catatan DNS, maka koneksi baru akan dibuka terhadap alamat IP lama karena cache klien dari catatan DNS. Membilas cache DNS klien adalah satu-satunya solusi untuk ini yang saya ketahui.

Beberapa permintaan HTTP dapat dibuat melalui koneksi tunggal yang sama tetapi setelah membuka koneksi HTTP (dan koneksi TCP yang mendasarinya) tidak melakukan pencarian DNS lagi.

Benar lagi. Dalam swap produksi/pementasan di mana server yang ditukar masih merespons, ini akan menyebabkan banyak permintaan di masa mendatang untuk pergi ke server lama, yang buruk. Namun, percakapan terbaru adalah tentang skenario di mana server gagal dan Manajer Lalu Lintas bertukar ke server baru. Apa yang terjadi pada koneksi yang ada ke server yang gagal tidak diketahui. Jika ini adalah kegagalan perangkat keras yang parah, maka ada kemungkinan besar koneksi akan terputus. Itu akan memaksa klien untuk membangun kembali koneksi dan di situlah TTL rendah berguna. Namun, jika kegagalan server tidak merusak server dan itu hanya mengembalikan respons 5XX maka akan berguna bagi server untuk mengembalikan koneksi: tutup untuk memastikan bahwa permintaan di masa mendatang akan dibuat pada koneksi baru, semoga berfungsi dengan baik. server

Penyegaran DNS ini tidak ada hubungannya dengan HttpClient, yang hanya menggunakan HttpClientHandler secara default (yang dengan sendirinya menggunakan tumpukan soket HttpWebRequest)

Iya dan tidak. Pada inti .Net, HttpClientHandler telah ditulis ulang dan tidak lagi menggunakan HttpWebRequest dan oleh karena itu tidak menggunakan ServicePointManager. Oleh karena itu alasan untuk masalah ini.

Saya melihat lebih dekat pada IIS dan tampaknya tidak ada cara untuk mendapatkan respons 5XX untuk datang dengan koneksi: tutup header. Penting untuk mengimplementasikan HttpModule untuk melakukan keajaiban itu.

Sebagai FYI, inilah posting terkait yang membahas masalah ini dan solusi sementara. Waspadalah terhadap HttpClient

ServicePointManager harus dibawa ke .NET Core

Meskipun kami telah membawa ServicePointManager dan HttpWebRequest untuk paritas platform, itu tidak mendukung sebagian besar fungsionalitas di .Net Core karena tumpukan yang mendasarinya diselesaikan ke WinHTTP atau Curl yang tidak mengekspos tombol kontrol lanjutan.

Menggunakan ServicePointManager untuk mengontrol HttpClient sebenarnya adalah efek samping dari penggunaan HttpWebRequest dan tumpukan HTTP terkelola di .Net Framework. Karena WinHttpHandler/CurlHandler digunakan pada .Net Core, SPM tidak memiliki kendali atas instance HttpClient.

atau fungsi serupa yang setara harus diaktifkan dengan cara lain.

Inilah jawaban tim WinHTTP:

  1. Untuk alasan keamanan, saat klien terus mengirim permintaan dan _ada koneksi aktif_, WinHTTP akan terus menggunakan IP tujuan. Tidak ada cara untuk membatasi waktu koneksi ini tetap aktif.
  2. Jika semua koneksi ke titik akhir jarak jauh ditutup oleh server, koneksi _new_ akan dibuat meminta DNS dan dengan demikian menuju IP baru.

Untuk memaksa klien ke IP berikutnya, satu-satunya solusi yang layak adalah memastikan bahwa server menolak koneksi baru dan menutup yang sudah ada (sudah disebutkan di utas ini).
Ini sama dengan apa yang saya pahami dari dokumentasi ATM : deteksi dibuat berdasarkan permintaan GET yang gagal 4 kali (non-200 tanggapan) dalam hal ini koneksi akan ditutup oleh server.

Mengingat perangkat alat jaringan lain yang melakukan caching DNS (mis. router/AP rumahan), saya tidak akan merekomendasikan DNS fail-over sebagai solusi untuk latensi rendah, teknik ketersediaan tinggi. Jika itu diperlukan, rekomendasi saya untuk kegagalan yang terkontrol adalah memiliki LB (perangkat keras atau perangkat lunak) khusus yang tahu cara menguras-stop dengan benar.

sebagaimana adanya, aplikasi dengan HttpClient statis yang menyelesaikan DNS (tanpa disadari) oleh pengelola lalu lintas tidak akan pernah menerima host baru saat host yang diselesaikan sebelumnya menjadi tidak sehat.

Seperti disebutkan di atas, jika tidak sehat yang Anda maksudkan bahwa server mengembalikan kode kesalahan HTTP dan menutup koneksi TCP saat Anda mengamati DNS TTL kedaluwarsa, ini memang bug.

Jelaskan skenario Anda secara lebih rinci:

  1. Selama failover, apa cache DNS dan TTL mesin klien. Anda dapat menggunakan ipconfig /showdns dan nslookup -type=soa <domain_name> untuk membandingkan apa yang mesin pikirkan tentang TTL dan TTL NS otoritatif.
  2. Apakah ada koneksi aktif ke server jauh? Anda dapat menggunakan netstat /a /n /b untuk melihat koneksi dan proses yang memilikinya.
  3. Membuat repro akan banyak membantu kami: harap lampirkan info yang tersedia seperti: versi .Net Core/Framework, kode untuk klien/server, jejak jaringan, LB DNS/Manajer Lalu Lintas DNS jarak jauh yang terlibat, dll.

Jika Anda terhubung ke mesin dan koneksi TCP/HTTP terus berfungsi, mengapa pada titik tertentu Anda harus menganggap server tidak lagi sesuai.
Saya pikir ada ruang untuk perbaikan di sisi Azure. Misalnya, ketika mesin tidak sehat atau bertukar lingkungan, koneksi yang ada dapat ditutup.

atau buang saja ... yang mendasari ServicePoint

@manigandham Bagaimana? Itu tidak sekali pakai dan satu-satunya metode relevan yang dapat saya lihat adalah CloseConnectionGroup yang tidak dapat Anda gunakan karena nama grup adalah detail implementasi (saat ini beberapa hash dari pawang). Juga, saya tidak yakin apa yang akan terjadi jika Anda mencoba membuang ServicePoint saat HttpClient menggunakannya (terutama secara bersamaan).

@ohadschn

.NET Core 2.0 menghadirkan kembali kelas dan fungsionalitas ServicePoint : https://docs.microsoft.com/en-us/dotnet/api/system.net.servicepoint?view=netcore-2.0

Anda dapat kembali menggunakan batas waktu sewa koneksi untuk menetapkan jangka waktu maksimum untuk koneksi aktif sebelum mereka disetel ulang.

Tidak ada yang aneh tentang menutup koneksi saat permintaan HttpClient sedang berlangsung, itu sama saja dengan Anda kehilangan konektivitas saat menjelajah internet. Entah permintaan tidak pernah berhasil atau memang demikian dan Anda tidak mendapatkan respons kembali - keduanya akan menyebabkan kesalahan http yang dikembalikan dan Anda harus menanganinya di aplikasi Anda.

Dengan pengaturan batas waktu sewa koneksi, Anda dapat memastikan ini dilakukan hanya setelah permintaan dikirim dan diatur ulang sebelum permintaan berikutnya melewati batas waktu.

.NET Core 2.0 menghadirkan kembali kelas dan fungsionalitas ServicePoint: https://docs.microsoft.com/en-us/dotnet/api/system.net.servicepoint?view=netcore-2.0
Anda dapat kembali menggunakan batas waktu sewa koneksi untuk menetapkan jangka waktu maksimum untuk koneksi aktif sebelum mereka disetel ulang.

Sebenarnya, itu tidak mengembalikan fungsionalitas sepenuhnya. Permukaan API kembali. Tetapi pada dasarnya ini adalah larangan karena tumpukan HTTP tidak menggunakan model objek itu.

cc: @stephentoub @geoffkizer

Saya akan menganggap banyak peserta di utas ini sebagai semacam "tim impian" dalam materi pelajaran ini, namun saya masih tidak yakin apakah ada konsensus yang dicapai tentang praktik terbaik apa yang diberikan apa yang kita miliki saat ini. Akan sangat bagus untuk mendapatkan jawaban yang menentukan dari grup ini pada beberapa poin kunci.

Katakanlah saya memiliki perpustakaan HTTP tujuan umum yang menargetkan banyak platform, tidak semuanya mendukung ServicePointManager , dan saya mencoba memberikan perilaku yang mengelola instance HttpClient dengan cerdas, sesuai praktik terbaik, secara default. Saya tidak tahu sebelumnya apa host yang akan dipanggil, apalagi apakah mereka berperilaku baik sehubungan dengan perubahan DNS/ koneksi C

  1. Bagaimana cara mengelola instans HttpClient secara optimal? Satu per titik akhir? Satu per host/skema/port? Secara harfiah satu singleton total? (Saya ragu, karena konsumen mungkin ingin memanfaatkan header default, dll.)

  2. Bagaimana cara paling efektif menangani masalah DNS ini? Buang instans setelah 1 menit? Perlakukan itu sebagai "sangat tidak mungkin" dan jangan berikan perilaku pembuangan apa pun secara default?

(Bukan situasi hipotetis btw; Saya sedang bergulat dengan pertanyaan-pertanyaan yang tepat ini sekarang.)

Terima kasih!

Saya bahkan tidak akan diundang ke uji coba tim impian, tetapi saya memiliki satu wawasan tentang komentar HttpClient singleton Anda. Pertama, Anda selalu dapat menggunakan metode SendAsync untuk menentukan header dan alamat yang berbeda, sehingga Anda dapat membungkusnya dengan kelas Anda yang menyediakan data bersama yang serupa dengan HttpClient (misalnya header default, alamat dasar) akhirnya memanggil klien tunggal yang sama. Tetapi lebih baik lagi, Anda dapat membuat beberapa HttpClient instance yang semuanya berbagi HttpClientHandler : https://github.com/dotnet/corefx/issues/5811.

Adapun masalah DNS, konsensus di sini tampaknya adalah:

Untuk memaksa klien ke IP berikutnya, satu-satunya solusi yang layak adalah memastikan bahwa server menolak koneksi baru dan menutup yang sudah ada

Jika ini tidak layak untuk Anda, Darrel Miller menyarankan beberapa opsi lagi di sini: https://github.com/dotnet/corefx/issues/11224#issuecomment -270498159.

@ohadschn Terima kasih, dan semoga saya tidak terlalu keluar dari topik, tetapi apakah ada _manfaat_ sama sekali untuk berbagi HttpClient (atau HttpClientHandler) yang sama di antara banyak host? Saya bisa saja salah tetapi menurut saya host baru berarti pencarian DNS baru, koneksi baru, soket baru. Bisakah soket di TIME_WAIT direklamasi dan digunakan kembali untuk host yang berbeda? Saya berasumsi tidak, tapi kami pasti mencapai batas keahlian saya. Jika bisa, mungkin ini keuntungan menggunakan HttpClient tunggal bahkan dengan banyak host?

Mengenai saran DNS, saya merasa di situlah konsensus paling kurang, dan dapat dimengerti. Memastikan server berperilaku dengan benar tidak layak jika Anda tidak memiliki kendali atas apa yang terjadi di akhir itu. Saya _bisa_ mendesain sesuatu di mana instance dibuang secara berkala. Pertanyaannya adalah apakah itu sepadan dengan pertukaran dalam sebagian besar kasus. Saya kira itu sebagian besar terserah saya untuk membuat keputusan. :)

Bagi saya manfaat yang paling jelas untuk berbagi HttpClient [ Handler ] adalah kesederhanaan. Anda tidak perlu menyimpan hal-hal seperti pemetaan antara host dan klien. Saya tidak akan tahu tentang hal-hal TIME_WAIT, benar-benar bukan keahlian saya juga.

Mengenai DNS, Anda menyebutkan satu kemungkinan pendekatan ketika Anda tidak mengontrol server. Anda juga dapat menerapkan mekanisme yang secara berkala menanyakan DNS dan membuang instance hanya jika terjadi perubahan aktual...

Sementara jawaban yang diberikan yang menentukan apa yang harus terjadi di sisi server akurat untuk dunia yang ideal, di dunia nyata pengembang sering tidak memiliki kendali atas tumpukan sisi server penuh, yang mereka komunikasikan. Dalam hal itu saya sangat menyukai konsep ConnectionLeaseTimeout, karena merupakan konsesi terhadap realitas kehidupan sehari-hari John dan Jane Doeveloper.
Seseorang menyarankan untuk menulis middleware untuk memberlakukan batas waktu seperti itu pada .NET Core. Apakah kelas ini berdasarkan NodaTime dan System.Collections.Immutable melakukan pekerjaan itu?

    public class ConnectionLeaseTimeoutHandler : DelegatingHandler
    {
        private static string GetConnectionKey(Uri requestUri) => $"{requestUri.Scheme}://{requestUri.Host}:{requestUri.Port}";

        private readonly IClock clock;
        private readonly Duration leaseTimeout;
        private ImmutableDictionary<string, Instant> connectionLeases = ImmutableDictionary<string, Instant>.Empty;

        public ConnectionLeaseTimeoutHandler(HttpMessageHandler innerHandler, IClock clock, Duration leaseTimeout)
            : base(innerHandler)
        {
            this.clock = clock;
            this.leaseTimeout = leaseTimeout;
        }

        protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            string key = GetConnectionKey(request.RequestUri);
            Instant now = clock.GetCurrentInstant();

            Instant leaseStart = ImmutableInterlocked.GetOrAdd(ref connectionLeases, key, now);

            if (now - leaseStart > leaseTimeout)
            {
                request.Headers.ConnectionClose = true;
                ImmutableInterlocked.TryRemove(ref connectionLeases, key, out leaseStart);
            }

            return base.SendAsync(request, cancellationToken);
        }
    }

@snboisen Saya pikir itu terlihat benar tetapi jangan pegang saya untuk itu. :)

Bagi saya pertanyaan yang lebih besar adalah apakah mengirim tajuk Connection: close bahkan merupakan solusi yang layak. Patut diulangi di sini apa yang dikatakan @darrelmiller di komentar posting blog yang mendorong utas ini:

ConnectionLeaseTimeout adalah binatang aneh, yang tidak saya sadari sampai Oren menyebutkannya hari ini. Ini akan menyebabkan permintaan keluar untuk menyertakan koneksi C : Tutup header setelah masa sewa berakhir, menyebabkan koneksi dihentikan setelah server mengirimkan responsnya. Masuk akal mengapa ini disetel ke tak terbatas ke default karena ini adalah cara aneh untuk memaksa koneksi ditutup ketika klien secara aktif membuat permintaan.

Saya menghormati pendapat Darrel dan itu membuat seluruh pendekatan ini tampak agak retas. Di sisi lain, saya setuju bahwa apa yang harus dilakukan pengembang yang tidak memiliki kendali atas apa yang terjadi di sisi server? Jika berhasil _kadang-kadang_, mungkin itu pilihan terbaik yang kita miliki? Ini tentu saja "lebih murah" daripada membuang HttpClients secara berkala atau melakukan pencarian DSN secara berkala.

Apakah ada tiket Azure terbuka untuk masalah ini?
Dari sudut pandang saya, tampaknya Anda semua mencoba untuk mengatasi cara ini diterapkan di manajer lalu lintas Azure.
Saya bukan pengguna Azure, jadi saya melihatnya dari kejauhan, merasa tidak ingin melompati rintangannya.

@tmds Saya belum pernah melihatnya, tetapi seperti yang telah disebutkan orang lain, ini terkait dengan lebih dari sekadar Manajer Lalu Lintas Azure: AWS memiliki konsep serupa dan ada Layanan Aplikasi Azure dengan pertukaran slot staging/produksi. Dan saya yakin penyedia cloud lain juga menawarkan sesuatu yang mirip dengan mekanisme pertukaran ini.

@snboisen Apakah Anda mengatakan AWS dan penyedia cloud lainnya (yang?) juga menggunakan batas waktu DNS untuk mengimplementasikan fitur ini?

@tmds Untuk AWS, ya, setidaknya untuk failover: https://aws.amazon.com/route53/faqs/#adjust_ttl_to_use_failover
Saya tidak tahu tentang penyedia cloud lain, tetapi sepertinya beberapa juga melakukannya.

@tmds Untuk AWS, ya, setidaknya untuk failover: https://aws.amazon.com/route53/faqs/#adjust_ttl_to_use_failover
Saya tidak tahu tentang penyedia cloud lain, tetapi sepertinya beberapa juga melakukannya.

Ada dua skenario bermasalah di sini:

  • klien terhubung ke server yang sudah tidak ada lagi
  • klien terhubung ke server yang sekarang menjalankan versi perangkat lunak yang ketinggalan zaman

Kegagalan DNS terkait dengan yang pertama. Ini tepat untuk menghapus server yang tidak dapat dijangkau dari DNS (di AWS, Azure, ...).
Cara yang tepat untuk mendeteksinya pada klien adalah dengan mekanisme timeout. Saya tidak yakin apakah ada properti seperti itu di HttpClient (batas waktu balasan maksimum pada koneksi yang dibuat).
Pada tingkat protokol, protokol websocket dan http2 yang lebih baru mendefinisikan pesan ping/pong untuk memeriksa keaktifan koneksi.

Ketika saya menyarankan untuk membuka masalah dengan Azure, itu untuk skenario kedua.
Tidak ada alasan klien harus menutup koneksi yang berfungsi. Jika server tidak lagi sesuai, klien harus diputuskan dan server harus dibuat tidak dapat dijangkau.
Saya menemukan dokumen yang bagus tentang penerapan AWS Blue/Green: https://d0.awsstatic.com/whitepapers/AWS_Blue_Green_Deployments.pdf.
Ini daftar beberapa teknik. Bagi mereka yang menggunakan DNS disebutkan _DNS TTL complexities_. Bagi mereka yang menggunakan penyeimbang beban _tidak ada kompleksitas DNS_.

@tmds Terima kasih atas tautannya, itu sangat menarik.

Saya bertanya-tanya seberapa umum mengandalkan DNS TTL vs menggunakan penyeimbang beban. Yang terakhir sepertinya solusi yang jauh lebih andal secara umum.

Mengalami beberapa perilaku serupa saat bekerja dengan 2 Aplikasi API berbeda di Layanan Aplikasi Azure yang berkomunikasi melalui HttpClient . Kami melihat sekitar 250 permintaan dalam pengujian beban kami, kami akan mulai mendapatkan batas waktu dan "Sambungan tidak dapat dibuat" HttpRequestException - Tidak masalah apakah itu pengguna bersamaan, atau permintaan berurutan.

Saat kami beralih ke blok using untuk memastikan HttpClient dibuang di setiap permintaan, kami tidak menerima pengecualian ini. Hit kinerja, jika ada, dapat diabaikan dari sintaks Singleton hingga using .

Saat kami beralih ke blok using untuk memastikan HttpClient dibuang di setiap permintaan, kami tidak menerima pengecualian ini. Hit kinerja, jika ada, dapat diabaikan dari sintaks Singleton hingga using .

Ini belum tentu tentang kinerja, ini tentang tidak membocorkan koneksi TCP dan mendapatkan SocketException s.

Dari MSDN :

HttpClient dimaksudkan untuk dipakai sekali dan digunakan kembali sepanjang umur aplikasi. Khususnya dalam aplikasi server, membuat instance HttpClient untuk setiap permintaan akan menghabiskan jumlah soket yang tersedia di bawah beban berat. Ini akan menghasilkan kesalahan SocketException .

Juga, lihat https://aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/

@khellang Terima kasih atas tautannya (dan klarifikasi tentang SocketException s, saya pasti memiliki kesalahpahaman di sana) - Saya telah menemukan posting itu dan 3 atau 4 posting lain yang menguraikan hal yang persis sama.

Saya mengerti bahwa instantiasi tunggal adalah tujuannya, tetapi ketika kami menggunakannya di Layanan Aplikasi Azure, kami secara konsisten mencapai HttpRequestExceptions bawah beban yang cukup sederhana (disebutkan di atas, 250 permintaan berurutan). Kecuali ada solusi lain, membuang HttpClient adalah solusi yang harus kami terapkan untuk menghindari pengecualian yang konsisten ini.

Saya berasumsi solusi "yang lebih benar" adalah dengan menangkap pengecualian ini, membatalkan semua permintaan yang tertunda secara eksplisit membuang HttpClient , membuat ulang instance HttpClient , dan mencoba lagi semua permintaan.

Sepertinya sedikit berantakan untuk sesuatu yang

dimaksudkan untuk dipakai sekali dan digunakan kembali sepanjang masa pakai aplikasi

Kami menginginkan solusi yang lebih bersih, tetapi sepertinya itu bukan sesuatu yang salah dengan kode kami, melainkan batasan dengan kerangka kerja. Saya lebih dari senang untuk salah, saya hanya perlu beberapa panduan tentang bagaimana kita dapat menggunakan ini sebagaimana dimaksud dan tidak menghadapi masalah ini.

@snboisen Saya menguji ConnectionLeaseTimeoutHandler Anda dan saya menemukan bahwa itu tidak berfungsi dengan banyak koneksi. "Tutup" dikeluarkan hanya untuk satu koneksi setiap kali waktu sewa habis, tetapi mungkin ada beberapa koneksi yang terbuka dengan satu instans HttpClient saat mengirim permintaan secara paralel. Dari apa yang saya lihat di fiddler (saya menggunakan alamat IP yang buruk untuk menghasilkan kesalahan untuk memeriksa sakelar DNS) setelah "tutup" dikirim beberapa permintaan menggunakan IP baru dan beberapa permintaan menggunakan IP lama. Dalam kasus saya, saya memiliki batas koneksi 2 dan perlu beberapa iterasi dari batas waktu sewa koneksi untuk menyegarkan kedua koneksi. Jelas akan jauh lebih buruk dengan lebih banyak koneksi bersamaan dari server produksi, tetapi mungkin pada akhirnya akan beralih setelah beberapa waktu.

Saya tidak tahu cara untuk mengeluarkan "dekat" ke setiap koneksi individu yang digunakan oleh instance HttpClient. Itu pasti ideal, tetapi yang akan saya lakukan adalah menggunakan metode pabrik GetOrCreate() untuk HttpClient dan membuat instance HttpClient baru setiap 120 detik untuk memastikan semua koneksi baru dibuat. Saya hanya tidak yakin bagaimana cara membuang instance HttpClient lama setelah semua permintaan selesai untuk menutup koneksi, tetapi saya pikir .NET menanganinya karena tidak pernah menjadi masalah dalam membuat instance HttpClient baru per permintaan.

Sebagai catatan tambahan, saya percaya penyegaran harus terjadi pada klien. Server tidak bertanggung jawab untuk mengomunikasikan perubahan DNS atau middleware apa pun. Tujuan DNS adalah untuk mengimbangi tanggung jawab tersebut sehingga Anda dapat mengubah IP kapan saja tanpa koordinasi antara klien dan server dan bukan hanya untuk memberikan nama yang ramah untuk IP. Kasus penggunaan yang sempurna adalah alamat IP AWS Elastic. Perubahan hanya tercermin dalam DNS. AWS tidak akan tahu untuk mengirim tajuk "tutup" dari server web Anda yang berjalan pada instans EC2. AWS tidak akan mengetahui setiap server web yang berada di atas instans EC2 yang mereka kelola. Skenario untuk server lama yang tidak mengirim melalui header "tutup" adalah penerapan server baru di mana perangkat lunak yang sama persis sedang digunakan ke server baru dengan semua lalu lintas dialihkan oleh DNS. Tidak ada yang harus berubah di server lama, terutama jika Anda harus beralih kembali. Semuanya harus diubah dengan lancar di satu tempat dengan DNS.

Terlepas dari masalah yang lebih besar yang dibahas di sini, apakah ConnectionLeaseTimeout sekarang diimplementasikan dalam inti? Dan jika demikian, mengapa masalah ini tidak ditutup? Saya dapat membuat kode contoh persis seperti posting asli tanpa masalah sekarang. Apakah itu memecahkan masalah DNS koneksi saya atau tidak, itu _tampaknya_ ConnectionLeaseTimeout _is_ diimplementasikan dalam inti.

ServicePointMananager.ConnectionLeaseTimeout tidak diterapkan di .NET Core. Menggunakan properti ini di .NET Core tidak dapat dilakukan. Ini hanya berfungsi di .NET Framework. Dan secara default, properti ini disetel ke "nonaktif" di .NET Framework.

Saya mengerti bahwa instantiasi tunggal adalah tujuannya, tetapi ketika kami menggunakannya di Layanan Aplikasi Azure, kami secara konsisten mencapai HttpRequestExceptions di bawah beban yang cukup sederhana (disebutkan di atas, 250 permintaan berurutan). Kecuali ada solusi lain, membuang HttpClient adalah solusi yang harus kami terapkan untuk menghindari pengecualian yang konsisten ini.

Kami telah berhasil mengatasi masalah kelelahan soket dengan membungkus HttpClient dalam API khusus yang memungkinkan setiap permintaan http dalam aplikasi untuk menggunakan kembali instance HttpClient (tidak hanya ini , seperti RestSharp tetapi ini juga salah satu manfaatnya). Mengambil ini berada di belakang lock{} karena setiap 60 menit kami membuat HttpClient dan mengembalikannya sebagai gantinya. Ini memungkinkan kami untuk melakukan permintaan http volume tinggi dari aplikasi web kami (karena integrasi berat yang kami miliki) sambil tetap tidak menggunakan kembali koneksi lama yang belum ditutup. Kami telah melakukan ini selama sekitar satu tahun sekarang dengan sukses (setelah mencapai masalah kelelahan soket).

Saya yakin masih ada implikasi kinerja dalam hal ini (terutama karena semua penguncian) tetapi lebih baik daripada semuanya mati karena kelelahan soket.

@KallDrexx mengapa Anda perlu mengunci instance 'global'? Secara naif saya akan menyimpannya dalam keadaan statis dan hanya menggantinya setiap 60 menit dengan yang baru. Apakah itu tidak cukup?

Kode kita untuk mendapatkan HttpClient adalah:

```c#
var time SinceCreated = DateTime.UtcNow - _lastCreatedAt;
if (time SinceCreated.TotalSeconds > SecondsToRecreateClient)
{
kunci (gembok)
{
time SinceCreated = DateTime.UtcNow - _lastCreatedAt;
if (time SinceCreated.TotalSeconds > SecondsToRecreateClient)
{
_currentClient = HttpClient baru();
_lastCreatedAt = DateTime.UtcNow;
}
}
}

        return _currentClient;

```

Jadi saya kira kunci hanya terjadi sekali per menit sehingga banyak utas tidak mencoba membuat HttpApiClient secara bersamaan. Saya pikir kami mengunci lebih agresif.

Begitu, jadi itu adalah alasan kenyamanan.
Atau Anda dapat menggunakan pembaruan berbasis Timer (async), atau mengizinkan beberapa dari mereka dibuat secara paralel (gaya inisialisasi malas thread-tidak aman), atau menggunakan mekanisme sinkronisasi yang berbeda dan tidak memblokir utas lainnya selama waktu pembuatan (mereka dapat menggunakan kembali yang lama).

Begitu, jadi itu adalah alasan kenyamanan.

Saya tidak tahu apakah saya akan mengklasifikasikannya sebagai kenyamanan.

Jika terlalu banyak utas mencoba membuat HttpClient pada saat yang sama, kita masih berisiko kehabisan soket karena terlalu banyak yang dibuat setiap menit, terutama jika soket lama belum dibersihkan dengan benar dalam satu menit itu (menyebabkan kaskade).

Selain itu, saya masih memerlukan beberapa ukuran penguncian karena saya tidak tahu apakah memperbarui DateTime adalah operasi atom (saya kira tidak) dan oleh karena itu beberapa utas dapat membaca nilai _lastCreatedAt di tengah operasi pembaruan.

Dan agar semua utas menggunakan kembali klien lama sekaligus memiliki satu utas membuat klien baru membutuhkan banyak logika kompleks sehingga kami dijamin bahwa satu utas berhasil membuat klien baru. Belum lagi kami masih membutuhkan kunci karena kami tidak dapat menjamin bahwa satu utas tidak akan mengembalikan _currentClient sementara utas lain sedang membuat instance.

Ada terlalu banyak hal yang tidak diketahui dan menambah kerumitan untuk mengambil risiko melakukan hal itu dalam produksi.

@KallDrexx

  • Tampaknya ReaderWriterLockSlim akan lebih cocok untuk penggunaan Anda.
  • DateTime harus atomik jika Anda menjalankan true x64 (karena berisi satu bidang ulong ). Perhatikan bahwa kode Anda saat ini tidak thread-safe jika bukan itu masalahnya, karena Anda mengamati nilai DateTime luar kunci.
  • Pendekatan berbasis timer yang disarankan oleh @karelz tidak memerlukan DateTime sama sekali... timer hanya akan mengganti HttpClient . Anda masih perlu mengelilingi bidang HttpClient dengan beberapa penghalang memori ( volatile , Interlocked.Exchange dll).

Tampaknya ReaderWriterLockSlim akan lebih cocok untuk penggunaan Anda.

Rapi Saya tidak tahu tentang kelas itu! Namun, Anda menyebutkan ini juga membuat saya berpikir untuk juga menggunakan SemaphoreSlim , karena itu ramah async/await (di mana tampaknya ReaderWriterLockSlim tidak), yang dapat membantu kemungkinan pertikaian utas ketika HttpClient diperlukan. Kemudian lagi ReaderWriterLockSlim akan menangani lebih baik potensi masalah non-atomic DateTime Anda tunjukkan dengan benar, jadi saya harus memikirkan ini, terima kasih!

Pendekatan berbasis timer yang disarankan oleh @karelz tidak akan memerlukan DateTime sama sekali... timer hanya akan mengganti HttpClient. Anda masih perlu mengelilingi bidang HttpClient dengan beberapa penghalang memori (volatile, Interlocked.Exchange dll).

Ah aku salah membaca apa yang dia maksud. Itu masuk akal, meskipun saya perlu lebih mengenal mekanisme penghalang memori untuk melakukannya dengan benar.

Terima kasih.

Sunting: Sekedar menambahkan, ini adalah alasan bagus mengapa saya pikir sesuatu harus dibangun untuk menangani ini, jadi setiap konsumen HttpClient tidak harus menerapkan kembali/melalui ini.

Saya ingin tahu apakah ini masih menjadi masalah di .net core 2.0? Apakah kita masih perlu khawatir tentang perubahan DNS?

Saya ingin tahu apakah ini masih menjadi masalah di .net core 2.0? Apakah kita masih perlu khawatir tentang perubahan DNS?

Pemahaman saya adalah bahwa itu bukan masalah dengan Dns itu sendiri, hanya saja HttpClient akan mencoba menggunakan kembali koneksi yang ada (untuk mencegah kelelahan soket), dan dengan demikian bahkan ketika DNS berubah, Anda masih terhubung ke yang lama server karena Anda akan melalui koneksi sebelumnya.

@KallDrexx , jadi itu berarti masih ada masalah untuk penyebaran biru-hijau?

@withinoneyear dari pemahaman saya ya. Jika Anda membuat HttpClient dan menggunakannya melawan Production Green, kemudian menukar produksi ke Blue, HttpClient akan tetap memiliki koneksi terbuka ke Green hingga koneksi ditutup.

Saya tahu ini sudah tua, tetapi saya yakin Anda tidak boleh menggunakan DateTime.UtcNow untuk pengukuran interval waktu. Gunakan sumber waktu monitonik seperti Stopwatch.GetTimestamp. Dengan cara ini Anda kebal terhadap penyesuaian waktu lokal oleh operator atau sinkronisasi waktu. Ada beberapa chipset buggy yang membuat nilai QPC kembali, tapi saya tidak percaya banyak dari mereka yang digunakan sekarang.

var sp = ServicePointManager.FindServicePoint(new Uri("http://foo.bar/baz/123?a=ab"));
sp.ConnectionLeaseTimeout = 60*1000; // 1 menit

Kode ini ditempatkan di konstruktor?

@ whynotme8998 @lundcm saya rasa tidak. Jika Anda HttpClient lajang dan Anda mengakses beberapa titik, konstruktor tidak akan menjadi tempat yang tepat untuk menempatkannya.
Periksa implementasi ini . Juga di README proyek ada tautan ke posting blog yang menjelaskan masalahnya. Artikel itu juga menunjuk ke utas ini.

Adakah yang bisa membantu saya memahami dengan tepat apa arti ConnectionLeaseTimeout ?

Jika di App saya saya set selama 1 menit, apakah itu berarti setiap menit sewa koneksi akan habis? Apa sebenarnya artinya berbicara dengan back-end saya?

Saya melihat orang-orang berbicara tentang pembaruan DNS di back-end? Pada Aplikasi Web Azure standar, akankah menerbitkan back-end ASP.NET saya menyebabkan penyegaran DNS?

Bukankah batas waktu 1 menit berpotensi meninggalkan jendela di mana DNS diperbarui namun batas waktu masih belum terjadi?

Sunting. Menyadari ini tidak bekerja di .NET Standard 2.0. Apa pekerjaan di sekitar?

Mengubah ConnectionLeaseTimeout tidak berfungsi di Xamarin dengan .netstandard 2.0 !!!

@paradisehuman Saya berasumsi maksud Anda ServicePoint.ConnectionLeaseTimeout . AFAIK tidak berfungsi baik di .NET Core. Di .NET Core 2.1 kami memperkenalkan SocketsHttpHandler.PooledConnectionLifetime . Juga HttpClientFactory di ASP.NET dapat memanfaatkan keduanya dan melakukan lebih banyak lagi untuk Anda.
Mono/Xamarin memiliki implementasi tumpukan jaringan sendiri (mereka tidak menggunakan kode sumber CoreFX untuk jaringan) - jadi akan lebih baik untuk mengajukan bug di repo mereka dengan lebih detail.

Sayangnya, tidak ada cara untuk melakukan ini dengan .NET Core hari ini. ServicePointManager harus dibawa ke .NET Core atau fungsi serupa yang serupa harus diaktifkan dengan cara lain.

@onovotny , SocketsHttpHandler di .NET Core 2.1 mengekspos PooledConnectionLifetime, yang melayani tujuan yang mirip dengan ConnectionLeaseTimeout, hanya di tingkat handler. Bisakah kita mempertimbangkan masalah ini dibahas pada saat ini?

@stephentoub baru melihat ini sekarang, ya, saya pikir PooledConnectionLifetime harus mengatasinya. Komunitas dapat membuka isu lain jika masih diperlukan.

@onovotny @karelz @stephentoub ,

Apakah Anda semua setuju bahwa ini adalah ringkasan yang akurat tentang cara terbaik untuk memecahkan masalah HttpClient/DNS tunggal yang asli?

  • Di .NET Framework 2.0+, gunakan ServicePoint.ConnectionLeaseTimeout .

  • Di .NET Core 2.1, gunakan SocketsHttpHandler.PooledConnectionLifetime .

  • Untuk semua platform/target/versi lain, tidak ada solusi/retas/penyelesaian yang andal, jadi jangan repot-repot mencoba.

Saat saya terus mempelajari hal-hal dari utas ini dan lainnya (seperti ConnectionLeaseTimeout tidak bekerja dengan andal di seluruh platform di .NET Standard 2.0), saya kembali ke papan gambar mencoba menyelesaikan ini dari perpustakaan dengan cara yang bekerja pada sebanyak mungkin platform/versi. Mengendus platform baik-baik saja. Membuang/membuat ulang HttpClient secara berkala tidak masalah, jika itu efektif. Saya cukup yakin saya salah dalam upaya pertama saya, yaitu hanya mengirim header connection:close ke Host secara berkala. Terima kasih sebelumnya atas saran apa pun!

@tmenier Untuk semua platform/target/versi lain, tidak ada solusi/retas/penyelesaian yang andal, jadi jangan repot-repot mencoba.

Anda selalu dapat mendaur ulang instance secara teratur (mis. buat saja instance baru dan setel ke variabel statis yang digunakan orang lain).
Itulah yang dilakukan HttpClientFactory . Anda dapat memilih untuk menggunakan HttpClientFactory sebagai gantinya.

@karelz Terima kasih, saya pikir ini memberi saya jalan ke depan. Mungkin saya harus melewatkan platform sniffing dan mendaur ulang instance di mana-mana, atau disarankan untuk menggunakan pendekatan lain jika tersedia (untuk menghindari overhead, dll.)?

Sedikit rumit mungkin mengetahui _kapan_ aman untuk membuang instance daur ulang (saya perlu khawatir tentang permintaan konkurensi/tertunda), tetapi saya dapat mengintip bagaimana HttpClientFactory menanganinya. Terima kasih lagi.

@tmenier Anda tidak ingin mendaur ulang instance setiap panggilan HttpClient , karena itu akan menyebabkan Anda kehabisan soket tcp. Daur ulang perlu dikelola (batas waktu atau mempertahankan kumpulan dengan HttpClient yang dapat kedaluwarsa.

@KallDrexx Benar, saya hanya berbicara tentang _secara berkala_ mendaur ulang singleton (atau "pseudo"-singleton), seperti setiap beberapa menit. Saya percaya itu akan melibatkan pengelolaan kumpulan dan semacam pembuangan instans mati yang tertunda, setelah ditentukan bahwa mereka tidak memiliki permintaan yang tertunda.

Ah maaf salah paham apa yang Anda maksud dengan daur ulang.

Anda tidak perlu membuang yang lama. Biarkan GC mengumpulkannya.
Kode harus sesederhana mengatur "semu" -singleton baru secara berkala berdasarkan timer. Tidak ada lagi.

Saya telah menemukan bahwa tidak membuangnya dapat menyebabkan pelambatan saat Anda kehabisan koneksi http dalam skenario kinerja tinggi.

@tmenier Tentang menggunakan SocketsHttpHandler.PooledConnectionLifetime di Dalam .NET Core 2.1, pembuatan HttpClientHandler secara lengkap dikemas dalam https://github.com/dotnet/wcf/blob/master/src/System.Private.ServiceModel/src/System/ ServiceModel/Channels/HttpChannelFactory.cs. Apakah ada cara untuk melakukan ini saat menggunakan klien WCF?

@edavedian Saya sarankan untuk bertanya di repo dotnet/wcf. cc @mconnew @Lxiamail

tumpukan yang mendasarinya diselesaikan ke WinHTTP atau Curl yang tidak mengekspos tombol kontrol lanjutan

Apakah ada di .Net Core klien HTTP yang bekerja melalui soket?

Apakah ada di .Net Core klien HTTP yang bekerja melalui soket?

Ya, SocketsHttpHandler, dan pada 2.1 ini adalah default.

Apakah HttpClient men-cache URI yang terkena , mirip dengan apa yang saya yakini dilakukan oleh

Saya melihat bahwa caching hanya dilakukan di RestClient jika proyeknya adalah Aplikasi .Net Core 2.1+?

Apakah HttpClient men-cache URI yang terkena, mirip dengan apa yang saya yakini dilakukan oleh RestClient?

HttpClient tidak melakukan caching apa pun.

@SpiritBob tidak jelas apa bentuk caching yang Anda maksud. Masalah ini ditutup; jika Anda mau, silakan buka edisi baru dengan pertanyaan, kami dapat membantu Anda menemukan jawaban.

@scalablecory Saya percaya davidsh merespons dengan apa yang ada dalam pikiran saya. Terima kasih!

Baru saja selesai membaca utas ini, dan sepertinya ada kasus penggunaan yang tidak ditangani.

Saat menggunakan HttpClientFactory , akankah HttpClient s yang dihasilkan secara otomatis menutup koneksi dan melakukan pencarian DNS baru ketika mereka menerima HttpRequestException dengan SocketException bagian dalam yang menunjukkan bahwa host tidak lagi valid dan DNS itu berpotensi berubah (kode kesalahan 11001 - tidak ada host yang diketahui)?

Jika tidak, apa solusi untuk membuat HttpClient melakukan pencarian DNS sebelum TTL kedaluwarsa pada catatan DNS?

Saat ini saya menggunakan HttpClientFactory dengan HttpMessageHandler kustom (dikonfigurasi melalui injeksi ketergantungan menggunakan AddHttpClient<T, U>().ConfigurePrimaryHttpMessageHandler(...) ) dan ketika catatan DNS berubah sebelum TTL kedaluwarsa, itu error. Secara khusus, saya melihatnya terjadi ketika melakukan banyak unggahan ke Azure Blob Storage.

Apakah halaman ini membantu?
0 / 5 - 0 peringkat

Masalah terkait

omariom picture omariom  ·  3Komentar

v0l picture v0l  ·  3Komentar

chunseoklee picture chunseoklee  ·  3Komentar

noahfalk picture noahfalk  ·  3Komentar

GitAntoinee picture GitAntoinee  ·  3Komentar