分布式架构之系统拆分

article/2025/10/3 0:46:00

系统拆分是单体程序向分布式系统演变的关键一步,也是很重要的一步,拆分的好坏直接关系到未来系统的扩展性、可维护性和可伸缩性等,拆分工作不难理解,但是如何正确拆分、有什么样的方法和原则能帮助我们拆分得到一个我们理想中的系统:高可用、可扩展、可维护、可伸缩的分布式系统。

MartinFowler的《重构改善既有代码的设计》一书给重构的定义:在不改变代码外在行为的前提下,对代码做出修改,以改进程序的内部结构。拆分也是在不改变系统行为的前提下,对系统进行各种拆解,所以可以看出拆分就是重构,是重构的一种方式。

这里主要从三个方面来分析系统拆分工作:拆分需求、拆分原则和拆分方法;

一、拆分需求

什么情况下系统才需要进行拆分? 当然并不是所有的系统都需要拆分,也并不是所有的系统都适合进行拆分,因为系统拆分是一个耗时、耗力又风险比较高的工作,在决定对系统进行拆分前,多问自己几次真的需要进行拆分吗?还有其它更好的方法吗?

拆分的需求主要来源于下面几个方面:

1、组织结构变化:从最初的一个团队逐渐成长并拆分为几个团队,团队按照业务线不同进行划分,为了减少各个业务系统和代码间的关联和耦合,几个团队不再可能共同向一个代码库中提交代码,必须对原有系统进行拆分,以减少团队间的干扰。

2、安全:这里所指的安全不是系统级别的安全,而是指代码或成果的安全,尤其是对于很多具有核心算法的系统,为了代码不被泄露,需要对相关系统进行模块化拆分,隔离核心功能,保护知识产权。

3、替换性:有些产品为了提供差异化的服务,需要产品具有可定制功能,根据用户的选择自由组合为一个完整的系统,比如一些模块,免费用户使用的功能与收费用户使用的功能肯定是不一样的,这就需要这些模块具有替换性,判断是免费用户还是收费用户使用不同的模块组装,这也需要对系统进行模块化拆分。

4、交付速度:单体程序最大的问题在于系统错综复杂,牵一发而动全身,也许一个小的改动就造成很多功能没办法正常工作,极大的降低了软件的交付速度,因为每次改动都需要大量的回归测试确保每个模块都能正确工作,因为我们不清楚改动会影响到什么,所以需要做大量重复工作,增加了测试成本。这时候就需要对系统进行拆分,理清各个功能间的关系并解耦。

5、技术需求:

1)单体程序由于技术栈固定,尤其的是比较庞大的系统,不能很方便的进行技术升级,或者说对引入新技术或框架等处于封闭状态;每种语言都有自己的特点,单体程序没有办法享受到其它语言带来的便利;对应到团队中,团队技术相对比较单一。

2相比于基于业务的垂直拆分,基于技术的横向拆分也很重要,使用数据访问层可以很好的隐藏对数据库的直接访问、减少数据库连接数、增加数据使用效率等;横向拆分可以极大的提高各个层级模块的重用性。

6、业务需求:由于业务上的某些特殊要求,比如对某个功能或模块的高可用性、高性能、可伸缩性等的要求,虽然也可以将单体整体部署到分布式环境中实现高可用、高性能等,但是从系统维护的角度来考虑,每次改动都要重新部署所有节点,显然会增加很多潜在的风险和不确定定性因素,所以有时候不得不选择将那些有特殊要求的功能从系统中抽取出来,独立部署和扩展。

上面通过从团队、产品、交付、技术以及业务方面分析了系统拆分的需求,从更大的范围来看,拆分可以分为两种:纵向和横向。纵向拆分主要从业务角度进行,根据业务分割为不同的子系统;而横向拆分侧重于技术的分层,每个层级的技术侧重点不同,可以充分发挥和培养团队中每个人的技术特长。

二、拆分原则

有了拆分需求,下面就要对系统进行拆分了,面对动辄百万行代码的系统,我们从哪里下手呢?要注意哪些问题?等等一系列问题接踵而来,下面就介绍几个系统拆分的基本原则,可以帮助我们快速的开始对系统进行拆分:

1、业务优先:每个系统天然都会按业务功能分成多个模块,每个模块又包含许多业务相关的功能,在系统拆分时,我们就可以优先考虑按照业务边界进行切割,切割完成后再针对每个模块进行拆解,循序渐进,逐渐迭代深入,最终完成系统的拆解。这个过程类似庖丁解牛,要找到关节之处下刀,方能事半功倍。

2、循序渐进:系统拆分过程中包含两个非常重要的工作:拆分和测试。二者缺一不可,并且二者是并行进行的,一定要边拆分边测试。每一步拆分完成都要保证系统功能是完整的,保证系统的测试是完整的。拆分要小步前进,如此以来可以减少累计错误的发生。这一点在《重构》这本书中也讲到了。

3、兼顾技术:系统不能为了分布式而分布式,系统拆分的代价相当昂贵;当然如果有拆分的需要,我们也不能白白浪费这么好的学习机会:

重构:拆分过程不仅仅是业务梳理的过程,也是系统进行重构的过程。通过系统的重构我们可以使用一些模式让代码结构更清晰,具有更好的可读性,并且方便日后的修改。

分层:拆分可以让系统分解为许多功能单一的系统,这些系统可以根据需要使用不同的技术和架构进行实现,可以让熟悉不同技术的人做不同的事,工作更高效,产品质量也可以提高。比如那些熟悉UI技术的人可以专注用户体验方面的研发,那些JAVA,C++方面的专家就可以把精力放在服务端程序的开发上,而那些熟悉数据库技术的人就可以话更多精力在数据库的优化上,术业有专攻,合适的人做合适的事。

4、可靠测试:“重构之前,首先检查自己是否有一套可靠的测试机制,这是MartinFowler在《重构》这本书中说到的,它同样对系统拆分有效。拆分是在对系统进行大手术,每一次的改动都要保证系统保持原来的行为不变。测试使得我有足够的信心进行下一步的拆分或重构,不至于在错误的道路上越走越远,以至于错误累积。测试与拆分如影随形,每一步都要有足够的测试。没有测试的拆分和重构我真的不敢想象结果会是什么样子。

三、拆分方法

前面介绍了那么多,都在为拆分做准备,如何进行拆分这才是重点。拆分分为数据拆分和功能拆分。数据拆分主要指数据库的拆分和数据访问对象的拆分。在系统拆分过程中,一般情况下我会先进行数据拆分,难后再进行功能拆分。

数据拆分

首先对数据库按照业务进行拆分,把需要拆分的业务的相关表放到一个新的数据库中,但是保持上层系统结构不变(如下图)。

 

数据库的拆分相对于业务的拆分来说比较容易,对系统的影响也容易判断。拆分数据库时,对于一些公共数据(既出现在A系统又出现在B系统或者其它系统的具有公共属性的数据表),可以分两步进行处理:

第一步、在AB系统中保留两份相同的数据,注意这里指的是具有公共属性的表,不包括那些与业务相关的数据表,虽然业务数据也会被其它模块引用。拆分过程一定要把握好业务边界,只有定义清晰的业务边界才能拆分出具有清晰定义的模块,这一点非常重要。

第二步、处理公共数据,主要有两种方式:

1、        建立公共服务模块

将这部分数据连同业务拆分为独立的服务模块,通过API对外提供服务,在系统拆分或重构的过程中,很有必要首先将一些公共的基础功能拆分为基础服务。如果将系统拆分工作看作是一个主干,那构建公共服务模块的工作就是一些分支,拆分的过程需要处理大量的公共功能,因为拆分就是要将不相关的功能分开,把相关的功能合并的过程。做完这些公共模块的工作还是要回到主干继续下面的工作。

2、  对于不需要抽象为公共服务的数据,可以保持一定的数据冗余,但是冗余的数据拷贝数不要太多,这会对数据同步提出很高的要求;根据数据的不同使用不同的数据同步机制确保各个模块中数据的一致性,至于要实现强一致性还是最终一致性要根据业务需求来定,不同的数据库在数据一致性方面的都有相关的实现,这里不再赘述。

第三步:建立数据服务层,在拆分后的数据库基础之上建立一层数据服务层,对数据库访问进行封装和隐藏,对外提供数据访问接口。

 

功能拆分

      完成数据拆分后,就可以开始业务的拆分;拆分过程中需要坚持一个基本原则:高内聚、低耦合。拆分的实际工作就是解耦,下面主要介绍基于Proxy-Façade模式的系统拆分方法:

1)找出A模块中对其它模块的调用或引用,在A模块中建立一层代理(Proxy),用于代理A对其它模块的访问,所有的外部访问都需要通过这些代理对象实现。

2)找出所有外部模块对A模块内的类和对象的调用或引用,同样在A模块内建立一些Façade类,其它模块对A模块的访问都需要动过Façade类, Façade类隐藏了A模块的内部实现细节。

 

为什么使用Proxy-Façade模式?Proxy-Façade模式的优点在哪里?

系统拆分最重要的目标就是要实现服务化,隐藏模块内部的实现细节,以接口形式提供服务和使用服务,实现高内聚低耦合的目的。Proxy-Façade模式可以很好的满足这一目标,Proxy将模块与外部模块的通信进行封装和隐藏,使用方不用关心对方的业务实现,通过Proxy就像直接与相应的模块在通信;Façade隐藏了模块的内部实现细节,对外提供友好的接口。Proxy-Façade模式不仅可以隐藏业务细节,还可以隐藏通讯实现,使用方无需关心服务是本地调用还是通过RPC的远程调用。Proxy-Façade模式不仅实现业务的高内聚而且也能够保证模块间的低耦合。

至此我们已经知道了如何拆分一个系统的方法和原则,但是实际拆分工作会非常复杂和繁琐,比如接口的膨胀化、接口的改变、重复业务的重构等;我们有时候将重构和拆分比喻为表面风平浪静下面却暗流涌动的海洋。


http://chatgpt.dhexx.cn/article/RveCvviZ.shtml

相关文章

水平拆分

水平拆分 概述水平分库示例水平拆分的优点水平拆分的缺点分片原则 概述 水平拆分指的是通过某种策略将数据分片存储,包含库内分表和分库两种,每片数据会分散到不同的MySQL表或库,达到分布式的效果,能够支持非常大的数据量。前面的…

微服务拆分策略

拆分策略可以按功能和非功能维度进行考虑,功能维度主要是划分清楚业务的边界,非功能维度主要考虑六点包括扩展性、复用性、高性能、高可用、安全性、异构性。接下来详细介绍下。 1、功能维度 功能维度主要是划分清楚业务边界,采用的主要设计…

微服务拆分

如何定义一个微服务架构?通常情况下,定义应用程序架构分三步。但是,世界上并没有一个机械化的流程可以遵守,然后指望这个流程输出一个合理的架构。这里只能介绍一个笼统的方法,现实世界中,这是一个不断迭代…

每日一题:为什么要进行系统拆分?

原文来自 GitHub 开源社区 Doocs,欢迎 Star 此项目,如果你有独到的见解,同样可以参与贡献此项目。 面试题 为什么要进行系统拆分?如何进行系统拆分?拆分后不用 dubbo 可以吗? 面试官心理分析 从这个问题开始…

个人对系统拆分的理解

在本人现在的公司和本人工作过的上一家公司,本人有幸参与并实施了公司业务系统的架构拆分,现将之前的工作总结下。 1,为什么要进行系统拆分 首先我们需要想想,到底什么样的系统需要进行拆分?并不是所有的系统都需要进…

登录+注册界面的实现(代码)

先看效果图&#xff01; 话不多说&#xff0c;直接上代码&#xff01; //布局文件&#xff1a;activity_login.xml <?xml version"1.0" encoding"utf-8"?> <RelativeLayout xmlns:android"http://schemas.android.com/apk/res/android&qu…

简单WEB登录页面代码实现

longin.html&#xff1a;登录页面&#xff0c;此处action引用**/**类型的地址&#xff0c;JSP可以用${ pageContext.request.contextPath }/LS <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd&qu…

编写简单的登陆页面

1.简单登录界面&#xff08;自己设置css样式&#xff09; 代码如下 <form id"loginForm" action"#" method"post" novalidate"novalidate"><div class"login_box"><div class"login_box_left"&g…

实现网页登录代码

python 一、前言 本文通过selenium工具实现工作所用网站的自动登录&#xff0c;下图为网站登录界面。 1、运行环境 操作系统&#xff1a;Windows10 python版本&#xff1a;python3.7 2、需要的python第三方库 1、selenium 安装&#xff1a; pip install selenium selen…

【html】【一个简单的用户登录页面代码】

结果 代码 <!DOCTYPE html> <html><head><title>用户登录.html</title><meta http-equiv"keywords" content"keyword1,keyword2,keyword3"><meta http-equiv"description" content"this is my pag…

html 【一个简单的用户登录页面代码】

效果图 <!DOCTYPE html> <html><head><title>用户登录.html</title><meta http-equiv"keywords" content"keyword1,keyword2,keyword3"><meta http-equiv"description" content"this is my page&…

简单登录页面html代码

【实例简介】 js/html基础示例&#xff1a;简单登录页面 【实例截图】 【核心代码】 文档&#xff1a;590m.com/f/25127180-496787472-732294&#xff08;访问密码&#xff1a;551685&#xff09; 以下内容无关&#xff1a; -------------------------------------------分…

登录界面源代码

拿走请三联&#xff0c;并注明出处&#xff01; 没有上传原背景图&#xff0c;使用的话需自己更改图片名称 可连接注册界面&#xff0c;和用户照片墙&#xff0c;此文只有登录界面代码&#xff0c;代码存在些许问题&#xff0c;望观看的大佬们多多指教&#xff01; <!DOC…

python实现网站的自动登录(selenium实现,带验证码识别)

python实现网站自动登录&#xff08;selenium实现&#xff0c;带验证码识别&#xff09; 一、前言 这是鄙人写的第一篇博客&#xff0c;旨在总结一下近期所学&#xff0c;本文通过selenium工具实现工作所用网站的自动登录&#xff0c;下图为网站登录界面。 1、运行环境 操作…

登录页面的代码

登录页面的代码 在把页面和数据库做好之后&#xff0c;我的登录页面只需要 用户名和密码 &#xff0c;所以代码比较简单。 先找到登录按钮&#xff0c;给一个点击事件&#xff0c;然后再获取他们的表单值&#xff0c;然后对用户名和密码进行判断&#xff0c;判断是否填写了资料…

核函数(多项式,高斯核)以及svm解决回归问题

文章目录 一、SVM最优化问题转换1、多项式核函数 二、高斯核函数1.引入库1、多项式特征2、高斯核函数升维举例3、高斯核函数超参数gamma 三、svm解决回归问题总结 一、SVM最优化问题转换 变换为数学上一个更好解的 在这个式子中有重要的一项Xi&#xff0c;Xj 两个样本的点乘…

高斯核-高斯模糊

大白话高斯模糊 以二维高斯为例&#xff0c;公式&#xff1a; 高斯模糊的原理,可以理解成每一个像素都取周边像素的加权平均值 以高斯分布取g矩阵的值得到的模糊方法即为高斯模糊 权重矩阵 假定中心点的坐标是&#xff08;0,0&#xff09;&#xff0c;那么距离它最近的8个点的…

数值实验-高斯核函数 python/matlab 实现

支持向量机 支持向量&#xff1a;支持平面把两类类别划分开的超平面的向量点机&#xff1a;一种算法SVM 是一种二分类模型线性可分支持向量机&#xff1a;通过硬间隔最大化&#xff0c;学习一个线性分类器线性支持向量机&#xff1a;通过软间隔最大化&#xff0c;学习一个线性…

CS131专题-2:高斯核、噪声、滤波

目录 1 高斯核 1.1 一维定义 1.2 二维定义 1.2.1 应用高斯核的过程 1.2.2 不同σ值的高斯核情况 1.2.3 不同核宽度情况 1.2.4 高斯核&#xff08;滤波&#xff09;特性 1.2.5 使用高斯核做平滑滤波相对箱式滤波的优点 2 噪声 和 滤波 2.1 椒盐噪声、脉冲噪声 2.1.1 …

python高斯核函数_机器学习:SVM(核函数、高斯核函数RBF)

一、核函数(Kernel Function) 1)格式 K(x, y):表示样本 x 和 y,添加多项式特征得到新的样本 x、y,K(x, y) 就是返回新的样本经过计算得到的值; 在 SVM 类型的算法 SVC() 中,K(x, y) 返回点乘:x . y 得到的值; 2)多项式核函数 业务问题:怎么分类非线性可分的样本…