程序员过关斩将--论系统设计的高可扩展性
此文仅仅代表个人意见,并非行业标准
“MQ是万能的高扩展方式?
“面向接口是万能的高扩展方式?
说到系统设计的三高,每一高都是一个很庞大的话题,甚至可以用一本书甚至N本书来详细阐述。其中高可扩展性是系统架构的众多目标之一。归根结底,系统的架构要为最终的业务服务,脱离业务来谈架构其实比耍流氓更无耻。
在我们心目中最理想的软件架构要像搭积木一样简单,并且快捷,而且高效。但是现实往往比996更残酷,多数的系统在初期为了配合业务快速上线,扩展性这个指标并不理想。别的不谈,一个系统要完美的做到“对修改封闭,对扩展开放”其实一点也不简单,不知道你有没有遇到过修改一个bug蹦出另外一个bug的痛苦经历?
为了做到系统的高扩展性,其实有很多借鉴的案例,尤其是设计模式。但是今天我还是要说一说我自己的看法。无论什么样的系统,抽象起来其实都是模块和模块之间的交互,这里模块的含义是广义的,即可以代表函数,也可以代表进程,甚至可以代表目前流行的微服务,如下图所示
image
图是不是很简单?但是要想把A和B之间的交互做到高扩展其实并不容易,这要求系统的设计者必须要想办法在满足A和B正常交互的情况下尽量解耦A和B,只有正确的解耦,才能从容的应对A和B独立扩展的业务需求
同一进程内
在同一进程内的情况是一种最常见的存在方式,对应到我们平时的代码,表现为函数的调用,而这里的函数调用可以是同一模块内的函数调用,比如最典型的三层架构中,业务层调用持久化层来进行数据的操作,如下代码:
- //user 业务层
- public class UserBLL
- {
- UserDAL dal = new UserDAL();
- public int AddUser(User user)
- {
- //其他业务
- return dal.AddUser(user);
- }
- }
- //user持久化层
- public class UserDAL
- {
- public int AddUser(User user)
- {
- //进行数据库操作
- return 0;
- }
- }
我真的希望实际项目中的代码能像以上代码这么简单,毕竟代码就和项目一样,简单即是美。这段代码排除业务之外,从架构来讲也有很多问题,用开头的A和B的方式来表示,A代表的是UserBLL,B代表的是UserDAL,这里最容易看出的就是强耦合,即:A严重依赖于B,如果B有什么风吹草动,势必会影响A的执行。
怎么办呢?所以有了B的抽象层,对应到代码上是IDAL接口层,当然这个抽象层应该是稳定的,如果三天两头修改抽象层,那说明抽象的有问题。A在执行上改为依赖IDAL,这是系统内设计最常见的面向接口设计模式,其实更准确的说,应该是面向抽象设计模式。由于引入了稳定的抽象层,不再稳定的实现层就可以根据实际的业务去修改,这里体现的是系统设计中依赖倒置的原则,当然为了实现依赖倒置,你可能需要使用IOC等技术来实现项目落地。
- //user 业务层
- public class UserBLL
- {
- IUserDAL dal = "依赖注入";
- public int AddUser(User user)
- {
- //其他业务
- return dal.AddUser(user);
- }
- }
- //user的持久化层抽象
- public interface IUserDAL
- {
- int AddUser(User user);
- }
- //user持久化层
- public class UserDAL: IUserDAL
- {
- public int AddUser(User user)
- {
- //进行数据库操作
- return 0;
- }
- }
不同进程间
不同的进程之间互相协作是目前分布式模式下主要的交互方式,例如之前的SOA,现在的微服务,都是在利用分散在不同位置的模块来组装系统,这些模块之间的通信是一个分布式系统必备的条件。
和进程内函数调用类似,分布式系统也可以抽象为A和B的关系模型,我们要解决的也是A和B能够独立变化的问题。现在假设A服务依赖于B服务,B服务由于压力大需要扩容,会有哪些影响呢?
- B自己内部的状态变化,如果B服务是有状态的,扩展起来可能会设计到数据的迁移等操作,如果B是无状态的,理论来说可以很方便的横向扩展
- B的扩容对A或者其他依赖于B的系统有什么影响,依赖方能否做到自动适配,而不必修改任何配置
和进程内函数调用不同,进程间的通信需要通讯协议的支持,最常见的RPC调用都是基于TCP协议,Restfull基于http协议,使用这些协议底层都需要指定明确的IP和端口。所以需要某种解决方案在被依赖方扩展的时候,依赖方能够得到感知。聪明的你可能想到了“注册中心”,不错,这也是注册中心最主要的职责。
解决方案2
用注册中心的方式,理论上属于通知依赖方的方案,在依赖方感知被依赖方有扩展变动的时候,需要作出对应的变化。与之对应的其实我们也可以把变动封装在被依赖方,这个时候就引入了以下代理模式,最常见的就是网关模式。
分布式系统使用网关到底是好还是坏?
其实代理模式非常常见,比如Nginx做反向代理,数据库的中间件。这些设施都是对依赖方透明的,依赖方不会因为被依赖方实施了扩展而受影响。
解决方案3
目前很多业务下有一种很常见的场景,依赖方和被依赖方通信并不需要知道执行结果,最典型的场景像:新用户注册给用户发欢迎邮件或者短信欢迎语。如果业务代码中冗余了发邮件或者短信的代码的话,一旦要添加新的欢迎方式就必须要修改业务代码,无论你是否有抽象层,为了不影响主要的业务又最大化解耦系统,一般都会把这种非主要业务通过消息的方式分离出来。最常见的解决方案就是MQ。这也是典型发布订阅模式,但是这种模式如上所说,调用方并不能实时的得到业务处理结果。
利用MQ来进行系统的解耦,来实现系统的高可扩展是一种非常常见的方式,优势有很多,我不再阐述,但是需要注意消息的可靠性,因为消息经过了几个环节之后,难保某个环节出现问题而丢失消息。
写在最后
A和B之间的通信如果只是单向的话,可以理解为上下级关系,但是在微服务情况下,A和B很多时候是平行的互相调用的兄弟关系。有的架构师不赞成平行关系的微服务互相调用,这是有一定道理的,因为这很容易造成复杂的网络调用模式,如果是符合MQ消息的形式通信,我也推荐首推利用MQ来解耦服务间的依赖。
高可扩展性系统的最终目标是在应对业务变化的时候,用最小的代价去实现。而如何实现系统的扩展性,并非只有以上所说的“面向接口编程”,利用MQ这些方式,你还知道哪些可以帮助系统扩展的解决方案吗?欢迎你给我留言!!
“只要一提到解耦,有的“高手”一上来就说利用MQ,真的对吗?如果调用方需要实时的业务处理结果呢?
本文转载自微信公众号「架构师修行之路」,可以通过以下二维码关注。转载本文请联系架构师修行之路公众号。

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
加密技术竟然被人用来损害我们自己的利益
在不久前一则带着头盔看房的小视频出现在我们的视野前,在了解事情的前因经过后,我发现原本为消费者服务的科技在某些人手中似乎变了味道。当购房者进入到售楼大厅后,就已经进入到售房系统的人脸识别系统,并对购房者进行了“无感抓拍”。 为什么售楼处费钱、费力地对购房者进行抓拍,对于购房者这样抓拍又有怎样的意义呢? 通过搜索我们找到了专门有为售楼处定制人脸识别服务的公司,在客户进入售楼处大门时就自动抓拍客户人脸照片,并自动上传到人脸识别系统中。经过后台的数据比对了可以判断用户是否为老客户(之前来过),匹配成功后则系统自动调出该客户的姓名、性别等信息并将该信息推送到该客户销售顾问的手机上。如果为新客户则销售正常接待,并等级客户信息到数据库。 这些公司称客户人脸识别可以帮助售楼处更好的安排相关影响活动,各类销售活动,提供客户转换率。但是房企是怎么做的么? 一些社会经验丰富的朋友都知道,在买房前看好楼盘后,不要着急下单。可以四处了解一些中介的价格,最后可以省下不少的钱。这是因为购房者自己售楼处属于自然到访,在中介属于渠道到访。简单来说自然到访属于零售价,而货比三家后房子就变成了批发价。 售楼处对购房者进行...
- 下一篇
PBS(proxmox backup server)尝鲜记
作者:田逸(vx:formyz,mail:sery@163.com) 终于等到pbs发布正式版本pbs 1.0 ,迫不及待去官网下载好proxmox-backup-server_1.0-1.iso文件,将该文件放到我的proxmox VE的iso目录,创建好虚拟机,并以pbs镜像文件作为引导磁盘(当然,也可以克隆成u盘或者dvd光盘在物理服务器进行安装)。 前期规划 备份至少要考虑一下几个因素: 容量:评估好需要备份的虚拟机或者容器的总容量,预留足够的余量。比如虚拟机有10T,则建议备份可用容量为20-30T。 性能:影响备份写入性能的瓶颈有网络带宽、磁盘IO、内存大小等几个因素。为了获取更大的容量和更经济的成本,往往使用廉价的sata低转速硬盘。如果一次需要的虚拟机备份数量过多,必须考虑用ssd的方式在前端进行缓存以提高性能。就目前市场来说,内存价格已经比较低了,备份服务器配备64G内存代价也不高。网络方面,建议千兆及以上。 可用性:系统与备份存储空间分离,系统盘建议用ssd或者高速sas盘,两块盘做R_A_I_D 1(这也是敏感词服了!!!);备份数据的磁盘,至少做成R...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- Hadoop3单机部署,实现最简伪集群
- SpringBoot2整合MyBatis,连接MySql数据库做增删改查操作
- CentOS7编译安装Gcc9.2.0,解决mysql等软件编译问题
- SpringBoot2配置默认Tomcat设置,开启更多高级功能
- SpringBoot2整合Redis,开启缓存,提高访问速度
- Windows10,CentOS7,CentOS8安装Nodejs环境
- MySQL8.0.19开启GTID主从同步CentOS8
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- Eclipse初始化配置,告别卡顿、闪退、编译时间过长
- 设置Eclipse缩进为4个空格,增强代码规范