论坛首页 编程语言技术论坛

关于rails大容量网站部署的性能讨论

浏览 175120 次
该帖已经被评为精华帖
作者 正文
   发表时间:2006-05-10  
前段时间就rails的部署的负载能力进行了相关的讨论,请看:

http://www.iteye.com/topic/19534
http://www.iteye.com/topic/18675

这两天在安装服务器,顺便到处看了一下,搞清楚了一些对rails的误解。因此对服务器部署有了一些新的想法,和大家探讨一下。

以前我以为rails像PHP那样,以apache的server mod方式运行,今天仔细看了一下FastCGI/SCGI/mongrel的安装手册,这才搞明白,我弄错了。

当FastCGI/SCGI/mongrel方式部署的时候,ruby并不是直接运行在apache的进程中的,而是独立的运行在CGI或者server上面的。在这种情况下lighthttpd/apache仅仅充当了一个前端HTTP请求分发的代理作用(和静态页面的处理),动态内容交给了后台的ruby CGI/Server去处理的。

其实这种部署方式和我们J2EE常用的apache+(mod_jk)+n个tomcat实例的方式本质上是没有什么区别的。更进一步来说,IBM WebSphere的cluster实际上也是这种方式,在前端使用Apache作为请求分发代理,后面若干个WebSphere实例来处理请求。

在J2EE群集部署方案中,虽然目前的企业应用都强调了应用服务器提供的Session复制功能,EJB调用的负载均衡能力,但是考虑到目前J2EE潮流发展的趋势,已经不再使用EJB的负载均衡,同时Session复制也被证明为影响cluster水平扩展的主要障碍之一。因此对于大容量的J2EE水平扩展群集而言,保持每个节点的无状态性,不再使用Session来保持全局状态是必经之路。

因为只有每个JVM进程不保持全局状态,才能够保证n个JVM节点的幂等性,那些所有涉及到全局状态的,必须放在JVM进程之外,例如用户ID可以使用cookie,session可以放入数据库,文件可以放在共享存储系统中。

这样的方案做下来,前端的apache也仅仅是一个HTTP请求代理,后面的应用服务器实例几乎是可以无限水平扩展的,瓶颈永远不会出现在应用服务器层,只会出现在apache端,或者数据库端。当然apache不行,还可以用lighthttpd,甚至使用四层交换机硬件进行请求的分发工作,后端的单台数据库不行,还可以使用多个数据库同步复制,甚至使用Oracle Grid。

这个时候我们考察一下J2EE的群集方案,竟然会发现和Rails的群集方案没有多大的差别了。为了讨论的简单,我们拿J2EE的apache2.2 + tomcat5.5和apache2.2 + mongrel来对比一下:

先看J2EE群集方案:

Apache2.2 proxy分发请求给后面n个tomat5.5实例(这里甚至都不需要使用mod_proxy_ajp,apache直接转发请求给tomcat的http端口);
每个tomcat实例没有内部全局状态,完全是无状态的服务,用户标示从cookie取得,session可以放在数据库中,假设不使用分布式Cache。每个tomcat实例收到一个请求以后,自行处理,然后返回给apache。

再看rails群集方案:

Apache2.2 proxy分发请求给后面n个mongrel实例;
每个mongrel实例也是无状态的,用户标示使用cookie,从apache收到一个请求以后,自行处理,然后返回给apache。

从两者的对比来看,J2EE的每个节点是一个JVM进程,里面若干Java线程都是无状态的,而mongrel据说也是多线程的,rails的每个节点是一个Ruby进程,里面若干ruby线程都是无状态。竟然完全一致的模型!

在这种情况下,究竟是进程多一点,线程少一点;还是进程少一点,线程多一点,都不是最重要的讨论话题,焦点是J2EE和Rails的群集方案是一致的,在应用逻辑处理层的群集水平扩展能力都是近乎无限的,因此都不是系统的瓶颈所在。这意味着什么呢?

这意味着,只要硬件管够,J2EE系统和Rails系统的网站负载能力不会有多大的差别。

也许,ruby的解析执行速度比Java慢,由于没有数据库连接池导致每个请求需要多消耗一些建立物理连接的时间。但是这些因素只能导致单个用户请求的响应时间比Java慢,不会导致整个网站的负载能力差。

也就是说,如果Java的系统,用户打开一个页面需要两秒钟,而Rails的系统,用户打开一个页面可能需要四秒钟,但是他们都能够每天负载100万的PV,这100万个请求,rails大概也同样是四秒钟,这方面没有什么差别(同样的网站负载,mongrel的实例数量也许远多于tomcat实例数量,但是总体处理能力没有区别)。

当然,J2EE群集方案和Rails群集方案还是有两点不同:

1、J2EE有内置分布式Cache,例如JBoss Cache,而rails的方式是独立的Cache进程在运行,这两种方式来说,对于群集水平扩展,甚至rails的Cache方案还要更好。

2、数据库连接池,对于mongrel,我觉得增加数据库连接池是完全做得到的事情。不过即使不增加连接池,这里也不会成为系统瓶颈,最多会导致数据库多花一些时间在处理连接的建立和断开上面。

最后这种群集部署方案下面,web server退化成为一个请求分发代理,找不到任何理由使用apache了,对,是lighthttpd出场kick off apache的时候。如果网站容量大到连lighthttpd都无法及时分发请求的时候,你还可以用四层交换机来分发请求,那lighthttpd也该被kick off了。

用J2EE看起来确实能够更加节省硬件,但是我们不能再用Rails无法负载大容量网站的理由来攻击rails了,只有硬件管够,不管是J2EE,还是Rails,都有近乎无限的水平扩展能力。
   发表时间:2006-05-10  
还有“无共享架构”(Share Nothing Architecture),不然也没法水平扩展。
0 请登录后投票
   发表时间:2006-05-10  
gigix 写道
还有“无共享架构”(Share Nothing Architecture),不然也没法水平扩展。


因为只有每个JVM进程不保持全局状态,才能够保证n个JVM节点的幂等性,那些所有涉及到全局状态的,必须放在JVM进程之外,例如用户ID可以使用cookie,session可以放入数据库,文件可以放在共享存储系统中。



赞同,所以那些以目录存储用户信息/上传文件等等的,都应该考虑是否可以水平扩展了。
0 请登录后投票
   发表时间:2006-05-10  
引用
所以那些以目录存储用户信息/上传文件等等的,都应该考虑是否可以水平扩展了


这个问题从硬件解决方案来说,反倒是最好解决的问题。各种各样性能的共享存储解决方案实在是太五花八门了。别的不说,单单就是nfs就可以搞定多台物理节点的共享文件存储。
0 请登录后投票
   发表时间:2006-05-10  
从水平扩展性来说是这样,但还有一个单台服务器性能问题.

我现在很关心的是,在单台服务器上,ruby和java的性能差距,因为单台服务器的性能决定了整个集群系统所需要的机器数量.

在某些web应用场合,访问量很大,甚至只能用CGI+C的方式来提高单台机器的性能.
0 请登录后投票
   发表时间:2006-05-10  
无明 写道
从水平扩展性来说是这样,但还有一个单台服务器性能问题.

我现在很关心的是,在单台服务器上,ruby和java的性能差距,因为单台服务器的性能决定了整个集群系统所需要的机器数量.

在某些web应用场合,访问量很大,甚至只能用CGI+C的方式来提高单台机器的性能.


看Agile Web Development with Rails最后一章的最后一段,有一些案例分析,可以作为参考。
0 请登录后投票
   发表时间:2006-05-10  
我看了一下memcached,这玩意真的很棒的。我们Java里面用的Cache,都是进程内的Cache,被JVM进程里面多个线程共享存取。但是一旦在cluster环境下,JVM进程之间要进行Cache同步,就是非常复杂和开销很大的操作了。

memcached是自己开了一个服务,监听一个端口,对外提供服务,本质上就是一个大HashMap,但是可以对外提供服务。所以cluster里面每个JVM进程都去到这个大HashMap去存取,就实现了分布式Cache,而且没有进程Cache同步的开销。而且这个东西有很现实的用处,例如可以作为群集环境下Session存放的地址。而且memcached支持PHP/Java/Ruby/Perl/Python/C#/C等等接口,想像一下,你用ruby写进入的数据,我用Java可以取出来,这不就是异构系统进行数据交换最方便和高效的方式吗?

对于大容量Web网站,memcached可以充当全局共享变量的通用存取地址,从而彻底扫清了节点无状态编程的最后障碍,哈哈,爽阿,我准备尝试一把memcached在开发中系统了。
0 请登录后投票
   发表时间:2006-05-10  
robbin 写道
我看了一下memcached,这玩意真的很棒的。我们Java里面用的Cache,都是进程内的Cache,被JVM进程里面多个线程共享存取。但是一旦在cluster环境下,JVM进程之间要进行Cache同步,就是非常复杂和开销很大的操作了。

memcached是自己开了一个服务,监听一个端口,对外提供服务,本质上就是一个大HashMap,但是可以对外提供服务。所以cluster里面每个JVM进程都去到这个大HashMap去存取,就实现了分布式Cache,而且没有进程Cache同步的开销。而且这个东西有很现实的用处,例如可以作为群集环境下Session存放的地址。而且memcached支持PHP/Java/Ruby/Perl/Python/C#/C等等接口,想像一下,你用ruby写进入的数据,我用Java可以取出来,这不就是异构系统进行数据交换最方便和高效的方式吗?

对于大容量Web网站,memcached可以充当全局共享变量的通用存取地址,从而彻底扫清了节点无状态编程的最后障碍,哈哈,爽阿,我准备尝试一把memcached在开发中系统了。


嘿,眼下我正有这么个问题,robbin的推荐也真是及时!不过,我还不敢用ruby
0 请登录后投票
   发表时间:2006-05-10  
memcached有Java Client API和C API,

http://www.whalin.com/memcached/
0 请登录后投票
   发表时间:2006-05-10  
无明 写道
从水平扩展性来说是这样,但还有一个单台服务器性能问题.

我现在很关心的是,在单台服务器上,ruby和java的性能差距,因为单台服务器的性能决定了整个集群系统所需要的机器数量.

在某些web应用场合,访问量很大,甚至只能用CGI+C的方式来提高单台机器的性能.

传统的CGI不可能有很高的效率,除非你用fcgi这种模式。
进程的启动就需要很高的开销,应该超过这两种语言之间的差异

何况还有更重要的瓶颈在于数据库的存取,服务段程序的开销和语言本身的效率并没有线性关系
0 请登录后投票
论坛首页 编程语言技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics