Haruskah sistem multi penyewa dengan SQL Server 2016, Shard atau memiliki isolasi penyewa melalui database terpisah per penyewa?

12

Diberi kasus penggunaan:

  • Data penyewa tidak boleh lintas bicara, penyewa tidak perlu data penyewa lain.
  • Setiap penyewa berpotensi memiliki volume data historis yang besar.
  • SQL Server di-host dalam contoh AWS EC2.
  • Setiap penyewa secara geografis jauh.
  • Ada niat untuk menggunakan alat visualisasi pihak ketiga seperti PowerBI Embedded
  • Volume data diperkirakan akan tumbuh seiring waktu
  • Biaya sistem terkendala.
  • Solusinya harus dipertahankan tanpa DBA produksi 24/7
  • Solusinya harus dapat skala secara horizontal.
  • Total jumlah penyewa kurang dari 50

Apa yang akan menjadi arsitektur yang direkomendasikan, apakah ada implementasi referensi untuk use case ini? Saya percaya banyak orang mungkin sudah menghadapi masalah ini untuk pengembangan perangkat lunak perusahaan.

Saya pikir ini adalah situasi yang berbeda dari Menangani semakin banyak Penyewa dalam Arsitektur Database Multi-penyewa . Kasus penggunaan yang disebutkan dalam pertanyaan itu berkaitan dengan jumlah penyewa yang lebih tinggi, yang sangat berbeda dengan memiliki sangat sedikit (50) penyewa besar. Arsitektur yang disebutkan mungkin menjadi solusi di sini, yang ingin saya ketahui lebih jauh.

DS
sumber

Jawaban:

16

Gotcha dengan sharding adalah bahwa aplikasi harus tahu shard yang mana yang harus di-query. Secara umum, ini dilakukan dengan mengoleskan sesuatu seperti klien. Saya akan menyesuaikan salah satu posting blog lama saya untuk digunakan sebagai jawaban saya.

Saat Anda membangun aplikasi untuk banyak klien, ada dua cara umum untuk mendesain database:

  • Opsi A: Tempatkan semua klien dalam database yang sama
  • Opsi 2: Bangun satu basis data per klien

Menempatkan Semua Klien di Database yang Sama

Ini sederhana: cukup tambahkan tabel Klien di bagian atas skema, tambahkan tabel ClientUsers untuk memastikan orang hanya melihat data mereka sendiri, dan kita lanjutkan.

Manfaat dari pendekatan ini:

Manajemen skema yang lebih mudah. Ketika pengembang menyebarkan versi baru aplikasi, mereka hanya perlu membuat perubahan skema dalam satu database. Tidak ada kekhawatiran tentang pelanggan yang berbeda yang tidak sinkron atau pada versi yang salah.

Penyesuaian kinerja yang lebih mudah. Kami dapat memeriksa penggunaan indeks dan statistik hanya di satu tempat, mengimplementasikan perbaikan dengan mudah, dan melihat efek langsung di semua klien kami. Dengan ratusan atau ribuan basis data, bahkan perubahan terkecil sekalipun bisa sulit untuk dikoordinasikan. Kami dapat memeriksa konten cache prosedur kami dan mengetahui dengan pasti kueri atau prosedur tersimpan mana yang paling intensif di seluruh aplikasi kami, sedangkan jika kami menggunakan basis data terpisah per klien, kami mungkin memiliki waktu penggunaan agregat yang lebih sulit untuk digunakan di seluruh rencana pelaksanaan yang berbeda.

Lebih mudah untuk membangun API eksternal. Jika kita perlu memberikan akses ke seluruh basis data kita untuk orang luar untuk membuat produk, kita bisa melakukannya dengan lebih mudah jika semua data ada dalam satu basis data. Jika API harus berurusan dengan pengelompokan data dari banyak basis data di beberapa server, itu menambah waktu pengembangan dan pengujian. (Di sisi lain, hal “banyak server” mulai mengisyaratkan pembatasan untuk skenario satu-database-untuk-memerintah-semuanya-semua: satu basis data biasanya berarti semua beban kami berdampak hanya pada satu server basis data.) Dalam kasus Anda , dengan PowerBI, memiliki semua orang dalam satu basis data akan membuat mengelola koneksi lebih mudah.

Ketersediaan tinggi & pemulihan bencana lebih mudah. Sangat mudah mengelola mirroring basis data, pengiriman log, replikasi, dan pengelompokan jika yang perlu kita khawatirkan hanyalah satu database. Kita bisa membangun infrastruktur dengan cepat.

Menempatkan Setiap Klien di Database atau Shard Sendiri

Anda masih memerlukan daftar klien, tetapi sekarang menjadi direktori - untuk setiap klien, Anda juga melacak beling tempat tinggalnya. Pada saat startup, aplikasi Anda menanyakan tabel ini, dan menyimpannya dalam RAM. Ketika membutuhkan data untuk klien, itu terhubung langsung ke beling itu (database & server).

Manfaat dari pendekatan ini:

Memulihkan klien tunggal lebih mudah. Klien adalah kantung daging yang tidak bisa diandalkan. (Kecuali saya - mereka adalah kantong daging yang dapat diandalkan.) Mereka memiliki semua jenis "oops" saat mereka ingin mengambil semua data mereka kembali ke suatu titik waktu, dan itu adalah rasa sakit yang sangat besar di belakang jika data mereka berbaur dengan data klien lain dalam tabel yang sama. Mengembalikan dalam skenario database-klien-tunggal mudah mati otak: cukup pulihkan database klien. Tidak ada orang lain yang terpengaruh.

Ekspor data yang lebih mudah. Klien suka mendapatkan data mereka. Mereka ingin keamanan mengetahui bahwa mereka bisa mengeluarkan data kapan saja mereka inginkan, menghindari skenario penguncian vendor yang ditakuti, dan mereka ingin melakukan pelaporan sendiri. Dengan data masing-masing klien diisolasi ke dalam basis data mereka sendiri, kami cukup memberikan salinan cadangan basis data mereka sendiri. Kami tidak harus membuat API ekspor data.

Skalabilitas multi-server yang lebih mudah. Ketika aplikasi kita membutuhkan lebih banyak daya daripada yang bisa kita dapatkan dari satu server, kita dapat membagi database antara beberapa server. Kami juga dapat menyebarkan muatan secara geografis, menempatkan server di Asia atau Eropa agar lebih dekat dengan klien.

Penyesuaian kinerja per-klien yang lebih mudah. Jika beberapa klien menggunakan fitur atau laporan berbeda, kami dapat membuat serangkaian indeks khusus atau tampilan indeks hanya untuk klien tersebut tanpa memperbesar ukuran data setiap orang. Memang, ada beberapa risiko di sini - dengan memungkinkan perbedaan skema antara klien, kami baru saja membuat penerapan kode kami sedikit lebih berisiko dan manajemen kinerja kami lebih sulit.

Manajemen keamanan yang lebih mudah. Selama kami telah benar-benar mengunci keamanan dengan satu pengguna per basis data, kami tidak perlu khawatir tentang Klien X mengakses data Klien Y. Namun, jika kami hanya menggunakan satu login untuk semua orang, maka kami belum benar-benar mengatasi masalah ini.

Jendela perawatan yang lebih mudah. Dalam lingkungan global di mana pelanggan tersebar di seluruh dunia, lebih mudah membuat pelanggan offline untuk pemeliharaan jika kita bisa melakukannya dalam kelompok atau zona.

Yang mana yang tepat untuk Anda?

Tidak ada pilihan yang tepat: Anda harus mengetahui kekuatan dan kelemahan perusahaan Anda sendiri. Mari kita ambil dua klien saya sebagai contoh.

Perusahaan A unggul dalam penyempurnaan kinerja perangkat keras. Mereka sangat, sangat pandai memeras sedikit terakhir dari kinerja perangkat keras, dan mereka tidak keberatan mengganti perangkat keras SQL Server mereka pada siklus 12-18 bulan. (Mereka menyegarkan server web setiap 4-6 bulan!) Tumit Achilles mereka adalah persyaratan kepatuhan dan keamanan yang ekstrem. Mereka memiliki kebutuhan audit yang luar biasa, dan hanya lebih mudah bagi mereka untuk menerapkan kontrol anti peluru pada satu server, satu basis data daripada untuk mengelola persyaratan tersebut di ribuan basis data di lusinan server. Mereka memilih satu database, satu server, banyak klien.

Perusahaan 2 unggul dalam praktik pengembangan. Mengelola perubahan skema dan penyebaran kode di ribuan basis data bukan masalah bagi mereka. Mereka memiliki klien di seluruh dunia, dan mereka sedang memproses transaksi kartu kredit untuk para klien sepanjang waktu. Mereka membutuhkan kemampuan untuk menyebarkan beban secara geografis, dan mereka tidak ingin mengganti server di seluruh dunia setiap 12-18 bulan. Mereka memilih satu database untuk setiap klien, dan hasilnya terbayar ketika mereka mulai menempatkan SQL Server di Asia dan Eropa untuk klien luar negeri mereka.

Brent Ozar
sumber
"Dalam kasus Anda, dengan PowerBI, memiliki semua orang dalam satu basis data akan membuat mengelola koneksi jauh lebih mudah". Saat ini PowerBI Embedded tidak memiliki keamanan Tingkat Row dan dengan demikian setiap penyewa dalam satu database menyebabkan beberapa keraguan tentang kasus penggunaan ini, lihat: community.powerbi.com/t5/Developer/… , mengingat informasi ini dapat Anda ulangi ini atau menyarankan alternatif atau memperbaiki pemahaman saya?
DS
Juga, "Menempatkan Setiap Klien di Basis Data atau Shard Sendiri" dapatkah Anda menguraikan perbedaan di sini di antara kedua saran ini
DS
Saya hanya akan mengatakan bahwa harus menggunakan lebih dari satu database tidak seburuk yang Anda buat. Pada 2017 kami memiliki banyak opsi yang membuatnya sangat mudah untuk menerapkan perubahan ke 1, 5, atau 900 basis data. Dan ketika Anda memiliki pengecualian untuk pelanggan tertentu, ini biasanya dapat diperkenalkan ke database tersebut sedemikian rupa sehingga mereka tidak mengganggu kode umum.
Aaron Bertrand
5

Satu pertimbangan lebih lanjut yang belum saya lihat dalam jawaban lain.

Memiliki desain yang memungkinkan banyak penyewa dalam satu basis data akan memberikan fleksibilitas nanti. Jika memuat / skala keluar / keamanan / lokasi geo menuntut kemudian menyarankan penyewa harus memiliki database terpisah itu dapat dibuat dengan mengembalikan DB arus pada contoh baru. Data penyewa lainnya masih dilindungi oleh mekanisme apa pun yang ada. Data yang sekarang sudah usang dapat dihapus sedikit demi sedikit dari basis data lama dan baru jika waktu mengizinkan.

Kebalikannya tidak benar. Menggabungkan banyak basis data satu penyewa akan membutuhkan lebih banyak pekerjaan.

Michael Green
sumber
4

Salah satu praktik yang membuat model multi-penyewa jauh lebih mudah, meskipun itu melanggar normalisasi *, adalah dengan memasukkan kolom pada setiap tabel untuk penyewa. Anda bisa menyebutnya TenantID. Dengan begitu setiap kueri yang dijalankan terhadap basis data dapat memfilter pada TenantID di setiap tabel, dan Anda dapat menggunakan partisi basis data untuk mengisolasi data untuk setiap penyewa dan mempercepat kueri dengan menyejajarkan partisi. Jauh lebih mudah untuk memiliki semua penyewa dalam satu basis data dengan cara ini.

* Itu tidak selalu melanggar normalisasi, tetapi itu bisa. Misalnya, jika Anda memiliki a Persondan PersonAddresstabel. The Persontabel akan memiliki TenantID, PersonIDsebagai Primary Key. The PersonAddresstabel akan memiliki TenantID, PersonID, AddressTypeIDsebagai Primary Key dengan apa yang saya sarankan.

Biasanya hanya PersonIDakan cukup, karena Anda dapat bergabung kembali ke Personmeja untuk menemukan Tenant. Saya menyarankan Anda TenantIDmeneruskan ke setiap tabel berikutnya, bahkan ketika kunci yang lebih tipis akan bekerja.

Pemahaman saya bahwa meneruskan informasi apa saja ke tabel yang dapat diturunkan dari data lain dianggap melanggar normalisasi. Tapi mungkin menggunakan kunci tipis adalah praktik terbaik.

Matthew Sontum
sumber
Terima kasih, saya setuju dengan saran dan menambahkan di atasnya, saya ingin menyebutkan bidang ini TenantID harus merupakan tipe integer dan bukan GUID, kami terbakar seperti itu untuk kinerja.
DS
3
Tetapi bahkan jika Anda memilih untuk membawa TenantID ke tabel anak, yang tidak harus Anda lakukan, kunci yang lebih luas tidak berarti normalisasi "rusak." Sama seperti memilih GUID daripada IDENTITAS (kunci yang lebih luas) tidak melanggar normalisasi, juga tidak memilih kunci alami yang lebih luas daripada menggunakan pengganti sama sekali.
Aaron Bertrand