Aralarında geçiş yapmak için raylarda birden fazla veritabanı bağlantı havuzu olması mümkün müdür?


12

Biraz arka plan

Daire mücevher yıllardır çok kiracılık uygulaması çalıştırmak için kullanıyor . Son zamanlarda veritabanını ayrı ana bilgisayarlara ölçeklendirme ihtiyacı geldi, db sunucusu artık daha fazla dayanamıyor (hem okuma hem de yazma çok fazla oluyor) - ve evet, donanımı maks. donanım, 64 çekirdek, raid 10'da 12 Nvm-e sürücü, 384Gb ram vb.).

Ben bu kiracı başına (1 kiracı = 1 veritabanı bağlantısı yapılandırma / havuz) yapmayı düşünüyordum çünkü number-of-tenantsuygulama kod değişiklikleri bir sürü yapmadan-kez daha fazla kapasite almak için "basit" ve verimli bir yol olacaktır .

Şimdi, 4,2 atm raylar çalıştırıyorum, yakında 5.2'ye yükseltiyorum. Raylar 6 model başına bağlantı tanımları için destek eklediğini görebiliyorum, ancak 20 kiracımın her biri için tamamen yansıtılmış bir veritabanı şemasına sahip olduğum için bu gerçekten ihtiyacım olan şey değil. Ben sadece search_pathPostgresql ayarlar ve gerçek bağlantıyı değiştirmez gibi, tipik olarak ben "veritabanı" istek (ara katman yazılım) veya arka plan işi (sidekiq ara katman yazılım) başına, ancak bu şu anda önemsiz ve ny apart gem, ele . Kiracı başına bir barındırma stratejisine geçerken, tüm bağlantıyı istek başına değiştirmem gerekecek.

Sorular:

  1. Ben bir ActiveRecord::Base.establish_connection(config)istek / arka plan işi başına yapabileceğini anlıyorum - ancak, ben de anladığım gibi, bu tamamen yeni bir veritabanı bağlantısı el sıkışma yapılacak ve raylar içinde yumurtlamak için yeni bir db havuzu tetikler - değil mi? Uygulamama gelen her istekte bu tür bir yükü oluşturmak için bir performans intiharı olacağını tahmin ediyorum.
  2. Bu nedenle herkesin birden fazla (toplam 20) veritabanı bağlantısı / havuzu (örneğin, uygulamanın önyükleme öncesi) önceden oluşturulması gibi raylar ile seçeneği görebiliyor ve sadece istek başına bu havuzlar arasında geçiş merak ediyorum? Böylece db bağlantıları zaten yapılmış ve kullanıma hazırdır.
  3. Bütün bunlar kötü bir fikir değil mi? Bunun yerine farklı bir yaklaşım mı aramalıyım? Örneğin, 1 uygulama örneği = belirli bir kiracıya özel bir bağlantı. Veya başka bir şey.


1
Yakın zamanda mevcut Rails şubesine tam olarak ihtiyaç duyduğunuz özelliği ekleyen Rails'in GitHub deposunda bu PR ile ilgilenebilirsiniz master. Rails Egde'yi çalıştırmak, bu özelliği mevcut Rails sürümünüz için bir seçenek veya geri itme olur mu?
spickermann

@spickermann ActiveRecord::Base.connected_to(shard: :shard_one) do ... end, havuzun her seferinde tamamen yeni bir bağlantı oluşturmak yerine (yeniden) kullanılacağı anlamına mı geliyor?
Ben

Yanıtlar:


4

Anladığım kadarıyla, çoklu kiracılık uygulaması için 4 desen var:

1. Özel model / Çoklu Üretim Ortamları

Her örnek veya veritabanı örneği tamamen farklı kiracı uygulamasına ev sahipliği yapar ve kiracılar arasında hiçbir şey paylaşılmaz.

Bu 1 vaka uygulaması ve 1 kiracı için 1 veritabanı. Geliştirme, sadece 1 kiracıya hizmet ediyormuş gibi kolay olurdu. Ama 100 kiracı varsa adanmışlar için kabus olacak.

2. Kiracıların Fiziksel Ayrımı

Tüm kiracı için 1 örnek uygulaması ancak 1 kiracı için 1 veritabanı. Aradığın şey bu. Kullanabileceğiniz gibi ActiveRecord::Base.establish_connection(config), taşlar kullanarak veya diğer önerileriyle Rails 6'ya güncelleyebilirsiniz. Aşağıdaki (2) cevabına bakınız.

3. İzole şema modeli / Mantıksal Ayrımlar

Yalıtılmış bir Şemada, kiracı tabloları veya veritabanı bileşenleri mantıksal bir şema veya ad alanı altında gruplandırılır ve diğer kiracı şemalarından ayrılır, ancak şema aynı veritabanı örneğinde barındırılır.

Daire mücevher ile yaptığınız gibi tüm kiracı için 1 örnek uygulaması ve 1 veritabanı.

4. Kısmen İzole Edilmiş Bileşen

Bu modelde, ortak işlevlere sahip bileşenler kiracılar arasında paylaşılırken, benzersiz veya ilgisiz işlevlere sahip bileşenler yalıtılır. Veri katmanında, kiracıları tanımlayan veriler gibi yaygın veriler tek bir tabloda gruplandırılır veya saklanırken kiracıya özgü veriler tablo veya örnek katmanında yalıtılır.


(1) gelince, ActiveRecord::Base.establish_connection(config)doğru kullanırsanız istek başına db için el sıkışma değil. Buradan kontrol edebilir ve tüm yorumu buradan okuyabilirsiniz .

(2) 'ye gelince, kullanmak istemiyorsanız establish_connection, gem multiverse (4.2 rayları için çalışır) veya diğer mücevherleri kullanabilirsiniz. Ya da, başka bir öneride bulunarak, Rails 6'ya güncelleyebilirsiniz.

Düzenleme: Multiverse mücevher kullanıyor establish_connection. database.ymlHer alt sınıf aynı bağlantıyı / havuzu paylaşacak şekilde bir temel sınıf ekler ve bir temel sınıf oluşturur. Temel olarak, kullanma çabamızı azaltır establish_connection.

(3) 'e gelince, cevap:

Çok fazla kiracı yoksa ve uygulamanız oldukça karmaşıksa, Özel Model modelini kullanmanızı öneririm. Yani 1 uygulama örneği = belirli bir kiracıya özel bir bağlantı için gidin. Birden çok veritabanı bağlantısı ekleyerek uygulamalarınızı daha karmaşık hale getirmeniz gerekmez.

Ancak çok fazla kiracınız varsa, Kiracıların Fiziksel Ayrımını veya Kısmen Yalıtılmış Bileşen'i kullanmanızı öneririm.

Her iki durumda da, yeni mimariye uymak için uygulamanızı güncellemeniz / yeniden yazmanız gerekir.


Merhaba cevap için teşekkürler. Eğer iyi bir çözüm ise ödülün cevaplarından birini ödüllendirmeden önce öneriyi test etmek için biraz zamana ihtiyacım olacak.
Niels Kristian

1 ve 2 ile ilgili birkaç sorum var. 1: Referanslarınızı anladığımdan emin değilim. Db el sıkışma yapmadan / db anketini yeniden oluşturmadan .establish_connection (config) diyebileceğim ne diyor? Bu durumda, iki bağın bunu nasıl açıkladığından emin değilim? 2: Çokluevren için, tüm uygulama için tüm bir db anahtarından ziyade model başına bir veritabanı geçişi değil mi? Belgelerinin oldukça belirsiz olduğunu hissediyorum
Niels Kristian

Sanırım yanlış anladım. Bu cümleleri ayrıntılandırmayı düşünür müsünüz? Ben istek / arka plan iş başına bir ActiveRecord :: Base.establish_connection (config) yapabilirdi anlamak - ancak, ben de anladığımız kadarıyla, raylar içinde spawn tamamen yeni veritabanı bağlantısı tokalaşma yapılabilmesi için bu tetikleyiciler ve yeni db havuz O bir istek bir db havuzu oluşturmak öneririz?
KSD Putra

Yani: (1) Sadece farklı veritabanları / ülkeler arasında geçiş yapmak için her istekte ActiveRecord :: Base.establish_connection (config) çağırmak zorunda kaldığımda performans / ağ yükü hakkında endişeliyim
Niels Kristian

Tepegöz için endişelenmenize gerek yok. Şimdi, tek bir DB kullanıyorsanız, bir bağlantı havuzunuz var (yukarıdaki bağlantıya (1) cevabından bağlantı ile ilgili bağlantıyı kontrol edebilirsiniz). establish_connectionModelde şu şekilde kullanırsanız : class SecondTenantUser < ActiveRecord::Base; establish_connection(DB_SECOND_TENANT); endve 5 modeliniz varsa, DB_SECOND_TENANT için 5 bağlantı havuzu oluşturursunuz. Ve her havuz eşit muamele görür. Yani, istek başına bir havuz oluşturmazsınız establish_connection.
KSD Putra

3

Anladığım kadarıyla, (2) Raylar 6'daki manuel bağlantı anahtarlaması ile mümkün olmalıdır .


Ancak teşekkürler, bu benim kullanım durumumdan oldukça uzak görünüyor. Bu prosedürü her yerde kullanmak için tüm uygulamanın yeniden yazılması anlamına gelir.
Niels Kristian

3

Sadece birkaç gün önce GitHub'daki Ruby on Rails'in şubesine yatay parçalama eklendi master. Şu anda, bu özellik resmi olarak yayınlanmamıştır, ancak uygulamanızın Rails sürümüne bağlı olarak, Rails'i aşağıdakilere masterekleyerek kullanmayı düşünebilirsiniz Gemfile:

gem "rails", github: "rails/rails", branch: "master"

Bu yeni özellik ile Rails'in veritabanı bağlantı havuzundan yararlanabilir ve veritabanını koşullara göre değiştirebilirsiniz.

Bu yeni özelliği kullanmadım, ancak oldukça basit görünüyor:

# in your config/database.yml
production:
  primary:
    database: my_database
    # other config: user, password, etc
  primary_tenant_1:
    database: tenant_1_database
    # other config: user, password, etc

# in your controller for example when updating a tenant
ActiveRecord::Base.connected_to(shard: "primary_tenant_#{tenant.database_shard_number}") do
  tenant.save
end

Kiracı numarasını nasıl belirlediğiniz veya başvurunuzda yetkilendirmenin nasıl yapıldığı hakkında fazla ayrıntı eklemediniz. Ama en kısa sürede kiracı sayısını belirlemek için çalışacağını söyledi application_controllerbir in around_action. Böyle bir şey bir başlangıç ​​noktası olabilir:

around_filter :determine_database_connection

private

def determine_database_connection
  # assuming you have a method to determine the current_tenant and that tenant
  # has a method that returns the number of the shard to use or even the 
  # full shard identifier
  shard = current_tenant.database_shard # returns for example `:primary_tenant_1` 

  ActiveRecord::Base.connected_to(shard: shard) do
    yield
  end
end

Bu durumda da varsayılan bağlantıya geri dönmek aynı anlama gelir mi? github.com/influitive/apartment#middleware-considerations
Ben

1
ActiveRecord::Base.connected_to ... doBloktan çıktıktan sonra tekrar varsayılan bağlantı kullanılır.
spickermann

@ spickermann ben bu taş ab okuyordu, sadece raylar için değil6?
7urkm3n

@ 7urkm3n Geçerli Rails masterşubesine dahildir.
spickermann

Merhaba cevap için teşekkürler. Eğer iyi bir çözüm ise ödülün cevaplarından birini ödüllendirmeden önce öneriyi test etmek için biraz zamana ihtiyacım olacak.
Niels Kristian
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.