Kami memiliki API yang diimplementasikan menggunakan ServiceStack yang di-host di IIS. Saat melakukan pengujian beban API, kami menemukan bahwa waktu responsnya bagus tetapi memburuk dengan cepat segera setelah kami mencapai sekitar 3.500 pengguna bersamaan per server. Kami memiliki dua server dan ketika memukul mereka dengan 7.000 pengguna, waktu respons rata-rata berada di bawah 500 ms untuk semua titik akhir. Kotak-kotak berada di belakang load balancer sehingga kami mendapatkan 3.500 persetujuan per server. Namun begitu kami meningkatkan jumlah pengguna secara bersamaan, kami melihat peningkatan yang signifikan dalam waktu tanggapan. Meningkatkan pengguna secara bersamaan menjadi 5.000 per server memberi kami waktu respons rata-rata per titik akhir sekitar 7 detik.
Memori dan CPU di server cukup rendah, baik saat waktu respons baik dan ketika setelah memburuk. Pada puncaknya dengan 10.000 pengguna secara bersamaan, rata-rata CPU di bawah 50% dan RAM berada di antara 3-4 GB dari 16. Ini membuat kami berpikir bahwa kami mencapai semacam batasan di suatu tempat. Tangkapan layar di bawah ini menunjukkan beberapa penghitung kunci dalam perfmon selama tes beban dengan total 10.000 pengguna secara bersamaan. Penghitung yang disorot adalah permintaan / detik. Di sebelah kanan tangkapan layar Anda dapat melihat grafik permintaan per detik menjadi sangat tidak menentu. Ini adalah indikator utama untuk waktu respons yang lambat. Segera setelah kami melihat pola ini, kami melihat waktu respons lambat dalam uji beban.
Bagaimana kita mengatasi masalah kinerja ini? Kami mencoba mengidentifikasi apakah ini masalah pengkodean atau masalah konfigurasi. Apakah ada pengaturan di web.config atau IIS yang dapat menjelaskan perilaku ini? Kumpulan aplikasi menjalankan .NET v4.0 dan versi IIS 7.5. Satu-satunya perubahan yang kami lakukan dari pengaturan default adalah memperbarui kumpulan panjang nilai antrian aplikasi dari 1.000 menjadi 5.000. Kami juga telah menambahkan pengaturan konfigurasi berikut ke file Aspnet.config:
<system.web>
<applicationPool
maxConcurrentRequestsPerCPU="5000"
maxConcurrentThreadsPerCPU="0"
requestQueueLimit="5000" />
</system.web>
Keterangan lebih lanjut:
Tujuan API adalah untuk menggabungkan data dari berbagai sumber eksternal dan kembali sebagai JSON. Saat ini menggunakan implementasi cache InMemory untuk cache panggilan eksternal individu di lapisan data. Permintaan pertama ke sumber daya akan mengambil semua data yang diperlukan dan permintaan berikutnya untuk sumber daya yang sama akan mendapatkan hasil dari cache. Kami memiliki 'pelari cache' yang diimplementasikan sebagai proses latar belakang yang memperbarui informasi dalam cache pada interval waktu tertentu. Kami telah menambahkan penguncian di sekitar kode yang mengambil data dari sumber daya eksternal. Kami juga telah mengimplementasikan layanan untuk mengambil data dari sumber eksternal secara asinkron sehingga titik akhir seharusnya hanya selambat panggilan eksternal paling lambat (kecuali kami memiliki data dalam cache tentu saja). Ini dilakukan dengan menggunakan kelas System.Threading.Tasks.Task.Mungkinkah kita mencapai batasan dalam hal jumlah utas yang tersedia untuk proses?