Skip to content

一文说清楚微服务架构的挑战

About 5213 wordsAbout 17 min

架构新书

2026-06-11

定义

微服务架构,是基于应用架构,把架构中的组件开发成多个松耦合和高内聚,可独立部署的服务,每个服务是一个独立的进程, 服务之间通过轻量级的协议如RESTful、Dubbo等协议交互,或者是通过轻量级消息平台交互。

实例

物联网系统按照功能可以拆分成主网关,网关,设备状态查询,业务代理,网关管理等服务。网关又可以进一步拆分成设备网关和用户网关

电商中:电商系统拆分为商品,营销,订单,支付,库存等微服务,库存系统可以拆分库存查询,库存预占服务

微服务的特点把系统拆分为多个独立部署的服务,主要目的是提升系统的质量,获得高伸缩性和高可用性,高性能,以及易于修改性,易于部署等特性。主要好处如下:

主要优势描述举例
松耦合和高内聚在使用微服务前,松耦合高内聚的设计原则还只停留在设计层面,系统在实现过程中可能逐渐混沌化构, 使用微服务后,微服务拥有较小的工程体积,必然要求高内聚和松耦合成为设计微服务的首要原则。较小的工程,让敏捷开发成为可能;高内聚的设计,易于开发人员理解;较小的工程容易开发,测试和重构;团队允许分布在国内各个地方协作开发
独立的技术栈微服务可以使用不同的技术栈实现,包括不同的语言和平台。比如简单的Servlet实现,或者使用Spring Cloud ,或者国产Solon框架 。服务A可以使用Spring Boot 4,而服务B还沿用Spring Boot 2。团队自己决定使用什么技术栈实现微服务;团队可自由试点新技术,新框架;充分利用硬件资源,比如计算类微服务的耗费CPU资源可以部署在CPU更强的主机上。
独立部署每个服务可以独立部署并按需部署节点实例。 比如库存系统,库存查询服务可以部署较多节点,而库存预占服务部署较少节点。快速编译和部署;服务实例节点按需扩展;充分利用硬件资源,比如计算类微服务的耗费CPU资源可以部署在CPU更强的主机上。
去中心化的数据库每个服务拥有自己私有专属数据库,其他服务想访问这库数据需要调用服务提供的API各个微服务团队独立设计数据库。数据库按照实际使用情况按需扩展。
系统满足高质量高伸缩性、高可用性、性能、可修改、容易维护系统拆分成多个微服务,一个微服崩溃不影响其他微服务。微服服务中的一个节点实例崩溃或者正常运维也不影响微服务整体功能;按需部署实例节点,比如传统LV协议的设备较多,可以在网关部署数千个LV网关节点,新设备较少,使用MQTT协议。可以部署数百个MQTT网关;微服务更小的工程让代码更容易理解。后续迭代更简单。

注意:不要认为一旦采用微服务,微服务必然就高内聚,低耦合,业务边界清晰。实际上系统拆分不取决于采用的技术架构,这取决于业务架构,应用架构和数据架构,如果应用架构中的组件职责不清晰, 后期微服务可能还出现合并或者重组,或者多个微服务功能冗余的可能。

如下是微服务架构的架构,主要分为分布式调用协议,服务治理,流量管理,可观测性。适用于Spring Cloud,Dubbo等微服务框架。

组件描述
分布式调用协议通常有基于HTTP的和基于二进制的,比如Spring Cloud Feigh是基于HTTP调用。 Dubbo则支持多种二进制协议,如HTTP,Dubbo2,Triple等
服务治理包括编写分布式服务,服务注册和发现,以及配置中心。分布式服务通常是一个简单的Java POJO类,但除了核心业务逻辑外,通常还集成了流量管理,可观测性管理,配置等多个功能。微服务框架通常自带了服务注册和发现,以及配置中心。比如Dubbo就使用Zookeeper实现其功能,或者可选使用Nacos,Apollo等其他软件
流量管理包括了API网关,熔断,负载均衡,限流等组件或者平台。
可观测性通过收集日志,以及操作系统,JVM,尤其是微服务自身的技术和业务指标,提供展示,搜索,告警功能。
CI/CD持续集成和持续交付 (CI/CD),适用于微服务频繁的发布.
基础设施包括数据库,NSQL,消息平台,Zookeeper等。微服务或者服务治理,流量控制的组件也依赖这些基础设施,可观测平台依赖ES和普罗米修斯
其他模块微服务提高了研发,测试和部署的门槛,对应需要专门的单元测试&集成测试方案,需要容器化方案,以及分布式任务执行方案等。

下图是一个企业IT系统采用了SOA架构和微服务架构。金融系统整体使用SOA架构集成各个系统,在SOA架构章节我们提到了,SOA架构以消息驱动,提供了服务和消息的管理和监控。

  • 风险管理系统采用微服务架构,包含了风险评估服务,事件采集服务,决策引擎,工单服务等服务。技术栈使用Spring Cloud。
  • 贷款管理系统是一个基于Spring Boot技术栈的系统,提供了俩个单体系统并通过Niginx对外提供统一服务。企业服务总线将适配Nginx 提供对其他系统的调用
  • OA系统和财务系统为单体系统,均为单体的Web系统,同样通过ESB对外提供Web Service服务
  • 微服务基础设施,指微服务中的服务注册于发现、配置中心、API网关、持续集成和部署,容器化部署和编排等基础设施。

传统企业应用,如金融,电信等使用ESB集成各个系统。现代互联网,物联网使用轻量级消息中间件集成,或者直接使用RESTful相互调用

很多新生代程序员就业就直接进入微服务架构项目,需要知道,微服务之前系统可以拆分成独立部署的多个子系统,并通过网关提供统一接口给其他服务,或者通过Portal技术整合前端界面,这是一种早期单体系统拆分方式。这种方式使用同一个技术栈构建的技术框架,系统的功能单独开发并单独部署并使用同一个数据库。这些系统通常很少相互交互 。上面的贷款管理系统基于这种拆分方法。这种好处是即有单体系统的简单,又满足一定的质量属性,如上在线编辑文档服务可能耗费CPU计算,需要单独部署。巨大的单体系统可以通过这种拆分分成多个较小的系统易于维护,如上贷款管理系统可能拆分成贷前,贷中,贷后3个子系统。

微服务架构早期被称为细粒度的SOA,它与SOA架构俩个共同点都是按照业务拆分,并采用一定分布式技术栈,俩个有如下重要区别,

区别描述
拆分和集成区别微服务是拆分一个系统的方式,比如采用微服务拆分风险管理系统为多个服务,而SOA则是集成企业应用的一种架构方式,如金融企业集成风险、财务,OA等系统。传统IT企业在集成方面有较高挑战,比如严格监管要求和复杂的技术栈(历史原因采用不同语言,技术,平台),因此通常使用SOA技术定义了服务接口和企业总线调用方式。微服务技术栈在集成系统的功能上偏弱,不如SOA。
业务架构和应用架构区别SOA:业务架构明确了系统之间调用,这些系统可以采用SOA相关技术集成或者轻量级协议集成。
微服务:系统内,无论是单体; 还是微服务,其相互调用无需业务架构师参与,由技术架构师分析得出应用架构后,应用架构的组件形成微服务。
技术栈区别微服务采用了更轻量级技术栈和基础设施,比如REST+API网关+轻量级消息中间件,SOA通常使用是ws-*重量级交互协议配合ESB。当然SOA也可以使用微服务技术栈,微服务也可以使用SOA技术栈

微服务架构和SOA都以分布式调用为核心,这与JavaEE很相似。 JavaEE是面向企业应用,以分布式技术为核心的架构。 它建立了远程对象的概念,试图屏蔽分布式调用细节,看起来像调用本地(同一进程)对象一样。这在高并发,高流量系统中是不可取的。在1.8 分布式系统认知中我们已经看到分布式系统调用的各种问题。微服务架构从来没有回避这些问题,且提供了一系列策略,工具来解决,如超时,重试,幂等,限流,降级,可观测等。本书的重点之一是这些策略和工具。

现在有的微服务系统是基于Cloud Native (云原生)架构构建,它是最新的微服务架构的技术补充,通过云计算和高度自动化部署,极大的提高了伸缩性。这里不再详细描述。

微服务架构的定义很简单,即高内聚低耦合拆分系统,目的也很明确,以提高系统质量属性为目的,它是现代系统优先的架构风格。但考虑到分布式带来的挑战,微服务让一个系统产生了大量的独立部署的服务和大量的相互之间分布式调用,量变引起质变,放大分布式带来的问题,造成系统性问题!

下表从研发到部署到生产运维,列出了微服务带来的问题和解决思路,其详细描述将在本书剩余部分完成。

研发阶段挑战解决方法
设计如何拆分服务以高内聚,低耦合的原则,结合业务架构、应用架构和数据架构进行拆分。不应该以技术为驱动来拆分系统。 表后总结了特定的一些情况下使用单体系统的情况。
编码服务注册和发现服务过注册到服务中心才能被其他服务调用,服务中心有Zookeeper,Nacos等实现。服务中心自身的高可用、高性能成了微服务系统的关键。Zookeeper因为在数据存储上调强一致。可能导致一个具备大量微服务的系统在集中注册服务时候遇到性能瓶颈
如何提高服务性能不同于单机应用,调用方法是纳秒级。微服务调用的通信成本是毫秒级,级联过多的分布式调用,或者不正确的分布式调用(比如设置较短的调用超时)导致性能急剧下降。 本书提供了单机优化,以及分布式优化的策略
如何对其他系统暴漏服务系统之间,可以用过API网关,或者消息中间件,暴漏服务给其他系统。系统内的微服务之间调用则使用服务查找&调用。这样的API网关有Spring Gateway,Niginx等。 消息中间件可以使用Kafka,Rabbit MQ。
如何单元测试微服务不同于单体系统,依赖大量其他服务和基础设施,如何单元测试?可以通过Mockito等工具模拟其他服务,通过TestContaine 启动本数据库或者Redis,Kafka等基础设施。实现微服务单元测试会带来极高的收益,本书专门章节描述微服单元测试的困难和实现方法
运行和调试实现单元测试是在本机调试的基础。如果一个微服务无法调试,则从开发到上线,浪费较多的时间和人力资源另外一种调试手段是可以把微服务部署到验证环境,并开启JVM 远程Debug进行调试。
重构单体系统重构在IDE的帮助下非常简单,但微服重构,可能影响其他微服务系统。比如微服务中序列化对象增减属性,修改属性类型(从int改成long) ,调整异常处理逻辑等作者曾经碰到某大厂,因为删除了接口方法的一句注释导致上游系统崩溃问题,据说是上游系统竟然是根据异常行号来判断微服务错误类型,找不到期望的行号导致空指针异常!!!
如何配置单体系统,只使用application.properties这样的配置文件即可,如果是为了测试,可能使用 application-test.properties. 微服务使用统一的配置中心,如Apollo,Nacos。配置的调整统一通过配置中心,配置中心也支持不同的研发环境。这样数千个微服务节点的配置可以使用配置中心统一配置
如何保证事务微服务架构下,服务调用跨越多个微服务以及存储系统,像JavaEE的俩阶段提交事务不再适用,更多采用柔性事务解决方案或者通过业务代码实现出错后事务补偿
服务之间如何安全调用服务之间安全调用需要使用认证服务器,或者使用JWT技术。 如KeyCloak。
如何查询分布在各个微服务的数据?每个微服务都需要提供数据查询接口,如果需要跨越多个微服务,则使用专门的聚合查询服务。另外一个办法供主数据用于跨服务的查询。主数据是解决微服务数据库导致的孤岛,提供一致实时的数据。
集成测试如何完成集成测试集成测试不仅仅要验证其功能正确,还要测试其高可用和容错等特性。比如引入猴子捣乱,模拟各种故障情况下微服仍然能正常,或者流量恢复后正常,重启后恢复正常等。
运维如何发布系统数百个微服务的频繁的开发和发布,需要DevOps,持续集成和交付
流量管控微服务可以使用限流,熔断等措施保证服务高可用。这些措施可以由微服务自身根据业务评估实现,或者微服务接入限流中间件平台实现
如何诊断问题在微服务架构下,用户请求会经过数个,或者数十个微服务。需要提供功能完备的可观测性平台,包括分布式链路,操作系统&JVM监控,以及服务自身的指标监控
负载均衡微服务之间的负载均衡通过微服务框架实现, 服务对外的接口的负载均衡可以使用API网关或者Nginx代理。

从这个表看,微服务导致开发增加了技术栈复杂度,测试和运维难度增加,团队规模增加,需要的硬件资源增加,我在1.8《分布式系统认知》里也提到,编程语言第一课的HelloWorld程序,只有一行代码,但在微服务架构下考虑可观测以及高可用,变得非常难写和较多工作量。那么,我们还要不要构建系统一开始就先使用微服务架构? 我认为虽然微服务架构是构建现代软件系统优先使用的架构,但下列条件满足多个情况下,应该优先需要考虑使用单体系统,否则,使用微服务架构

考察点描述
业务架构简单比如一个作业管理系统,日志管理系统等。使用单体系统即可。
应用架构简单业务架构复杂,比如业务架构出现较多组织,拥有复杂的业务流程,但应用架构和数据架构简单。比如一个以工作流为核心的业务系统可以使用单体系统
缺少基础设施技术上缺少微服务基础设施如CI/CD,API网关等,容器化,Zookeeper,可观测平台。
小团队小规模团队建议避免微服务。从上表格看出微服务导致开发、测试、运维成本增加。小团队应该优先迭代业务功能
创业期间同上,在人员较少情况下,应该优先瞒住业务快速迭代
无高质量要求是否有高可用可用,灵活性,伸缩性等质量要求,以及高性能和可修改性的要求。在电商,一个商家管理系统,没有高伸缩性要求,可以做一个单体系统。 但电商的基础交易系统,如商品,订单业系统需高伸缩性和高可用。通常使用微服务架构。
事务强一致事务强一致需求建议使用单体系统实现。
目标用户量少目标用户数量不多的,比如只有企业内部数百员工人使用的金融管理系统,或者只有医院内部病人使用的AI系统。
经济因素无法雇佣更多的研发和运维,或者人员和经济上无法支撑微服务的需要的基础设施,或者公司正在降本增效。

如果满足上面条件,可以考虑先构建为单体系统,并设计好应用架构和软件架构,在单体内的各个组件定义清晰的职责以方便拆分,为微服务架构做准本。 团队同时应该提早引入微服务技术栈和基础设施

单体系统可以采用如下建议,让单体系统具备重构为微服务架构的能力:

设计重点描述
清晰的应用架构应用架构清晰定义了架构内各个组件的功能。拆分时候依据组件拆分。
拥有数据域的数据架构数据架构先定义数据域,然后再定义数据模型。拆分微服务,数据域可以作为一个微服务专属的单独的数据库系统
Facade模式使用Facade模式作为各个模块的交互唯一接口。Facade模式应该提供粗力度接口,并确保接口参数可序列化。如果拆分微服务,这个Facade类将作为服务边界。这里粗力度接口是指供调用方一次调用获取所需结果,而不是需要循环多次或者多次调用不同的Facade接口才能实现。
事件总线使用事件总线(比如Guava的EventBus类)在系统内部实现消息驱动架构,解耦各个模块,并确保消息可序列化。如果拆分微服务,使用Kafka这样的消息平台代替
多个数据域如果应用架构内的组件使用数据架构定义的多个数据域,则组件变成微服务时候,其他服务需要提供查询接口来共享这个域数据。

知行合一