Skalabilitas
Istilah, skalabilitas, sering disalahgunakan. Untuk bagian ini, definisi ganda disediakan:
- Skalabilitas adalah kemampuan untuk sepenuhnya memanfaatkan daya pemrosesan yang tersedia pada sistem multiprosesor (2, 4, 8, 32, atau lebih prosesor).
- Skalabilitas adalah kemampuan untuk melayani sejumlah besar klien.
Kedua definisi terkait ini umumnya disebut sebagai peningkatan skala. Akhir topik ini memberikan tips tentang penskalaan.
Diskusi ini berfokus secara eksklusif pada penulisan server yang dapat diskalakan, bukan klien yang dapat diskalakan, karena server yang dapat diskalakan adalah persyaratan yang lebih umum. Bagian ini juga membahas skalabilitas hanya dalam konteks server RPC dan RPC. Praktik terbaik untuk skalabilitas, seperti mengurangi ketidakcocokan, menghindari kesalahan cache yang sering terjadi di lokasi memori global, atau menghindari berbagi palsu, tidak dibahas di sini.
Ketika panggilan RPC diterima oleh server, rutinitas server (rutinitas manajer) dipanggil pada utas yang disediakan oleh RPC. RPC menggunakan kumpulan utas adaptif yang meningkat dan menurun saat beban kerja berfluktuasi. Dimulai dengan Windows 2000, inti dari kumpulan alur RPC adalah port penyelesaian. Port penyelesaian dan penggunaannya dengan RPC disetel untuk rutinitas server ketidakcocokan nol hingga rendah. Ini berarti bahwa kumpulan utas RPC secara agresif meningkatkan jumlah utas layanan jika beberapa menjadi diblokir. Ini beroperasi dengan anggapan bahwa pemblokiran jarang terjadi, dan jika utas diblokir, ini adalah kondisi sementara yang dengan cepat diselesaikan. Pendekatan ini memungkinkan efisiensi untuk server pertikaian rendah. Misalnya, server RPC panggilan kekosongan yang beroperasi pada server 550MHz delapan prosesor yang diakses melalui jaringan area sistem berkecepatan tinggi (SAN) melayani lebih dari 30.000 panggilan batal per detik dari lebih dari 200 klien jarak jauh. Ini mewakili lebih dari 108 juta panggilan per jam.
Hasilnya adalah bahwa kumpulan utas agresif benar-benar menghalangi ketika pertikaian di server tinggi. Untuk mengilustrasikan, bayangkan server tugas berat yang digunakan untuk mengakses file dari jarak jauh. Asumsikan server mengadopsi pendekatan yang paling mudah: hanya membaca/menulis file secara sinkron pada utas tempat RPC memanggil rutinitas server. Selain itu, asumsikan kami memiliki server empat prosesor yang melayani banyak klien.
Server akan dimulai dengan lima utas (ini sebenarnya bervariasi, tetapi lima utas digunakan untuk kesederhanaan). Setelah RPC mengambil panggilan RPC pertama, RPC mengirimkan panggilan ke rutinitas server, dan rutinitas server mengeluarkan I/O. Jarang, itu melewatkan cache file dan kemudian memblokir menunggu hasilnya. Segera setelah diblokir, utas kelima dirilis untuk mengambil permintaan, dan utas keenam dibuat sebagai siaga panas. Dengan asumsi setiap operasi I/O kesepuluh melewatkan cache dan akan memblokir selama 100 milidetik (nilai waktu arbitrer), dan dengan asumsi server empat prosesor melayani sekitar 20.000 panggilan per detik (5.000 panggilan per prosesor), pemodelan sederhana akan memprediksi bahwa setiap prosesor akan menghasilkan sekitar 50 utas. Ini mengasumsikan panggilan yang akan memblokir datang setiap 2 milidetik, dan setelah 100 milidetik utas pertama dikosongkan lagi sehingga kumpulan akan stabil pada sekitar 200 utas (50 per prosesor).
Perilaku aktual lebih rumit, karena tingginya jumlah utas akan menyebabkan sakelar konteks ekstra yang memperlambat server, dan juga memperlambat laju pembuatan utas baru, tetapi ide dasarnya jelas. Jumlah utas naik dengan cepat saat utas di server mulai memblokir dan menunggu sesuatu (baik itu I/O, atau akses ke sumber daya).
RPC dan port penyelesaian yang gerbang permintaan masuk akan mencoba mempertahankan jumlah utas RPC yang dapat digunakan di server agar sama dengan jumlah prosesor pada komputer. Ini berarti bahwa pada server empat prosesor, setelah utas kembali ke RPC, jika ada empat atau lebih utas RPC yang dapat digunakan, utas kelima tidak diizinkan untuk mengambil permintaan baru, dan sebaliknya akan duduk dalam keadaan siaga panas jika salah satu blok utas yang saat ini dapat digunakan. Jika utas kelima menunggu cukup lama sebagai siaga panas tanpa jumlah utas RPC yang dapat digunakan turun di bawah jumlah prosesor, itu akan dilepaskan, artinya, kumpulan utas akan berkurang.
Bayangkan server dengan banyak utas. Seperti yang dijelaskan sebelumnya, server RPC berakhir dengan banyak utas, tetapi hanya jika utas sering memblokir. Di server tempat utas sering diblokir, utas yang kembali ke RPC segera diambil dari daftar siaga panas, karena semua blok utas yang saat ini dapat digunakan, dan diberi permintaan untuk diproses. Saat utas memblokir, dispatcher utas di kernel mengalihkan konteks ke utas lain. Sakelar konteks ini dengan sendirinya mengonsumsi siklus CPU. Utas berikutnya akan menjalankan kode yang berbeda, mengakses struktur data yang berbeda, dan akan memiliki tumpukan yang berbeda, yang berarti laju hit cache memori (cache L1 dan L2) akan jauh lebih rendah, yang mengakibatkan eksekusi yang lebih lambat. Banyaknya utas yang dijalankan secara bersamaan meningkatkan ketidakcocokan untuk sumber daya yang ada, seperti tumpukan, bagian penting dalam kode server, dan sebagainya. Ini semakin meningkatkan ketidakcocokan saat konvoi pada formulir sumber daya. Jika memori rendah, tekanan memori yang ditingkatkan oleh jumlah utas yang besar dan terus bertambah akan menyebabkan kesalahan halaman, yang selanjutnya meningkatkan laju di mana utas memblokir, dan menyebabkan lebih banyak utas dibuat. Tergantung pada seberapa sering ia memblokir dan berapa banyak memori fisik yang tersedia, server dapat stabil pada tingkat performa yang lebih rendah dengan laju peralihan konteks tinggi, atau mungkin memburuk ke titik di mana ia hanya berulang kali mengakses hard disk dan peralihan konteks tanpa melakukan pekerjaan aktual. Situasi ini tidak akan ditampilkan di bawah beban kerja ringan, tentu saja, tetapi beban kerja yang berat dengan cepat membawa masalah ke permukaan.
Bagaimana ini bisa dicegah? Jika utas diharapkan untuk memblokir, nyatakan panggilan sebagai asinkron, dan setelah permintaan memasuki rutinitas server, antrekan ke kumpulan utas pekerja yang menggunakan kemampuan asinkron sistem I/O dan/atau RPC. Jika server pada gilirannya melakukan panggilan RPC membuat panggilan tersebut asinkron, dan pastikan antrean tidak tumbuh terlalu besar. Jika rutinitas server melakukan I/O file, gunakan I/O file asinkron untuk mengantrekan beberapa permintaan ke sistem I/O dan hanya memiliki beberapa utas yang mengantrenya dan mengambil hasilnya. Jika rutinitas server melakukan I/O jaringan, sekali lagi, gunakan kemampuan asinkron sistem untuk mengeluarkan permintaan dan mengambil balasan secara asinkron, dan gunakan seserang mungkin utas. Ketika I/O selesai, atau PANGGILAN RPC yang dibuat server selesai, selesaikan panggilan RPC asinkron yang mengirimkan permintaan. Ini akan memungkinkan server untuk berjalan dengan sesenggukan utas mungkin, yang meningkatkan performa dan jumlah klien yang dapat dilayvisikan oleh server.
RPC dapat dikonfigurasi untuk bekerja dengan Penyeimbangan Beban Jaringan (NLB) jika NLB dikonfigurasi sehingga semua permintaan dari alamat klien tertentu masuk ke server yang sama. Karena setiap klien RPC membuka kumpulan koneksi (untuk informasi selengkapnya, lihat RPC dan Jaringan), sangat penting bahwa semua koneksi dari kumpulan klien yang diberikan berakhir di komputer server yang sama. Selama kondisi ini terpenuhi, kluster NLB dapat dikonfigurasi untuk berfungsi sebagai satu server RPC besar dengan skalabilitas yang berpotensi sangat baik.