Hari ketika Dodo berhenti. Skrip asinkron

Halo, Habr! Setiap SRE di tim kami pernah bermimpi tidur nyenyak di malam hari. Mimpi menjadi kenyataan. Dalam artikel ini saya akan membicarakan hal ini dan bagaimana kita mencapai kinerja dan stabilitas sistem Dodo IS kita.


Serangkaian artikel tentang runtuhnya sistem Dodo IS * :

1. Hari ketika Dodo berhenti. Script sinkron.
2. Hari ketika Dodo berhenti. Skrip asinkron.

* Materi ditulis berdasarkan kinerja saya di DotNext 2018 di Moskow .
Dalam artikel sebelumnya, kami melihat memblokir masalah kode dalam paradigma Preemptive Multitasking. Seharusnya itu perlu untuk menulis ulang kode pemblokiran pada async / menunggu. Jadi kami melakukannya. Sekarang mari kita bicara tentang masalah apa yang muncul ketika kita melakukan ini.

Kami memperkenalkan istilah Concurrency


Sebelum Anda masuk ke async, Anda harus memasukkan istilah Concurrency.
Dalam teori antrian, Concurrency adalah jumlah klien yang saat ini ada di dalam sistem. Konkurensi terkadang dikacaukan dengan Paralelisme, tetapi dalam kenyataannya ini adalah dua hal yang berbeda.
Bagi mereka yang baru mengenal Concurrency untuk pertama kalinya, saya merekomendasikan video Rob Pike . Konkurensi adalah ketika kita berurusan dengan banyak hal pada saat yang bersamaan, dan Paralelisme adalah ketika kita melakukan banyak hal pada saat yang bersamaan.

Di komputer, tidak banyak hal terjadi secara paralel. Salah satunya adalah komputasi pada banyak prosesor. Tingkat paralelisme dibatasi oleh jumlah utas CPU.

Faktanya, Threads adalah bagian dari konsep Preemptive Multitasking, salah satu cara untuk memodelkan Concurrency dalam sebuah program ketika kita mengandalkan sistem operasi dalam pertanyaan Concurrency. Model ini tetap bermanfaat selama kita memahami bahwa kita berurusan secara khusus dengan model Concurrency, dan bukan dengan concurrency.

Async / await adalah gula sintaksis untuk State Machine, model Concurrency berguna lainnya yang dapat berjalan dalam lingkungan berulir tunggal. Intinya, ini adalah Multitasking Kooperatif - model itu sendiri tidak memperhitungkan paralelisme sama sekali. Dalam kombinasi dengan Multithreading, kami mendapatkan satu model di atas yang lain, dan hidup sangat rumit.

Perbandingan kedua model


Cara kerjanya dalam model Preemptive Multitasking


Katakanlah kita memiliki 20 Utas dan 20 permintaan dalam pemrosesan per detik. Gambar menunjukkan puncak - 200 permintaan dalam sistem secara bersamaan. Bagaimana ini bisa terjadi:

  • permintaan dapat dikelompokkan jika 200 klien mengklik tombol pada saat yang sama;
  • pemulung dapat menghentikan permintaan beberapa puluh milidetik;
  • permintaan dapat ditunda dalam antrian apa pun jika proksi mendukung antrian.

Ada banyak alasan mengapa permintaan untuk periode waktu singkat telah terakumulasi dan datang dalam satu bundel. Bagaimanapun, tidak ada yang mengerikan terjadi, mereka berdiri di antrian Pool Thread dan perlahan-lahan selesai. Tidak ada lagi puncak, semuanya berjalan, seolah-olah tidak ada yang terjadi.

Misalkan algoritma pintar Thread Pool (dan ada elemen pembelajaran mesin di sana) memutuskan bahwa sejauh ini tidak ada alasan untuk menambah jumlah Thread. Kolam Koneksi di MySql juga 20 karena Thread = 20. Karenanya, kita hanya perlu 20 koneksi ke SQL.



Dalam kasus ini, level Concurrency server dari sudut pandang sistem eksternal = 200. Server telah menerima permintaan ini, tetapi belum menyelesaikannya. Namun, untuk aplikasi yang berjalan dalam paradigma Multithreading, jumlah permintaan simultan dibatasi oleh ukuran Thread Pool = 20 saat ini. Jadi, kita berurusan dengan derajat Concurrency = 20.

Bagaimana semuanya bekerja dalam model async




Mari kita lihat apa yang terjadi dalam aplikasi yang menjalankan async / menunggu dengan beban dan distribusi permintaan yang sama. Tidak ada antrian sebelum membuat Tugas, dan permintaan segera diproses. Tentu saja, Utas dari ThreadPool digunakan untuk waktu yang singkat, dan bagian pertama dari permintaan, sebelum menghubungi basis data, dieksekusi segera. Karena Thread dengan cepat kembali ke Thread Pool, kami tidak perlu banyak Thread untuk diproses. Dalam diagram ini kita tidak menampilkan Thread Pool sama sekali, itu transparan.



Apa artinya ini bagi aplikasi kita? Gambaran eksternal adalah sama - tingkat Concurrency = 200. Pada saat yang sama, situasi di dalamnya telah berubah. Sebelumnya, permintaan "ramai" dalam antrian ThreadPool, sekarang derajat Concurrency aplikasi juga 200, karena kami tidak memiliki batasan pada bagian dari TaskScheduler. Hore! Kami telah mencapai tujuan async - aplikasi "mengatasi" dengan hampir semua derajat Concurrency!

Konsekuensi: degradasi sistem nonlinier


Aplikasi telah menjadi transparan dari sudut pandang Concurrency, jadi sekarang Concurrency diproyeksikan ke database. Sekarang kita membutuhkan kumpulan koneksi dengan ukuran yang sama = 200. Basis data adalah CPU, memori, jaringan, penyimpanan. Ini adalah layanan yang sama dengan masalahnya, seperti yang lainnya. Semakin banyak permintaan yang kami coba jalankan pada saat yang sama, semakin lambat dijalankan.

Saat memuat penuh pada database, paling baik, Waktu Respons menurun secara linear: Anda memberi dua kali lebih banyak pertanyaan, itu mulai bekerja dua kali lebih lambat. Dalam praktiknya, karena persaingan permintaan, overhead akan selalu terjadi, dan mungkin ternyata sistem akan menurun secara non-linear.

Mengapa ini terjadi?


Alasan untuk urutan kedua:

  • Sekarang database perlu disimpan secara bersamaan dalam memori struktur data untuk melayani lebih banyak permintaan;
  • Sekarang database perlu melayani koleksi yang lebih besar (dan ini secara algoritmik tidak menguntungkan).

Alasan urutan pertama:


Pada akhirnya, async berjuang melawan sumber daya yang terbatas dan ... menang! Basis data gagal dan mulai melambat. Dari ini, server semakin meningkatkan Concurrency, dan sistem tidak dapat lagi keluar dari situasi ini dengan hormat.

Sindrom Kematian Tiba-tiba Server


Terkadang situasi yang menarik terjadi. Kami memiliki server. Dia bekerja untuk dirinya sendiri seperti itu, semuanya teratur. Ada sumber daya yang cukup, bahkan dengan margin. Lalu kami tiba-tiba mendapat pesan dari klien bahwa server melambat. Kami melihat grafik dan melihat ada beberapa peningkatan dalam aktivitas pelanggan, tetapi sekarang semuanya normal. Memikirkan serangan atau kebetulan DOS. Sekarang semuanya tampak baik-baik saja. Hanya sekarang server terus bodoh, dan semuanya lebih sulit sampai batas waktu mulai mengalir. Setelah beberapa waktu, server lain yang menggunakan database yang sama juga mulai membungkuk. Situasi yang biasa?

Mengapa sistem mati?


Anda dapat mencoba menjelaskan ini dengan fakta bahwa pada titik tertentu server menerima jumlah permintaan puncak dan β€œbangkrut”. Tetapi kita tahu bahwa bebannya berkurang, dan server setelah itu tidak menjadi lebih baik untuk waktu yang sangat lama, sampai bebannya benar-benar hilang.

Pertanyaan retoris: apakah server seharusnya rusak karena beban yang berlebihan? Apakah mereka melakukan itu?

Kami mensimulasikan situasi server crash


Di sini kita tidak akan menganalisis grafik dari sistem produksi nyata. Pada saat server crash, kita sering tidak bisa mendapatkan jadwal seperti itu. Server kehabisan sumber daya CPU, dan sebagai hasilnya, ia tidak dapat menulis log, memberikan metrik. Pada diagram pada saat bencana terjadi, keretakan pada semua grafik sering diamati.

SRE harus dapat menghasilkan sistem pemantauan yang kurang rentan terhadap efek ini. Sistem yang dalam situasi apa pun menyediakan setidaknya beberapa informasi, dan pada saat yang sama, dapat menganalisis sistem post-mortem menggunakan informasi yang terpisah-pisah. Untuk tujuan pendidikan, kami menggunakan pendekatan yang sedikit berbeda dalam artikel ini.

Mari kita coba membuat model yang secara matematis berfungsi seperti server yang sedang dimuat. Selanjutnya, kita akan mempelajari karakteristik server. Kami membuang nonlinearitas server nyata dan mensimulasikan situasi di mana deselerasi linier terjadi ketika beban tumbuh di atas nominal. Dua kali lebih banyak permintaan sesuai kebutuhan - kami melayani dua kali lebih lambat.

Pendekatan ini akan memungkinkan:

  • pertimbangkan apa yang akan terjadi terbaik;
  • ambil metrik yang akurat.

Navigasi Terjadwal:

  • biru - jumlah permintaan ke server;
  • hijau - respons server;
  • kuning - batas waktu;
  • abu-abu gelap - permintaan yang berasal dari sumber daya server karena klien tidak menunggu respons waktu habis. Kadang-kadang klien dapat melaporkan hal ini ke server dengan memutus hubungan, tetapi secara umum, kemewahan seperti itu secara teknis tidak mungkin, misalnya, jika server melakukan pekerjaan yang terikat CPU, tanpa kerja sama dengan klien.




Mengapa grafik permintaan klien (berwarna biru pada diagram) ternyata begitu? Biasanya, jadwal pesanan di restoran pizza kami tumbuh dengan lancar di pagi hari dan menurun di malam hari. Tapi kami mengamati tiga puncak dengan latar belakang kurva seragam yang biasa. Bentuk grafik ini tidak dipilih untuk model secara kebetulan, melainkan. Model ini lahir selama investigasi insiden nyata dengan server pusat kontak pizzeria di Rusia selama Piala Dunia.

Kasus "Piala Dunia"


Kami duduk dan menunggu pesanan lagi. Disiapkan untuk Kejuaraan, sekarang server akan dapat lulus ujian kekuatan.

Puncak pertama - penggemar sepakbola menonton kejuaraan, mereka lapar dan membeli pizza. Selama babak pertama, mereka sibuk dan tidak bisa memesan. Tetapi orang-orang yang acuh tak acuh terhadap sepak bola bisa, maka pada grafik semuanya berjalan seperti biasa.

Dan kemudian babak pertama berakhir, dan puncak kedua datang. Fans menjadi gugup, lapar dan membuat pesanan tiga kali lebih banyak daripada di puncak pertama. Pizza dibeli pada tingkat yang mengerikan. Kemudian babak kedua dimulai, dan sekali lagi tidak ke pizza.

Sementara itu, server pusat kontak mulai menekuk perlahan dan melayani permintaan lebih dan lebih lambat. Komponen sistem, dalam hal ini, server web Pusat Panggilan, tidak stabil.

Puncak ketiga akan datang ketika pertandingan selesai. Kipas dan sistem menunggu penalti.

Kami menganalisis alasan kerusakan server


Apa yang terjadi Server dapat menampung 100 permintaan bersyarat. Kami memahami bahwa itu dirancang untuk kekuatan ini dan tidak akan tahan lagi. Sebuah puncak tiba, yang dengan sendirinya tidak begitu besar. Tetapi area abu-abu Concurrency jauh lebih tinggi.

Model ini dirancang sedemikian rupa sehingga Concurrency secara numerik sama dengan jumlah pesanan per detik, sehingga secara visual pada grafik itu harus dari skala yang sama. Namun, jauh lebih tinggi karena menumpuk.

Kami melihat bayangan dari grafik di sini - ini adalah permintaan yang mulai kembali ke klien, dieksekusi (ditunjukkan oleh panah merah pertama). Skala waktu bersyarat untuk melihat offset waktu. Puncak kedua sudah merobohkan server kami. Dia jatuh dan mulai memproses permintaan empat kali lebih sedikit dari biasanya.



Pada paruh kedua grafik, jelas bahwa beberapa permintaan masih dieksekusi pada awalnya, tetapi kemudian bintik kuning muncul - permintaan berhenti sepenuhnya.



Sekali lagi seluruh jadwal. Dapat dilihat bahwa Concurrency menjadi liar. Sebuah gunung besar muncul.



Biasanya kami menganalisis metrik yang sangat berbeda: seberapa lambat permintaan itu selesai, berapa banyak permintaan per detik. Kami bahkan tidak melihat Concurrency, kami bahkan tidak memikirkan metrik ini. Tetapi sia-sia, karena justru kuantitas ini yang terbaik menunjukkan momen kegagalan server.

Tapi dari mana datangnya gunung sebesar itu? Puncak beban terbesar telah lama berlalu!

Hukum Kecil


Hukum Little mengatur Concurrency.

L (jumlah pelanggan dalam sistem) = Ξ» (kecepatan tinggal mereka) βˆ— W (waktu yang mereka habiskan di dalam sistem)

Ini rata-rata. Namun, situasi kita berkembang secara dramatis, rata-rata tidak cocok untuk kita. Kami akan membedakan persamaan ini, lalu mengintegrasikan. Untuk melakukan ini, lihat buku John Little, yang menemukan formula ini, dan lihat integral di sana.



Kami memiliki jumlah entri dalam sistem dan jumlah orang yang meninggalkan sistem. Permintaan tiba dan pergi ketika semuanya selesai. Di bawah ini adalah grafik pertumbuhan wilayah yang sesuai dengan pertumbuhan linear Concurrency.



Ada beberapa permintaan hijau. Inilah yang sebenarnya sedang diimplementasikan. Yang biru adalah yang datang. Antara waktu, kami memiliki jumlah permintaan yang biasa, situasinya stabil. Tapi Concurrency masih terus berkembang. Server tidak akan lagi mengatasi situasi ini sendiri. Ini berarti dia akan segera jatuh.

Tetapi mengapa konkurensi meningkat? Kami melihat integral dari konstanta. Tidak ada yang berubah dalam sistem kami, tetapi integralnya tampak seperti fungsi linier yang hanya tumbuh.

Akankah kita bermain?


Penjelasan dengan integral adalah rumit jika Anda tidak ingat matematika. Di sini saya mengusulkan untuk menghangatkan dan memainkan permainan.

Game nomor 1


Prasyarat : Server menerima permintaan, masing-masing membutuhkan tiga periode pemrosesan pada CPU. Sumber daya CPU dibagi secara merata antara semua tugas. Ini mirip dengan bagaimana sumber daya CPU dikonsumsi selama Preemptive Multitasking. Angka dalam sel berarti jumlah pekerjaan yang tersisa setelah pengukuran ini. Untuk setiap langkah kondisional, permintaan baru tiba.

Bayangkan Anda menerima permintaan. Hanya 3 unit pekerjaan, pada akhir periode pemrosesan pertama 2 unit tetap.

Pada periode kedua, permintaan lain berlapis, sekarang kedua CPU sibuk. Mereka melakukan satu unit kerja untuk dua pertanyaan pertama. Tetap menyelesaikan 1 dan 2 unit untuk masing-masing permintaan pertama dan kedua.

Sekarang permintaan ketiga telah tiba, dan kesenangan dimulai. Tampaknya permintaan pertama seharusnya sudah selesai, tetapi dalam periode ini tiga permintaan sudah berbagi sumber daya CPU, sehingga tingkat penyelesaian untuk ketiga permintaan sekarang fraksional pada akhir periode pemrosesan ketiga:



Lebih jauh lebih menarik! Permintaan keempat ditambahkan, dan sekarang tingkat Concurrency sudah 4, karena keempat permintaan membutuhkan sumber daya dalam periode ini. Sementara itu, permintaan pertama pada akhir periode keempat telah selesai, tidak masuk ke periode berikutnya, dan masih ada 0 pekerjaan tersisa untuk CPU.

Karena permintaan pertama telah selesai, mari kita simpulkan untuknya: permintaan itu berjalan sepertiga lebih lama dari yang kami harapkan. Diasumsikan bahwa panjang setiap tugas secara horizontal idealnya = 3, sesuai dengan jumlah pekerjaan. Kami menandainya dengan oranye, sebagai tanda bahwa kami tidak sepenuhnya puas dengan hasilnya.



Permintaan kelima tiba. Tingkat Concurrency masih 4, tetapi kita melihat bahwa di kolom kelima pekerjaan yang tersisa lebih total. Ini karena ada lebih banyak pekerjaan yang tersisa di kolom keempat daripada di kolom ketiga.

Kami melanjutkan tiga periode lagi. Menunggu jawaban.
- Server, halo!
- ...



"Teleponmu sangat penting bagi kami ..."



Nah, akhirnya datang jawaban untuk permintaan kedua. Waktu respons dua kali lebih lama dari yang diharapkan.



Tingkat Concurrency sudah tiga kali lipat, dan tidak ada yang menandakan bahwa situasinya akan berubah menjadi lebih baik. Saya tidak menggambar lebih jauh, karena waktu respons terhadap permintaan ketiga tidak lagi sesuai dengan gambar.

Server kami telah memasuki kondisi yang tidak diinginkan, dari mana ia tidak akan pernah keluar dengan sendirinya. Game usai

Apa yang mencirikan status GameOver di server?


Permintaan diakumulasikan dalam memori tanpa batas. Cepat atau lambat, ingatan akan berakhir begitu saja. Selain itu, dengan peningkatan skala, overhead CPU untuk melayani berbagai struktur data meningkat. Misalnya, kumpulan koneksi sekarang harus melacak timeout untuk lebih banyak koneksi, pengumpul sampah sekarang harus memeriksa ulang lebih banyak objek di heap, dan sebagainya.

Menjelajahi semua konsekuensi yang mungkin terjadi dari akumulasi objek aktif bukanlah tujuan dari artikel ini, tetapi bahkan akumulasi sederhana data dalam RAM sudah cukup untuk mengisi server. Selain itu, kita telah melihat bahwa server klien memproyeksikan masalah Concurrency ke server database, dan server lain yang digunakan sebagai klien.

Hal yang paling menarik: sekarang bahkan jika Anda mengirimkan beban yang lebih rendah ke server, itu masih tidak akan pulih. Semua permintaan akan berakhir dengan batas waktu, dan server akan menggunakan semua sumber daya yang tersedia.

Dan apa yang sebenarnya kita harapkan ?! Bagaimanapun, kami dengan sadar memberi server sejumlah pekerjaan yang tidak bisa ditangani.

Ketika berhadapan dengan arsitektur sistem terdistribusi, ada baiknya memikirkan bagaimana orang-orang biasa memecahkan masalah seperti itu. Ambil contoh, klub malam. Ini akan berhenti berfungsi jika terlalu banyak orang memasukinya. Penjaga itu mengatasi masalah itu dengan sederhana: terlihat berapa banyak orang di dalamnya. Satu kiri - meluncurkan yang lain. Seorang tamu baru akan datang dan menghargai ukuran antriannya. Jika garis panjang, dia akan pulang. Bagaimana jika Anda menerapkan algoritma ini ke server?



Ayo main lagi.

Game nomor 2


Prasyarat : Sekali lagi kami memiliki dua CPU, tugas yang sama dari 3 unit, tiba di setiap periode, tetapi sekarang kami akan mengatur bouncer, dan tugas akan menjadi pintar - jika mereka melihat bahwa antriannya adalah 2, maka mereka langsung pulang.





Permintaan ketiga datang. Pada periode ini ia berdiri dalam barisan. Dia memiliki angka 3 di akhir periode. Tidak ada angka fraksional dalam residu, karena dua CPU melakukan dua tugas, satu untuk suatu periode.

Meskipun kami memiliki tiga lapisan permintaan, tingkat Concurrency di dalam sistem = 2. Yang ketiga ada dalam antrian dan tidak masuk hitungan.



Yang keempat datang - gambar yang sama, meskipun lebih banyak pekerjaan telah diakumulasikan.


...
...

Pada periode keenam, permintaan ketiga selesai dengan lag ketiga, dan tingkat Concurrency sudah = 4.



Tingkat konkurensi meningkat dua kali lipat. Dia tidak bisa tumbuh lagi, karena kami telah menetapkan larangan yang jelas tentang ini. Dengan kecepatan maksimum, hanya dua permintaan pertama yang diselesaikan - mereka yang datang ke klub terlebih dahulu, sementara ada ruang yang cukup untuk semua orang.

Permintaan kuning ada di sistem lebih lama, tetapi mereka berdiri dalam antrean dan tidak menunda sumber daya CPU. Karena itu, mereka yang berada di dalam bersenang-senang. Ini bisa berlanjut sampai seorang pria datang dan berkata bahwa dia tidak akan mengantri, tetapi dia akan pulang. Ini adalah permintaan yang gagal:



Situasi dapat diulang tanpa akhir, sementara waktu eksekusi kueri tetap pada tingkat yang sama - tepat dua kali selama yang kita inginkan.



Kami melihat bahwa pembatasan sederhana pada level Concurrency menghilangkan masalah viabilitas server.

Cara Meningkatkan Viabilitas Server Melalui Batas Level Concurrency


Anda dapat menulis sendiri "tukang pukul" paling sederhana. Di bawah ini adalah kode yang menggunakan semaphore. Tidak ada batasan untuk panjang garis di luar. , .

const int MaxConcurrency = 100; SemaphoreSlim bulkhead = new SemaphoreSlim(MaxConcurrency, MaxConcurrency); public async Task ProcessRequest() { if (!await bulkhead.WaitAsync()) { throw new OperationCanceledException(); } try { await ProcessRequestInternal(); return; } finally { bulkhead.Release(); } } 

Untuk membuat antrian terbatas, Anda perlu dua semafor. Untuk ini, perpustakaan Polly , yang direkomendasikan Microsoft, cocok. Perhatikan pola Sekat. Diterjemahkan secara harfiah sebagai "sekat" - elemen struktural yang memungkinkan kapal tidak tenggelam. Sejujurnya, saya pikir istilah bouncer lebih cocok. Yang penting adalah bahwa pola ini memungkinkan server untuk bertahan dalam situasi tanpa harapan.

Pertama, kami memeras segala yang mungkin pada bangku beban dari server sampai kami menentukan berapa banyak permintaan yang dapat ditampungnya. Misalnya, kami menentukan bahwa itu 100. Kami menempatkan sekat.

Selanjutnya, server hanya akan melewatkan jumlah permintaan yang diperlukan, sisanya akan mengantri. Akan bijaksana untuk memilih nomor yang sedikit lebih kecil sehingga ada margin. Saya tidak punya rekomendasi siap pakai mengenai hal ini, karena ada ketergantungan yang kuat pada konteks dan situasi khusus.

  1. Jika perilaku server secara stabil tergantung pada beban dalam hal sumber daya, maka angka ini dapat mendekati batas.
  2. Jika medium mengalami fluktuasi beban, jumlah yang lebih konservatif harus dipilih, dengan mempertimbangkan ukuran fluktuasi ini. Fluktuasi seperti itu dapat terjadi karena berbagai alasan, misalnya, lingkungan kinerja dengan GC ditandai dengan puncak kecil beban pada CPU.
  3. Jika server melakukan tugas-tugas berkala sesuai jadwal, ini juga harus dipertimbangkan. Anda bahkan dapat mengembangkan sekat adaptif yang akan menghitung berapa banyak kueri yang dapat dikirim secara bersamaan tanpa degradasi server (tetapi ini sudah di luar ruang lingkup penelitian ini).

Eksperimen Permintaan


Lihatlah post-mortem ini terakhir, kita tidak akan melihatnya lagi.

Semua tumpukan abu-abu ini jelas berkorelasi dengan server crash. Gray adalah kematian bagi server. Mari kita potong saja dan lihat apa yang terjadi. Tampaknya sejumlah permintaan akan pulang, tidak akan dipenuhi. Tetapi berapa banyak?

100 di dalam, 100 di luar



Ternyata server kami mulai hidup dengan sangat baik dan menyenangkan. Dia terus-menerus membajak dengan kekuatan maksimum. Tentu saja, ketika puncak terjadi, itu menendang keluar, tetapi tidak lama.

Terinspirasi oleh kesuksesan, kami akan mencoba memastikan bahwa dia tidak terpental sama sekali. Mari kita coba tambah panjang antrian.

100 di dalam, 500 di luar




Itu menjadi lebih baik, tetapi ekornya tumbuh. Ini adalah permintaan yang dieksekusi untuk waktu yang lama kemudian.

100 di dalam, 1000 di luar


Karena sesuatu telah menjadi lebih baik, mari kita coba membawanya ke titik absurditas. Mari kita selesaikan panjang antrian 10 kali lebih banyak dari yang dapat kami layani secara bersamaan:



Jika kita berbicara tentang metafora klub dan penjaga, situasi ini hampir tidak mungkin - tidak ada yang mau menunggu lebih lama di pintu masuk daripada menghabiskan waktu di klub. Kami juga tidak akan berpura-pura bahwa ini adalah situasi normal untuk sistem kami.

Lebih baik tidak melayani klien sama sekali daripada menyiksanya di situs atau di aplikasi seluler dengan memuat setiap layar selama 30 detik dan merusak reputasi perusahaan. Lebih baik segera memberi tahu sebagian kecil pelanggan bahwa sekarang kami tidak bisa melayani mereka. Jika tidak, kami akan melayani semua pelanggan beberapa kali lebih lambat, karena grafik menunjukkan bahwa situasinya bertahan cukup lama.

Ada satu risiko lagi - komponen sistem lain mungkin tidak dirancang untuk perilaku server seperti itu, dan, seperti yang sudah kita ketahui, Concurrency diproyeksikan ke klien.

Oleh karena itu, kami kembali ke opsi pertama "100 per 100" dan berpikir tentang cara meningkatkan kapasitas kami.

Pemenang - 100 di dalam, 100 di luar




Β― \ _ (ツ) _ / Β―

Dengan parameter ini, degradasi terbesar dalam runtime tepat 2 kali lipat dari "nominal". Pada saat yang sama, itu adalah degradasi 100% dalam waktu eksekusi permintaan.

Jika klien Anda sensitif terhadap runtime (dan ini biasanya benar baik dengan klien manusia dan klien server), maka Anda dapat berpikir tentang lebih jauh mengurangi panjang antrian. Dalam hal ini, kita dapat mengambil beberapa persentase dari Konkurensi internal, dan kita akan tahu pasti bahwa layanan tidak menurun dalam waktu respons lebih dari rata-rata persentase ini.

Faktanya, kami tidak mencoba membuat antrian, kami mencoba melindungi diri dari fluktuasi beban. Di sini, seperti halnya dalam hal menentukan parameter pertama sekat (kuantitas di dalam), hal ini berguna untuk menentukan fluktuasi apa dalam beban yang mungkin disebabkan klien. Jadi kita akan tahu dalam hal apa, secara kasar, kita akan kehilangan keuntungan dari layanan potensial.

Lebih penting lagi untuk menentukan fluktuasi latensi apa yang dapat menahan komponen sistem lain yang berinteraksi dengan server. Jadi kita akan tahu bahwa kita benar-benar memeras maksimal dari sistem yang ada tanpa bahaya kehilangan layanan sepenuhnya.

Diagnosis dan perawatan


Kami memperlakukan Concurrency yang Tidak Terkendali dengan Isolasi Bulkhead.
Metode ini, seperti yang lain yang dibahas dalam seri artikel ini, mudah diterapkan oleh perpustakaan Polly .

Keuntungan dari metode ini adalah akan sangat sulit untuk mengacaukan komponen individu dari sistem. Sistem memperoleh perilaku yang sangat dapat diprediksi dalam hal waktu untuk permintaan yang berhasil dan peluang yang jauh lebih tinggi untuk permintaan lengkap yang berhasil.

Namun, kami tidak menyelesaikan semua masalah. Misalnya, masalah daya server tidak mencukupi. Dalam situasi ini, Anda harus memutuskan untuk "menjatuhkan pemberat" jika terjadi lompatan muatan, yang kami anggap berlebihan.

Langkah-langkah lebih lanjut yang tidak dibahas oleh penelitian kami dapat mencakup, misalnya, penskalaan dinamis.

Source: https://habr.com/ru/post/id461081/


All Articles