SD2C:CSDN产品总监范凯——用Rails构建高性能Web应用

    2010年的SD大会已经结束两个星期了,官方的PPT说是出来了,却不让下载(提示用户名密码错误),让人感觉这1800大洋花的很有些怨气。最可恨的是,官方提供的现场演讲实录整理的实在不敢恭维,要想在团队内传播或是个人收藏,都需要自己精心整理。

 

    本次大会最有价值的演讲,个人认为是Robbin的《用Rails构建高性能Web应用》,于是在官方提供的演讲实录(http://news.csdn.net/a/20101210/283439.html)上进行了一些整理,与大家分享。关于版权问题,我想Robbin本人肯定是乐于分享的,若CSDN认为存在版权问题请指出,本人会在第一时间删除。

 

    这篇演讲实录有相当大的价值,最好能结合PPT看,但目前我还没有下载到PPT,并且CSDN的意思是这些PPT是不共享的,所以……文中还有一些不太记得的词汇没有整理,大家凑合着看吧。不说废话了,上菜。

 

SD2C:CSDN产品总监范凯——用Rails构建高性能Web应用

CSDN产品总监范凯做大会演讲

以下是演讲实录:

范凯:出了一点状况,我的苹果电脑投不上去。投不上去的原因也挺奇怪,自从我苹果操作系统版本升级到10.6.5以后,有一些古老的投影仪就投不出来了。我上午在另外一个会场主持,上午的主持是产品跟设计那个分会场,当时上午有四个演讲嘉宾,前三个演讲嘉宾都是用苹果的,而且一点问题都没有,所以我对这个问题也比较大意,没有想到在这个会场遇到不识别的问题,所以我临时把PPT转移到微软的操作系统上去。

中午我跟几个朋友聊天,我前几年做了很多技术的培训、讲座,也搞了很多大会,也做过很多演讲嘉宾。我说现在我都一心潜心做产品了,所以对于演讲的事情已经越来越不太愿意去做了。我刚才跟朋友说,这是我人生的最后一讲。

我想大家已经比较疲倦了,我今天不准备讲特别长的时间。我大概用半个小时的时间,从原理上举一些简单的案例,跟大家分析一下过去我在用Rails做Web应用的总结,剩下的时间大家有什么问题都可以来问我。

实在是没办法,因为换了一台电脑,所以有一些应用程序没有办法给大家演示,我简单说一下。

我今天演讲的题目是《用Rails构建高性能Web应用》,我今天用比较快的时间讲完,留比较多的时间跟大家讨论。Rails我05年就接触了Rails框架,当时我是想把Java网站重写一遍,但是人比较少,研发人员就我一个人,我考虑用Java去做研发周期比较长,写的代码比较多,希望找节省工作的方法,就是懒惰,懒惰就会找一些更好的开发工具。到现在我用Rails有五年的时间了,整个Rails在这五年也得到了飞速的发展,特别在Web开发领域应该是非常领先的框架,当然也会面临一些问题,也不能叫问题,会有很多质疑——它在大规模的Web实际案例比较少。大家耳熟能祥的就是twitter,大家对twitter的印象,当出现一个热点事件的时候就会出现twitter大鲸鱼,表示twitter宕掉了。包括核心开发人员,还有外围开发人员,他们在技术上特别追求新的东西,在大规模的应用上面比较少有人投入时间和精力研究这些事情。他们感兴趣我如何很酷、很漂亮的实现一项新的功能,实现一项很酷的产品。第三点过去给人留下好的印象,Web大规模的应用上面有一些质疑。

我们说说利用高性能的Web应用有什么样的特征呢?我简单总结了一下,第一个它是高并发的访问请求,对于这一点,比原来普通应用数据分析有很大的不同。所谓大规模访问请求,通常它的数据结构相对来说比较简单,它的访问量很高,每次访问请求需要在比较短的时间内能够相应,这是第一特征。第二个特征服务的高可用性。我们不能平白无故的去宕机,当然遇到峰值请求的时候,让整个网站能有一个很好的网页响应时间。我现在也偶尔写写Java代码,过去做互联网的特别头疼,它所谓有一点规模Java的Web应用,完成一次request要20秒左右,如果初始化数据特别多有时候要一分钟、两分钟。对一个强调响应性的网站,老是中间断一分钟、两分钟,这是不可接受的事情。由于遇到这样发布的问题,开发人员不倾向于频繁地更换代码,我们是不是每个月更换一次。第四个就是良好的可伸缩性。特别明显的例子,不是普通的Web的应用,比如一个开发的网页小游戏,一开始访问量没有多少,一两台服务器就OK;一上线以后,一推广非常受欢迎,访问量一下子飙升上来,马上要几十台,上百台服务器,首先应用良好的可伸缩性,或者流量上来代码比较少的改动下能够提供更多的访问。刚才我说高性能Web特征,我想说的,虽然我们这个题目是《用Rails构建高性能的Web应用》,它不是一个框架问题,是整个架构的问题。在技术社区里面经常有一些争论,比如说某某编程语言执行特别高,或者Java效率高。有很多人热衷于比较,比如说比较JSP页面,执行一个特定循环的时候多少秒之内能执行完,来比较一下简单的页面,用Rails写的话,它的吞吐量能够有多大,每秒能够处理多少次的请求。经常进行这种简单的比较,这种东西没有意义。大规模高性能的Web应用基本上不是单纯的编程语言,或者一个特定的框架来决定,比如像PHP是简单的解析语言,但解析性能也不是很高。这一句话是戴维,那个丹麦人提出来的,他说了这样一句话,当时他的主题演讲叫,就是限制才会导致解放,这一句话怎么理解呢?我是这么理解的,这么些年,包括自己创业,有很多深的感悟,你自己做一项事业,你知道最容易导致失败的原因是什么吗?就是你融资,你拿了很多钱,你拿了一两千万美元,你觉得自己手里有非常多的资源,可以做很多事情,所以这一件事情你也想做,那一件事情也想做,最后很难成功。为什么小型创业公司可以打败大的公司,就是你的资源是有限的,你的人也是有限的,你的时间也是有限的,就是因为在有限的情况下它才能够让你放弃一些常规的做法,而寻求一些高性能的解决方案,资源的限制才会导致创新,才能够强迫你用更新的方式解决我们面临的问题。所以我今天的演讲,整个的主题也是围绕这个核心思想,我们会看到很多很多限制,就是因为有了这些限制我们就会想一些办法去解决它。

我简单说一下,我们JavaEye网站的统计情况,一个是每天的Rails处理的请求数,每天处理超过100万的动态请求,就是在单台的,一台物理服务器上,每天动态请求数处理300万以上,这个数据挺惊人的。第二个包括静态资源在内的,下载,图片,所有的东西加在一块,一天要处理1500万,这个也是在单台服务器。另外因为我们大量使用了全文检索,这个检索量非常大,它不单在网站上搜索,包括相关文章的推荐,还有搜索自动的提示,所有的底层都通过全文搜索提供支持。整个网站峰值访问期间,在Web服务器上它的并发连接数会达到1400个并发连接,大概在每天下午四五点的时候,sql每秒80条。这是我们的统计数据,基本上从这个统计数据可以看出,我们在单台服务器上跑出这样的数据已经非常惊人了。为什么能够取得这么高的性能,也是前面说的,你要看到Constraint,才能想到Liberation。目前网站两台服务器,一台Web,后端是Ruby的应用程序,后面还有搜索服务器,DB服务器有少量Ruby的程序,还有主要跑数据库服务器,还有后台的任务,基本上就两台服务器。现在像Web服务器这台机器每天要支撑1500万静态HTTP请求,300万的动态请求,再加上100万的fulltext,加在一起CPU使用的峰值不到50%,它有非常大的潜力可挖。DB服务器它的CPU更低了,因为主要跑数据库服务器,一般CPU 10%到20%。因为跑数据库服务器磁盘操作稍微高一点,一般是低于15%。

我们如何才能架构一个高性能的Web应用呢?我今天简单几个方面来说一下,第一建议大家用REST的架构风格来编写Rails的应用,第二个从整体架构上设计各个层面缓存方案,消除整个架构上的各个单点性能瓶颈

先说第一个REST是什么?实际上Rails开始,整个互联网开发的行业才开始重视REST,特别是最近两年,传统的SOAP基本被REST取代了。REST实际上是什么呢?它定义两种东西,一种叫做资源,一种叫做操作。这个资源指的是什么呢?这个资源指的如果在我们的互联网应用当中,一段资源用URL表示的东西,一个URL表达了一项资源。比方说我们Java网站,域名后面news,对于这样的资源可以施加什么样的操作,就是用标准的HTTP协议操作。我们整个Web运营用HTTP协议对资源进行各种各样的操作,可以增加删除增加查询。第一个我们对于所有能够暴露出来的,我们都要设计它的URL的格式,这就是Rails它特别重视URL的一个格式的设计,这个在Rails当中叫Rules,在其它框架很难见到对URL这样一个书写格式这么重视。所有URL都是资源,第二所有的资源有一个唯一的标志符。我们做很多网站,喜欢把不同的资源标好入口,比如我做一个专区,从某一个专区点进去是专区的文章,从论坛点进去还是这篇文章,我再举一个例子,我们有的时候做一些论坛帖子,比如我后面跟一个数字,指向主题帖,主题帖某一个回帖单独给它一个地址,其实它都会指向同一个帖子,不同的位置。所有这些情况其实都是违反Rails架构资源的,因为它不符合每个资源有一个唯一的标识符,这样会带来很多问题,你没有办法用统一的地址进行浏览缓存。第三个做一些操作,再有对资源的操作不改变资源的状态,我访问一项资源的时候,不会让这项资源去改变,这个我待会举一个简单例子的跟大家说一下。

就这样一个例子,大家看上面URL,这不管是其它编程语言也好,这样做其实是不符合Rails的语义,而底下这种方式符合。我刚才简单说一下Rails架构,很多人很困惑,包括很多Rails程序员。我前几个月招聘的时候,程序员来面试我就问,我说你现在Rails已经到3.0了,很多人用Rails架构来编程,你能说说Rails有什么用吗?很多人说不上来,他说可以把代码语言整的更干净一些。其实很多人在自己的Web应用当中会这样去写,看似没有什么问题,其实有很多问题。比方说我举一个最简单的例子,这是一个真人真事,原来我有一个朋友在博客网站,他写了好几百篇博客文章。有一次他找朋友搬家,这个网站也不提供博客搬家功能,他就说我抓吧,登陆后台就抓。他再登陆自己的博客所有的博客都没了。他非常惊讶,找了半天才找到原因,就是我上面说的第一个原因,就是博客后台所有的删博客的链接设定这样一个格式,他用这个工具抓网页的同时把自己的博客全部删光了,这是挺悲剧的事情。 

具体来说,像我的JavaEye网站,因为我们第一个版本Rails1.2还没有出来,第一个版本也不是Rails风格的,碰到很多这种问题,各种各样的爬虫会访问你页面的链接,它在后台会抛出大量的错误,有一些有权限的被爬虫访问一次带来很大的副作用。本身保证你的Web请求不会产生副作用,Web请求不产生副作用的前提下我们才有可能产生前面我说的那些作用。第二对内容网站提供最好的SU效果,大家知道JavaEye网站SU效果很好,不是我们作-弊怎么样,本身就是你符合HTTP。第三从构建高性能Web应用角度来讲,如果一个应用符合Rails的语义,它会实现浏览器端缓存。很多大型的系统不是简单单一的codebase,目前JavaEye网站开发了很多频道,我当时之所以没有拆分成,我不希望拆成好几项,在版本代码管理产生不一致,所以我刻意做成一个单一的项目,第四个特点还不是特别的鲜明,现在我在做的一项工作,把CSDN整个网站模块化,一块一块重新来做,这个做的过程当中就体会到Rails的作用。CSDN做了很多的不同的频道,用不同的编程语言实现,之间有的是独立的系统,还有很多各种各样的,dot net,还有一些Java,很多系统都有。它是一个大型的异构系统,大型的异构系统当中有很多模块可以抽离出来。比方说我现在做的整个搜索模块,还有统一用户的数据库跟用户资源的管理,很多很多的模块,这些模块其实都可以单独抽取出来。这些模块怎么实现,我们都是用Rails的方式实现,它带来的好处,应用系统之间的交互方式特别好。不但特别好,当一个特点模块请求量急剧上升的时候,比如一开始做搜索的只是提供用户输入关键词来实现,后面实现文章的自动分类,这样搜索量急速的膨胀,我估计CAT搜索一天至少达到500万次以上,后面整个功能上去,单台机器肯定不够,可能要五台,六台,甚至更多的服务器来提供搜索服务,在这种情况下我们全部用REST来实现。 

接下来说一说基于HTTP资源的缓存。比如你访问JavaEye的一篇博客,博客是符合REST风格的,这表明了一项资源,就是这一篇博客网站在互联网唯一的资源。当浏览器访问这一项资源的时候,我是以get请求访问的,我们的服务器返回的时候,其实它会在HTTP Head里面加两个参数的,这是所有的服务器都支持的。ETag就是给这个资源起了一个标识符,表示这个是互联网唯一的资源,当然这个资源是域名之下的资源。第二个就是这项资源最后被修改的时间是什么时间。浏览器当它第二次再去访问资源的时候,它其实会把上一次的服务器发给他的两个状态记录下来,它会以另外两个状态发请求,自从这个时间之后你做过修改吗,这项资源你做过修改吗?ETag是不是符合?所有的浏览器都会发给Server的,Server拿这两项跟自己的资源做比对,相对于浏览器把上次访问的地址记录下来,然后它拿自己的版本号给服务器,服务器去比对;服务器拿到这个版本号会比对,看版本号符不符合,如果符合说明这项Load了,既然资源都没有被修改过,意思就是说,浏览器不需要重新再下载一次网页了,从本地缓存当中取页面就可以了。所以Server给他发一个HTTP的状态码,整个网页内容就会传输了。很多人会问,如果用这种方式做页面缓存,都不返回页面了,如果我嵌第三方的流量统计系统,是不是流量都不在内了?在这里面其实JavaEye所有的REST都可以用同样的方式做缓存,比如所有新闻的文章,所有论坛主题帖,甚至包括论坛的版面,所有这些论坛的版面,还有所有的博客文章,反正所有的Rails的,能够被URL标识的资源都可以用这样的方式标识缓存,在我们那个网站用的特别多。

第一行就是新闻。当你访问一篇新闻的时候,我服务器端怎么样来判断这个版本号符不符合呢?其实在Rails当中很简单,它有一个方法,就是你指定最后一个修改时间和ETag,如果我发一篇新闻以后,我可以拿这篇新闻创建日期,最后这项资源,最后被修改的时间,ETag可以用这篇新闻最后的ID,这样写的话如果浏览器第二次访问Server就会返回304。第二个是显示博客的。我如何决定一篇博客它有没有修改过呢,就是做两项工作,你要给浏览器,告诉它我这篇修改的时间是多少,第二个博客的ETag。我如何产生这篇文章的的ETag呢,我ETag用什么方式实现的?用这篇博客所有的评论,加上这篇博客所有的评论数,用这个数字做了一个算法,用它生成了一个ETag,意味着只要这篇博客内容被修改,或者这篇博客评论数被增加,这项资源就被改变了。如果不是这项情况,这是我用自己的方式生成了一个ETag。刚才说到两个参数,一个ETag,还有一个lastModified,这两项你不需要都提供。 

这边列出来一个例子,是论坛版面的页面,论坛版面页面是分页显示的,第一屏是大家讨论的帖子,第二页是其它的,我在这个里面我是怎么判断的呢?这个版面所有主题帖最后回帖的时间来生成lastModified的时间,所有的主题帖子回帖数作为ETag,只要有新的回帖我就认为资源被改变了,如果没有这种情况资源就没有改变,这种例子很多。还比如说像这个例子,我就做一个更复杂的例子,论坛的帖子,论坛当中我们自己做了广告,在主题帖下面还可以嵌广告.如果主题帖没有改,一年前的帖子没有回复了,可是我要换广告,换了广告,内容没有改,是不是告诉浏览器你本地缓存是旧的,你应该再来取了,怎么做呢?就是生成ETag生成一个参数,我可以生成一个广告的发布时间,生成广告参数。这个效果是挺明显的,在很多资源加了缓存的效果之后,通过服务器日志的跟踪,每天产生的304的状态,服务器端产生的304的响应状态,每天有30万次请求,30万次请求需要在服务器渲染页面,由于我们用了这些算法,利用Rails架构提供的便利,有30万次页面下载被节约掉了,30万次的页面访问也被节约掉了,每天有300万次请求,至少有10%的总体的性能的提升。 

这是第一个,刚才我上面说的Rails的架构,在Rails应用当中,当你使用Rails架构的时候,第一个可以利用HTTP的便利让我们最大限度的节约服务器的资源,做浏览器端的缓存,第二个在系统当中整体模块的可扩展性特别好。第二个我简单讲讲缓存,其实缓存这个东西是非常复杂的东西,我简单画了一个Web的结构图,同时有服务器,Web服务器,后端有数据库,还有底层的操作系统,存储设备,所有的设备当中做缓存的目的是什么呢?我们知道从硬件结构上来一定是磁盘的机械操作是最缓慢的,做所有缓存终级目的避免对磁盘做一些机械操作,磁盘操作都是终极的瓶颈,它为了减少磁盘机械操作,数据库本身也有缓存,内存的,它是为了减少对文件系统频繁的读写,操作。还有应用程序的缓存,还包括Web服务器的缓存,这些缓存很多。其实操作系统,数据库我都不说了,简单说说在Rails当中一些注意的地方。其实我们有一个误区,特别是做互联网应用有一个误区,传统的企业应用,DBA在设计的时候通常会避免涉及很多小表,都会设计大的统计的表,然后便于它做统计查询。在做互联网应用的时候,它有很多数据库反复出现,包括现在特别流行的NoSQL DB,它有更鲜明的特点,特别做互联网有一个误区,很多人害怕出现n + 1 SQL。比如我要查出最近十条帖子,一个是状元,一个是关联查询,把当前的回帖能够查出来。后面比方说有分页,第一页有十个结果,这十个结果按照主键把后面十条语句查出来,应用程序员很害怕,我下面程序员碰到n + 1 SQL都很怕的。反倒n + 1 SQL是高性能的选择,对数据库来说终极是减少磁盘的机械操作,难以避免会发生比较大的一个大段的磁盘扫描,磁盘扫描整体磁盘性能很差,虽然有N条SQL,本身不会产生磁盘操作的。

这是2007年2月份的时候,最早的时候像JavaEye的事件,因为JavaEye论坛跟博客是同一个表,到07年2月份它的数据库磁盘非常非常高了,当时把POSTS表大的大字段剥离出来了,如果对大字表发生任何扫描操作,基本整个数据库都被堵住的。我看了简单的表结构,它早期所有的帖子都存在Posts表里面,这个磁盘空间已经膨胀到6G了,把大字段放在一个叫text的表里面,然后还有一个body,帖子的内容有6G大小.另外记录帖子其它信息,这个表到现在只有210兆,这个表数据条数有四万条了,如果本身放在一张表以后,一旦发生磁盘扫描整个数据库都被锁定了。当数据量大的时候,那些大表发生磁盘扫描,整个网站,整个服务器,从操作系统的监控工具上可以看到LV非常高,会到百分之五十六十。

我这里是简单截了一个图,有6G,有415万条记录,往下数第五行大小只有210兆,非常小。通过表分离的操作能够达到很好的性能,包括剖克塞楼表,被访问一次它就不会再被访问了,长期呆在缓存里面,虽然这个表6GB,经常访问的数据全都在缓存里面。

谈谈Rails的应用缓存,在一个Web应用当中对整体的性能提升有巨大的作用,包括有对象缓存。对象缓存的原则,特别对于我们互联网型的应用,有的时候你希望设计的比较好,把一些大表拆成小表,做小表的时候也不要怕n + 1 SQL。我刚开始给大家一个数据,以JavaEye现在的统计数据来看,每天处理300万动态请求,因为每天有86400秒,每秒处理的动态请求有30多条动态请求。我刚才又给大家一个数据,每秒SQL查询数据是30条,每一次动态请求我们应用程序平均向数据库发六条语句,同时我又说对缓存服务器,我们每秒有600次请求,缓存命中率在90%以上,基本上有将近550次命中缓存。每秒处理30次动态请求,每次动态请求,我每次处理一个Rails的请求,我平均会查6次数据库,我算算,130,会向数据库发6条SQL,差不多20次,一个6次请求会60次访问缓存数据库,其实它对于底层的通讯非常频繁,这种情况下整体性能很高。大家不要害怕n + 1 SQL,这个都没有问题。对象缓存还有一个意义,我们做群体缓存很容易扩展,特别Rails这种无状态的架构,可以一直加服务器,一直一直扩展出去。特别数据库磁盘很高就没有办法做扩展了,比方说我在数据库上拆表,还有干脆动态页面静态化,那些会带来非常高的成本。前期在架构设计好,至少在百万千万级别都不需要拆表,或者我要做动态页面静态化,当然上亿次的访问就是另外一种架构设计。

然后我们自己写了一个Cache Plug。这是很早之前的数据,其实向Cache方面twitter本身做的非常好,twitter虽然经常宕机。twitter不是通过人,通过浏览器页面去访问的,绝大多数情况都是通过各种各样的客户端请求的,客户端有很多第三方的API,都是循环请求,它的请求负载远远超过普通的页面访问链接。因此twitter Rails应用承受的访问量非常之大,它做了一个凯奇马特。还有页面片断缓存,这里面我们大量的使用,用的非常非常多,包括博客页面左侧博客的分类,留言,整个博客页面左边一块全部被缓存起来,还有网站,包括首页,新闻频道,基本上大量的运用就是片断缓存。运用片断缓存有一个好处,就是降低Ruby负载,我已经生成页面片断已经,我放在缓存里面带来的好处是,我不需要在Ruby那端做匹配。我们早期遇到的一个问题很有意思,我们那个Web服务器它的负载比DB服务器高,但是现在Web服务器也比DB高,我们这边高的原因就是Ruby它的表达处理比较低效,我们虽然做了很多对象缓存,但是对Ruby那一端没有什么效果,它最后是运算性能差,最后用ERP渲染性能也好不到哪里去,做了一个新的东西,我测试过性能也不怎么样。有一些比较智能的,假如我在帖子写了一个URL地址,我可以自动给你地址加上超链接,还有为了避免脚本攻击要对标签做过滤。Ruby性能是挺糟糕的,所以从架构上来说,我们要避免做这种大量的操作。

早期的时候我们会把帖子的内容缓存起来,我们把帖子缓存只是节约对数据库的访问,Ruby还是要做大量的处理,做各种各样的转移,做bbcode的转换,还有自动加链接,诸如此类的操作,后来我们把一个帖子生成的结果,把它做成缓存了。

大家可以看看第二行,把这个内容做了各种各样的转发,生成了一个结果,生成这个帖子已经转成了HTTP的一个片断,把这个片断缓存起来,下一次显示这个页面的时候,不但不需要访问数据库,甚至Ruby那边不需要做任何处理了,它速度很快。这样做了以后它的性能就特别快了,这是整体统计的情况。我刚才说的是一些缓存的方案,从整体架构上来讲,除了刚才说的第一个可以做Rails整体的架构,第二个从各个层面上,提高性能,其实在很多方面我们还有很多的技巧,比如我在这些方面列一些,对我来说我遇到的一些问题,我们有的时候遇到这样一个事情,我们做底层的搜索,有些搜索关键词特别多,它查询量特别大,它相应速度很慢。因为很多页面都会访问缓存,导致整个网站会被堵住,后来给所有可能出现的地方我们设置了一个参数,比如现在设置的是两秒钟,我的Ruby程序访问后端Java全文检索超过两秒钟还没有返回请求,我直接返回一个空结果,这一次没有搜索到,避免整个请求被堵住。第二个这个挺有意思,有一些请求天生很慢,有一些请求天生速度很快,比如访问一个帖子,我们应用程序都是几十毫秒都会返回的。这种特定的我举一个例子,比如生成谷歌塞麦,这种速度特别慢,一般正常情况下你如果有几个请求去访问,导致的结果是什么呢?导致这些请求被挂住,后面执行速度特别快的请求就没有办法响应进来,都会被堵在外面。还有一个办法可以设计一个特别的迪斯拜杰,有一个新的Ruby框架叫由尼扣,包括我们现在用的前端Web Server,它能选择路径,堵了很多请求,它可以在其它进程上转发。还有像其它功能的实现,比方像大量运用memcache做应用缓存。 

有的人恶意的登陆,不断尝试想破解你的帐户。这个登陆的时候记录IP过来的IP地址,第一次访问15分钟之内,过期时间15分钟,15分钟之内就变成二,他第三次再请求就变成三,他再请求,再请求,比如说六次,15分钟六次反复的登陆失败,我就直接给它封掉,再登陆告诉他一个小时不能访问,这些功能其实都是用麦普泰克实现的,我们还可以用它来实现做前端的防火墙。做Web应用,有很多规模偏小的网站,比如一天的访问量十万,十几万,爬虫一晚上爬上百万。我碰到一个很极端的情况,有一次网站特别慢,网易有一个有道的阅读器,有一次晚上爬了一百万次,对我们网站服务器爬了一百万次。你必须想办法来处理,各种各样的爬虫,就实现了动态防火墙可以防爬虫。但是实现这个爬虫还是有问题,所有的爬虫要求你在服务器绑黑名单。后来有的时候碰到一些僵尸网络攻击,有很多机器中了木马,IP地址特别分散,一封就封了一千多个网段,多的时候甚至两千个网段,一个存储最大只能一兆,超出一兆就失效,有人通过肉鸡的方式迫使我的防火墙爆掉。后来我就改,其实在这里面顺便说一下,我们寻求解决方案的时候可以多看一看新出的项目,比方说像Redis性能是瑞普泰克性能还要好,它可以有一些特定的数据结构。现在我把所有的黑名单IP地址段放在一个地址里面去,我判断黑名单,我把整个黑名单的对象抓Ruby应用程序里面来。如果这个黑名单特别大,它反复的通信,操作都是比较耗时,用Rails来实现把地址推给Rails。它带来的好处就是性能非常的好,而且可以存很大很大的黑名单,而且很大的数据操作都是在服务器端实现。 

黑名单做的太好的结果我们被封掉了,应该是11月底,还是12月初,电信会有一些叫舆情监控工具,到处扫描机房托管的服务器。我们这个黑名单挺智能,你老爬你就要填验证码,那个舆情监控真的就给它封掉了。当然他们工作人员也挺敬业的,后来我通过查日志发现的,被封掉以后,真的那个网段有人登陆去填验证码,那个IP地址封了以后,连续不断的403,接着访问验证码的页面。前一天它被封了很多次,到了第二天他怒了,老填验证码,就把我们给封掉了。除了这个之外还有很多类似的方式,它的好处可以做更好的做大规模的服务器的扩展。 

其实它这种进程架构做异步处理的时候要做特定的设计,我有的时候利用操作系统,我写的两个撇号,撇号可以直接命令。我在这儿举两个简单的例子,我从实际代码扣出来一小段,它是一个什么操作呢?这就演示了在服务器端怎么做异步操作。一个标准的异步操作的场景,异步操作场景有很多解决方案,多线程可以开线程去做,最简单的办法就是用撇号,有一个CUL命令,用CUL命令给谷歌发一个Ping,我在后面写了一个语的符号,它会在后台执行了,这样一种操作方式也就实现了异步操作。刚才我列的方式,不是访问特别频繁的,因为一般来说一天博客也就发800多篇博客,假如一天有十几万次请求,用这种方式操作,通过操作系统调一个命令访问,可能性能就成问题了。我们后面还在用一些更高级的方法,比如说用Redis来实现高性能的队列。Rails有一个类斯特特别好,它可以实现先进先出的队列,就像用Rails现在就可以做这些任务,如果有任务就帮你们插一条,后台有一条程序,从队列的尾部一条一条抓出去处理,我们应用程序一条一条往里抛就可以了。

时间的关系,我就不仔细讲了,我说的基本就是这些,大家有什么问题,可以跟我交流交流。

提问:我问一个具体的问题,Rails版本是2.0,还是3.3。为什么不升级到3.0的原因?

范凯:我们最早的版本是2.2写的,很多东西代码需要重新写,我觉得用Rails最大的好处重写代价也不是很大。

提问:你采用Ruby的解析器是哪个版本?

范凯:Ruby有一个企业版,挺好的,性能,内存管理挺稳定了,用起来挺好了,基本上它不会出什么,性能蛮好。

提问:你开始提到架构里面静态解决用的了莱挺,统一的处理那个日志。

范凯:静态我不分析,我主要分析动态的日志,静态我基本看看赖挺具体的信息就可以了。

提问:你没有讲到前端的处理分析,我最近用Rails做一个网站,我GS,Rails不是用普老泰开普,谷歌也提供了这个服务,我能不能用谷歌?

范凯:静态资源分摊有一定的好处,至于用不用谷歌,我觉得值得商榷,因为谷歌不稳定,如果谷歌访问不出来,你所有的网页效果不是出问题吗?国内大的互联网都会处理一个独立域名专门做静态资源的,新浪有一个专门静态资源都走域名,走另外一个域名有一个好处,连酷开信息都不带了。我们国内有很多软公司是搞白名单制度的,有一些网站只允许个别的网站能够访问,把这些静态资源分到其它域名上,好多人跟我投诉,CSS出不来了,他们公司还没有放到白名单里面去。

提问:我刚才注意到咱们JavaEye用的mysql,为什么不用RSM?

范凯:因为买RSM的话,它是表锁定,两个同时操作一张表,后面就锁定了。反正至少发帖,回帖对于表的操作多的,访问表可能会改一些帖子的访问基数,改的挺频繁的。

提问:咱们JavaEye用Cache,用的是一个实例。

范凯:目前用的是单实例。

提问:大概有多少内存?

范凯:我开了2G。

提问:我看到JavaEye上面用的缓存,有不同粒度的,还有比较粗一些的,当然还有缓存受访的频率也不一样。我假设首页做了一个页面的缓存,这个页面肯定访问挺高的,对象是长尾的东西,这可能有一个问题,不同的级别缓存如果都往一个Cache放,比如哪一天把你的首页频率高的缓存被ARU了,有这种可能吗?

范凯:你说的这种情况反倒少,更多跟存储有关系,它不需要GC,起来以后它分很多的Level,比如一栋大楼,一楼到19楼,一楼是大堂,不能这么说,一趟都是要格子间,二楼一个一室一厅,顶楼就是超级豪华公寓了,一个对象进来先看体积多大,如果是三口之家直接塞到三室一厅的房间里去,有几个大对象都在最顶层,不能往下塞,可能出现你说的情况,刚放进来把前面的踢进去了。

提问:另外一种对象访问频率很高,它也会被挤出来是吧?

范凯:对,目前看CPU进低的,不到50%,还没有做这个事情,你说的那个是对的,那个量进一步大的话,出现缓慢频繁,刚塞进去被踢出去的可能性很小。

提问:我可以跟大家分享一下,我之前出过这样一个问题,有一次我们有一个页面,这个页面它是一个页面的缓存,这个页面一般来讲访问不是很多,首页访问的比较多的,之前访问频率比较少的页面,突然有一天搜索引擎去爬这个页面,这个页面可能是几十个页面,结果把缓存删了,就把我们的首页也挤出来了,当时出现了这个问题,那个首页缓存失效以后就特别那个。

范凯:说到缓存,我想补充另外一个事情,吃过很多次教训。它虽然挺好的,但是有一个问题,比如说你的网站,因为各种各样的原因断掉了,机房搬迁,因为缓存的东西你关了以后肯定没有了,换了新的地方服务一起来,整个网站缓存体系依赖又特别大,导致你服务器刚起来,至少我的感觉,如果被关再重启一天之内它的访问速度都恢复不过来,因为缓存都是空的。

提问:这个应该可以做,比如说类似于HA这种方式,写两次,一个缓存。

范凯:我觉得代价比较大,我现在倾向于慢慢的,我准备用Rails来取代mencache,memcache用的另外一个框架,Rails自己写的,一个特别简单的,因为通用框架,性能更高,Rails的好处可以定期把Rails内容flush C盘上去,我不倾向更多从应用程序解决问题,我更倾向于从整体的架构,更好的产品角度把问题解决掉,减轻应用的负担,不要把应用程序写的特别负担。

提问:这个也可以应用透明,写一个基于memcache的东西,它也可以做,应用可以透明的。

范凯:是可以做。

提问:没问题了,谢谢。

提问:你好,我经常看JavaEye,我感觉JavaEye明显比CSDN快很多,我想问一下JavaEye和CSDN现在合作了,CSDN会不会和JavaEye一样快。

范凯:慢慢改,希望用一年的时间把它变得非常快。

提问:我经常用手机上网,用时候用JavaEye一下就打开了,用CSDN到家还没有打开。

范凯:我后台观察后台会堵,是应用程序的问题,另外前端的页面结构不太好,压缩打包不太好,前面下载太多的字节数,前端也慢,后端也慢,慢慢的改,一个产品一个产品慢慢的改。

提问:我有一个问题,你刚才一直提到缓存技术在网站当中扮演着很重要的角色,这个过程当中会还提到整页缓存的概念,比如我整页做缓存,动态部分利用Ajax,这个为什么没有使用?

范凯:动态页面这种用的挺多的,从我个人的角度来说,我认为在千万级别以内的网站没有必要。JavaEye一天处理300万以上的请求,这个量不太小了,我查它的排名大概120名。CPU使用率不到50%,这种情况你有必要动态页面静态化。另外CSDN有一些动态页面静态化了,有问题。现在CSDN有全站导航条,因为动态页面静态化了,导航条写在GS里了,这样就好改,要不然静态页面都已经生成了,改一次导航,整个静态页面还得重新生成一次,要不然还得重新下载一次,很麻烦。用这种方式处理,对ASU来说有非常不好的作用,因为我导航都是GS生成的,所以ASU搜不到导航,搜不导航的结果就是它的很多页面,一些很主要的页面它的评级会非常的低,查也查不出来。还有比方说如果我要对页面做一些比较大的改动,布局的改动,这种改动是整站的改动,整站有一些功能一起加,一起减,动态页面静态化很痛苦,今天改一点,重新生成一遍,明天再改再生成一遍。几千万,上亿动态可以,没到一千万没必要。

提问:我用PHP,我们做这个网站是用框架的,这个框架本身启动很慢,这个成问题了,就按照你们目前的方式进行局部页面缓存速度有多快,1.5秒到两秒钟,我做这个电子商务网站页面还是慢的,这个情况你有什么建议吗?

范凯:跟框架有关系,因为它有一些框架是挺慢的,你找一个比较快的,其实像这个问题本身也被很多人批评,有些大的框架,做CMS朱跑它非常慢,经常被人批评,有一些新的PHP框架,在这方面会做大量的框架,本身做轻量级,做小型框架进去,这样启动的过程还是挺快的,我建议不要用特别,因为本身Web开发还是强调比较敏捷,改动比较快,不建议用特别复杂的东西来做。

提问:谢谢。

范凯:没有问题,我们今天就结束了。

主持人:谢谢大家今天下午的参加。

范凯:谢谢大家。

 

你可能感兴趣的:(Web,应用服务器,网络应用,企业应用,Rails)