Menyapu jalan untuk tetap hidup

Meningkatkan aktivitas pertukaran data antara layanan microser sering menjadi masalah dalam arsitektur solusi TI modern. Peras maksimal dan bertahan dengan segala cara - tantangan serius untuk pengembangan apa pun. Oleh karena itu, pencarian solusi optimal adalah proses tanpa henti. Artikel ini secara singkat menguraikan masalah yang mungkin timbul saat menggunakan permintaan http yang sangat dimuat dan cara untuk memotongnya.


Kisah ini dimulai dengan sebuah kesalahan. Entah bagaimana kami melakukan pengujian beban, elemen utamanya adalah eksekusi sejumlah besar permintaan http pendek. Seorang klien yang ditulis di bawah netcore 2.2 , mulai dari beberapa titik, melempar System.Net.Sockets.SocketException: Alamat sudah digunakan . Dengan cepat menjadi jelas bahwa port tidak punya waktu untuk membebaskan pada klien, dan pada suatu titik sistem ditolak untuk membuka yang baru. Sekarang, jika kita menuju ke kode, masalahnya adalah menggunakan pendekatan lama dengan kelas dan konstruksi HttpWebRequest :


var request = WebRequest.CreateHttp(uri);
using(var resp = request.GetResponse()){ … }

Tampaknya kita melepaskan sumber daya, dan pelabuhan harus dirilis tepat waktu. Namun, netstat mengisyaratkan peningkatan pesat dalam jumlah port dalam status TIME_WAIT. Keadaan ini berarti menunggu koneksi untuk ditutup (dan mungkin menerima data yang hilang). Akibatnya, port mungkin ada di dalamnya selama 1-2 menit. Masalah ini dibahas secara rinci di banyak artikel ( Masalah dengan antrian TIME_WAIT , Riwayat tentang TIME_WAIT ). Namun demikian, ini berarti bahwa dotnet "jujur" mencoba untuk menutup koneksi, dan selanjutnya terjadi karena kesalahan pengaturan timeout dalam sistem.


Mengapa ini terjadi dan bagaimana menghadapinya


keep-alive. . , . msdn, KeepAlive HttpWebRequest true. HttpWebRequest «» , , . , HttpWebRequest «Connection: keep-alive», HTTP/1.1. , , KeepAlive. HttpWebRequest.KeepAlive = false, «Connection: close». , . nginx .


:


while (true)
{
  var request = WebRequest.CreateHttp(uri);
  request.KeepAlive = false;
  var resp = await request.GetResponseAsync();
  using (var sr = new StreamReader(resp.GetResponseStream()))
  {
    var content = sr.ReadToEnd();
  }
}

, ( 1000 ) . CLOSE_WAIT, LAST_ACK. - , . , «» .


,


, , . keep-alive HttpClient. .


, , ? keep-alive nginx:


  • keepalive_timeout – ( 15)
  • keepalive_requests – ( 100)

netstat wireshark, . keepalive_requests (> 1000) , .



http , . . , , keep-alive. keep-alive , .


:


  • RunHttpClient – HttpClient "Connection: keep-alive"
  • RunHttpClientClosed – HttpClient "Connection: closed"
  • RunWebRequestClosed - menggunakan mode HttpWebRequest kelas "Koneksi: ditutup"

Server nginx dikonfigurasi dengan parameter berikut:


  • keepalive_timeout 60s;
  • keepalive_requests 100000;

metodeNIklan-iklanBerarti
Runhttpclient10001963,3 ms
RunWebRequestClosed100013,857,4 ms
RunHttpClientClosed100011.612,4 ms
Runhttpclient10.00019.573,9 ms
RunWebRequestClosed10.000137.947,4 ms
RunHttpClientClosed10.000116.112.9 ms

All Articles