Arsitektur Integrasi CLR - Lingkungan yang Dihosting CLR

Berlaku untuk: SQL Server Azure SQL Managed Instance

SQL Server integrasi dengan runtime bahasa umum (CLR) .NET Framework memungkinkan pemrogram database menggunakan bahasa seperti Visual C#, Visual Basic .NET, dan Visual C++. Fungsi, prosedur tersimpan, pemicu, jenis data, dan agregat adalah salah satu jenis logika bisnis yang dapat ditulis oleh pemrogram dengan bahasa ini.

CLR menampilkan memori yang dikumpulkan sampah, utas preemptive, layanan metadata (refleksi jenis), keterverifikasi kode, dan keamanan akses kode. CLR menggunakan metadata untuk menemukan dan memuat kelas, meletakkan instans dalam memori, menyelesaikan pemanggilan metode, menghasilkan kode asli, menerapkan keamanan, dan mengatur batas konteks run-time.

CLR dan SQL Server berbeda sebagai lingkungan run-time dalam cara mereka menangani memori, utas, dan sinkronisasi. Artikel ini menjelaskan cara kedua run times ini terintegrasi sehingga semua sumber daya sistem dikelola secara seragam. Artikel ini juga membahas cara keamanan akses kode CLR (CAS) dan keamanan SQL Server terintegrasi untuk menyediakan lingkungan eksekusi yang andal dan aman untuk kode pengguna.

Konsep Dasar Arsitektur CLR

Dalam .NET Framework, programmer menulis dalam bahasa tingkat tinggi yang mengimplementasikan kelas yang mendefinisikan strukturnya (misalnya, bidang atau properti kelas) dan metode. Beberapa metode ini dapat menjadi fungsi statis. Kompilasi program menghasilkan file yang disebut assembly yang berisi kode yang dikompilasi dalam bahasa perantara Microsoft (MSIL), dan manifes yang berisi semua referensi ke rakitan dependen.

Catatan

Rakitan adalah elemen penting dalam arsitektur CLR. Mereka adalah unit pengemasan, penyebaran, dan penerapan versi kode aplikasi dalam .NET Framework. Dengan menggunakan rakitan, Anda dapat menyebarkan kode aplikasi di dalam database dan menyediakan cara yang seragam untuk mengelola, mencadangkan, dan memulihkan aplikasi database lengkap.

Manifes perakitan berisi metadata tentang assembly, yang menjelaskan semua struktur, bidang, properti, kelas, hubungan warisan, fungsi, dan metode yang ditentukan dalam program. Manifes menetapkan identitas rakitan, menentukan file yang membentuk implementasi perakitan, menentukan jenis dan sumber daya yang membentuk rakitan, memerinci dependensi waktu kompilasi pada rakitan lain, dan menentukan set izin yang diperlukan agar perakitan berjalan dengan benar. Informasi ini digunakan pada durasi untuk menyelesaikan referensi, menerapkan kebijakan pengikatan versi, dan memvalidasi integritas rakitan yang dimuat.

.NET Framework mendukung atribut kustom untuk membuat anotasi kelas, properti, fungsi, dan metode dengan informasi tambahan yang dapat ditangkap aplikasi dalam metadata. Semua pengompilasi .NET Framework mengonsumsi anotasi ini tanpa interpretasi dan menyimpannya sebagai metadata perakitan. Anotasi ini dapat diperiksa dengan cara yang sama seperti metadata lainnya.

Kode terkelola adalah MSIL yang dijalankan di CLR, bukan langsung oleh sistem operasi. Aplikasi kode terkelola memperoleh layanan CLR, seperti pengumpulan sampah otomatis, pemeriksaan jenis run-time, dan dukungan keamanan. Layanan ini membantu menyediakan platform yang seragam dan perilaku independen bahasa aplikasi kode terkelola.

Tujuan Desain Integrasi CLR

Saat kode pengguna berjalan di dalam lingkungan yang dihosting CLR di SQL Server (disebut integrasi CLR), tujuan desain berikut berlaku:

Keandalan (Keselamatan)

Kode pengguna tidak boleh diizinkan untuk melakukan operasi yang membahayakan integritas proses Mesin Database, seperti memunculkan kotak pesan yang meminta respons pengguna atau keluar dari proses. Kode pengguna seharusnya tidak dapat menimpa buffer memori Mesin Database atau struktur data internal.

Skalabilitas

SQL Server dan CLR memiliki model internal yang berbeda untuk penjadwalan dan manajemen memori. SQL Server mendukung model threading kooperatif dan non-preemtif di mana utas secara sukarela menghasilkan eksekusi secara berkala, atau ketika mereka menunggu kunci atau I/O. CLR mendukung model utas preemptive. Jika kode pengguna yang berjalan di dalam SQL Server dapat langsung memanggil primitif utas sistem operasi, maka kode pengguna tidak berintegrasi dengan baik ke dalam penjadwal tugas SQL Server dan dapat menurunkan skalabilitas sistem. CLR tidak membedakan antara memori virtual dan fisik, tetapi SQL Server secara langsung mengelola memori fisik dan diperlukan untuk menggunakan memori fisik dalam batas yang dapat dikonfigurasi.

Berbagai model untuk threading, penjadwalan, dan manajemen memori menghadirkan tantangan integrasi untuk sistem manajemen database relasional (RDBMS) yang diskalakan untuk mendukung ribuan sesi pengguna bersamaan. Arsitektur harus memastikan bahwa skalabilitas sistem tidak disusupi oleh kode pengguna yang memanggil antarmuka pemrograman aplikasi (API) untuk threading, memori, dan primitif sinkronisasi secara langsung.

Keamanan

Kode pengguna yang berjalan dalam database harus mengikuti aturan autentikasi dan otorisasi SQL Server saat mengakses objek database seperti tabel dan kolom. Selain itu, administrator database harus dapat mengontrol akses ke sumber daya sistem operasi, seperti file dan akses jaringan, dari kode pengguna yang berjalan dalam database. Praktik ini menjadi penting karena bahasa pemrograman terkelola (tidak seperti bahasa yang tidak dikelola seperti Transact-SQL) menyediakan API untuk mengakses sumber daya tersebut. Sistem harus menyediakan cara yang aman bagi kode pengguna untuk mengakses sumber daya mesin di luar proses Mesin Database. Untuk informasi selengkapnya, lihat Keamanan Integrasi CLR.

Performa

Kode pengguna terkelola yang berjalan di Mesin Database harus memiliki performa komputasi yang sebanding dengan kode yang sama yang dijalankan di luar server. Akses database dari kode pengguna terkelola tidak secepat Transact-SQL asli. Untuk informasi selengkapnya, lihat Performa Integrasi CLR.

Layanan CLR

CLR menyediakan sejumlah layanan untuk membantu mencapai tujuan desain integrasi CLR dengan SQL Server.

Verifikasi keamanan jenis

Kode jenis aman adalah kode yang mengakses struktur memori hanya dengan cara yang terdefinisi dengan baik. Misalnya, mengingat referensi objek yang valid, kode type-safe dapat mengakses memori pada offset tetap yang sesuai dengan anggota bidang aktual. Namun, jika kode mengakses memori pada offset arbitrer di dalam atau di luar rentang memori yang termasuk dalam objek, maka itu tidak aman jenis. Ketika rakitan dimuat di CLR, sebelum MSIL dikompilasi menggunakan kompilasi just-in-time (JIT), runtime melakukan fase verifikasi yang memeriksa kode untuk menentukan keamanan jenisnya. Kode yang berhasil melewati verifikasi ini disebut kode jenis aman yang dapat diverifikasi.

Domain aplikasi

CLR mendukung gagasan domain aplikasi sebagai zona eksekusi dalam proses host di mana rakitan kode terkelola dapat dimuat dan dijalankan. Batas domain aplikasi menyediakan isolasi antara rakitan. Rakitan diisolasi dalam hal visibilitas variabel statis dan anggota data dan kemampuan untuk memanggil kode secara dinamis. Domain aplikasi juga merupakan mekanisme untuk memuat dan membongkar kode. Kode hanya dapat dibongkar dari memori dengan membongkar domain aplikasi. Untuk informasi selengkapnya, lihat Domain Aplikasi dan Keamanan Integrasi CLR.

Keamanan Akses Kode (CAS)

Sistem keamanan CLR menyediakan cara untuk mengontrol jenis operasi apa yang dapat dilakukan kode terkelola dengan menetapkan izin ke kode. Izin akses kode ditetapkan berdasarkan identitas kode (misalnya, tanda tangan perakitan atau asal kode).

CLR menyediakan kebijakan di seluruh komputer yang dapat diatur oleh administrator komputer. Kebijakan ini menentukan pemberian izin untuk kode terkelola apa pun yang berjalan di komputer. Selain itu, ada kebijakan keamanan tingkat host yang dapat digunakan oleh host seperti SQL Server untuk menentukan batasan tambahan pada kode terkelola.

Jika API terkelola di .NET Framework mengekspos operasi pada sumber daya yang dilindungi oleh izin akses kode, API akan menuntut izin tersebut sebelum mengakses sumber daya. Permintaan ini menyebabkan sistem keamanan CLR memicu pemeriksaan komprehensif setiap unit kode (assembly) di tumpukan panggilan. Akses ke sumber daya akan diberikan hanya jika seluruh rantai panggilan memiliki izin.

Perhatikan bahwa kemampuan untuk menghasilkan kode terkelola secara dinamis, menggunakan Reflection.Emit API, tidak didukung di dalam lingkungan yang dihosting CLR di SQL Server. Kode tersebut tidak akan memiliki izin CAS untuk dijalankan dan karenanya akan gagal pada durasi. Untuk informasi selengkapnya, lihat Keamanan Akses Kode Integrasi CLR.

Atribut Perlindungan Host (HPAs)

CLR menyediakan mekanisme untuk membuat anotasi API terkelola yang merupakan bagian dari .NET Framework dengan atribut tertentu yang mungkin menarik bagi host CLR. Contoh atribut tersebut meliputi:

  • SharedState, yang menunjukkan apakah API mengekspos kemampuan untuk membuat atau mengelola status bersama (misalnya, bidang kelas statis).

  • Sinkronisasi, yang menunjukkan apakah API mengekspos kemampuan untuk melakukan sinkronisasi antar alur.

  • ExternalProcessMgmt, yang menunjukkan apakah API mengekspos cara untuk mengontrol proses host.

Mengingat atribut ini, host dapat menentukan daftar HPAs, seperti atribut SharedState, yang harus dilarang di lingkungan yang dihosting. Dalam hal ini, CLR menolak upaya oleh kode pengguna untuk memanggil API yang diannotasikan oleh HPAs dalam daftar yang dilarang. Untuk informasi selengkapnya, lihat Atribut Perlindungan Host dan Pemrograman Integrasi CLR.

Bagaimana SQL Server dan CLR Bekerja Sama

Bagian ini membahas bagaimana SQL Server mengintegrasikan model utas, penjadwalan, sinkronisasi, dan manajemen memori SQL Server dan CLR. Secara khusus, bagian ini memeriksa integrasi mengingat skalabilitas, keandalan, dan tujuan keamanan. SQL Server pada dasarnya bertindak sebagai sistem operasi untuk CLR ketika dihosting di dalam SQL Server. CLR memanggil rutinitas tingkat rendah yang diterapkan oleh SQL Server untuk threading, penjadwalan, sinkronisasi, dan manajemen memori. Rutinitas ini adalah primitif yang sama dengan yang digunakan mesin SQL Server lainnya. Pendekatan ini memberikan beberapa manfaat skalabilitas, keandalan, dan keamanan.

Skalabilitas: Alur, penjadwalan, dan sinkronisasi umum

CLR memanggil SQL SERVER API untuk membuat utas, baik untuk menjalankan kode pengguna maupun untuk penggunaan internalnya sendiri. Untuk menyinkronkan antara beberapa utas, CLR memanggil SQL Server objek sinkronisasi. Praktik ini memungkinkan penjadwal SQL Server untuk menjadwalkan tugas lain ketika utas menunggu objek sinkronisasi. Misalnya, ketika CLR memulai pengumpulan sampah, semua utasnya menunggu pengumpulan sampah selesai. Karena utas CLR dan objek sinkronisasi yang mereka tunggu diketahui oleh penjadwal SQL Server, SQL Server dapat menjadwalkan utas yang menjalankan tugas database lain yang tidak melibatkan CLR. Ini juga memungkinkan SQL Server untuk mendeteksi kebuntuan yang melibatkan kunci yang diambil oleh objek sinkronisasi CLR dan menggunakan teknik tradisional untuk penghapusan kebuntuan.

Kode terkelola berjalan lebih awal dalam SQL Server. Penjadwal SQL Server memiliki kemampuan untuk mendeteksi dan menghentikan utas yang belum menghasilkan untuk waktu yang signifikan. Kemampuan untuk mengaitkan utas CLR ke utas SQL Server menyiratkan bahwa penjadwal SQL Server dapat mengidentifikasi utas "runaway" di CLR dan mengelola prioritasnya. Utas pelarian seperti itu ditangguhkan dan dimasukkan kembali ke dalam antrean. Utas yang berulang kali diidentifikasi sebagai utas runaway tidak diizinkan untuk berjalan selama jangka waktu tertentu sehingga pekerja lain yang mengeksekusi dapat berjalan.

Ada beberapa situasi di mana kode terkelola yang berjalan lama akan menghasilkan secara otomatis, dan beberapa situasi yang tidak akan terjadi. Dalam situasi berikut, kode terkelola yang berjalan lama akan menghasilkan secara otomatis:

  • Jika kode memanggil SQL OS (untuk mengkueri data misalnya)
  • Jika memori yang cukup dialokasikan untuk memicu pengumpulan sampah
  • Jika kode memasuki mode preemptive dengan memanggil fungsi OS

Kode yang tidak melakukan salah satu hal di atas, misalnya perulangan ketat yang hanya berisi komputasi, tidak akan secara otomatis menghasilkan penjadwal, yang dapat menyebabkan penantian panjang untuk beban kerja lain dalam sistem. Dalam situasi ini, terserah pengembang untuk secara eksplisit menghasilkan dengan memanggil fungsi System.Thread.Sleep() dari .NET Framework, atau dengan secara eksplisit memasuki mode preemtive dengan System.Thread.BeginThreadAffinity(), di bagian kode apa pun yang diantisipasi untuk berjalan lama. Contoh kode berikut menunjukkan cara menghasilkan secara manual menggunakan masing-masing metode ini.

// Example 1: Manually yield to SOS scheduler.
for (int i = 0; i < Int32.MaxValue; i++)
{
 // *Code that does compute-heavy operation, and does not call into
 // any OS functions.*

 // Manually yield to the scheduler regularly after every few cycles.
 if (i % 1000 == 0)
 {
   Thread.Sleep(0);
 }
}
// Example 2: Use ThreadAffinity to run preemptively.
// Within BeginThreadAffinity/EndThreadAffinity the CLR code runs in preemptive mode.
Thread.BeginThreadAffinity();
for (int i = 0; i < Int32.MaxValue; i++)
{
  // *Code that does compute-heavy operation, and does not call into
  // any OS functions.*
}
Thread.EndThreadAffinity();
Skalabilitas: Manajemen memori umum

CLR memanggil SQL Server primitif untuk mengalokasikan dan membatalkan alokasi memorinya. Karena memori yang digunakan oleh CLR diperhitungkan dalam total penggunaan memori sistem, SQL Server dapat tetap berada dalam batas memori yang dikonfigurasi dan memastikan CLR dan SQL Server tidak bersaing satu sama lain untuk memori. SQL Server juga dapat menolak permintaan memori CLR ketika memori sistem dibatasi, dan meminta CLR untuk mengurangi penggunaan memorinya ketika tugas lain membutuhkan memori.

Keandalan: Domain aplikasi dan pengecualian yang tidak dapat dipulihkan

Ketika kode terkelola dalam API .NET Framework mengalami pengecualian penting, seperti kehabisan memori atau luapan tumpukan, tidak selalu mungkin untuk pulih dari kegagalan tersebut dan memastikan semantik yang konsisten dan benar untuk implementasinya. API ini menaikkan pengecualian pembatalakan utas sebagai respons terhadap kegagalan ini.

Ketika dihosting di SQL Server, pembatalan utas tersebut ditangani sebagai berikut: CLR mendeteksi status bersama apa pun di domain aplikasi tempat pembatalan utas terjadi. CLR mendeteksi ini dengan memeriksa keberadaan objek sinkronisasi. Jika ada status bersama di domain aplikasi, maka domain aplikasi itu sendiri dibongkar. Pembongkaran domain aplikasi menghentikan transaksi database yang saat ini berjalan di domain aplikasi tersebut. Karena kehadiran status bersama dapat memperlebar dampak pengecualian kritis tersebut terhadap sesi pengguna selain yang memicu pengecualian, SQL Server dan CLR telah mengambil langkah-langkah untuk mengurangi kemungkinan status bersama. Untuk informasi selengkapnya, lihat dokumentasi .NET Framework.

Keamanan: Set izin

SQL Server memungkinkan pengguna menentukan persyaratan keandalan dan keamanan untuk kode yang disebarkan ke dalam database. Saat rakitan diunggah ke dalam database, pembuat rakitan dapat menentukan salah satu dari tiga set izin untuk perakitan tersebut: AMAN, EXTERNAL_ACCESS, dan TIDAK AMAN.

Fungsionalitas SAFE EXTERNAL_ACCESS UNSAFE
Keamanan Akses Kode Jalankan saja Jalankan + akses ke sumber daya eksternal Tidak dibatasi
Pembatasan model pemrograman Ya Ya Tanpa batasan
Persyaratan keterverifikasian Ya Ya Tidak
Kemampuan untuk memanggil kode asli Tidak Tidak Ya

SAFE adalah mode yang paling andal dan aman dengan pembatasan terkait dalam hal model pemrograman yang diizinkan. Rakitan SAFE diberi izin yang cukup untuk menjalankan, melakukan komputasi, dan memiliki akses ke database lokal. Rakitan SAFE harus berjenis aman dan tidak diizinkan untuk memanggil kode yang tidak dikelola.

UNSAFE adalah untuk kode yang sangat tepercaya yang hanya dapat dibuat oleh administrator database. Kode tepercaya ini tidak memiliki batasan keamanan akses kode, dan dapat memanggil kode yang tidak dikelola (asli).

EXTERNAL_ACCESS menyediakan opsi keamanan perantara, memungkinkan kode untuk mengakses sumber daya di luar database tetapi masih memiliki jaminan keandalan SAFE.

SQL Server menggunakan lapisan kebijakan CAS tingkat host untuk menyiapkan kebijakan host yang memberikan salah satu dari tiga set izin berdasarkan kumpulan izin yang disimpan dalam katalog SQL Server. Kode terkelola yang berjalan di dalam database selalu mendapatkan salah satu kumpulan izin akses kode ini.

Pembatasan Model Pemrograman

Model pemrograman untuk kode terkelola dalam SQL Server melibatkan fungsi penulisan, prosedur, dan jenis yang biasanya tidak memerlukan penggunaan status yang diadakan di beberapa pemanggilan atau berbagi status di beberapa sesi pengguna. Selanjutnya, seperti yang dijelaskan sebelumnya, keberadaan status bersama dapat menyebabkan pengecualian kritis yang berdampak pada skalabilitas dan keandalan aplikasi.

Mengingat pertimbangan ini, kami mencegah penggunaan variabel statis dan anggota data statis kelas yang digunakan dalam SQL Server. Untuk rakitan YANG AMAN dan EXTERNAL_ACCESS, SQL Server memeriksa metadata perakitan pada waktu CREATE ASSEMBLY dan gagal dalam pembuatan rakitan tersebut jika menemukan penggunaan anggota dan variabel data statis.

SQL Server juga melarang panggilan ke API .NET Framework yang diannotasikan dengan atribut perlindungan host SharedState, Synchronization, dan ExternalProcessMgmt. Ini mencegah assembly AMAN dan EXTERNAL_ACCESS memanggil API apa pun yang memungkinkan status berbagi, melakukan sinkronisasi, dan memengaruhi integritas proses SQL Server. Untuk informasi selengkapnya, lihat Pembatasan Model Pemrograman Integrasi CLR.

Lihat juga

Keamanan Integrasi CLR
Performa Integrasi CLR