2011-12-22 64 views
6

我刚读完Paul Dix的书面向服务的设计与RoR我想创建一个基于Rails 3的Web应用程序关于我刚刚学到的东西。在单个服务器上托管多个rails服务+“启用api”网站的体系结构

我想我的基本架构是正确的,但一个简单的问题就是阻止我:我应该如何在同一台服务器上托管多个REST服务?

以下是我看到的东西的那一刻:

  • 创建*基于辛纳屈(我猜),其访问的资源提供REST端点服务的应用程序(UserService,XYZFeatureService,...)
  • 拥有一个带有controllers/views/...的前端Rails应用程序,该应用程序使用来自不同服务的数据。最终用户将通过http://www.myapp.com进行访问。
  • 最后,有一个独立的“API”应用程序来处理对https://api.myapp.com/*https://www.myapp.com/api/*的调用,以发布一个外部API,该API将使用可能的身份验证,限制等相同的服务。

这听起来像是一个很好的开始吗?根据我在书中读到的内容,我计划创建宝石来处理Rails应用程序和服务之间的通信(我可能会抛出一些RabbitMQ,但那是另一回事)。

但是,因为我只有一台物理服务器,所以我想知道如何让所有这些应用/服务在一起? 我的第一个猜测是在localhost上启动每个服务应用程序:xxxx其中xxxx是每个服务的不同非特权端口。我可以在我的Rails应用程序中配置每个客户端的Gem来使用这些端口。除此之外,我可能会运行Apache 2 + Passenger来服务我的rails前端和API服务,使用类似Rack :: URLMap(或者如果使用子域的虚拟主机)来引导请求到正确的应用。 我是否应该在生产环境中使用Passenger来运行我的服务?

这是正确的路吗?!这与我阅读和学习的内容一致,如果需要,也可以轻松拆分为几台物理服务器,但我想确保我不会错过任何东西。你会以不同的方式建立事物

非常感谢您的意见!

更新

我想一看回答的主要问题是:

  • 是适当的建立与外部API端点Web应用程序所描述的架构?
  • 可以在不同端口上的单个服务器上运行服务吗?

谢谢!

+0

观看http://confreaks.net/videos/709-rubyconf2011-threading-versus-evented后,您可能想要更改为jRuby。与乘客nginx是一个更普遍的路径去。 – drhenner 2011-12-22 17:01:56

+0

@ user458221谢谢,我会看看这个视频:) 虽然我关心的是更多关于当下的架构和设计选择! 但我猜这值得担心表现呢^^ – 2011-12-22 18:52:23

回答

0

所以这个问题有点超过3岁,我认为它可以从合理客观的答案中受益。

有趣的是,再次阅读这个问题时,最近看到它已被提升,当简单的“高级”答案只是:做你想做的事情/需要做的事情!

有没有神奇的规则可以观察,虽然我想这就是我当时所期待的。然而,有一些关键的事情需要记住:

  • 设计一个面向服务的体系结构意味着我们正在为扩展做准备。每个服务都是独立运行的,而不是依赖于与堆栈的其他服务在同一台服务器上运行。 不要情侣你的服务,他们需要保持独立

  • 但是不要“过度准备”这样的:诱惑是高花费大量时间来设计完美的架构,当你真正需要做是发运你的v1!

  • 当你建立单独的服务时,不要使它比需要的更复杂:一个简单的带有REST(类似)端点的Web栈可能足以开始。 RabbitMQ和其他消息队列也很棒,但它们可以解决您可能不具备的问题。

  • 就服务器而言,嗯......在一个理想的世界中,您希望每个服务的服务器都在一个数据中心内,并在另一个物理服务器上的第二个(或更多)服务器上进行复制分开的数据中心......这需要时间和金钱来建立和维护。如果你身处一个很大的组织,那可能是好的,但如果是这样的话,你可能不需要阅读这个答案。
    所以是的,你可以从小开始!一台或两台服务器,或者是一台带有虚拟化服务器的“大服务器”......这一切都取决于您对管理事情或您雇用系统管理员的信心。一台机器就足够了,并且可以毫不犹豫地在其上运行多个服务,前提是它们都可以共享相同的系统和内存。
    今天,我可能会使用nginx将请求分发到正确的服务,具体取决于主机名或端口,并在具有防火墙的不同端口(例如Shorewall)上运行私有服务,以阻止外部对这些端口的请求。

在那里......就像我说的那样,没有神奇的答案,但是为每个问题设计的解决方案都有待解决。我在过去三年中学到的主要工作是大中型项目,从简单开始就是关键。

1

我使用Apache-Passenger组合和一个脚本(见下文),但我读了很多关于推动Node的基准。JS在Nginx负载均衡器后面 - 并且至少提供webservices API,这可能是有道理的。

我的脚本是:

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 

的add_site耙确实在生产服务器上的远程工作 - 创建必要的文件夹,配置文件和链接脚本来得到一个新的“实例”上运行。通过这种方式,我可以扩展我的服务,并且只需付出一点努力,我就能够扩展负载平衡功能。

请注意,此解决方案是一个“共享源代码”版本

搂草脚本是这样的:

# 
# 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

感谢您的回答!它虽然没有解决我的主要问题,我会编辑我的帖子,在最后简短地重述它们 – 2011-12-26 00:54:04

相关问题