程序员过关斩将--论系统设计的高可扩展性

系统
说到系统设计的三高,每一高都是一个很庞大的话题,甚至可以用一本书甚至N本书来详细阐述。其中高可扩展性是系统架构的众多目标之一。归根结底,系统的架构要为最终的业务服务,脱离业务来谈架构其实比耍流氓更无耻。

[[354672]]

此文仅仅代表个人意见,并非行业标准

“MQ是万能的高扩展方式?

“面向接口是万能的高扩展方式?

说到系统设计的三高,每一高都是一个很庞大的话题,甚至可以用一本书甚至N本书来详细阐述。其中高可扩展性是系统架构的众多目标之一。归根结底,系统的架构要为最终的业务服务,脱离业务来谈架构其实比耍流氓更无耻。

在我们心目中最理想的软件架构要像搭积木一样简单,并且快捷,而且高效。但是现实往往比996更残酷,多数的系统在初期为了配合业务快速上线,扩展性这个指标并不理想。别的不谈,一个系统要完美的做到“对修改封闭,对扩展开放”其实一点也不简单,不知道你有没有遇到过修改一个bug蹦出另外一个bug的痛苦经历?

为了做到系统的高扩展性,其实有很多借鉴的案例,尤其是设计模式。但是今天我还是要说一说我自己的看法。无论什么样的系统,抽象起来其实都是模块和模块之间的交互,这里模块的含义是广义的,即可以代表函数,也可以代表进程,甚至可以代表目前流行的微服务,如下图所示

image

图是不是很简单?但是要想把A和B之间的交互做到高扩展其实并不容易,这要求系统的设计者必须要想办法在满足A和B正常交互的情况下尽量解耦A和B,只有正确的解耦,才能从容的应对A和B独立扩展的业务需求

同一进程内

在同一进程内的情况是一种最常见的存在方式,对应到我们平时的代码,表现为函数的调用,而这里的函数调用可以是同一模块内的函数调用,比如最典型的三层架构中,业务层调用持久化层来进行数据的操作,如下代码:

  1. //user 业务层 
  2.     public class UserBLL 
  3.     { 
  4.         UserDAL dal = new UserDAL(); 
  5.         public int AddUser(User user
  6.         { 
  7.             //其他业务 
  8.             return dal.AddUser(user); 
  9.         } 
  10.         
  11.     } 
  12.  
  13.     //user持久化层 
  14.     public class UserDAL 
  15.     { 
  16.         public int AddUser(User user
  17.         { 
  18.             //进行数据库操作 
  19.             return 0; 
  20.         } 
  21.     } 

我真的希望实际项目中的代码能像以上代码这么简单,毕竟代码就和项目一样,简单即是美。这段代码排除业务之外,从架构来讲也有很多问题,用开头的A和B的方式来表示,A代表的是UserBLL,B代表的是UserDAL,这里最容易看出的就是强耦合,即:A严重依赖于B,如果B有什么风吹草动,势必会影响A的执行。

怎么办呢?所以有了B的抽象层,对应到代码上是IDAL接口层,当然这个抽象层应该是稳定的,如果三天两头修改抽象层,那说明抽象的有问题。A在执行上改为依赖IDAL,这是系统内设计最常见的面向接口设计模式,其实更准确的说,应该是面向抽象设计模式。由于引入了稳定的抽象层,不再稳定的实现层就可以根据实际的业务去修改,这里体现的是系统设计中依赖倒置的原则,当然为了实现依赖倒置,你可能需要使用IOC等技术来实现项目落地。

  1. //user 业务层 
  2.     public class UserBLL 
  3.     { 
  4.         IUserDAL dal = "依赖注入"
  5.         public int AddUser(User user
  6.         { 
  7.             //其他业务 
  8.             return dal.AddUser(user); 
  9.         } 
  10.         
  11.     } 
  12.  
  13.     //user的持久化层抽象 
  14.     public interface IUserDAL 
  15.     { 
  16.         int AddUser(User user); 
  17.     } 
  18.  
  19.     //user持久化层 
  20.     public class UserDAL: IUserDAL 
  21.     { 
  22.         public int AddUser(User user
  23.         { 
  24.             //进行数据库操作 
  25.             return 0; 
  26.         } 
  27.     } 

不同进程间

不同的进程之间互相协作是目前分布式模式下主要的交互方式,例如之前的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,真的对吗?如果调用方需要实时的业务处理结果呢?

本文转载自微信公众号「架构师修行之路」,可以通过以下二维码关注。转载本文请联系架构师修行之路公众号。

 

责任编辑:武晓燕 来源: 架构师修行之路
相关推荐

2020-08-25 07:35:07

session分布式抽象

2020-12-29 08:01:22

安全登录系统

2020-09-01 08:10:47

高并发系统程序员

2020-12-15 08:05:02

redis单线程多线程

2021-03-03 07:29:00

开闭依赖倒置原则

2021-09-02 09:42:11

测试软件可扩展性开发

2023-12-20 09:26:20

高可用高吞吐高扩展性

2022-09-05 15:17:34

区块链比特币可扩展性

2020-11-03 07:43:24

MQ版本号程序员

2021-12-03 14:41:00

云存储可扩展性存储

2012-06-04 11:04:46

虚拟化

2021-05-17 07:28:23

Spring可扩展性项目

2016-10-13 14:38:51

OpenStack可扩展性IT人员

2021-12-09 05:36:16

云存储可扩展性数据存储云存储

2013-04-09 10:16:28

OpenStackGrizzlyHyper-V

2023-10-11 13:46:26

缓存Web应用程序

2009-04-20 11:33:47

光网络动态扩展

2017-01-05 19:29:10

公共云云存储微软

2023-05-17 15:53:21

2010-03-18 11:01:34

VMware
点赞
收藏

51CTO技术栈公众号