微服务到回归大单体

微服务到回归大单体

近些年来,刮起了一股微服务浪潮,企业中不管项目和团队的大小,都喜欢往无服务上靠,一股“逃离单体”之风兴起

一:业界标准的设计原则

微服务架构设计原则旨在提高系统的可维护性、可扩展性、可靠性和稳定性

除下面列出的内容外,业界还提出了许多其他理论,如AKF、BFF、DDD……

因为这些提到的设计原则,乍一听觉得头头是道,可却有点过于理想化了,毕竟实际项目会更加错综复杂,很难将提到的这些完全落地。

为此,大家在设计微服务系统时,这些原则可以作为适当参考的准则,但不能奉为必须落实的真理!

1:单一职责原则 SRP

每个微服务应该只负责一个明确的业务功能,而不是多个功能

这有助于保持服务的内聚性,并减少服务之间的耦合。

这样做能确保每个服务都专注于一个明确的业务领域,从而使其更加简单、可维护和可扩展

2:隔离性原则

微服务应该被设计为独立的进程,具有自己的数据库和其他资源

这可以确保一个服务的故障不会影响其他服务的正常运行。

这样做能提高系统的稳定性和可靠性,减少故障传播的风险

3:可伸缩原则

微服务应该能够在需要时水平扩展,以满足高负载和流量的需求

这意味着微服务应该被设计为可重复部署的、自治的服务单元。

这样做能确保系统能够灵活地应对负载变化,提高系统的可扩展性和可用性

4:可以替换性原则

微服务应该被设计为可替换的。

这意味着当一个服务不再满足需求时,应该能够轻松地将其替换为一个新的服务

这样做能提高系统的灵活性和可维护性,允许在不影响整个系统稳定性的情况下进行服务的升级和替换

5:可重用原则

微服务应该被设计为可重用的,这样其他服务或系统可以通过API访问它们

这有助于避免重复的代码和功能。这样做的好处是促进服务的共享和复用,减少重复开发和维护的成本

6:容错性原则

微服务应该被设计为容错的,以便在系统的某个部分失败时,整个系统可以继续正常运行

这意味着微服务应该有备用的服务或机制来处理故障。

这样做的优势在于:提高系统的可靠性和稳定性,确保在部分服务出现故障时,系统仍然能够继续提供服务

7:开闭原则 - OCP

微服务应该对扩展开放,对修改封闭。

这意味着在需要添加新功能时,应该通过添加新服务来实现,而不是修改现有的服务

这样做的好处是:保持系统的稳定性和可维护性,减少因修改现有服务而引入的潜在问题

8:服务自治性原则 - SAP

每个微服务都应该是自治的,即它应该包含其自己的数据和业务逻辑,而不依赖于其他服务

这样能提高服务的独立性和可维护性,减少服务之间的依赖和耦合

9:微服务独立性原则 - SIP

每个微服务应该是独立的,既不应该共享数据库或其他资源

相反,它们应该通过定义接口来进行通信。

这样能确保服务的独立性和可扩展性,减少因共享资源而引入的潜在问题

10:微服务可观察性原则 -SOP

每个微服务都应该是可观察的,即可以通过监控、日志记录和指标来追踪其性能和健康状况

这样做的好处是:提高系统的可维护性和可管理性,帮助开发人员和运维人员及时发现和解决问题

11:微服务部署可重复性原则 - SDRP

每个微服务都应该可以重复地进行部署,以确保系统的可靠性和稳定性

这样的好处是:提高系统的可部署性和可维护性,确保在部署过程中不会引入新的问题

二:饱经摧残后的感慨

1:服务过度拆分带来的痛

每个微服务都由一个专门的团队维护,大家都围绕着漂亮的、向后兼容的API开展工作,对接其他服务时,就好像这个微服务是由一个第三方供应商维护的一样,这是理想化的微服务自治状态。

可真正对接时,就会出现各种拉人进群讨论的现象,群里一开始只有十多个人,在实现业务需求的过程中,会不断拉入其他团队成员,最后群成员数增加到近百……

群聊中充斥着来自不同团队的消息,这些消息涉及发布、错误、配置更新、破坏性更改等。

在这种环境下,本来一个半天能做完的小需求,几个团队协调沟通下来,硬生生得两三天才能捣鼓好

2:盲目跟风微服务之殇

平均日活寥寥三位数,用户总体量也才数万,可是技术Leader大手一挥,分布式/微服务技术哐哐往架构图上画,最终拆分出十多个服务,可是整个开发团队的后端只有几个人,一个人就要负责好几个服务。

更离谱的是,光产品经理设计的一个列表页面,甚至都要横跨数个服务才能得到数据……

其次,有时想要用到某个功能/逻辑时,回想起自己好像写过了,结果一翻代码,却发现在另外一个服务里,自己调用自己写的代码,还需要封装一层远程接口才行。

这时,所谓的服务自治好像成了笑话,所谓的自治,变成了自己治自己。

除开这些与业务有关的问题外,你还会发现,有时代码突然就跑不起来了、服务之间貌似调用不了了、保障并发安全的锁也失效了、中间报错导致数据不一致了……

熬到项目上线时,拆好的十多个服务,加上一些例如注册中心、配置中心、数据库、中间件等基础组件,要部署到线上的节点数接近二十个,项目在线上运营一年,甚至连运维成本都没赚回来

3:跟风微服务背后的真正原因

一开始使用微服务架构,是奔着更灵活的拓展性、更松散的耦合性、不同业务的自治性等目标去的。

可到头来却发现,尽管微服务带来了不少好处,但是需要解决的问题同样不少,如并发安全、链路追踪、服务治理、数据一致性、故障监控等等,这些问题往往要投入大量精力去处理

除开要花费大量心思去解决非业务性的技术问题外,微服务还会让系统变得更复杂,以及带来更高的运维成本、沟通成本,尤其是当一个需求要基于多个服务实现、且维护各服务的团队相互独立自治,你就会发现沟通成本反而大大超出开发成本,因为你需要去协调各个团队排期支持,这样才能保证需求能正常推进

分布式/微服务带来的这一系列技术问题、现实问题,放在单体架构里并不存在,那你为什么要上微服务而不用单体架构?也许有人会搬出广为流传的那套观念,如支持异构、边界明确服务自治、更灵活的拓展性……。可除了那些人多、钱多、规模大的项目外,90%中小型项目在这些观点上站不住脚,那么你规模不大的项目为啥用微服务?

为啥用?不知道啊,看外面都在用,领导和同事也说要用,就用了啊…

其实微服务并不适合所有类型项目,尤其是体量不算大的业务场景,大部分企业选择跟风微服务,背后真正的原因很现实:因为微服务系统画出来的技术架构图格外高大上,领导们看了拍手称赞,还能在汇报的PPT上增添几笔亮彩;而老板/销售们在客户面前更好吹,甲方听看这么先进的技术名词和技术优势,就直拍大腿夸NB;最后,对于开发团队的马仔来说,既能通过生产项目来实践学到的新技术,还能为自己的简历留下一段宝贵的微服务项目经验、以及满足技术KPI的考核指标……

所以,用了微服务之后,领导的汇报更好看、老板/销售对外更好吹、客户觉得既厉害又靠谱、开发者也提升了个人职业发展的竞争力,四者各有所得,这种皆大欢喜的事情何乐而不为呢?

4:尽量避免分布式

作为系统架构设计的第一条原则,就是应该尽量避免使用分布式/微服务架构

因为一旦使用分布式架构,就等价于走上了一条不归路,所需要面临的技术挑战可以说是无穷无尽。为此,分布式架构在一开始,通常是作为迫不得已的情况下,才会使用的最终手段。

到了如今,随着各种技术组件、解决方案纷涌而至,分布式/微服务生态进一步成熟,分布式/微服务不再令人恐惧,反而成为了系统架构设计的首选方案。

毋庸置疑,分布式/微服务能给系统带来很大的优势,但它并不是一种能解决所有系统架构问题的银弹。

分布式有自己的适用场景,如果系统规模大、项目成员多、硬件资源够、工期时间足,那微服务架构的确是个不二选择

如果用户体量并不大,并且系统的流量峰值并不高,这种中小型项目完全没有必要使用分布式架构!

对于中小型系统而言,解决分布式架构产生的一系列弊端,所耗费的代价会更大,这时硬上分布式反而得不偿失。

并且单体架构足以支撑大多数中小型系统正常运转,而且不再需要耗费大量精力,去解决哪些根本不必要的技术问题(分布式带来的问题)

有人或许会说,那万一单体架构扛不住怎么办?

如果你也有这样的顾虑,只能说你对技术理解不够透彻,单体架构最大的问题是耦合度高,不同业务之间无法单独维护(如升级、拓展等)。

而所谓的单点故障可以通过集群解决,吞吐量不够可以升级硬件配置,扛不住就先把机器拉到16C32G,同时多加几台机子即可。

大多数情况下,业务流量大和项目收益挂钩,业务请求能把系统打到宕机,自然也不会差钱,无脑加机器比啥都好使,而且要铭记:单体架构的接口性能与响应速度,反而比分布式系统快上一个量级

如果你想说,设计时要考虑未来业务增长性呀,万一系统上线后,短期内变成“现象级应用”爆火了咋办?实在要面向未来设计的话,除非这个“未来”是绝对会出现的(如繁荣生态圈的新产品),否则也没必要一开始就上分布式,利用好Maven多模块构建单体项目即可,根据业务划分好模块,这时就算真的出现直线式增长,也能以极小的代价升级到微服务架构。

综上所述,做架构设计时能用单体就用单体,这样能避免许多麻烦出现,千万不要乱用、滥用分布式架构,比单体系统更糟糕的是错误的分布式系统。这也是如今许多企业开始回归大单体的原因,越来越多的企业选择将系统重构成单体架构,降低复杂度是一方面,同时单体系统的成本更低,系统扛不住时多加几台机器的钱,也远低于分布式系统的部署成本

三:分布式系统的设计原则

1:完善的基建设施(最重要)

如果打算使用分布式架构,首先要考虑并不是如何拆分服务、如何开发需求与设计接口

而是应该先为分布式系统做好全面的基础设施建设,因为这是分布式/微服务系统所需要的“温室”

  1. 虚拟容器和编排平台 -> 通过虚拟化容器结合容器编排技术,为分布式系统提供更好的运行环境
  2. CI/CD流水线 -> 从代码拉取 -> 扫描 -> 编译构建 -> 到打包 -> 单元测试 -> 应用部署的自动化流程
  3. 服务治理组件 -> 注册中心、配置中心、负载均衡器、服务网关、远程调用、服务保护等核心组件
  4. 日志收集和链路追踪APM -> 自动聚合系统所有节点产生的日志,并通过链路追踪搭建完善的可观测性
  5. 监控系统 -> 能持续观测硬件资源、系统流量、系统应用、中间件、业务指标的全方位监控系统
  6. 数据存储组件 -> 通过关系型/文档型/时序数据库、大数据组件、对象存储等提供多样化存储
  7. 中间件 -> 分布式缓存、消息中间件、搜索引擎、分布式调度中心、数据同步组件、负载均衡等
  8. 授权中心 -> 提供不同类型、维度、终端的认证鉴权服务,为系统提供单点登录、访问控制等支持

上面列了八大项微服务系统不可或缺的基础设施,这些基建是构建分布式系统的基石

如果你想要设计一个分布式系统,那你不应该先关注系统本身,这是我刚开始接触分布式/微服务吃的大亏,一上来就先对业务拆拆拆,然后闷头干干干,到头来走哪儿卡哪儿,每次都等问题暴露了再临时抱佛脚般做补救工作……。因此,大家首先更应该把精力放在搭建“温室”上面,当这些基础设施完善后,再构建分布式/微服务系统时会额外轻松

如果刚开始接触微服务生态,短时间内无法完善这些基建设施也没关系,但前期一定要先确认好方案,不要等到问题暴露出来了,才发现设计时没有考虑这块,然后做亡羊补牢的工作,这样会严重耽搁项目进展……

2:微服务拆分的粒度

微服务里的各个服务究竟怎么拆分才合适呢

服务拆分时要结合业务特性、流量规模、团队现状等多方因素考虑,应该遵循“适当微”原则。

3:服务分层

确认好合适的拆分粒度后,还要做好服务的分层设计,学会将业务服务里的共性操作,抽象成单独的、可复用的基层服务。

比如A服务需要发送企微/钉钉通知、B服务需要发送微信/小程序通知、C服务需要发送邮件/短信、D服务需要推送APP应用通知……,这些分散在不同服务里的需求,其实具备相同的技术特性:发送消息,唯一的区别就在于触达渠道与方式不同。

这时,就可以拆分出一个独立的消息中心/服务,负责对接不同渠道的消息推送能力,而后提供给前台业务服务统一接入,避免多个服务重复开发。

到了微服务架构中,服务通常会被分为基础服务、业务服务两大类

通过这种分层设计思想能将系统模块化,既能提升业务开发效率,也能增强可维护性及拓展性。

如何评判一个服务是否要下沉到基础服务层,这点因不同系统的需求而异,但有一点诸位要铭记:作为基础服务层的应用,通常会被整个系统几十上百个服务接入,因此稳定性是重中之重。

一个业务服务有些小Bug无伤大雅,可如果某个基础服务存在问题,一旦发生故障会波及整个系统,这也是分布式微服务的一大特点:一个应用所处的层级越靠下,它对整个系统的影响越广泛。

4:无状态设计

分布式/微服务架构的核心优势之一,就是运行期间能够弹性伸缩节点配置

而一个服务想要支持弹性伸缩,前提是它必须被设计成无状态服务

  • 有状态服务:在处理请求时,会依赖和修改特定的状态信息,如存储在服务内存中的数据;
  • 无状态服务:在处理请求时,只依赖于请求自身携带的信息,不依赖任何请求之外的状态信息;

在这里插入图片描述
A服务中,通过ScheduledThreadPoolExecutor、SpringTask这类定时调度技术,定时触发某项业务逻辑的执行,这就是一种有状态的表现,为什么?因为定时调度的状态,只存在于某个具体的服务实例中【有状态】,一旦将单实例的服务扩容成多个节点,这时会发生什么?

A服务部署多个节点时,每个节点的内存中都有各自的调度器,最终多个节点会一起定时触发业务逻辑的执行,好比这个业务逻辑对应的具体操作,就是定时推送数据至三方,那此时会出现多次调度推送重复数据

再比如在A服务里,把用户的登录态存放在服务器Session里,后续直接从Session中获取用户登录信息,这时当服务扩容成多个节点,会造成登录状态丢失。比如用户第一次请求分发到A1节点,此时将登录态放在A1Session(内存)中;而第二次请求被分发到A2节点,显然无法从A2Session里获取用户的登录信息

需要依赖先前请求状态、或依赖实例内存中的特定信息,来处理请求服务被称之为有状态服务,而有状态服务天生与分布式相悖,它无法支持集群式部署,这显然是分布式系统无法接受

正因如此,大家在做分布式系统开发时,除开特殊的服务外,业务服务一定要做好无状态设计。

5:容灾搭建

世界上不存在完美无缺的东西,互联网也不存在不发生故障的产品,因此,容灾设计成了大型系统不可避免的问题。设计容灾方案时,不仅要考虑代码Bug、组件崩溃……这种内部故障,还要考虑外部环境因素造成的突发状况,如光缆被挖断、机房发生故障、洪水/火灾/地震等自然灾害等。

而分布式系统通常会部署在同一个内网,毕竟内网交互更快,并且没有公网带宽成本,但所有服务部署在同一个内网,遇到上述突发状况时系统会瞬间瘫痪。

因此,为了大型系统的稳定性保障,容灾方案通常会考虑许多方面,如:

  • 数据备份:定时同步全量与增量数据,确保发生故障时能及时恢复;
  • 主从热备:通过主从或集群方案,解决单点故障带来的不可用问题;
  • 灾难告警:搭建完善的监控体系,能实时观测并反馈健康状态,达到阈值时自动通知相关人员;
  • 多机房灾备:全量冗余部署一套机房环境,当主用机房故障时能自动切流至备用机房;
  • 地理灾备:通过搭建异地多中心方案,确保某地发生自然灾害时,也能将流量切至其他中心;
  • 网络灾备:通过融合仓避免单一运营商故障导致网络不可用,及通过专线避免网络阻塞等问题;
  • 应用容灾:蓝绿发布确保升级时故障,能及时回滚到旧版本,金丝雀发布验证新功能稳定性;
  • 多云策略:基于多个云服务提供商,降低单一云服务商故障导致的系统不可用风险;
  • ……

容灾的目的是为了保障高可用,毕竟对于大型业务系统来说,短短几分钟的瘫痪会带来巨大损失,而且会对整个品牌造成负面影响,给用户/客户留下较差的观感,这种损失更是不可估量的!所以,越大型的系统越重视容灾设计,预设的灾备方案也会更加充分。但如果是中小型系统没必要面面俱到,因为容灾等于烧钱99%的时间里,准备的容灾资源都会处于闲置状态。

6:约定大于一切

约定大于配置,配置大于编码

前半句的意思是,在微服务开发过程中,大家都遵循既定的约定来实现系统功能,比如:

  • 包结构的约束:所有业务逻辑类放service包、控制器放controller包、数据访问类放mapper包等;
  • 接口风格的约束:所有接口都遵循RESTful+前后端分离风格,如POST对应保存、PUT对应修改等;

后半句配置大于编码的含义,是指通过外部配置来管理和调整系统行为,而不是在代码中硬编码

约定大于一切

对于“约定”这个词汇,在这里会有更广泛的解读。

所谓的约定,是指双方或多方都会遵循的准则,在实际的微服务开发中,约定将大于一切!

首先,在正式开始开发前,应当先给出统一的技术规范,这份技术规范包括但不限于:编码规范、数据库规范、安全规范、性能规范、Git规范、项目管理规范……,而这份技术规范将是整个团队所有成员都要遵循的约定,这样才能确保团队工作期的高度统一,否则会出现各种鸡毛蒜皮的小事相互扯皮。

其次,“约定”还应该包括公共类库!这点虽然不起眼,但却格外重要,先来看个例子:

比如对象的转换。有的人用Spring.BeanUtils转换、有的人用Apache.BeanUtils、有的人用cglib.BeanCopier、有的人手动Get/Setings、有的人用MapStruct……

可谓是八仙过海各显神通,光常见的Bean拷贝操作,不同成员的风格都不同,更别提值校验、报表导出等共性操作了,这种不同类库的交织在一起产生的代码,会给阅读者带来很强的割裂感,以及增加代码阅读成本,正因如此,对于常用的公共类库理当统一。

7:面向失败设计

永远不要完全相信其他的微服务,做好错误处理

8:摆脱单体开发思维

除了遵循契约开发、面向失败设计外,在做微服务开发时还有至关重要的一点,摆脱传统的单体开发思维

现在要统计不同店铺、每天各个支付渠道的支付总金额,列表支持店铺、日期、支付渠道筛选及汇总

上面是一个简单的单日汇总对账单需求,如果是你来负责,你会怎么实现?

  • 出一个对账单接口,通过SQL语句实时查询订单表统计对账数据,这种方式存在性能问题;
  • 改造支付链路,在支付成功后加个统计逻辑,数据存入对账表,可这种方式对现有代码侵入性高
  • 写个定时任务,定期扫描订单表,把支付成功的订单统计到对账表,但这种方式不具备实时性

如果你想到的也是上述三种方案之一,那说明你对分布式理解还不够熟练,具体怎么做呢?

所有分布式电商系统里,订单支付成功都会发送MQ消息,那咱们能否订阅这个消息来完成对账统计呢?

答案是当然可以,即对业务代码没有侵入,也不会有性能问题,并且能够有接近实时的对账数据,三者皆得!

这个例子只是起到抛砖引玉的作用,实际开发过程中,要学会合理使用不同中间件处理业务,比如有些业务通过Redis就能实现,没有必要非得通过数据库完成,这样还能获得更好的性能,担心数据丢失做个异步落库即可。

又比如某些检索条件复杂、数据量过大的场景,可以清洗数据放入ES来优化性能与体验感。又比如某些业务场景下,完全可以通过多线程、MQ异步处理提升性能与解耦……

熟练使用不同中间件满足业务场景后,还需要考虑分布式下的各种极端问题,例如写入链路从中间断开,如何保障数据的一致性?又比如某个接口出现并发请求,如何避免线程安全问题?又比如请求链路过长,如何降低耦合度及优化性能等等。

实现业务需求时,养成潜意识下思考这些问题的习惯,这将是你玩转分布式领域的必经之路

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值