当前位置: 首页 > news >正文

【微服务过度拆分的问题】

文章目录

  • 微服务过度拆分的问题
    • 微服务泥潭
    • 为什么要独立的微服务?
    • 逻辑解耦
    • 逻辑设计
    • 总结

微服务过度拆分的问题

微服务应该是现代后台架构最流行的方式了。尤其在JAVA世界,用Springboot启动一个服务太方便了,加上SpringCloud各种组件能很好地管理很多的独立的服务。
之前我也写过一个文章:《软件开发随笔系列一——分布式架构实现》介绍。说明我本人也是对微服务架构是推荐的。
但凡事都有个度,过犹不及,身边很多朋友的项目,包括自己以前做的一些平台,陷入了微服务泥潭。

微服务泥潭

听到最多的抱怨就是:

  • 明明一个问题,却要改了五六个地方,经手好几个人,原来半小时搞定的问题,现在一周都搞不定!
  • 部署脚本缺失或者有问题的时候,部署一个十几个节点的平台就是天灾。

更要命的时候,往往很多小公司的平台,可能除了数据库之外,所有的应用节点都部署在一个物理服务器上。想想也是,现在一个应用平台,自己开发的不算,至少得部署一个数据库,Redis,Nginx,复杂一点的可能还会有Nacos,GateWay,Dubbo以及各种监控消息队列之类的。加上自己的服务被拆分成五六个,就被弄十几个服务了。

不谈那些工具类(不涉及自己开发代码的),可能一个订单支付,就会经过对应接入端的服务(如移动端API服务),订单服务,中间需要调用商品/库存服务,然后支付服务。

一个跨域多服务的简单例子

看起来很合理,确实也没啥问题。大厂出来的架构不都这样的吗,很合理啊。

只是,您真的需要这样的架构吗?

反正我是不需要的,我不认为我做的平台可以在几年内达到某宝某东乃至于小一些的平台的用户数和并发量。核心交易有个几百并发被压垮的我觉得我做梦都能笑醒了。这也是很多年前我听一个人说过的,他说:如果我的系统被用户多的并发压垮了,我高兴死了。

一个提示就是,现在的机器性能,加上一些手段,比如前后分离,OSS之类,静态访问几乎都不会到应用服务器了,只要一个简单的负载均衡策略(简单的Nginx软负载都没问题),克隆两三个相同的节点,几百并发压力基本上是毫无问题的。又不是银行核心系统,基本都是强一致性的交易。

那,干嘛要搞这么复杂?可能,别人的护城河,对自己来说就是洪水滔天的。

为什么要独立的微服务?

独立有必要吗?肯定有必要。从学面向对象初级入门开始,我们就知道“解耦”这个词。从一个类,一个组件,一个模块,一个子系统。在每一个层次,我们都努力去设计以实现“高内聚,低耦合”。关于这个词的内涵,不同人有不同的认识和解释,各有各的正确。

在我的理解,并且实践采用的,就一种方法——专家模式。每一个类,每一个组件,每一个模块,每一个子系统,都是某一方面的专家。也有人说专家会懂得太多,太复杂,那是爱因斯坦,不是专家。专家懂一个方面就够了。

一个类是一个专家,其实挺好理解的,完全跟面向对象一样,这个专家(类)掌握某些知识(属性)能做对应的工作(方法)。但是,越往高层,就越容易迷糊了。

一个问题是,这个模块该不该独立成为一个子系统,单独部署,单独运行?

对于财大气粗的公司,回答就是,该,必须独立!

但对于小公司,尤其刚起步的系统,先给他否定再说。先思考一下,都放到一个服务,有什么问题呢?好像完全没有问题吧,还简化开发维护成本。

可能有人说以后扩展不好。以后?有没有以后都不一定。为了缥缈的未来让现在负重前行,能有未来吗?再说,好不好扩展完全不是以是否独立成为微服务决定的!完全不是!设计的不好,扩展更费劲。好的设计,让你轻松可以分开也可以合起来。

所以,我通常给的建议是,非要独立做一个服务的,就是:

这系统是现成的,你要用它,就集成它,把它变成你系统的一个子系统/服务

当然,异构语言的又是另一回事了,比如你得用python写一个ai方面的服务,通过web api集成。这超越了Sping微服务的范畴了,但本质也是一样。毕竟现在异构语言组成的系统也不少。

一个自己新开发的模块,为什么要弄一个单独的服务,单独开发,单独部署,单独维护呢?有什么理由呢?作为应用的一部分,谁也没信心可以把这个模块开发的以后完全不需要修改不需要维护吧。

逻辑解耦

一个模块独立部署,很大程度上就是为了彻底的隔离,也就是解耦,这是好事。但实践上,大部分这种所谓的“解耦”并不是在很好的业务分析的基础上,而是单纯的“技术架构”的要求,比如硬性的分层要求,或者纯粹就是设计者的技术偏好。而这种偏好,却又是很大程度上没有真正下力气做好业务分析,划分好业务模块。当然,业务应用系统需求不断迭代,但是任何时候都会有一个快照反应你现在要做的,设计者努力做到的就是,不要一个新需求或者修改一个功能,导致所有模块都要去修改一遍。

但往往,出现的情况就是相反的:一个新需求或者修改一个功能,到处都要改。

我觉得造成这种问题,某种程度上跟软件开发可视化和低代码平台的普及有关系。很多系统从一开始就没啥设计,直接上手,视图直接从物理层直接解决现实世界的问题。反正轻松开发,轻松构建,轻松运行。直接跳过了概念模型和逻辑模型。

在这里插入图片描述
而我们知道,软件世界里面,从一个现实问题的提出到编码实现,是要经过抽象概念模型,设计逻辑模型,然后才对应有物理模型的。现在流行谈的DDD(领域驱动设计)其实也是这个意思。领域设计跟代码有关系吗?其实大部分工作没关系,最难的是什么?你要在设计图纸(可能更多是脑海里)推演需要哪些模块,哪些功能,模块如何交互,先后顺序什么样,都得有那些数据/参数,哪些数据需要持久化,甚至于模块的名字/表的名字/重要字段的名字都叫什么,才能更好体现业务含义。所有这些问题,都要在动手之前去推演,就烧脑了,就放弃了。毕竟,相对而言,直接写代码多轻松啊,现在还有AI助力,黏贴过来运行看看效果,一目了然。脑子里面去推演对错,太难了。

就造成了两种极端结果:

  • 所有逻辑揉在一起,完全看不出组件化、模块化的思路,一个交易流程在各个包之间来回乱窜。
  • 直接拍脑门看名字大概意思就分成多个微服务,先切了再说。

帮很多公司处理老旧系统问题(多数是原来的核心开发走了之后,新加功能或者修改问题搞不定,无从入手),第一步肯定要梳理交易流程的,碰到第一种情况,其实是挺好的。第二种情况的,基本上梳理的时间精力加倍都不止。梳理清楚之后,对比开发工作量也是数倍。

为什么需要逻辑设计(认为软件开发就是复制黏贴的就不要继续看了,我认为软件架构设计是人类脑力活动的最高精华)?没有逻辑设计就做不到逻辑解耦。能逻辑解耦,意味着:

  • 现在系统还小,并发不高,可以快速低成本的完成系统开发维护;
  • 新增业务需求之后,能快速定位应该在什么地方增加什么内容;
  • 出现问题能快速定位问题在哪里,并能最大可能限制问题只在一个可控的局部范围,不需要到处修改;
  • 真的到那一天,并发暴增,需要拆分的时候,把模块代码已复制,加个壳子就独立成为服务;

逻辑设计

我最反感的一句话就是,敏捷开发不需要文档。什么是文档?文档就是设计过程。可以各种方式方法去帮助设计,呈现设计。但必须有设计。如果有人认为软件开发就是搬砖的活,有手就行,那就请他自己去搬。

关于设计,之前也写过一个文章《软件开发随笔系列二——关于架构和模型》有兴趣的可以去看看。

设计方式和文档呈现样式千千万,我最喜欢的就是画图,对,就是普通的线框图,方框+直线/折线的那种(数据模型用E-R另说)。设计就是推演的过程,推演完成,图纸呈现。我最关注的图两个:

  • 功能布局图:一个方框表示一个模块,里面包含什么功能,方框之间有连线,表示模块之间有关系,这是一种静态的关系图,体现应该有什么模块(功能),和模块(功能)之间的关系。
  • 核心流程图:对,就是古老的流程图,做一个系统肯定有核心流程,否则不用做了,比如电商的核心流程肯定是用户看到商品到支付完成的过程,核心流程都画不明白,做肯定也是瞎做;用流程图,时序图,泳道图都没关系。

看一个功能布局图,如果你觉得不优雅,肯定就不是好的设计,一般不优雅,我觉得最重要体现在连接线是不是太多,尤其:

  • 一个模块跟外面的连线太多,显然难看
  • 线有过多的交叉,更加难看

所谓“优雅”一个小的技巧就是,画联系线的时候,可以用直线,可以用折线,但尽量不要让线条交叉,基本上有交叉的,都说明关系太混乱。关系混乱,基本表示解耦不成功。

功能布局图弄完之后,核心流程图存在的一个价值就是验证功能布局,看看这个流程的实现,是一种主控式发起的(一个主控模块依次调用各个模块),还是链式的(一个一个模块的去调用),其实都无所谓。怕的是:

  • 一个交易要经过很多很多的模块,比如十几个,一般就恶心了
  • 一个交易中反复穿过同一个模块,这就彻底没解耦了

最后自己觉得优雅了,基本上就是一个好的设计了。

总结

好的设计,才是软件的根基。分布式架构非常好,而且天然的帮我们解决了很多问题。微服务架构更是简单便捷的利器。

但是一个业务系统没有自己的设计,直接往标准架构上直接套,硬去切割成多个微服务,还不如不分,一个整体应用打包更容易维护。

不知道怎么选择的时候,往往多不如少。

软件架构的设计是一个非常烧脑的过程,说不需要设计的人基本上是自己设计不了而已;试错式的开发只会把成本无限增加,并不是解决所谓业务快速发展的良药。

设计文档/图纸不一定需要交付给谁,首先是帮助自己设计软件的工具,更是锻炼自己逻辑思维、推理能力的工具。

http://www.lryc.cn/news/619050.html

相关文章:

  • web服务器tomcat内部工作原理以及样例代码
  • Airtable 入门指南:从创建项目到基础数据分析与可视化
  • C++中类之间的关系详解
  • LangChain 入门学习
  • 【限时分享:Hadoop+Spark+Vue技术栈电信客服数据分析系统完整实现方案
  • Docker概述与安装Dockerfile文件
  • Docker使用----(安装_Windows版)
  • 第二章:核心数据结构与面向对象思想之接口的奥秘
  • 3 Abp 核心框架(Core Framework)
  • Milvus 结合极客天成 NVFile 与 NVMatrix 实现高性能向量存储
  • LDAP 登录配置参数填写指南
  • 【VB.NET快乐数】2022-10-17
  • (树形 dp、数学)AT_dp_v Subtree 题解
  • 5年保留期+4次补考机会,灵活通关的申研机制
  • 【CV 目标检测】②——NMS(非极大值抑制)
  • git+lfs 如何安装
  • 股票智能体系统的设计与开发
  • Vue3 组合式API vs 选项式API:深度对比与最佳实践
  • SQL连接操作全解析:从入门到精通
  • 自动驾驶决策算法 —— 有限状态机 FSM
  • 基于SpringBoot的旅游网站系统
  • Jenkins + SonarQube 从原理到实战三:SonarQube 打通 Windows AD(LDAP)认证与踩坑记录
  • Linux内核进程管理子系统有什么第二十六回 —— 进程主结构详解(22)
  • 基于51单片机RFID智能门禁系统红外人流量计数统计
  • 【K8s】K8s控制器——Deamonset、Statefulset、Job与CronJob
  • 下一代防火墙部署
  • 树结构无感更新及地图大批量点位上图Ui卡顿优化
  • C#对接Ollama,调用大模型禁用思考模式
  • JMeter并发测试与多进程测试
  • pcl 按比例去除点云的噪点