Archive for October 22nd, 2007

高性能应用程序开发

Monday, October 22nd, 2007

高性能应用程序开发

Author: gashero
Date: 2007-10-22

目录

1 高性能的时代

当你面对汹涌而来的用户时,该怎么做?

产品策划的成功、推广的成功带来了汹涌而来的用户,随之问题开始凸显,曾经运行的很好的服务器,开始极度缓慢;运营经理哭丧着脸看着你显示出他回天无力一般的无奈。在一次成功的推广之后,突然访问量暴增了200%,然后,就在那个能够给你带来划时代推广意义的时候,服务器宕机了。

2 WEB应用的基本结构

一般的WEB应用包含几个基本结构:

  1. WEB应用
  2. 应用服务器
  3. 数据库

这似乎是无可挑剔的简洁,但是问题是当访问量猛增的时候,链条上任何一个结点都可能会成为瓶颈,并且让你欲死不能。

2.1 WEB应用

先进可以做WEB应用的技术很多,比较通用的有PHP、JSP、ASP.net等。一般来说,WEB应用技术本身的性能是无法构成瓶颈的,真正的瓶颈在于这些优雅的框架上编写出的低效的程序。那些经常 select count(*) from xxx 的程序员才是你的恶梦。当然,有一点不得不说,如果一个框架足够难学,那么意味着能够到达这个层次的程序员往往水平也很高,在数据结构、性能优化方面也往往经验丰富,这时候,他所能做的高性能的事情已经不再是一种框架可以制约的了。

PHP本身有着很方便的部署,PHP本身也不太难学,但是一个特点是PHP只有在Linux下才足够地道,导致了相当的学习成本。所以,国内的PHP程序员往往都是经久考验的。

JSP/Servlet本身是优秀的,但是在Java相关技术火热的发展起来之后,程序员队伍的总体素质就堪忧了。其实真正可以从J2SE一路学过来的也倒没什么大碍,关键是怕那些Java WEB速成派。当然从这里也侧面的想到那些IT培训学校所倡导的几个学速成加就业包票的讲法,实在是没的说。也许这个世界上从来都不曾有真正的窍门存在。

至于ASP.net,好用的工具还是要看归什么人用,ASP.net学习成本的低廉造就了一批水平也是相应的程序员。当然,不排除用ASP.net的高手,但是问题是平均水平。

2.2 应用服务器

应用服务器实际上对整个系统性能也有很大的影响,比如resin就比Tomcat性能要高,其他等等不一而足。同时应用服务器的配置也是个艺术。

2.3 数据库

数据库对整体性能影响也是比较大的,同时对于一个不断成长的系统,必须要考虑到未来扩展的可能。

3 高性能WEB应用的一般结构

从前端到后端依次是:

  1. 负载均衡Load Balance
  2. squid
  3. 应用服务器
  4. 中间件/memcache
  5. 数据库服务器

3.1 负载均衡

面对大规模的用户请求,负载均衡是不可或缺的。当然这个东东市场上卖的很贵,可以按照自己的需求来买。最近一段时间流行的第四层交换也可以考虑,产品多多。如果做的不是非常之专业的话,用squid来做目的代理服务器也有相同的功能。

一些软硬件防火墙一般也带有负载均衡的功能,可以利用起来,当然,某种产品中附带的某某功能,肯定是不如专业的好。

负载均衡妙处很多,可以自己慢慢发现,包括好偶面的squid到应用服务器这一层实际上也可以加上负载均衡来确保各个服务器稳定一点。

3.2 squid

用来缓存动态生成的页面,降低服务器的负载。不同的URL有时候需要不同的缓存超时时间。

当然squid在这里的主要用途是降低服务器负载,另外一种技术是网站静态化,达到类似的效果。总的来说加入这样一个缓存层次之后网站的总体负载就可以达到可控的地步了。另外,也可以对squid服务器层进行平行扩展以达到一定范围之内的网站扩容了。

3.3 应用服务器

同上所说,不过既然是在重负载的环境,也就需要好好配置了。

3.4 中间件/memcache

随着网站规模的不同可以选用中间件或memcache,简单一点的网站把数据库的中间查询结果缓存到memcache中即可。不过总体来说,即便是有中间件memcache也是很值得推荐的。

3.5 数据库服务器

巨无霸的Oracle未必就是最好的,多学一些数据库系统原理吧,适应你的需求哪怕是你自己写出来的sqlite集群也会比那些所谓成熟的解决方案好的多。

程序员作为一个以思考来吃饭的职业,如果不去思考,而把一切都寄希望于别人做好的东西可就不好了。不用怀疑,如果上面的那些技术你都用到了,那么说明这个网站已经开始遇到一些前人没有解决的问题了。想办法用你的聪明智慧来解决吧,因为这个时候你已经没法指望别人了。

4 一些基本原理

4.1 数据库连接

数据库的连接计算非常耗时,尽可能避免,如果不可避免那就尽可能减少连接的层次。甚至,你可以为了性能而不遵守各类范式。比如不去做连接,而是把被连接的数据串行化以后存到字段里面。

4.2 数据库统计

数据库的各类统计都是恶梦级别的,包括COUNT()、SUM()等函数调用,和排序操作。有如上面说的,为了性能你可以用尽各类方法,包括不遵守数据库的范式。一些函数的所得数据如果确实很必要,那么就把他们缓存起来。比如一个用户的某个资源数量统计,就可以存入这个用户的一个字段中,并且在每次资源增减时更新这个字段的值。

至于排序,很多时候其实是为了取得某个参数最高的几个,这时大可以在每次更新时把排序字段最高的几个缓存起来。

SUN的某牛曾说,计算机技术历史上最伟大的思想是缓存,用好缓存吧。

4.3 操作流程

每一种操作如果可以按照流程分步骤的话,就可以看清楚很多问题了。因为一个流程的耗时是各个流程耗时的和,这意味着如果可以减少流程,就会提高性能。

当然,与之相悖的是逻辑清晰度,减少划分的层次就会导致一些逻辑合并到了一起。这时如何取舍就是你自己的问题了。想想逻辑清晰的目的。曾经听过一句话:为了用户未必需要的未来的升级而预先做太多的提高灵活性、移植性等等的工作,实际上是违反软件工程师职业道德的体现。

这个事情上推荐去学习一下Tomcat的分层,作为反面典型。

4.4 数据库只是数据库

数据库只是用来存储数据的地方,不要过度依赖SQL语句带来的计算功能,也不要把计算的中间结果也存到数据库里面去。计算并不是数据库的强项,更何况你这样做毫无优化可言。所以当你看到一个很长的SQL语句时应该先仔细考虑他是否有优化的可能。再者,有些人喜欢把计算的每个中间结果都存到数据库里面去,并且把这些结果用于调试。这样做在网站稍微上一点规模的时候就会体现出严重的后果。

不过将数据库用于异构系统之间的数据通信倒是常事。

再就是别把数据库当文件系统,有意义的数据可以存入数据库,但是像用户的头像和上传的其他数据可就别往这东西里面放了。