微服务
参考资料
https://www.redhat.com/zh/topics/microservices/what-are-microservices
https://cloud.google.com/learn/what-is-microservices-architecture?hl=zh-cn
https://aws.amazon.com/cn/microservices/
https://www.ruanyifeng.com/blog/2021/05/scaling-problem.html
微服务是什么
微服务(microservice)是一种软件架构,正得到越来越多的关注。
但是,它到底是什么意思?什么样的架构可以叫做微服务?
网上的文章虽然很多,但是都太复杂,初学者不容易看懂。我认为,这个概念其实非常简单,可以很通俗地说明白。

1.单体软件
要理解微服务,首先需要理解软件架构的演变。
早期的软件,所有功能都写在一起,这称为单体架构(monolithic software)。
整个软件就是单一的整体,彷佛一体化的机器。
可以想到,软件的功能越多,单体架构就会越复杂,很多缺点也随之暴露出来。
(1)所有功能耦合在一起,互相影响,最终难以管理。
(2)哪怕只修改一行代码,整个软件就要重新构建和部署,成本非常高。
(3)因为软件做成了一个整体,不可能每个功能单独开发和测试,只能整体开发和测试,导致必须采用瀑布式开发模型。

2.软件开发难处
软件开发有一个难题,叫做"扩展"(scaling),即怎样服务更多的用户。 你有10000个并发用户,跟你有10个并发用户,这是完全不同的概念,哪怕功能完全相同,背后的实现是完全不一样的。
并发用户数上升一个数量级,软件就必须重构,大量问题随之产生。

大项目的技术难度高,管理难度更高,而且大团队的生产率往往很低,行动缓慢。
一个典型的大型软件项目,开发过程通常是下面这样。
最开始的时候,它是一个小项目,开发人员就是两三个人,甚至可能只有一个人。

产品比较简单,功能很有限。
第一版发布后,拿给客户使用,反响不错。客户要求的新功能,能够很快开发出来,Bug 修补也很快,因为早期客户往往可以与开发人员直接沟通,快速反馈。
公司于是决定投入更多人员,开发这个项目。团队慢慢变大了,软件开始变得复杂,开发速度逐渐变慢了,2.0 版花费的时间比预期要长一点。Bug 的修复难度开始增加。总之,新功能的开发日程变久了。
公司的自然反应是进一步扩充团队。
但是更多的新成员其实会降低其他人的生产率,一个普遍现象是团队规模越大,每个人的平均生产率越低。

几年以后,代码逐渐老化,复杂性不断增加,项目开始停滞不前。某些极端的情况下,软件的维护成本变得非常高昂,并且几乎不可能进行更改。
最终,这个项目成为技术债务,等待被新项目替换。
3.为什么大项目的开发效率低?
大项目就像一头大象,让人望而生畏。可是一旦需要奔跑,大象就会步履蹒跚,被猎犬远远甩在后头。它快不起来的原因有两个。
代码复杂度
随着代码量的增长,单个开发者想要理解整个代码库,变得越来越困难。如果团队超过五个人,每个人负责一个功能,那么单个人几乎不可能追踪系统的所有工作进度。
当你中途加入团队,整个项目是一个紧密耦合的大型系统,你又不理解系统的每一个工作细节。这时,你就不太敢修改以前的代码,因为不知道随之而来的全部影响。

你不真正理解系统,也就不会感到自己是代码的主人。你会很犹豫要不要重构,过时的代码开始累积,技术债务就这样出现了。长此以往,开发变得越来越不愉快和令人无法满意,最终导致人才流失。后面接手的新人,更难于重构那些遗留下来的代码。
团队原因
随着团队成员的增加,交流成本开始指数式上升。如果整个团队有 n 个程序员,为了了解其他人的工作,你需要跟 n - 1 个人逐一交流(口头或者书面),那么整个团队的交流路径总数就是 n * (n - 1) / 2。
这意味着,交流成本的增长速度是人员增长速度的平方,团队人数越多,协同的难度就越大。

大团队保持扁平化管理,也会越来越困难,必须拆分成较小的群体。这时,对等的交流会被自上而下的交流所取代。
团队成员会感觉,自己从平等的利益相关者,转变为普通的工作人员,工作动机受到了影响,责任感和主人翁意识都会淡漠。
解决方法:代码解耦
大项目的开发效率不高,把这个问题归咎于程序员的技术水平低和管理不善,都是没用的。 根本原因是软件规模的增长,必然使得代码和团队变得笨重。 除非很早就认识到问题的根据,采取缓解对策,否则前面描述的情况,迟早都会出现。
解决这个问题,要从代码和团队两方面着手。
代码层面的解决方法是,将软件解耦,拆分成组件或者模块,防止各个部分紧密地耦合在一起。
每个组件和模块,都可以独立开发,通过公开的接口被其它部分调用。

这样的话,就大大减轻了开发者的负担,只需要负责自己的代码即可,不需要关心其他部分的实现。每个部分都可以单独重构,不担心影响到其他部分。
解决方法:团队解耦
除了代码解耦,团队层面也需要解耦,要把人员分开。
这可以参考互联网的架构。互联网是迄今为止最成功的大型软件解耦实例,它之所以能够扩展,是因为它由一个个独立的节点组成。为了防止节点之间互相依赖,各个节点都遵循以下规则。
- 遵守公开的通信协议。
- 不需要了解其它节点的内部实现,就可以与之通信。
- 节点之间不直接共享状态,只通过通信交换数据。
- 每个节点单独开发和部署。
大团队也应该遵循类似的原则,进行解耦。
- 每个子团队都可以独立运作,不依赖外部人员。
- 子团队内部的运作,不需要被外部知道。
- 子团队之间的协调,应该按照公开的协议和规则,最好能够自动完成,避免私下协商。
4.理解SOA
于超老师第一次接触SOA,也就是在上海的外企,以Java、redhat的开发技术栈。
为了解决上面这些问题,很早就有人提出来,必须打破代码的耦合,拆分单体架构,将软件拆分成一个个独立的功能单元。
大概在20多年前,随着互联网的出现,功能单元可以用远程"服务"的形式提供,就诞生出了"面向服务架构"(service-oriented architecture,简称 SOA)。

通俗理解SOA
通俗理解SOA(Service-Oriented Architecture,面向服务的架构)可以用以下方式描述:
想象一家大型超市,超市中有各种商品,如食品、衣物、家居用品等。
每个商品都是一个独立的服务,可以通过它提供的功能来满足消费者的需求。
消费者可以根据自己的需求选择不同的商品进行购买。
在SOA中,类似超市中的商品,软件系统中的各个功能也被拆分成独立的服务。每个服务都具有自己的功能和接口,可以独立提供特定的业务功能。
这些服务可以通过网络进行通信,以满足不同应用之间的需求。
就像超市中的商品可以组合成购物清单,通过选购不同的商品来满足不同消费者的需求一样,在SOA中,服务也可以通过组合来满足复杂的业务需求。
通过将不同的服务组合起来,系统可以实现更高级的功能和流程。
SOA强调松耦合和可重用性。通过将功能拆分成独立的服务,可以减少系统间的耦合,使得系统更加灵活和可扩展。
此外,由于每个服务都是独立的,可以被其他应用程序或系统重复使用,提高了开发效率和系统的可维护性。
总之,SOA是一种将软件系统拆分成独立服务的架构思想,类似于超市中的商品,每个服务都是独立的、可组合的,以满足不同应用之间的需求。这种架构提供了灵活性、可扩展性和可重用性,有助于构建复杂的应用系统。


所谓服务(service)
就是在后台不间断运行、提供某种功能的一个程序。最常见的服务就是 Web 服务,通过80端口向外界提供网页访问。
"面向服务架构"就是把一个大型的单体程序,拆分成一个个独立服务,也就是较小的程序。
每个服务都是一个独立的功能单元,承担不同的功能,服务之间通过通信协议连在一起。

这种架构有很多优点。
(1)每种服务功能单一,相当于一个小型软件,便于开发和测试。
(2)各个服务独立运行,简化了架构,提高了可靠性。
(3)鼓励和支持代码重用,同一个服务可以用于多种目的。
(4)不同服务可以单独开发和部署,便于升级。
(5)扩展性好,可以容易地加机器、加功能,承受高负载。
(6)不容易出现单点故障。即使一个服务失败了,不会影响到其他服务。
跟单体架构不一样,面向服务架构是语言不敏感的,不同服务可以使用不同的语言和工具开发,可能需要部署在不同的系统和环境。
这意味着,面向服务架构默认运行在不同服务器上,每台服务器提供一种服务,多台服务器共同组成一个完整的网络应用。
5.微服务(使用容器完成SOA架构)
2014年,Docker出现了,彻底改变了软件开发的面貌。它让程序运行在容器中,每个容器可以分别设定运行环境,并且只占用很少的系统资源。

显而易见,可以用容器来实现"面向服务架构",每个服务不再占用一台服务器,而是占用一个容器。
这样就不需要多台服务器了,最简单的情况下,本机运行多个容器,只用一台服务器就实现了面向服务架构,这在以前是做不到的。这种实现方式就叫做微服务。

简单说,微服务就是采用容器技术的面向服务架构。它依然使用"服务"作为功能单元,但是变成了轻量级实现,不需要新增服务器,只需要新建容器(一个进程),所以才叫做"微服务"。
一个微服务就是一个独立进程,这个进程可以运行在本机,也可以运行在别的服务器,或者在云端(比如云服务和云函数 FaaS)。
它的特点与面向服务架构是一样的,但因为更轻量级,所以功能的解耦和服务化可以做得更彻底。而且,它可以标准化,同样的容器不管在哪里运行,结果都是一样的,所以市场上有很多 SaaS 产品,提供标准化的微服务。
正是由于微服务这些突出的优点,这几年才会变得如此流行。
它和容器技术、云服务一起,一定会在未来的软件开发中,扮演越来越重要的角色。
微服务架构演进
单体网约车APP架构

一套git代码仓库,包含所有功能。
这种单体应用比较适合于小项目,优点是:
- 开发简单直接,集中式管理
- 基本不会重复开发
- 功能都在本地,没有分布式的管理开销和调用开销
当然它的缺点也十分明显,特别对于互联网公司来说:
- 开发效率低:所有的开发在一个项目改代码,递交代码相互等待,代码冲突不断
- 代码维护难:代码功能耦合在一起,新人不知道何从下手
- 部署不灵活:构建时间长,任何小修改必须重新构建整个项目,这个过程往往很长
- 稳定性不高:一个微不足道的小问题,可以导致整个应用挂掉
- 扩展性不够:无法满足高并发情况下的业务需求
微服务网约车架构
微服务架构的设计思路不是开发一个巨大的单体式应用,而是将应用分解为小的、互相连接的微服务。
一个微服务完成某个特定功能,比如乘客管理和下单管理等。
每个微服务都有自己的业务逻辑和适配器。一些微服务还会提供API接口给其他微服务和应用客户端使用。
比如,前面描述的系统可被分解为:

此架构,使用pod、容器去部署应用,也方便单个服务的更新、版本控制、推进CICD的优化。
每个业务逻辑都被分解为一个微服务,微服务之间通过REST API通信。
一些微服务也会向终端用户或客户端开发API接口。
但通常情况下,这些客户端并不能直接访问后台微服务,而是通过API Gateway来传递请求。
API Gateway一般负责服务路由、负载均衡、缓存、访问控制和鉴权等任务。
微服务架构优点
- 解决了复杂性问题。它将单体应用分解为一组服务。虽然功能总量不变,但应用程序已被分解为可管理的模块或服务
- 体系结构使得每个服务都可以由专注于此服务的团队独立开发。只要符合服务API契约,开发人员可以自由选择开发技术。这就意味着开发人员可以采用新技术编写或重构服务,由于服务相对较小,所以这并不会对整体应用造成太大影响
- 微服务架构可以使每个微服务独立部署。这些更改可以在测试通过后立即部署。所以微服务架构也使得CI/CD成为可能
微服务架构缺点
微服务的一个主要缺点是微服务的分布式特点带来的复杂性。
开发人员需要基于RPC或者消息实现微服务之间的调用和通信,而这就使得服务之间的发现、服务调用链的跟踪和质量问题变得的相当棘手。
微服务的一大挑战是跨多个服务的更改
比如在传统单体应用中,若有A、B、C三个服务需要更改,A依赖B,B依赖C。我们只需更改相应的模块,然后一次性部署即可。
在微服务架构中,我们需要仔细规划和协调每个服务的变更部署。我们需要先更新C,然后更新B,最后更新A。
部署基于微服务的应用也要复杂得多
- 单体应用可以简单的部署在一组相同的服务器上,然后前端使用负载均衡即可。
- 微服务由不同的大量服务构成。每种服务可能拥有自己的配置、应用实例数量以及基础服务地址。这里就需要不同的配置、部署、扩展和监控组件。此外,我们还需要服务发现机制,以便服务可以发现与其通信的其他服务的地址
学微服务是学什么
- API Gateway(API 网关): API Gateway是微服务架构中的入口点,负责处理所有的外部请求。它提供统一的API接口,将客户端的请求路由到相应的微服务。API Gateway可以处理请求的认证、授权、数据转换、请求转发等功能,同时还可以实施许多与安全相关的策略,如访问控制、限流、监控等。
- 服务发现: 在微服务架构中,由于服务的数量较多且动态变化,服务发现变得关键。服务发现机制允许服务注册自身,并向服务注册中心报告其位置和可用性。客户端或其他服务可以通过服务注册中心查询可用的服务,并进行适当的负载均衡和路由决策,以调用所需的服务。
- 服务容错: 服务容错是指在微服务架构中处理服务故障和异常情况的能力。由于服务之间的通信是通过网络进行的,可能会出现网络延迟、故障、服务不可用等情况。服务容错机制包括断路器(Circuit Breaker)、超时机制、重试机制等,用于处理这些异常情况,保证系统的可靠性和稳定性。
- 服务部署: 在微服务架构中,每个微服务都有独立的部署单元,可以独立地进行开发、测试和部署。服务部署涉及将微服务的代码、配置和依赖项部署到相应的运行环境中。部署可以使用容器技术(如Docker)进行虚拟化,也可以使用自动化部署工具(如Kubernetes)来简化和管理部署过程。
- 数据调用: 微服务架构中的微服务之间需要进行数据交互和通信。数据调用包括通过网络调用其他服务的API,获取所需的数据和执行相应的操作。常见的数据调用方式包括使用HTTP/REST接口、消息队列、RPC(Remote Procedure Call)等。这些调用机制允许微服务之间进行数据传递和协作。
这些概念是微服务架构中常用的关键要素,它们共同构成了一个弹性、可伸缩、可靠的分布式系统。通过合理地使用API Gateway、服务发现、服务容错、服务部署和数据调用机制,可以实现微服务架构的优势,如灵活性、独立性、可扩展性和可维护性。
微服务框架
如何应对上述挑战,出现了如下微服务领域的框架
- Spring Cloud(各个微服务基于Spring Boot实现)
- Dubbo
- Service Mesh
- Linkerd
- Envoy
- Conduit
- Istio

学习计划(重点)
学习微服务时,Spring Cloud和Kubernetes(通常简称为k8s)是两个常用的技术栈,用于构建和管理微服务架构。下面是它们之间的一些对比:
- 架构层级:
- Spring Cloud:Spring Cloud是一个基于Java的开发框架,提供了一套用于构建微服务的工具和库。它在应用程序的代码层级上提供了解决方案,包括服务发现、负载均衡、断路器、配置管理等。
- Kubernetes:Kubernetes是一个容器编排平台,用于自动化部署、扩展和管理容器化应用程序。它在基础设施层级上提供了解决方案,可以管理和编排容器、服务发现、负载均衡、自动伸缩等。
- 部署和管理:
- Spring Cloud:Spring Cloud可以在各种云平台或自己的服务器上部署。它提供了一套开发框架和工具,帮助开发人员快速构建和管理微服务应用程序,但它对底层的基础设施并不直接负责。
- Kubernetes:Kubernetes是一个跨云平台的容器编排系统,用于自动化部署、管理和扩展容器化应用程序。它可以在各种云平台上运行,并提供了强大的管理功能,如自动伸缩、故障恢复、负载均衡等。
- 功能覆盖:
- Spring Cloud:Spring Cloud提供了一系列的组件和库,涵盖了微服务架构中常见的功能,如服务注册与发现(Eureka、Consul)、负载均衡(Ribbon)、服务调用(Feign)、断路器(Hystrix)、配置管理(Spring Cloud Config)等。
- Kubernetes:Kubernetes提供了一套强大的功能,包括容器编排、服务发现与负载均衡、自动伸缩、故障恢复、存储管理等。它可以管理和编排多个容器化应用程序,并提供弹性和高可用性的部署。
- 生态系统和语言支持:
- Spring Cloud:Spring Cloud是基于Java生态系统构建的,因此它与Spring框架紧密集成,并与许多其他Java库和工具协作。它提供了丰富的Java库和工具,用于构建和管理微服务应用程序。
- Kubernetes:Kubernetes是一个通用的容器编排平台,可以与各种编程语言和容器技术一起使用。它支持多种容器运行时(如Docker),并且可以与不同的语言和框架进行集成。
- 复杂度和学习曲线:
- Spring Cloud:Spring Cloud相对于Kubernetes来说,学习曲线较为平缓。它更加关注于微服务应用程序的开发和管理,并提供了一套简化的解决方案。如果您已经熟悉Spring框架,上手Spring Cloud会相对容易。
- Kubernetes:Kubernetes作为一个容器编排平台,拥有更复杂的架构和概念,学习曲线可能相对陡峭。它需要理解容器概念、Kubernetes资源对象、Pod、Deployment、Service等,并且需要配置和管理基础设施。
总结:
- Spring Cloud和Kubernetes是两个不同的技术栈,用于构建和管理微服务架构。
- Spring Cloud更加注重开发者友好性和快速开发微服务应用程序,而Kubernetes更注重跨平台的容器编排和基础设施管理能力。
- 在选择使用哪种技术栈时,可以根据具体的需求、团队的技术栈偏好和现有的基础设施来进行权衡。
- 有些情况下,两者也可以结合使用,例如使用Spring Cloud开发微服务应用程序,并使用Kubernetes进行容器编排和部署管理。
了解Spring Cloud
为什么java占市场开发语言比例第一,明显的,大而全,任何场景,任何模式,都有可选的成熟方案。
与Dubbo对比
做一个简单的功能对比:
| 核心要素 | Dubbo | Spring Cloud |
|---|---|---|
| 服务注册中心 | Zookeeper | Spring Cloud Netflix Eureka |
| 服务调用方式 | RPC | REST API |
| 服务监控 | Dubbo-monitor | Spring Boot Admin |
| 断路器 | 不完善 | Spring Cloud Netflix Hystrix |
| 服务网关 | 无 | Spring Cloud Netflix Zuul |
| 分布式配置 | 无 | Spring Cloud Config |
| 服务跟踪 | 无 | Spring Cloud Sleuth |
| 消息总线 | 无 | Spring Cloud Bus |
| 数据流 | 无 | Spring Cloud Stream |
| 批量任务 | 无 | Spring Cloud Task |
| …… | …… | …… |
从上图可以看出其实Dubbo的功能只是Spring Cloud体系的一部分。
这样对比是不够公平的,首先Dubbo是SOA时代的产物,它的关注点主要在于服务的调用,流量分发、流量监控和熔断。
而Spring Cloud诞生于微服务架构时代,考虑的是微服务治理的方方面面,另外由于依托了Spirng、Spirng Boot的优势之上,两个框架在开始目标就不一致,Dubbo定位服务治理、Spirng Cloud是一个生态。