Dalam beberapa artikel saya sebelumnya di sini tentang penyetelan kinerja, saya telah membahas beberapa jenis tunggu dan bagaimana mereka menunjukkan berbagai hambatan sumber daya. Saya memulai seri baru pada skenario di mana mekanisme sinkronisasi yang disebut latch adalah hambatan kinerja, dan khususnya latch non-halaman. Dalam posting awal ini saya akan menjelaskan mengapa kait diperlukan, apa sebenarnya, dan bagaimana mereka bisa menjadi hambatan.
Mengapa Kait Diperlukan?
Ini adalah prinsip dasar ilmu komputer bahwa setiap kali struktur data ada dalam sistem multi-utas, struktur data harus dilindungi dengan cara tertentu. Perlindungan ini memberikan ketentuan sebagai berikut:
- (Dijamin) Struktur data tidak dapat diubah oleh utas saat utas lain membacanya
- (Dijamin) Struktur data tidak dapat dibaca oleh utas saat utas lain mengubahnya
- (Dijamin) Struktur data tidak dapat diubah oleh dua atau lebih utas secara bersamaan
- (Opsional) Izinkan dua atau lebih utas membaca struktur data secara bersamaan
- (Opsional) Izinkan utas untuk mengantre secara berurutan untuk akses ke struktur data
Hal ini dapat dilakukan dengan beberapa cara, antara lain:
- Mekanisme yang hanya mengizinkan satu utas pada satu waktu untuk memiliki akses ke struktur data. SQL Server mengimplementasikan mekanisme ini dan menyebutnya sebagai spinlock. Ini memungkinkan #1, #2, dan #3 di atas.
- Mekanisme yang memungkinkan beberapa utas untuk membaca struktur data secara bersamaan (yaitu mereka memiliki akses bersama), memungkinkan satu utas untuk mendapatkan akses eksklusif ke struktur data (dengan mengesampingkan semua utas lainnya), dan mengimplementasikan cara yang adil dari antrian untuk akses. SQL Server mengimplementasikan mekanisme ini dan menyebutnya sebagai gerendel. Ini memungkinkan kelima ketentuan di atas.
Jadi mengapa SQL Server menggunakan spinlock dan latch? Beberapa struktur data diakses begitu sering sehingga latch terlalu mahal sehingga spinlock yang sangat ringan digunakan sebagai gantinya. Dua contoh struktur data tersebut adalah daftar buffer gratis di buffer pool dan daftar kunci di lock manager.
Apa itu Latch?
Latch adalah mekanisme sinkronisasi yang melindungi struktur data tunggal dan ada tiga jenis latch di SQL Server:
- Latch yang melindungi halaman file data saat sedang dibaca dari disk. Ini muncul saat PAGEIOLATCH_XX menunggu, dan saya membahasnya di pos ini.
- Latch yang melindungi akses ke halaman file data yang sudah ada di memori (halaman 8KB di buffer pool sebenarnya hanyalah struktur data). Ini muncul saat PAGELATCH_XX menunggu, dan saya membahasnya di pos ini.
- Kait yang melindungi struktur data non-halaman. Ini muncul saat LATCH_SH dan LATCH_EX menunggu.
Dalam seri ini, kita akan berkonsentrasi pada jenis kait ketiga.
Kait itu sendiri adalah struktur data kecil dan Anda dapat menganggapnya memiliki tiga komponen:
- Deskripsi sumber daya (tentang apa yang dilindunginya)
- Bidang status yang menunjukkan mode mana gerendel saat ini ditahan, berapa banyak utas yang menahan gerendel dalam mode itu, dan apakah ada utas yang menunggu (ditambah hal-hal lain yang tidak perlu kita khawatirkan)
- Antrian utas yang pertama-masuk-pertama-keluar yang menunggu akses ke struktur data, dan mode akses mana yang mereka tunggu (disebut antrian tunggu)
Untuk kait non-halaman, kami akan membatasi diri hanya untuk mempertimbangkan mode akses SH (berbagi) untuk membaca struktur data dan EX (eksklusif) untuk mengubah struktur data. Ada mode lain yang lebih eksotis, tetapi jarang digunakan dan tidak akan muncul sebagai poin pertengkaran, jadi saya akan berpura-pura tidak ada selama sisa diskusi ini.
Beberapa dari Anda mungkin tahu bahwa ada juga komplikasi yang lebih dalam seputar superlatches/sublatches dan partisi latch untuk skalabilitas, tetapi kita tidak perlu membahas lebih dalam untuk tujuan seri ini.
Memperoleh Kait
Saat sebuah utas ingin mendapatkan gerendel, ia melihat status gerendel.
Jika utas ingin mendapatkan kait dalam mode EX, itu hanya dapat dilakukan jika tidak ada utas yang menahan kait dalam mode apa pun. Jika demikian, utas memperoleh kait dalam mode EX dan menetapkan status untuk menunjukkannya. Jika ada satu atau lebih utas yang sudah memegang kait, utas menetapkan status untuk menunjukkan bahwa ada utas yang menunggu, masuk sendiri di bagian bawah antrian tunggu, dan kemudian ditangguhkan (pada daftar pelayan penjadwal itu aktif ) menunggu LATCH_EX.
Jika utas ingin mendapatkan kait dalam mode SH, itu hanya dapat dilakukan jika tidak ada utas yang menahan gerendel atau satu-satunya utas yang menahan gerendel dalam mode SH *dan* tidak ada utas yang menunggu untuk mendapatkan gerendel. Jika demikian, utas memperoleh kait dalam mode SH, menetapkan status untuk menunjukkan itu, dan menambah jumlah utas yang memegang kait. Jika kait ditahan dalam mode EX atau ada satu atau lebih utas yang menunggu, maka utas menetapkan status untuk menunjukkan bahwa ada utas yang menunggu, masuk dengan sendirinya di bagian bawah antrian menunggu, dan kemudian ditangguhkan menunggu LATCH_SH.
Pemeriksaan utas menunggu dilakukan untuk memastikan keadilan utas menunggu kait dalam mode EX. Itu hanya perlu menunggu utas yang menahan kait dalam mode SH yang memperoleh kait sebelum mulai menunggu. Tanpa pemeriksaan itu, istilah ilmu komputer yang disebut 'kelaparan' dapat terjadi, ketika aliran konstan dari utas memperoleh kait dalam mode SH mencegah utas mode EX untuk dapat memperoleh kait.
Melepaskan Kait
Jika utas menahan gerendel dalam mode EX, status yang menunjukkan gerendel ditahan dalam mode EX tidak disetel, lalu memeriksa untuk melihat apakah ada utas yang menunggu.
Jika utas menahan kait dalam mode SH, itu akan mengurangi jumlah utas mode SH. Jika hitungannya sekarang bukan nol, utas pelepasan dilakukan dengan kait. Jika hitungan *adalah* sekarang nol, statusnya tidak disetel yang menunjukkan kait ditahan dalam mode SH dan kemudian memeriksa untuk melihat apakah ada utas yang menunggu.
Jika tidak ada utas yang menunggu, utas pelepasan dilakukan dengan kait.
Jika kepala antrian menunggu sedang menunggu mode EX, utas pelepas melakukan hal berikut:
- Menyetel status untuk menunjukkan gerendel ditahan dalam mode EX
- Menghapus utas menunggu dari kepala antrean dan menetapkannya sebagai pemilik kait
- Menandakan utas menunggu bahwa itu adalah pemiliknya dan sekarang dapat dijalankan (dengan, secara konseptual, memindahkan utas tunggu dari daftar pelayan di penjadwalnya ke antrean yang dapat dijalankan di penjadwal)
- Dan selesai dengan gerendelnya
Jika kepala antrian menunggu sedang menunggu dalam mode SH (yang hanya dapat terjadi jika utas pelepas dalam mode EX), utas pelepas melakukan hal berikut:
- Menyetel status untuk menunjukkan kait ditahan dalam mode SH
- Untuk semua thread dalam antrian menunggu yang sedang menunggu mode SH
- Menghapus utas menunggu dari kepala antrian
- Meningkatkan jumlah utas yang menahan kait
- Menandakan utas menunggu bahwa itu adalah pemilik dan sekarang dapat dijalankan
- Dan selesai dengan gerendelnya
Bagaimana Kait Menjadi Titik Pertarungan?
Tidak seperti kunci, gerendel umumnya hanya ditahan selama operasi baca atau ubah, jadi cukup ringan, tetapi karena ketidakcocokan SH vs. EX, gerendel dapat menjadi titik pertengkaran yang sama besarnya dengan kunci. Ini dapat terjadi ketika banyak utas mencoba untuk mendapatkan kait dalam mode EX (hanya satu per satu yang bisa) atau ketika banyak utas mencoba untuk mendapatkan kait dalam mode SH dan utas lain menahan kait dalam mode EX.
Ringkasan
Semakin banyak utas dalam sistem yang bersaing untuk kait 'panas', semakin tinggi pertentangan dan semakin negatif efeknya pada throughput beban kerja. Anda mungkin pernah mendengar tentang masalah pertikaian kait yang terkenal, misalnya seputar bitmap alokasi tempdb, tetapi pertengkaran juga dapat terjadi untuk kait non-halaman.
Sekarang saya telah memberi Anda latar belakang yang cukup untuk memahami kait dan cara kerjanya, dalam beberapa artikel berikutnya saya akan memeriksa beberapa masalah perebutan kait non-halaman di kehidupan nyata dan menjelaskan cara mencegah atau mengatasinya.