2011-12-22 10 views
6

Ho appena finito di leggere il libro di Paul Dix Design orientato al servizio con RoR e mi piacerebbe creare un'app Web Rails 3 basata su quello che ho appena imparato.Hosting di servizi su più server su un singolo server + architettura di un sito web "abilitato"

Penso di avere l'architettura di base giusta, ma una semplice domanda mi blocca un po ': come dovrei ospitare diversi servizi REST su uno stesso server?

Ecco come vedo le cose, per il momento:

  • Crea * applicazioni di servizio (UserService, XYZFeatureService, ...) sulla base di Sinatra (credo), che forniscono gli endpoint REST per accedere alle risorse
  • Avere un'app di front-end Rails con controller/viste/... che consuma dati dai diversi servizi. Ad esempio, gli utenti finali potrebbero accedervi tramite http://www.myapp.com.
  • E infine avere un'app standalone "API" per gestire le chiamate a https://api.myapp.com/* o https://www.myapp.com/api/* per pubblicare un'API esterna che utilizzerebbe gli stessi servizi con possibile autenticazione, limitazione e così via su di essa.

Ti sembra un buon inizio per te?

Per quanto riguarda l'implementazione, da quello che ho letto nel libro ho intenzione di creare gemme per gestire la comunicazione tra l'app per le rotaie e i servizi (potrei introdurre qualche RabbitMQ ma questa è un'altra storia).

Tuttavia, poiché ho solo un server fisico, mi chiedo come farò vivere tutte queste app/servizi insieme? La mia prima ipotesi è di avviare ogni app di servizio su localhost: xxxx dove xxxx è una porta diversa non privilegiata per ogni servizio. Potrei configurare ciascun gioiello del cliente nella mia app per rails per utilizzare queste porte.

Insieme a questo, probabilmente eseguirò Apache 2 + Passenger per servire il mio binario front-end e il servizio API, usando qualcosa come Rack :: URLMap (o host virtuali se si utilizza un sottodominio) per indirizzare richieste al giusta app. Dovrei quindi utilizzare Passenger per eseguire i miei servizi anche in un ambiente di produzione?

È la strada giusta da percorrere ?! Mi sembra coerente con ciò che ho letto e imparato, e facilmente diviso in diversi server fisici, se necessario, ma mi piacerebbe essere sicuro di non mancare qualcosa. Costruiresti le cose in modo diverso?

Grazie mille per il vostro contributo!

Aggiornamento

domande principali che mi piacerebbe veder un risposto sono:

  • è l'architettura descritta appropriata per costruire una web app con gli endpoint API esterne?
  • È OK avere servizi in esecuzione su un singolo server su porte diverse?

Grazie!

+0

Dai un'occhiata a http://confreaks.net/videos/709-rubyconf2011-threading-versus-eventato dopo aver visto che potresti voler passare a jRuby. nginx con passeggero è una strada più comune da percorrere. – drhenner

+0

@ user458221 Grazie, darò un'occhiata a questo video :) Anche se la mia preoccupazione è più sulle scelte di architettura e design per il momento! Ma immagino che valga la pena di preoccuparsi anche delle prestazioni ^^ –

risposta

0

Quindi questa domanda è un po 'più di 3 anni, e Penso che potrebbe trarre beneficio da una risposta ragionevolmente obiettiva.

È divertente leggere di nuovo questa domanda e vedere che è stata svalutata di recente quando la semplice risposta di "alto livello" è semplicemente: fai ciò che vuoi/devi fare!

Non c'è una regola magica da osservare, anche se immagino sia quello che stavo cercando in quel momento. Ci sono, tuttavia, alcune cose fondamentali per cercare di tenere a mente:

  • Progettare una Service-Oriented Architecture significa che stiamo preparando per il ridimensionamento. Ogni servizio è pensato per essere eseguito da solo e non dipende dall'essere eseguito sullo stesso server degli altri servizi dello stack. Non accoppiare i propri servizi, cui hanno bisogno per rimanere indipendenti

  • Tuttavia non "over-preparare" in questo modo: la tentazione è alta a spendere un sacco di tempo a progettare l'architettura perfetta, quando quello che è effettivamente necessario fai spedire la tua v1!

  • Quando si creano servizi separati, non renderlo più complicato del necessario: un semplice stack Web con endpoint REST (-like) sarà probabilmente sufficiente per iniziare. RabbitMQ e altre code di messaggi sono fantastici, ma risolvono problemi che potresti non avere.

  • Per quanto riguarda i server, beh ... in un mondo ideale si vorrebbe un server per servizio, tutto in un datacenter, con replica su un secondo (o più!) Insieme di server in un altro fisicamente datacenter separato ... ciò richiede tempo e denaro per l'installazione e la manutenzione. Se ti trovi in ​​una grande organizzazione potrebbe andare bene, ma in questo caso probabilmente non hai bisogno di leggere questa risposta.
    Quindi sì, puoi iniziare in piccolo! Uno o due server, o un "grande" con server virtualizzati su di esso .... tutto dipende dalla tua sicurezza nell'amministrare la cosa o il tuo ingaggio di un amministratore di sistema. Una singola macchina può essere sufficiente e non esitare a eseguire diversi servizi su di essa, a condizione che tutti possano condividere lo stesso sistema e la stessa memoria.
    Oggi, probabilmente utilizzerei nginx per inviare richieste ai servizi corretti, a seconda dei nomi degli host o delle porte, ed eseguire servizi privati ​​su porte diverse con un firewall (Shorewall per esempio) per bloccare le richieste dall'esterno su quelle porte.

C'è ... come ho detto, non c'è una risposta magica, ma soluzioni da escogitare per ogni problema che c'è da risolvere. Quello che ho imparato negli ultimi 3 anni, lavorando per lo più da solo su progetti di medie/grandi dimensioni, è che l'avvio semplice è la chiave.

1

Uso la combinazione Apache-Passenger e uno script (vedi sotto) ma ho letto molto sui benchmark che spingono il nodo.JS dietro un sistema di bilanciamento del carico Nginx e, almeno per fornire l'API dei servizi Web, potrebbe avere senso.

mio script è:

def build_a_new_oxenserver() 
    site = siteurl.gsub(/\./,"_") 
    system("rake add_site['#{siteurl}','#{site}','#{id}']") if Rails.env.production? 
    default_tmpl = open(File.expand_path(Rails.root + "public/default_template.html")).read 
    tmpl = Template.create(:ox_id=>id, :name=>"first template", :content=>default_tmpl) 
    pg=Page.create(:ox_id=>id, :language_id=>1, :template_id=>tmpl.id, :title=>"Home", :menu_label=>"Zu Hause", :ancestry=>nil, :root=>true) 

    # add the Paragraph element to this ox's toolbox 
    self.elements << Element.find(1) 

    # add an Article, a Paragraph, and a Post 
    pe = PageElement.create(:element_id => Element.find(1)) 
    pe.elementable = Paragraph.create(:content=>"This is written *in bold* -") 
    pe.save 
    pg.page_elements << pe 


end 

Il rake add_site fa un lavoro remoto sul server di produzione - creare le cartelle necessarie, file di configurazione e script legati a ottenere una nuova 'istanza' esecuzione. In questo modo sono in grado di estendere i miei servizi e con un piccolo sforzo, sarei in grado di estendere le funzionalità di bilanciamento del carico.

Si prega di osservare che questa soluzione è un 'shared-source' versione

Lo script di rake si presenta così:

# 
# rake add_site["www.domain.tld", "www_domain_tld", 131] 
desc "Task for adding new oxenserver site" 
task :add_site, :domain, :site, :ox_id do |t, args| 
    service_path = /data/www/html/app_service 
    site_string = %{ 
    <VirtualHost *:80> 
     ServerName #{args[:domain]} 
     DocumentRoot #{service_path}/sites/#{args[:site]}/public 
     PassengerAppRoot #{service_path}/sites/#{args[:site]} 
     SetEnv OX_ID #{args[:ox_id]} 
     <Directory #{service_path}/sites/#{args[:site]}/public> 
       AllowOverride all 
       Options -MultiViews 
     </Directory> 
    </VirtualHost> 
    } 
    File.open("tmp/#{args[:site]}.conf", "w") do |f| 
    f.write site_string 
    end 

    site_start = %{ 
    mv #{service_path}/current/tmp/#{args[:site]}.conf /data/apache/conf.d/#{args[:site]}.conf 
    service httpd restart 
    } 

    File.open("tmp/#{args[:site]}.sh", "w") do |f| 
    f.write site_start 
    end 

    # 
    sites_dir = "#{service_path}/sites/#{args[:site]}" 
    shared_sites_dir = "#{service_path}/shared/sites/#{args[:site]}" 
    shared_oxen_dir = "#{service_path}/shared/sites/oxen" 
    current = "#{service_path}/current" 


    # prepare system files/directories 
    system "mkdir #{sites_dir} #{shared_sites_dir} #{shared_sites_dir}/public" 
    system "cd #{sites_dir} && cp -rus #{current}/* ." 
    system "cd #{shared_sites_dir}/public && cp -r #{shared_oxen_dir}/public/* ." 
    system "cd #{shared_sites_dir} && mkdir log tmp && cd #{sites_dir} && rm -rf public log tmp && ln -s #{shared_sites_dir}/public public && ln -s #{shared_sites_dir}/log log && ln -s #{shared_sites_dir}/tmp tmp" 
    system "cd #{sites_dir} && touch tmp/restart.txt log/production.log" 
    system "mv tmp/#{args[:site]}.sh public/system/job_queue/#{args[:site]}.sh" 
end 
+0

Grazie per la risposta! Tuttavia, non affronta le mie domande principali; Modificherò il mio post per riformularlo brevemente alla fine –

Problemi correlati