Sedikit latar belakang
Saya telah menggunakan permata Apartment untuk menjalankan aplikasi multi-sewa selama bertahun-tahun. Sekarang baru-baru ini kebutuhan untuk memperbesar basis data menjadi beberapa host telah tiba, server db tidak dapat mengikuti lagi (baik membaca dan menulis sudah terlalu banyak) - dan ya, saya meningkatkan perangkat keras ke max (didedikasikan perangkat keras, 64 core, 12 Nvm-e drive dalam serangan 10, ram 384Gb dll.).
Saya sedang mempertimbangkan untuk melakukan ini per-penyewa (1 penyewa = 1 konfigurasi koneksi database / kolam) karena itu akan menjadi cara "sederhana" dan efisien untuk mendapatkan hingga number-of-tenants
-lebih banyak kapasitas tanpa melakukan banyak perubahan kode aplikasi.
Sekarang, saya menjalankan rel 4.2 atm., Segera meningkatkan ke 5.2. Saya dapat melihat bahwa rails 6 menambahkan dukungan untuk definisi koneksi per-model, namun itu tidak benar-benar apa yang saya butuhkan, karena saya memiliki skema database yang sepenuhnya dicerminkan untuk masing-masing dari 20 penyewa saya. Biasanya saya mengganti "database" per permintaan (di middleware) atau per latar belakang pekerjaan (sidekiq middleware), namun ini saat ini sepele dan ditangani oleh permata Apartment, karena hanya mengatur search_path
di Postgresql dan tidak benar-benar mengubah koneksi yang sebenarnya. Saat beralih ke strategi hosting per-penyewa, saya harus mengganti seluruh koneksi per permintaan.
Pertanyaan:
- Saya mengerti bahwa saya bisa melakukan pekerjaan
ActiveRecord::Base.establish_connection(config)
per permintaan / latar belakang - namun, seperti yang saya juga mengerti, yang memicu jabat tangan koneksi database yang sama sekali baru untuk dibuat dan kolam db baru untuk muncul di rel - kan? Saya kira itu akan menjadi kinerja bunuh diri untuk membuat semacam overhead pada setiap permintaan tunggal untuk aplikasi saya. - Karena itu saya bertanya-tanya apakah ada yang bisa melihat opsi dengan rel misalnya pra-membangun beberapa (total 20) koneksi database / pool dari awal (misalnya pada saat boot aplikasi), dan kemudian hanya beralih di antara kolam-kolam per permintaan? Sehingga koneksi dia sudah dibuat dan siap digunakan.
- Apakah semua ini hanya ide yang buruk dan haruskah saya mencari pendekatan yang berbeda? Misalnya 1 instance aplikasi = satu koneksi spesifik ke satu tenant tertentu. Atau sesuatu yang lain.
sumber
master
cabang Rails saat ini . Apakah menjalankan Rails Egde menjadi opsi atau memproteksi fitur itu ke versi Rails Anda saat ini?ActiveRecord::Base.connected_to(shard: :shard_one) do ... end
berarti bahwa pool akan digunakan (kembali), alih-alih membuat koneksi baru setiap saat?Jawaban:
Seperti yang saya mengerti, ada 4 pola untuk aplikasi multi-tenancy:
1. Model khusus / Beberapa Lingkungan Produksi
Setiap instance atau basis data seluruhnya menampung aplikasi penyewa yang berbeda dan tidak ada yang dibagikan di antara penyewa.
Ini adalah aplikasi 1 contoh dan 1 database untuk 1 penyewa. Pengembangannya akan mudah seolah Anda hanya melayani 1 penyewa. Tetapi akan menjadi mimpi buruk bagi para biarawan jika Anda memiliki, katakanlah, 100 penyewa.
2. Pemisahan Fisik Penyewa
1 contoh aplikasi untuk semua penyewa tetapi 1 basis data untuk 1 penyewa. Ini yang Anda cari. Anda dapat menggunakan
ActiveRecord::Base.establish_connection(config)
, atau menggunakan permata, atau memperbarui ke Rails 6 seperti yang disarankan lainnya. Lihat jawaban untuk (2) di bawah ini.3. Model skema terisolasi / Segregasi Logis
Dalam Skema Terpencil, tabel penyewa atau komponen basis data adalah grup di bawah skema logis atau ruang nama dan dipisahkan dari skema penyewa lain, namun skema tersebut dihosting dalam instance database yang sama.
1 instance app dan 1 database untuk semua penyewa, seperti yang Anda lakukan dengan permata apartemen.
4. Komponen Sebagian Terisolasi
Dalam model ini, komponen yang memiliki fungsi umum dibagi di antara penyewa sementara komponen dengan fungsi yang unik atau tidak terkait diisolasi. Pada lapisan data, data umum seperti data yang mengidentifikasi penyewa dikelompokkan atau disimpan dalam satu tabel sementara data spesifik penyewa diisolasi pada tabel atau lapisan contoh.
Adapun (1),
ActiveRecord::Base.establish_connection(config)
tidak jabat tangan ke db per permintaan jika Anda menggunakannya dengan benar. Anda dapat memeriksa di sini dan membaca semua komentar di sini .Adapun (2), Jika Anda tidak ingin menggunakan
establish_connection
, Anda dapat menggunakan permata multiverse (ini berfungsi untuk rel 4.2), atau permata lainnya. Atau, seperti saran lainnya, Anda dapat memperbarui ke Rails 6.Sunting: Permata multiverse sedang digunakan
establish_connection
. Ini akan menambahkandatabase.yml
, dan membuat kelas dasar sehingga setiap subclass berbagi koneksi / kolam yang sama. Pada dasarnya, ini mengurangi upaya kami untuk menggunakanestablish_connection
.Adapun (3), jawabannya:
Jika Anda tidak memiliki banyak penyewa, dan aplikasi Anda cukup rumit, saya sarankan Anda menggunakan pola Model Khusus. Jadi Anda menggunakan 1 instance aplikasi = satu koneksi spesifik ke satu penyewa tertentu. Anda tidak perlu membuat aplikasi Anda lebih kompleks dengan menambahkan beberapa koneksi basis data.
Tetapi jika Anda memiliki banyak penyewa, saya sarankan Anda menggunakan Segregasi Fisik Penyewa atau Komponen Terpisah Sebagian tergantung pada proses bisnis Anda.
Either way, Anda harus memperbarui / menulis ulang aplikasi Anda untuk mematuhi arsitektur baru.
sumber
establish_connection
model seperti iniclass SecondTenantUser < ActiveRecord::Base; establish_connection(DB_SECOND_TENANT); end
:, dan mengatakan Anda memiliki 5 model, Anda membuat 5 kumpulan koneksi ke DB_SECOND_TENANT. Dan setiap kolam diperlakukan sama. Jadi, Anda tidak membuat kumpulan per permintaan, tetapi perestablish_connection
.Dari apa yang saya mengerti, (2) harus dimungkinkan dengan switching koneksi manual di Rails 6.
sumber
Hanya beberapa hari yang lalu sharding horizontal ditambahkan ke
master
cabang Ruby on Rails di GitHub. Saat ini, fitur ini tidak dirilis secara resmi tetapi tergantung pada versi Rails aplikasi Anda, Anda mungkin ingin mempertimbangkan untuk menggunakan Railsmaster
dengan menambahkan ini keGemfile
:Dengan fitur baru ini, Anda dapat memanfaatkan kumpulan koneksi basis data Rails dan mengganti basis data berdasarkan kondisi.
Saya belum pernah menggunakan fitur baru ini, tetapi sepertinya cukup mudah:
Anda tidak menambahkan banyak detail tentang bagaimana Anda menentukan nomor penyewa atau bagaimana otorisasi dilakukan dalam aplikasi Anda. Tetapi saya akan mencoba untuk menentukan angka penyewa sesegera mungkin di
application_controller
dalamaround_action
. Sesuatu seperti ini mungkin menjadi titik awal:sumber
ActiveRecord::Base.connected_to ... do
blok itu akan menggunakan koneksi default lagi.master
cabang Rails saat ini .