分布式和集群之间的对比
单机服务器
业务系统做了模块化设计,每一个模块都包含很多特定的业务。
拿聊天服务器举例子,一个server上,有若干个模块构成,比如,用户管理、好友管理、群组管理、消息管理、后台管理模块。每一个模块都包含特定的业务,比如用户管理模块就包含用户的登录(通常用一个方法来做登录业务),再如用户的注册、用户的注销。好友管理模块包含添加好友、删除好友;群组管理包含加群、创建群、删除群成员等等;消息管理包含离线消息、一对一聊天消息、群聊消息;后台管理包含广播消息等。
问题:单机服务器在性能、设计上有何瓶颈?
- 聊天服务器所能承受的用户的并发量受限于硬件资源。比如32位服务器,最多支持2w多人同时在线聊天,即直接受限于socket资源。
- 所有模块耦合在一个单体服务器上,如果修改任意一个模块,哪怕是几行代码,都会导致整个项目代码重新编译、部署。
- 各模块对于硬件资源的需求不一样。有些模块属于CPU密集型(计算量大),有些是属于IO密集型的。CPU密集型模块应当部署在CPU性能高的机器上,IO密集型则对CPU性能要求不高,而是需要内存资源多、带宽大的机器。
集群服务器
现在,把同一个服务器程序,独立地运行在三个服务器上,分别是server1、server2、server3,每一台服务器都是一套独立的聊天系统。
解决了单机服务器的问题1,提升了用户的并发量。但是没有解决问题2,如果需要修改代码,仍需重新编译,只不过只需要编译1份,但是仍需重新部署在多台服务器上。针对问题3,单纯的集群只是水平地扩展硬件机器,每一台机器上的程序并没有分模块去针对性地分配硬件资源。
比如,后台管理使用的用户并不多,只有极个别的管理员才能使用,因此此模块根本不需要高并发。如果将后台管理部署在每一台服务器上,可能会浪费硬件资源。
因此,可以想到,如果不能很好地分配集群环境中的机器资源,可能不能把整体系统的性能发挥到最大,即不分模块进行部署则不能充分利用全部资源。
优点是,部署很简单,因为没有过多的设计,每台机器的部署方式是一样的,直接运行同一个程序即可。
分布式服务器
现有三台服务器,server1部署用户管理、消息管理模块;server2部署好友管理、群组管理模块;server3部署后台管理模块。
相对于集群服务器,如果server2失效,整个系统仍可以正常运行。而如果分布式系统中,任何一个服务器失效,都会造成整个系统的失效。因此,分布式系统是所有服务器共同构成一个聊天系统,给客户端提供服务。因此也把每个服务器称为分布式节点。
解决了问题2,因为分模块部署,如果只修改了某一模块的代码,只需要部分编译,只需要对某一节点进行单独的部署。
解决了问题3,比如节点3后台管理模块包含CPU密集型业务,则其对应的机器可以针对性增加CPU性能,相对地减少内存资源、网络带宽资源。相反的,节点1的用户管理、消息管理模块对应的机器增加内存资源、网络带宽资源,而不需要过高的CPU性能。如此,可以有利于硬件资源的合理分配。
分布式+集群服务器
根据节点的并发要求,可以针对某一节点再做节点模块集群部署。
分布式节点1主要负责用户连接、信息传递的处理,对并发量要求大,所以此时我们需要针对此节点进行扩容,即增加服务器同样部署用户管理、消息管理模块。
而且,也可以灵活的调整不同节点的职责,比如,可以同样在节点2上部署用户管理模块,当节点1失效时,可以启用节点2的用户管理模块。
带来的挑战
- 软件设计:需要设计整个系统的软件模块划分,否则各模块可能会实现大量重复的代码
- 框架设计:各模块之间如何访问、通信?各模块都运行在不同的进程里,比如好友管理模块、群组管理模块。需要一个机制使函数调用透明化。
分布式系统框架解决的问题
比如,节点1负责完用户的登录后,需要获取好友列表,则需要一个机制访问节点2上的好友管理模块。节点1上的模块怎么调用机器2上的模块的一个业务方法?机器1上的一个模块进程1怎么调用机器1上的模块进程2里面的一个业务方法?
需要在网络上传递函数的标识,函数复杂的参数的数据给其他机器。其他机器执行完毕后,返回数据的过程也是需要在网络上传递给调用方机器。
这个过程很复杂,因为有可能每个传递过程都会存在网络异常问题,需要有机制去告诉调用方传输状态。所以,需要把整个过程封装到分布式网络通信框架之中。则在用户看来,调用远端的方法就和调用本地进程内的方法一样简单,不用关注具体细节。
总的来说,分布式是为了克服部署解耦化、资源分配最大化而生。而实现分布式框架需要封装网络通信的具体细节,尤其是,一,传递函数的标识,函数复杂的参数的数据给其他机器,二,需要有机制去告诉调用方每一个传递过程中的传输状态。