【系统架构】高性能网站的十大原则,系统拆分

导读:
技术的进步源于需求的推动,在原始时代,单兵作战的服务器节点很容易满足零星的访问和简单的业务,随着系统业务复杂度增加,访问流量的不断增加,单兵作战的服务器很难招架住千万人的“同时蹂躏”,在此种情形下有以下方案可供选择,A选择性能更加优良的服务器(几乎不可行),B垂直拆分系统,将不同的模块(业务)分散到不同的机器上。C水平拓展,将系统整体分担到不同的机器上,D.同时运用垂直拆分与水平拓展,用某社交网站的架构图展示如下:
  
本文旨在到讨论垂直拆分系统,所涉及的问题的如下
1.为什么需要系统拆分?
2.系统拆分的一般原则
3.系统拆分所面临的额外的问题
           3.1系统拆分后的数据同步问题
           3.2查分后系统之间的通信问题,接口标准化
           3.3系统拆分后单点的问题
4.浅谈数据库拆分的策略
           4.1关系型数据库的拆分
           4.2非关系型数据库的拆分

1.为什么需要系统拆分?
  性能考虑 :一个大的系统,往往其中的某个部分,承担了很大的并发压力,或者逻辑运算特别复杂,因此成为系统的性能瓶颈 ,这时就可以考虑将这部分独立出来,从而实现单独部署,再通过负载均衡等手段,来解决性能的问题 
  逻辑清晰 :根据业务上、流程上的不同环节,将整个系统拆分为不同的子系统,在逻辑上会更加清晰,从而更容易在架构上说清楚,或者进一步做优化 
  分而治之 :减少系统之间的耦合,一个模块出问题,不影响其他模块的运行,同时在开发时可以减少代码冲突
  流量限定:将大流量的业务单独剥离出来,提升系统的可控制性
  便于管理:随着业务的发展,模块之间的耦合性越来越强 ;开发人员越来越多,相互之间代码版本也难以管理

2.系统拆分的一般原则
   按照业务应用拆分:一般的企业内部都是按照业务增长方式比较多,所以随着业务的增加,将系统进行拆分的是比较多的,也就是将一个较大的系统拆分为多个小的系统
   按照系统瓶颈拆分:当系统做庞大后,不不同的功能点会遇到不同的瓶颈,如安全瓶颈,性能瓶颈等,通过拆分可以解决此类问题
   单节点机器的限制:单个节点机器的CPU处理能力,硬盘存储有限,例如:当单节点上的硬盘容量不足时必须进行转移处理,如采用部分转移,拆分则是一个良策

3.系统拆分面临的额外的问题
          3.1系统拆分后的数据同步问题     
         业务拆分后最好能同时进行数据拆分,减少数据之间的耦合,降低数据层面出问题的可能,一旦数据被拆分,则会面临数据之间的同步的问题,如在京东上下单后,一部分数据流入支付入口,另一部分数据流入
   物流入口,处理数据同步问题从根本上讲有两种解决方案,一种是时钟同步,另一种是条件触发,条件触发可以从数据库层面考虑(触发器,数据库链路),也可以从应用的角度上去做,如下图所示

   
          3.2查分后系统之间的通信问题,接口标准化
   当系统被拆分后,面临的另一个问题就是以前是属于一个工程内部的系统,相互之间的调用就可以直接调用到,现在很麻烦,要两边来做接口,接口还得联调,尤其是两个厂商之间来联调尤其繁琐,无规矩不成方圆,
   接口之间尽量标准化,这样在后期的维护可以减少不必要的麻烦,服务器之前常用的通信方式,有以下几种webservice,java RMI ,或者直接使用socket,下面将一一分解
   有关通信就说到早期的socket,这个socket虽然是最古老的技术,不过它也算是目前所有网络技术衍生的基石,网络的交互的不断优化过程就是socket特征不断变化的过程。说到socket就是编写程序比较麻烦,
    双方调用和接受都需要编写   单独程序去通信,要求传输的内容都可以被序列化,写的一方有点类似于写文件,读的一方有点类似读文件,不过它也是使用IO本身的一种方法去通信;很多程序员初手在调用完了也会搞忘把socket关掉。
    面对java想要把底层封装的,而且尽量减少程序员的错误,所以RMI诞生了,远程方法调用诞生了,RMI是jvm自己封装的一种远程方法调用的协议,中间通过对象序列化来完成,调用方需要有远程的接口,由于RMI本身调用过程中配置 比较麻烦,但是又有了这种技术,于是EJB诞生了,EJB在RMI的基础上衍生出标准化的分布式编程模型,不过它都是基于RMI来编写的,主要目的是将业务和VIEW分解开,不过它是物理上将其分开了,在部署和调试程序上相对比较困难,最头痛的就是RMI里头在调用完后会自己做一个System.gc()方法,将会导致Full GC,于此同时衍生出不同厂商不同系统的通信方法也是沿用EJB,是的各个工程里头都有和自己不想管的系统的代码和jar包,Perm区域增加的开销暂时忽略掉,不过系统的移植性和产品化就出现了很多困难(如果在另一个地方要发布同样的系统,但是这个系统中有很多外部调用需要,要么最后工程鱼龙混杂,要么要把这些东西分解出来是很困难的事情,甚至于会报一些诡异的错误)
    后来基于RPC的webservice出来了,它跨语言,因为它传递过程中你可以认为它不是传递对象(后来EJB也把它融进去了),不过我们很多时候还是喜欢用spring来集成它,高版本的webservice可以通过注解完成大部分的工作,不过tomcat发布这个玩意一直不是很好用;另外Spring里头也提供了对于RMI本身的封装的支持,以及spring hessian也是非常不错的交互框架,而且spring是轻量级的,越来越多的人开始选择spring了,因为EJB很多功能它都有,没有的大部分东西也不想要,用了EJB还有各种各样的问题
    最最简单的交互方法,HttpClient,这种是apache组织提供的一种非常轻量级的交互方法,其实也是基于socket写的,因为浏览器本身和服务器交互也是一种socket,只是建立了协议包头和一些短连接机制;所以HttpClient就是使用socket模拟的一个浏览器客户端发起的一次提交操作,可以发起Get和POST的请求,也可以控制参数的传递的字符集等等,传递和结果信息由双方决定;服务方只需要通过正常的response输出数据即可,只是这个时候不是输出一个页面,而是输出一些客户端可以被解释的数据,如json结构或xml结构的字符串信息。
    总之,系统一旦拆分,通信是避免不了,从这里也可以看出,并不是系统想怎么拆分就怎么拆分的,要尽量减少相互之间的通信,就需要了解系统,做到系统的低耦合、高内聚,减少外部依赖,不然系统大部分时间就在通信了,没有做其他的事情,不过也不排除有这种情况,那就是有些系统是专门用来做通信的,这种系统可以例外,它处理的核心就是通信处理,做中间转换。其余的业务系统尽量做到减少通信的模块数量。
         3.3系统拆分后单点的问题
     关于系统拆分后的单点问题,下面的文章会详细讲解
4.浅谈数据库拆分的策略
      首先,前端有压力,数据库自然也有,而且数据库压力肯定比前端压力会更多(当然前端可以采用很多缓存技术来环节数据库的压力),数据库的复杂性比前端要更多,因为它是数据的核心,需要对数据库的安全、一致性等做保障,
鉴于以上原因,需要对需要对数据库进行拆分,下面对数据库拆分进行简单的介绍
      4.1关系型数据库的拆分
           4.1.1数据跟随业务拆分,每个服务单独使用一个数据库Schema(垂直拆分)
           4.1.2简单的表分区,提高数据库查询的性能
           4.1.2如果数据量很大,数据库扛不住,还可能需要做缓存&数据库的水平拆分(相同的数据库分解到多个物理库中) 
                    传统应用中的range分区,如果用在分布式上,就是放在多个主机上的多个库上的多个表,这种用于自动增长列或时间上比较多,需要提前预知数据增长量,假设数据平稳增长
                    A中存储3个月的数据就达到上限,第四个月时开始添加B,以后几个月的几个月的数据全部落到B中,这种方式比较容易理解,
                   
                   但是存在一个比较严重的问题, 这种拆分Insert操作始终落在最后一台机器的最后一个表的最后一个block上,如果每秒有几千个insert和update、delete这样做肯定是不行的,热块将严重影响数据库的性能
                   为了解决热块的问题,开始对数据库进行负载均衡,负载均衡最常用的策略就是hash算法,hash算法最简单的就是求模,如将一个表拆分为100个表,那么按照绝大部分情况按照某个编号去求模得到的是0-99之间的数据,这一百个表编号为0-99,分别对应存储即可,无论是自动增长还是非自动增长也不太可能落在同一个表上面去;而对于某些热点用户,如果按照用户拆分,这些热点用户的访问就会被反复访问到同一个表,比如类似微博这种东西,也许某个热门人物的他的好友个数就会非常多,可能会导致某个表非常大,所以为了缓解这种问题,我们会再做二次hash;而对于一些非数字类的数据,我们一般会采取对其前几个字符的ascii或者hash值等取出来做操作,具体看实际情况而定;
                  
      
  4.2非关系型数据库的拆分
       非关系型的数据库的拆分以mongodb为代表,详细请参考


    

     



版权声明:文章中的观点或直接饮用,均会在下面列出
 
   
  





your support will encourage me to continue to create!
版权声明:自由转载-非商用-非衍生-保持署名(创意共享3.0许可证)