技术专题:大型应用系统的一些讨论
第一:作为OLTP应用(联机事物处理,区别于OLAP),响应速度和处理并访能力是系统整体性能评价的第一要旨。
作为带动性能提升的主要因素,占第一位的是系统的体系架构、第二位的是数据结构定义、第三位的才是选择怎样的语言和系统平台。当然,很多情况下在考虑体系结构的时候是有基于系统平台的考量,但是一般而言,系统体系结构并不是依存于某特定平台才能确定的。
作为高并访应用的OLTP而言,一般在涉及数据库操作和数据存储操作的时候,应当明确的关键问题是,数据库操作的触发和执行是不应当基于用户请求的,这也是三层体系结构的真谛所在。也就是说,如果一个用户请求就触发了一个数据库操作,不管你使用的是php,jsp,asp,cfm,fcg还是com组件或其他什么东东,严格讲都不是真正的三层体系,因为这时中间层实际上并不存在。即便使用了预编译,即便使用了数据连接池(Connect Pool),即使系统提供了足够的缓冲处理,都是不够的。
举个例子而言,如果你在一个页面上使用了计数器,最简单的方法是每次页面请求的时候,处理程序直接数据库中相关记录加1,不管使用什么语言,什么平台,或调用什么控件,亦或采用了数据库内部的存储过程处理(显然这样效率很高)。但是这还不够,比如类似于易数统计这样的系统,当它每天处理几百万至上千万请求的时候,任何数据库就都无法容忍这样的操作,因为对于update操作,数据库缓冲的存在基本是无用的。
那么取代的手段是怎样的,前台的API程序将来访请求的一些信息按照一个指定规范直接扔到指定缓冲区里面,这样API程序(请注意这里我不提CGI,CGI效率那么差,在这样的场合是不推荐的)的处理过程很简单,效率很高。后台的看守进程从缓冲区读取数据,通过指定管道(数据连接池,固定数据库连接进程维持常连接状态)和数据库进行数据更新操作,这样的好处有以下几点,第一是当并访瞬间高峰时,前台响应不会受很大影响,缓冲可能会造成溢出而损失数据,但是不会影响前台的展示,而且当缓冲合理分配时,这种压力也会减轻,而后台看守进程可以将任务负载均衡分布处理,一时处理不完的在系统负载减轻时可以继续处理,这样后台负载可以均担,减少因瞬态高峰造成系统崩溃的隐患;第二是当缓冲区数据存储合理安排时,后台可以作到批量处理,要知道数据库批量更新比一个一个单独更新的效率会高很多,这样从处理任务量上减轻系统负载!
针对以上补充一点说明,一般而言,针对良好的商业数据库而言,select操作比update操作的效率高一个数量级,因为前者可以充分利用缓冲,而后者不能,因此将update操作批量化和后台化是非常重要的!
第二:动态页面的静态化至关重要
很多人会对这个问题感到疑惑,因为提到动态页面,自然是能够根据不同条件动态显示的页面,这也是相对于静态主页的优势,为什么要退回去静态化?
其实静态化不等于就是静态主页,这也是基于效率和性能的考虑。还是用例子表达。
范例1:新闻系统
新闻的时效性是最重要的,为了减少维护和提高更新速度,现有的新闻系统很强调后台更新的即时展示。
我们现在要考虑一个问题,一个新闻系统的首页每天显示动辄几万至几百万次,而新闻每天的更新频率最多几十到几百次,也就是在新闻标题列表两次更新之间,有几千至几万人看到的是同样的东西,类似这样的东东,就要考虑静态化处理了。同样,对于每一条新闻而言,几百至几千人看到的是同样的东西,依然有这样的处理需求。类似这样的问题,作为新闻标题列表的页面和单一新闻页面,都应当是静态html发布,这样最符合效率原则,而后台的维护程序仅仅在更新和发布新闻的时候,对这种静态html以文本文件方式打开和操作,这样就不会影响时效性和维护的便捷性。新浪的新闻系统绝对是这样的,我还看到了很多免费共享软件,可惜没有这样处理的。
范例2:广告交换系统
广告交换系统和上述有一些区别,在于每个用户所看到的东西都是不同的,每次用户刷新也是不同的,这种情况下上述方式就无法解决。但是静态化的工作还是需要的。
实际上这里面有一个小窍门就是广告交换系统或类似系统(即便是商业广告投放系统)从需求定义而言并不需要100%严格的交换比例,甚至也不可能作到100%严格的交换比例,这时候后台进程就应当对需要投放的广告内容定时进行预生成(比如间隔三分钟生成一次),并放入缓冲,前台的API程序在接受用户请求后,根据用户请求的参数和条件,在预生成的广告队列里面进行二次生成,并将这次投放的记录放到存放统计的缓冲(这是本文刚开始就提到的手段,后台对统计信息的处理同前文),前台程序虽然也进行了动态生成过程,但是由于数据来源是缓冲中的预生成信息,因此处理量小,处理效率高,而后台进程则将原本需要每次请求进行的类似操作集中一次进行,同样从架构上减少了系统处理的工作量。而作为代价,仅仅是投放过程中的交换显示比会由于三分钟预生成中的统计变化而显得不那么精确,但是当系统运营时间很长以后,这种不精确会逐步调整到可以完全忽略的地步。
第三:那种语言效率最高
这是一个最原始的问题,php+zend,fcg,jsp,IIS API都宣称自己非常之快,实际上他们都是采用了提前加载,预编译,驻留内存,缓冲分配等手段,使得处理请求响应的速度非常之快,但是这种速度仅仅是处理响应的速度,当系统需要对后台数据库,对后台文件,甚至对后台shell进行操作的时候,最快的毋庸质疑,还是C语言,而且是标准C语言,有一个事实必须提醒诸位,尽管高级语言层出不穷,但是从70年代到21世纪,世界上最值钱的程序员一直是标准C的程序员(当然还有更原始的汇编程序员)。其实一个大型系统,前台动态展示采用asp也好,cfm也好,fcg也好,jsp也好都是无关紧要的,关键是采用合适的架构并把烦琐的数据操作尽可能放到后台执行。
放到后台执行的准则是,将动态化过程中所有可以集中批量处理的,所有可以通过缓冲交换的,所有重复性的工作,所有与用户请求没有直接关联的,一概放到后台,以看守进程,或者定时程序进行。
第四:安全问题考虑。
当一个大的网上应用系统,如果有些程序,访问量不高,因此网站设计者认为效率无所谓,可以通过api直接对数据库进行烦琐操作,那么就危险了,实质上那种程序往往成为基于CGI的D.o.s攻击的靶子,(本人恰恰是这方面的专家
)。因为当有人通过伪装报文,瞬间大量请求这个处理效率不高,反应缓慢的程序的时候,系统资源就会大量被占用,很快就会因为系统资源过载而导致系统崩溃或拒绝服务。
请注意这种攻击是导致系统资源的过载而不是带宽,由于宽带网的接近,基于带宽的拒绝服务攻击将越来越困难,但是恰恰相反的是,基于系统资源的拒绝服务攻击将越来越容易,所以网站设计者,千万不可在任何一个地方掉以轻心,而烦琐操作后台化,对这样的攻击行为就有很好的抗击能力,这一点也是我这里再次要强调的。
再补充一句,进行这样的攻击非常容易,以至于一个完全不会写程序的人,只要懂得一些网络,就可以在很短时间掌握,并给大型站点带来严重打击。
第五:数据支持
本人罗里罗嗦这么半天,大家不知道是不是不耐烦,我有何德何能在此逞强?
www.isme.net是目前每天支撑接近300万次广告链调用的免费广告交换系统,瞬间高峰每秒请求超过50次,每天流量12G以上。我在系统正常运行的过程中作过测试(系统已经有一定负载),通过apache的ab进行标准测试,对广告链投放程序,测试结果是在100个并访情况下,瞬间处理能力可达到每秒1300次广告链请求!如果不是合理分配内存缓冲和后台看守进程的预生成,如果每个请求程序都要到数据库跑一趟,这个数字是绝对不可能达到的。
任何人都可以在apache下面用ab对自己写的程序进行速度评测,看看你的程序能达到怎样的处理能力?