性能驱动下的架构实例
大型WEB互联网应用都是在市场的锤炼中成长的,以前提到过性能需求的驱动对于架构的影响,一个1M PV和一个100M PV的网站肯定是不一样的。这里仅仅给出几个典型的例子,兴许你对此能有收获。
初期,只有简单的应用服务器和DB服务器分家,使用简单的Jetty容器,系统的瓶颈在DB侧。简单就是美,网站刚刚运营,不考虑太多,能访问就是王道,给用户提供丰富的内容:
=================================================================
系统在发展中不断地演化。
有一天发现用户压力越来越大,终于无法承受了,系统屡屡到达崩溃的边缘,在现有硬件和架构条件下很难支撑现有的业务,做出了这样的改变:
在这次改变中,做了这几件重要的事情:
1、引入了全页面的缓存。互联网应用缓存为王,全页面的缓存可以起到立竿见影的效果。
2、把页面展现抽象成为“主题”,和页面数据分离开来。并且,为此,引入了“聚合”的概念,它为以后的进一步发展打下了一个伏笔。
3、为了缓解数据库的瓶颈,使用了RAC方式做持久层的集群。
4、对于JS、CSS、图片等几乎一成不变的静态资源,引入反向代理,优先处理。
=================================================================
网站安安静静地发展,悄悄地演化。
终于有一天,用户访问量激增,百万级的PV达到了,WEB2.0业务也增加进来,缓存的命中率越来越低,CPU成为了瓶颈,访问异常缓慢。这一次,又要动刀了:
这一次的架构重构做了这么几件重要的事情:
1、静态资源(特别是可供下载的文件),使用CDN缓解压力。
2、把请求拆分成主请求、异步数据请求和静态资源请求,其中主请求仅仅是获取页面不变的部分(模板+静态数据),动态的数据以异步JSON的方式获取,并在浏览器端使用JavaScript聚合。这一步把某些聚合操作放置到了客户端进行,缓解了服务端压力。
3、真正将页面的聚合展现和页面的生成拆分开来,保证了用户响应是快速的。
4、引入多层次缓存(内存中对象集合使用Memcached缓存,接口层面缓存报文,页面缓存缓存文件等),同时,对于层次的划分,容易将整个系统拆分成若干个子部件独立运作,简单、独立。
5、数据库进一步拆分,读写分离。
6、页面分块。这是大型Web2.0网站共有的特点,一个页面上往往总有那么一部分是固定不变的,这些部分应当能以页面片段的形式缓存到磁盘上,每次页面生成的时候只需要更关注变化的部分即可。
=================================================================
继续、继续。
访问量增长了几十倍,集群的服务器也第一次达到了三位数,系统不稳定,速度重新落下,问题定位也无比困难,一切又开始扑朔迷离起来。
这一次,不可避免地又做了架构上的调整,首要的目标,是以隔离解耦的方式增加系统稳定性,同时,更便于产品化管理:
1、整体采用SOA方式布局,按照功能划分集群,并且每个功能集群定义为一个“服务”,内部采用REST风格的接口访问服务。服务驱动和编制引擎(ESB角色)定时把可以提前生成的静态数据存放到共享存储上。
2、清晰化聚合逻辑,静态的数据尽量在服务端聚合完成,减少客户端数据请求的流量。
3、引入NOSQL数据库和廉价存储,适当放弃一致性,为海量数据做准备。
4、开发核心业务功能包部署引擎(基于OSGi),对于业务的定制,只需要按照功能包定义的格式开发,完成后可做到不重启应用增加业务功能。
文章系本人原创,转载请注明作者和出处