首页 > 代码库 > 蚂蚁变大象:浅谈常规网站是如何从小变大的(三)(转)

蚂蚁变大象:浅谈常规网站是如何从小变大的(三)(转)

原文:http://blog.sina.com.cn/s/blog_6203dcd60100xon9.html

 

         【第七阶段 拆分】

 

         到上面一个阶段,我们初步接触到了逻辑、存储等的多机模式。这样的结构,对于逻辑不是特别复杂的网站,足以撑起千万级的压力。所以大多数网站,只要能够用好上面的结构就可以很好的应对服务压力了。只不过还有很多细节的工作需要精细化,比如:多机的运维、稳定性的监控、日志的管理、请求的分析与挖掘等。

         如果流量持续增长,或者是业务持续的扩展,上述的架构可能又将面临挑战。比如,多人开发常常出现版本冲突;对于数据库的更新量变大;一个表里面的记录数已经超过千万甚至过亿等等。

         怎么解决呢?还记得我们之前介绍过一个CAP理论嘛?三要素里面有一个东东叫:分区容忍性(Partition tolerance)。其实,这个就是我们接下来解决问题的基础:切分!

         一、从数据流向来看,切分包括:请求的切分、逻辑的切分、数据的切分。

         数据的切分:将不同的数据放到不同的库中,将原来的单一的一个库,切分成多个库。

         逻辑的切分:将不同的业务逻辑拆分成多份代码,用不同的代码管理路径来管理(如svn目录)。

         请求的切分:将不同的逻辑请求分流到不同的机器上。比如:图片请求、视频请求、注册请求等。

 

         二、从数据组织来看,切分包括:水平切分、垂直切分。

         数据库的变大通常是朝着两个方向来进行的,一个是功能增加,导致表结构横向扩展;一个是提交数据持续增多,导致数据库表里的数据量持续纵向增加。

 

 

        数据量变大以后,单机性能会下降很明显,因此我们需要在合适的时候对数据进行切分(这个我没有太深入的研究过相关数据库的最合适的切分点,只是从经验上来讲,单表的字段数控制在20个以内,记录数控制在5千万以内会比较好些)。

        垂直切分和水平切分,其实是挺纠结的两个词。我之前对这两个词经常搞混。后来自己画了个图,就很直接明了了。

 

        水平切分:

 

        水平切分就是因为记录数太多了,需要横着来一刀,将原来一张表里面的数据存入到多张表中,用于减少单张表里的数据量。

 

        垂直切分:


        垂直切分就是因为业务逻辑需要的字段太多,需要竖着来一刀,将原来放在一张表里的所有字段,拆分成多张表,通过某一个Key来做关联(如关系数据库中的外键),从而避免大表的产生。

 

        (笔记本马上没电了,加上该做午饭了。暂时先到这儿吧。^_^

        好了,有了上述的基础以后,我们再来看实际问题如何来解决。

        假设,现在我们有一个博客网站,这个网站拥有多个功能,如:图片、博客、用户信息等的插查删改操作。而现在博客数据膨胀比较厉害。

        首先,我们从数据流向来看,用户访问博客、图片、用户信息等这几个逻辑没有直接的耦合,对应的业务逻辑关联也很少。

        因此,我们第一步从入口上就可以把三者分开。最简单的方式就是通过域名来切分,比如:img.XXX.comblog.XXX.comuser.XXX.com。然后通过不同的WebServer来接收这些请求。

        第二步,我们的业务逻辑代码,很明显可以将这些逻辑分开(从部署上分开)。一部分专门处理图片的请求,如ImageUploadAction/ImageDisplayAction/ImageDeleteAction,一部分专门处理博客请求,如:BlogDisplayAction/BlogDeleteAction,一部分专门处理用户相关请求,如:UserModifyAction/UserDisplayAction等等。

        第三步,从数据库存储上,将三者剥离开。简单的就是分成三个不同的库。

        这样,从数据流向上,我们就按不同的功能,将请求进行了拆分。

 

        其次,从数据存储上来看,由于博客数据量增长比较快,我们可以将博客的数据进行水平的拆分。拆分方法很多,比如常用的:

        1、按区间拆分。假定我们用blog_id作为Key,那么我们可以每1千万,做一次切分。比如[1,1kw)[1kw,2kw)等等。这样做的好处就是可以不断的增长。但访问可能会因为博客新旧的原因,集中到最新的几个库或表中。另外,要根据数据的增长动态的建表。

        2、按取模拆分。比如我们预估我们的blog_id最多不超过10亿,如果每张表里面我们预估存入1千万的数据,那么我们就需要100张表(或库)。我们就可以按照blog_id % 100 这样来做切分。这样做的好处是简单,表在一开始就全部建立好了。且每个表或者库的访问都比较均匀。但问题就是,如果数据持续扩张,超出预期,那么扩展性就成为最主要的问题。

        3、其他还有一些衍生的方式,比如按Hash值切分等等,大多大同小异。

 

        这样一来,我们通过访问模式、数据组织等多个维度的拆分以后,我们单机能够提供服务的能力就变的比较强悍了。具体的架构如下图。


        上述结构看似比较完美,但是在实际的使用中可能会遇到以下几个问题:

        1、业务关联问题。多个Service之间不可能没有任何关联,如果出现关联,怎么办?特别是如果是提交的信息要修改多个业务的数据的时候,这个会比较头疼。

        2、服务运维问题。这样拆分以后,随着机器数量的膨胀,对于机器的管理将会变的愈发的困难。这个问题直接会影响到整体架构的设计。面向运维的设计是架构设计中必须要考虑的重要因素。

        3、还有一个问题是我们WebServer始终是单机的,如果出现宕机等问题,那影响将是致命的。这个我们还没有解决。

        这些问题都会在接下来的部分详细来解决。