Pengujian beban: bagaimana cara menghasilkan permintaan per detik?

14

Saya memiliki komponen server yang berjalan di Zeroc-ICE. Ketika saya ingin memuat mengujinya, saya berpikir bahwa menggunakan perpustakaan paralel untuk membuat beberapa permintaan akan melakukannya. Tapi itu tidak berakhir seperti itu. Menggunakan pustaka Paralel (Paralel. Untuk) dari C # tampaknya lebih mudah tetapi tampaknya tidak persis menghasilkan segala sesuatu yang paralel secara instan. Jadi itu tidak bisa menjadi definisi untuk membuat permintaan N per detik. Bagaimana saya harus melakukannya? Saya kira siapa pun yang ingin melakukan pengujian beban terlebih dahulu akan benar-benar memikirkan hal ini.

  1. Apa cara efisien untuk benar-benar membuat permintaan N dalam benar-benar per detik?

  2. Mitos lain adalah tentang pemrograman paralel. Harap beri tahu kami, jika Anda telah menggunakan pola pemrograman paralel di C # atau .Net secara umum. Bayangkan saya punya 5 proses. Bagaimana memulai semua lima proses pada saat bersamaan. Apa artinya konsumsi sumber daya saya? Saya telah mencoba membaca banyak materi yang tersedia di internet tetapi saya mendapatkan lebih banyak pertanyaan daripada menjadi jawaban atas pertanyaan saya.

  3. Saya menggunakan Parallel.For dan membuat N thread dan mengukur waktu. Kemudian saya mencoba hal yang sama menggunakan Task.Factory.start untuk penghitungan tugas. Waktu yang diukur berbeda. Jadi, apa sebenarnya perbedaan antara menggunakan ini? Kapan saya harus menggunakan kelas yang sesuai dan untuk tujuan apa tepatnya? kita sering memiliki banyak kekayaan tetapi hanya saja kita tidak tahu bagaimana membedakan satu dari yang lain. Ini adalah salah satu kasus bagi saya, tidak dapat menemukan mengapa saya tidak boleh menggunakan satu dari yang lain.

  4. Saya menggunakan kelas stopwatch untuk mengukur waktu ini yang mengklaim sebagai yang terbaik. Dalam skenario saya memuat pengujian suatu komponen, apa yang akan menjadi cara untuk mengukur waktu respons. Stopwatch tampaknya menjadi solusi terbaik bagi saya. Pendapat apapun dipersilahkan.

ps: Ada banyak alat pengujian beban untuk aplikasi web. Milik saya adalah kasus khusus komponen server. Dan pertanyaan saya lebih berkaitan dengan membuat N thread per detik.

Semua opini diterima. Hanya saja, jangan berpikir itu bukan pertanyaan pemrograman. Tentu saja. Seharusnya membunyikan lonceng untuk setiap programmer yang ingin QE barang sendiri untuk mengetahui kinerja produknya, tangan pertama oleh dirinya sendiri. Saya telah mencoba banyak pilihan dan kemudian harus kembali pada bagaimana saya harus benar-benar melakukannya?

Raja
sumber
Faq mengatakan jika itu berkaitan dengan masalah pemrograman tertentu dan jika itu merupakan masalah praktis yang dapat dijawab dalam profesi pemrograman, itu bisa ditanyakan. orang yang skeptis dan lesu ini. Tolong beri komentar anda.
Raja
Apa yang Anda maksud dengan "momen yang sama"? Saya ingin tahu apakah Anda dapat memaksa TPL atau PLinq dengan cara apa pun untuk mencapai itu.
Gert Arnold
Pertanyaan saya adalah tentang menghasilkan permintaan N per detik. Jadi instan yang sama dalam skenario ini dimaksudkan untuk pemahaman saya tentang menggunakan paralel akan memulai thread secara paralel.
Raja
Sudahkah Anda melakukan analisis sekuensial?
3
Mungkin berkaitan dengan pemrograman, tetapi ada terlalu banyak pertanyaan di posting Anda (setidaknya 4). Saya akan menguranginya menjadi satu pertanyaan yang ingin Anda tanyakan sebelum ditutup karena terlalu luas. Berikan info yang relevan, seperti 10000 yang baru saja Anda sebutkan, jumlah core di mesin uji Anda). Menampilkan kode biasanya membantu.
Gert Arnold

Jawaban:

10

Saya tidak punya semua jawaban. Mudah-mudahan saya dapat menumpahkan beberapa cahaya di atasnya.

Untuk menyederhanakan pernyataan saya sebelumnya tentang model .NET's threading, hanya tahu bahwa Perpustakaan Paralel menggunakan Tugas, dan TaskScheduler default untuk Tugas, menggunakan ThreadPool. Semakin tinggi Anda masuk dalam hierarki (ThreadPool di bagian bawah), semakin banyak overhead yang Anda miliki saat membuat item. Overhead tambahan itu tentu saja tidak berarti lebih lambat, tapi senang mengetahui bahwa itu ada di sana. Pada akhirnya kinerja algoritme Anda dalam lingkungan multi-utas bermuara pada desainnya. Apa yang berkinerja baik secara berurutan mungkin tidak berkinerja juga secara paralel. Ada terlalu banyak faktor yang terlibat untuk memberi Anda aturan keras dan cepat, mereka berubah tergantung pada apa yang Anda coba lakukan. Karena Anda berurusan dengan permintaan jaringan, saya akan mencoba dan memberikan contoh kecil.

Biarkan saya menyatakan bahwa saya bukan ahli soket, dan saya tidak tahu apa-apa tentang Zeroc-Ice. Saya tahu sedikit tentang operasi asinkron, dan ini adalah tempat yang sangat membantu Anda. Jika Anda mengirim permintaan sinkron melalui soket, saat Anda menelepon Socket.Receive(), utas Anda akan diblokir hingga permintaan diterima. Ini tidak baik. Utas Anda tidak dapat membuat permintaan lagi karena diblokir. Menggunakan Socket.Beginxxxxxx (), permintaan I / O akan dibuat dan dimasukkan ke dalam antrian IRP untuk soket, dan utas Anda akan terus berjalan. Ini artinya, utas Anda sebenarnya dapat membuat ribuan permintaan dalam satu lingkaran tanpa pemblokiran sama sekali!

Jika saya memahami Anda dengan benar, Anda menggunakan panggilan melalui Zeroc-Ice dalam kode pengujian Anda, tidak benar-benar mencoba mencapai titik akhir http. Jika itu masalahnya, saya bisa mengakui bahwa saya tidak tahu cara kerja Zeroc-Ice. Saya akan, bagaimanapun, menyarankan mengikuti saran yang tercantum di sini , terutama bagian: Consider Asynchronous Method Invocation (AMI). Halaman menunjukkan ini:

Dengan menggunakan AMI, klien mendapatkan kembali utas kontrol segera setelah doa telah dikirim (atau, jika tidak dapat segera dikirim, telah diantrikan), memungkinkan klien untuk menggunakan utas itu untuk melakukan pekerjaan bermanfaat lainnya dalam waktu yang bersamaan. .

Yang tampaknya setara dengan apa yang saya jelaskan di atas menggunakan soket .NET. Mungkin ada cara lain untuk meningkatkan kinerja ketika mencoba melakukan banyak pengiriman, tetapi saya akan mulai di sini atau dengan saran lain yang tercantum di halaman itu. Anda sudah sangat kabur tentang desain aplikasi Anda, jadi saya bisa lebih spesifik daripada yang saya sudah di atas. Hanya ingat, jangan menggunakan lebih banyak utas daripada yang diperlukan untuk menyelesaikan apa yang perlu Anda lakukan, jika tidak, Anda mungkin akan menemukan aplikasi Anda berjalan jauh lebih lambat dari yang Anda inginkan.

Beberapa contoh dalam pseudocode (mencoba membuatnya sedekat mungkin dengan es tanpa saya benar-benar harus mempelajarinya):

var iterations = 100000;
for (int i = 0; i < iterations; i++)
{
    // The thread blocks here waiting for the response.
    // That slows down your loop and you're just wasting
    // CPU cycles that could instead be sending/receiving more objects
    MyObjectPrx obj = iceComm.stringToProxy("whateverissupposedtogohere");
    obj.DoStuff();
}

Cara yang lebih baik:

public interface MyObjectPrx : Ice.ObjectPrx
{
    Ice.AsyncResult GetObject(int obj, Ice.AsyncCallback cb, object cookie);
    // other functions
}

public static void Finished(Ice.AsyncResult result)
{
    MyObjectPrx obj = (MyObjectPrx)result.GetProxy();
    obj.DoStuff();
}

static void Main(string[] args)
{
    // threaded code...
    var iterations = 100000;
    for (int i = 0; i < iterations; i++)
    {
        int num = //whatever
        MyObjectPrx prx = //whatever
        Ice.AsyncCallback cb = new Ice.AsyncCallback(Finished);
        // This function immediately gets called, and the loop continues
        // it doesn't wait for a response, it just continually sends out socket
        // requests as fast as your CPU can handle them.  The response from the
        // server will be handled in the callback function when the request
        // completes.  Hopefully you can see how this is much faster when 
        // sending sockets.  If your server does not use an Async model 
        // like this, however, it's quite possible that your server won't 
        // be able to handle the requests
        prx.GetObject(num, cb, null);
    }
}

Ingatlah bahwa ada lebih banyak utas! = Kinerja yang lebih baik ketika mencoba mengirim soket (atau benar-benar melakukan apa pun). Utas bukan sulap karena mereka akan secara otomatis memecahkan masalah apa pun yang sedang Anda kerjakan. Idealnya, Anda ingin 1 utas per inti, kecuali utas menghabiskan banyak waktunya menunggu, maka Anda dapat membenarkan memiliki lebih banyak. Menjalankan setiap permintaan di utasnya sendiri adalah ide yang buruk, karena perubahan konteks akan terjadi dan pemborosan sumber daya. (Jika Anda ingin melihat semua yang saya tulis tentang hal itu, klik edit dan lihat revisi-revisi sebelumnya dari postingan ini. Saya menghapusnya karena sepertinya hanya mengaburkan masalah utama yang ada.)

Anda pasti dapat membuat permintaan ini di utas, jika Anda ingin membuat sejumlah besar permintaan per detik. Namun, jangan berlebihan dengan pembuatan utas. Temukan keseimbangan dan pertahankan. Anda akan mendapatkan kinerja yang lebih baik jika Anda menggunakan model asinkron vs model sinkron.

Saya harap itu membantu.

Christopher Currens
sumber
Mengapa Anda begitu banyak berbicara tentang kinerja? Tampaknya bukan itu yang diinginkan OP.
svick
@svick baik posting asli ops punya 4 pertanyaan awalnya, dan mereka mengajukan pertanyaan tentang kinerja tugas paralel vs, kemudian diedit, dan sekarang mereka kembali. Jadi, banyak dari apa yang Anda baca adalah hasil dari itu. Pada akhirnya, meskipun pertanyaannya ada hubungannya dengan kinerja, karena ia memiliki ide umum yang benar, tetapi tampaknya kurang dalam implementasinya. Saya percaya jawaban saya yang tajam pada akhirnya menjawab pertanyaan yang tidak dia edit.
Christopher Currens
Saya terpaksa mengurangi pertanyaan saya karena mereka ingin memilih untuk menutup. Sekarang tampaknya, ini berlaku untuk memilikinya. @ChristopherCurrens +1 poin bagus untuk perbedaan dengan threadpool untuk tugas. Itu memperluas pemahaman saya. Tapi saya masih terjebak bagaimana menghasilkan beberapa permintaan N per detik benar-benar mungkin? Apa sebenarnya cara terbaik untuk melakukan itu?
Raja
@ Raja - Saya kira saya tidak sejelas yang saya kira. 3-4 paragraf terakhir yang saya pikir akan membantu Anda. Saya berasumsi Anda sudah menggunakan semacam lingkaran. Jika Anda melakukan itu, masalahnya adalah bahwa soket Anda mengirim / menerima memblokir, dan dengan demikian memperlambat permintaan Anda. Mungkin saya akan menemukan waktu untuk memposting beberapa contoh kode semu.
Christopher Currens
Saya tidak punya masalah dalam mengirim mereka melalui ICE. Masalahnya adalah apa yang mendefinisikan implementasi yang benar-benar akan membuat permintaan N dan sesuatu yang dapat dikatakan benar untuk nomor itu, N.
Raja
2

Saya akan melewatkan pertanyaan 1) dan langsung ke # 2, karena itu umumnya cara yang dapat diterima untuk mencapai apa yang Anda cari. Di masa lalu untuk mencapai n pesan per detik, Anda dapat membuat satu proses yang kemudian akan meluncurkan p AppDomains. Setiap AppDomain pada dasarnya baru mulai menjalankan loop permintaan setelah titik waktu tertentu telah tercapai (menggunakan Timer). Waktu ini harus sama untuk setiap AppDomain untuk memastikan bahwa mereka mulai mengenai server Anda pada titik waktu yang sama.

Sesuatu seperti ini seharusnya berfungsi untuk mengirim permintaan Anda:

WaitCallback del = state => 
{ 
    ManualResetEvent[] resetEvents = new ManualResetEvent[10000]; 
    WebClient[] clients = new WebClient[10000]; 

    for (int index = 0; index < 10000; index++) 
    { 
        resetEvents[index] = new ManualResetEvent(false); 
        clients[index] = new WebClient(); 

        clients[index].OpenReadCompleted += new OpenReadCompletedEventHandler (client_OpenReadCompleted); 

        clients[index].OpenReadAsync(new Uri(@"<REQUESTURL>"), resetEvents[index]); 
    } 

    bool succeeded = ManualResetEvent.WaitAll(resetEvents, 10000); 
    Complete(succeeded); 

    for (int index = 0; index < 10000; index++) 
    { 
        resetEvents[index].Dispose(); 
        clients[index].Dispose(); 
    } 
}; 

while(running)
{
    ThreadPool.QueueUserWorkItem(del);
    Thread.Sleep(1000);
}

Ini mungkin akan menghancurkan kinerja pada mesin mana pun Anda menjalankannya, sehingga Anda selalu dapat menerapkan jenis loop yang serupa dari beberapa mesin yang berbeda jika Anda memiliki sumber daya (menggunakan proses alih-alih domain aplikasi).

Untuk pertanyaan ketiga Anda, berikan tautan ini baca http://www.albahari.com/threading/

Terakhir, stopwatch harus dipasangkan dengan hit counter untuk melacak durasi & hit unik di server Anda. Itu seharusnya membiarkan Anda melakukan beberapa analisis setelah fakta.

Chris
sumber
2
Apa alasan yang memungkinkan Anda membuat AppDomains terpisah di sini? Tampaknya sama sekali tidak perlu.
svick
0

Jangan ganggu dengan utas, jika N cukup kecil. Untuk menghasilkan N permintaan per detik, gunakan waktu jam dinding ( DateTime.Now). Luangkan waktu sebelum dan sesudah permintaan, lalu tambahkan Sleepuntuk menunda permintaan berikutnya.

Misalnya, dengan N = 5 (200 ms):

Before request: 12:33:05.014
After request: 12:33:05.077
Sleep(137)
Before request: 12:33:05.214
After request: 12:33:05.271
Sleep(131)

Ini tidak sempurna; Anda mungkin menemukan itu Sleeptidak tepat. Anda dapat menyimpan hitungan penyimpangan yang berjalan (sebelum permintaan X'th, waktunya harus X-1 / N nanti) dan menyesuaikan periode Tidur yang sesuai.

Setelah N menjadi terlalu besar, Anda cukup membuat utas M dan membiarkan setiap utas menghasilkan permintaan N / M dengan cara yang sama.

MSalters
sumber
Saya harus menghasilkan jumlah permintaan yang sangat tinggi. Jadi ini tidak bisa menjadi pilihan karena akan meminum memori saya (RAM 4GB) bahkan sebelum 100 utas.
Raja
Saya telah membuat 20.000 permintaan per detik dari utas tunggal, dalam kode 250 ribu. Anda tidak memiliki cukup CPU untuk menjalankan 100 utas (kelas mesin itu tidak datang dengan 4GB). Masalah selanjutnya adalah mendorong semua permintaan itu; apakah Anda memiliki 10 Gbit / s Ethernet antara pembuat konten dan server Anda? Jadi, Anda mungkin ingin memeriksa persyaratan Anda yang sebenarnya.
MSalters
Untuk memperjelas, saya memiliki sesuatu seperti 20+ Gbps. Jadi itu bukan masalah. Tentang kelas mesin, Apa yang Anda maksud? jumlah prosesor?
Raja
@ King: untuk mendorong 100 utas, saya mengharapkan mesin 48 inti. SGI menjual mesin dengan banyak core, misalnya, tetapi pada mereka Anda biasanya mendapatkan 32GB atau lebih.
MSalters
0

Cara termudah untuk mencapai pengujian beban untuk proyek .NET adalah dengan membeli edisi Ultimate Visual Studio. Ini dilengkapi dengan alat pengujian terintegrasi untuk membantu membentuk semua jenis pengujian termasuk uji beban. Tes beban dapat dilakukan sebelumnya dengan membuat pengguna virtual baik pada satu PC atau didistribusikan di beberapa untuk jumlah pengguna yang lebih besar, ada juga program kecil yang dapat diinstal pada server target untuk mengembalikan data tambahan selama durasi pengujian.

Ini mahal, tetapi edisi pamungkasnya hadir dengan banyak fitur, jadi jika semua digunakan akan menjadi harga yang lebih masuk akal.

Ryathal
sumber
0

Jika Anda benar-benar ingin memiliki semua utas X mengenai sumber Anda pada saat yang bersamaan, Anda dapat menempatkan setiap utas di belakang kait hitung mundur dan menentukan jangka waktu tunggu pendek antara pemeriksaan semaphore.

C # memiliki implementasi (http://msdn.microsoft.com/en-us/library/system.threading.countdownevent(VS.100).aspx).

Pada saat yang sama, jika Anda stres menguji sistem Anda, Anda mungkin benar-benar ingin memeriksa kondisi balapan juga, dalam hal ini Anda ingin mengatur periode tidur utas pada setiap utas yang berulang dari waktu ke waktu dengan frekuensi acak dan puncak / cuti.

Demikian pula Anda mungkin tidak benar-benar ingin hanya dengan cepat mengirim beberapa permintaan, Anda mungkin memiliki kesuksesan yang lebih baik dalam menempatkan server Anda dalam keadaan buruk / menguji kinerja dunia nyata dengan menyiapkan sejumlah kecil utas yang menghabiskan lebih banyak waktu dalam mengkonsumsi dan mengirim pesan kembali dan sebagainya melalui soket, karena server Anda kemungkinan akan perlu memutar utasnya sendiri untuk menangani pesan lambat yang sedang berlangsung.

Keith Membawa
sumber