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

集群服务 | 云微服务 | 快速入门

快速入门

[!NOTE]

吐槽:以下文章来自于对 https://martinfowler.com/articles/microservices.html 的阅读笔记。

1.微服务的概念

简而言之,微服务架构风格是一种将单个应用程序开发为一套小型服务的方法,每个服务都在自己的进程中运行,并与轻量级机制(通常是 HTTP 资源 API)进行通信。

这些服务围绕业务功能构建,可通过完全自动化的部署机制独立部署。微服务架构尽量减少中心化管理,不同的服务甚至可以用不同的编程语言编写,并采用 不同的数据存储技术。

为了更好地理解微服务架构,最好的方式是把它和单体架构进行对比:在传统的单体架构里,一个应用通常由三部分组成:

  1. 前端 UI:浏览器中的 HTML 页面 + JS 代码
  2. 数据库:通常是一个关系型数据库,包含多个数据表
  3. 后端服务器:负责处理 HTTP 请求、执行业务逻辑、操作数据库,并渲染 HTML 页面返回给前端

在这种架构下,后端服务器是一个整体,所有功能都打包到一个可执行文件中。如果系统需要更新,即使只是改动了一个小功能,整个后端应用也必须重新构建并部署。

单体架构的 优点:

  • 逻辑集中,所有代码运行在同一个进程里,方便管理
  • 开发和测试较为简单,可以直接在开发者的电脑上运行完整应用
  • 部署相对容易,可以打包一个大应用,直接部署到服务器上
  • 可以通过负载均衡水平扩展(比如运行多个实例)

但随着应用规模变大,单体架构开始暴露出问题:

  • 改动一个小功能,整个应用都要重新部署,开发效率低
  • 代码越来越复杂,模块之间高度耦合,维护成本高
  • 难以针对某个模块单独扩展,即使只是某个功能需要更多资源,也必须整体扩展整个应用
  • 云环境下难以灵活部署,不像微服务那样可以针对不同需求单独优化

为什么越来越多人选择微服务?因为微服务架构解决了单体架构的一些问题:

  • 更灵活的部署,每个服务都是独立的,可以单独更新,不影响其他部分
  • 更容易扩展,可以只扩展某个需要高性能的服务,而不是整个应用
  • 技术选型更自由,不同的微服务可以用不同的技术栈,比如用户服务用 Go,订单服务用 Java
  • 更容易维护,每个团队可以专注于一个特定的服务,减少相互影响

不过,微服务也带来了一些新的挑战:

  • 服务间通信变得复杂,不再是简单的函数调用,而是通过 API 请求
  • 数据一致性管理更难,因为不同服务可能有不同的数据库
  • 部署和监控要求更高,需要 DevOps 自动化工具来管理

总的来说,微服务架构适合复杂、大型、需要频繁更新的应用,尤其是云原生场景,而小型应用或简单业务用单体架构可能更高效。

在这里插入图片描述

[!IMPORTANT]

补充:有人会问:“微服务不就是 SOA 吗?” 其实两者确实有相似之处,但也有关键区别。SOA 这个概念被很多大公司用来设计企业级系统,但实践中很多 SOA 方案太过复杂,导致问题频发,比如:

  • ESB 变得过于复杂,隐藏了系统的核心逻辑,让维护变得困难。
  • 耗费巨大成本却收效甚微,一些 SOA 项目花费数百万美元,却没有实际价值。
  • 集中过度管理,反而限制了系统的灵活性,导致修改或扩展服务变得困难。

微服务架构可以看作是 “正确地实现 SOA”,它避免了 SOA 里那些复杂、低效的做法,而是更专注于 独立的、小型的、自主的服务

2.微服务的特点

微服务架构没有一个固定的官方定义,但我们可以总结出一些常见的特点。并不是所有微服务架构都会具备这些特点,但大多数都符合其中的大部分。我们并不是在制定一个标准,而是根据自身经验和行业案例,描述微服务的主要特性。

2.1.通过服务来实现模块化

在软件开发中,开发人员一直希望能像拼装积木一样构建系统,把不同的功能模块组合在一起。近年来,编程语言的生态系统提供了大量的标准库,这大大推动了模块化的发展。

一个“组件”可以简单理解为一个可以独立替换和升级的软件单元。在微服务架构中,虽然仍然会使用库(Library),但核心的模块化方式是把软件拆分成独立的服务(Service)。

我们可以这样区分:

  • 库(Library):直接嵌入到程序中,通过内存调用执行(像普通的函数调用)。
  • 服务(Service):是独立运行的进程,通过远程调用(如 HTTP 请求或 RPC)来进行交互。

假设您的应用是一个大项目,里面包含多个库。如果您修改了其中一个库,通常需要重新构建并部署整个应用。但如果这个应用被拆分成多个独立的服务,那么修改某个服务后,只需要重新部署该服务,而不是整个系统。

当然,这也不是绝对的——如果某个修改影响了多个服务的接口,就需要做一定的协调。但良好的微服务架构会通过合理划分边界和稳定的服务契约来尽量减少这种情况。

在传统的程序开发中,不同模块之间的边界往往不够清晰,可能会因为代码调用方式不规范,导致模块间的耦合过于紧密。而微服务由于必须通过远程调用来交互,使得接口更加明确,避免了内部实现细节被随意访问。

虽然微服务架构有很多优点,但它也有一定的成本:

  • 远程调用(如 HTTPRPC)比本地函数调用慢得多,因为涉及网络通信。
  • 远程 API 需要更粗粒度,不能像本地函数一样频繁调用,否则会影响性能。
  • 如果需要调整某个功能模块的职责,跨进程的变更比修改本地代码更复杂。

一般来说,一个服务通常对应一个独立运行的进程,但这只是一个大致的原则。例如,一个微服务可能包含多个进程(比如应用进程+数据库进程),但它们始终作为一个整体开发和部署。

2.2.围绕业务能力组织团队

在拆分大型应用程序时,管理层通常会按技术层面划分团队,比如 UI 团队、后端逻辑团队和数据库团队。但这种划分方式会导致哪怕是一个简单的修改,都可能涉及多个团队,增加沟通成本,甚至需要额外的预算审批。面对这种情况,团队通常会选择折中方案——把逻辑塞进自己能改的地方,导致代码逻辑分布在各个应用中,变得杂乱无章。这正是康威定律的典型体现:任何设计一个系统的组织,其最终的系统架构都会反映该组织内部的沟通结构

微服务架构采用的是 围绕业务能力拆分 的方式,而不是按照技术层面来分割。每个微服务都包含整个业务功能所需的完整技术栈,例如前端界面、数据库、持久化存储以及与其他系统的交互。

因此,微服务架构下的团队是跨职能的,具备完整的开发能力,包括 UI 设计、数据库管理和项目管理等。这种团队划分方式,使得每个团队能够独立地交付和维护自己的业务功能,减少了跨团队协作的复杂度。

“微服务”这个词容易让人关注服务的大小,甚至有人争论什么才算“微”。在实践中,微服务的规模差别很大。

  • 大点的微服务 遵循 Amazon 提出的 “两块披萨团队” 原则,即一个团队不超过 10-12 个人,确保沟通高效。
  • 更小的微服务 可能由 6 人团队负责 6 个微服务,每个团队成员都能维护多个服务。

不同规模的微服务是否应该归为同一类,目前还没有定论。我们暂时认为它们都属于微服务,但未来可能会细分出不同类别。

即便是单体架构,也可以按业务能力进行模块化拆分,不过现实中并不常见。我们建议开发单体架构时,也应按业务划分团队,而不是按技术栈划分。然而,单体架构往往涉及太多业务上下文,导致团队成员难以掌握完整的系统逻辑。

相比之下,微服务架构的团队边界更清晰,强制了更加严格的模块化,有助于提升团队协作的效率。

2.3.是产品而非项目的理解

  • 传统的软件开发采用 项目模式,即开发团队完成一个项目后,软件交付给运维团队维护,而开发团队随即解散。

  • 但微服务架构提倡 产品模式,强调团队对产品的全生命周期负责。这种模式受到 Amazon你开发,你运维(You build it, you run it) 原则的启发,即开发团队不仅要编写代码,还要负责产品的长期维护。这种模式的优势是:

    • 开发人员能直接看到代码在生产环境的表现,快速发现和修复问题。
    • 增强团队与用户的联系,团队需要承担一部分用户支持工作,从而更关注用户体验和业务需求。

产品思维关注的是如何持续改进软件来增强业务能力,而不仅仅是按时交付一个项目。这种思维方式同样适用于单体架构,但微服务的小规模粒度更容易让开发团队与用户建立紧密联系。

2.4.端点来智能通信要简单

简单来说,就是让每个服务自己处理逻辑,而让通信通道尽可能简单。

在一些传统架构里,比如企业服务总线(ESB),很多复杂的功能(如消息路由、数据转换、业务规则)都放在了通信机制里。但微服务架构不这么做,它遵循 “智能端点,哑巴管道” 的理念,让每个服务自己负责业务逻辑,而通信机制(如 HTTP、消息队列)只是简单地传输数据,不做额外处理。

具体来说,微服务通常采用两种方式进行通信。

  • HTTP 请求-响应(REST API):这种方式类似于 Web 的工作方式,比如前端调用后端 API。简单、易懂,且可以利用 Web 现有的缓存机制提高性能。关键原则是 “属于 Web,而不是隐藏在 Web 之后”(即尽量用 Web 原生的方式进行交互)。
  • 轻量级消息队列(如 RabbitMQ、ZeroMQ):适用于需要异步处理的场景,比如订单处理、事件通知等。消息队列本身不做业务处理,只是传递数据,所有的业务逻辑仍然由微服务自己负责。

[!IMPORTANT]

补充:在整体式架构(单体应用)中,组件之间直接通过函数调用或方法调用进行通信。但在微服务架构中,由于服务是分布式的,直接的函数调用行不通,必须通过 HTTP 或消息队列 来替代。但如果简单地把方法调用改成 RPC 调用,会导致通信变得非常频繁(“话太多”),影响性能。所以,微服务通常采用更大粒度的通信方式,减少交互次数,提高效率。

[!IMPORTANT]

补充:一般来说微服务需要做 API 网关,因为客户端不是直接调用服务,而是调用 API 网关,API 网关将调用转发到后端的相应服务。

2.5.去中心化治理更加灵活

集中式治理的一个常见问题是对单一技术平台的过度依赖。实践证明,这种做法过于死板。不是所有问题都适用于同一种工具,就像并非所有问题都是钉子,也不是所有解决方案都是锤子。相比之下,我们更倾向于选择适合具体任务的技术。虽然传统的单体架构应用可以在一定程度上使用不同的编程语言,但这种做法并不常见。

将单体架构拆分成多个独立服务后,我们在构建每个组件时可以灵活选择技术方案。例如:

  • 想用 Node.js 搭建一个简单的报表页面?完全可以!
  • 需要用 C++ 来处理一个高性能的实时计算模块?没问题!
  • 想为某个组件更换更适合其读取行为的数据库?技术上完全可行!

当然,技术选择的自由度增加并不意味着可以随意滥用,但这种架构至少为我们提供了更大的选择空间。

在微服务架构中,团队对于“标准化”有着不同的理解。他们更倾向于使用可复用的工具,而不是依赖一套写在纸上的固定标准。这些工具通常是从实践中提取出来的,并在团队内部乃至整个公司范围内共享,有些甚至采用类似开源的管理模式。

随着 GitGitHub 成为事实上的版本管理标准,开源协作的方式也逐渐被企业内部采纳。例如 Netflix,他们鼓励开发人员将经过实践检验的代码封装成共享库,以便其他团队复用。这种方式既能提高开发效率,也能确保架构的一致性,同时仍然允许在特定情况下使用不同的技术方案。

如今的技术栈早已不限于单一语言。例如,JVM 生态支持多种语言混合使用,开发者可以在高层使用高级语言进行抽象封装,而在底层采用更高效的低级语言优化性能。然而,许多传统的单体架构往往是单语言的,并且试图减少技术栈的多样性,以降低维护成本。

相比之下,微服务架构鼓励团队在保证服务契约的前提下自由选择技术。例如:

  • 采用 Tolerant ReaderConsumer-Driven Contracts 等模式,使服务契约能够独立演进,减少系统耦合。
  • 通过消费者驱动的契约测试,在新功能开发前就定义好 API 交互,确保服务间的兼容性。
  • 一些团队甚至在开发新服务时,先定义契约,并将其作为自动化构建的一部分,只有当服务满足契约后,才算真正完成。

这一切都减少了对中心化合同管理的需求,使服务更加独立。

去中心化治理的巅峰案例当属 Amazon 提出的 “Build it, Run it”(自己开发,自己运维) 理念。在这种模式下,开发团队不仅负责编码,还要承担运维责任,包括全天候确保系统正常运行。这种做法虽然不是行业普遍标准,但越来越多的公司正在朝这个方向发展。

Netflix 也是这一理念的践行者之一。在这样的环境下,开发人员需要直接对服务的稳定性负责——如果代码质量不佳,可能意味着凌晨 3 点就会被报警电话叫醒。这种责任机制极大地促进了工程师对代码质量的关注,从而推动整个系统架构的优化。

2.6.分散的数据管理持久化

在这里插入图片描述

数据管理的去中心化主要体现在两方面:概念模型和数据存储。不同系统或部门对同一事物的理解可能不同,比如销售和客服对“客户”的定义不一致。领域驱动设计(DDD)通过限界上下文来划分不同业务领域,避免这种混淆。

微服务架构去中心化了数据存储,每个服务管理自己的数据库,而不是共享一个数据库,这种方式称为多样化持久化。

数据更新方面,传统单体应用使用事务保证一致性,但微服务由于难以实现分布式事务,更倾向于采用最终一致性,通过补偿操作来处理错误。企业通常愿意接受短暂的不一致,以换取更高的业务灵活性。

2.7.基础设施的自动化管理

在这里插入图片描述

近几年,基础设施自动化技术发展迅猛,特别是云计算和 AWS 的进步,大大降低了构建、部署和运行微服务的复杂性。

很多采用微服务架构的团队,之前就有丰富的持续集成(CI)和持续交付(CD)经验,因此,他们高度依赖基础设施自动化。例如,在软件构建过程中,会运行大量自动化测试,确保代码质量,同时使用自动化工具将软件逐步部署到不同的环境中。

[!IMPORTANT]

补充:CI/CD, 持续继承/持续交付或持续部署 是现代软件开发中的两个核心概念,它们的目标是提高软件开发效率、减少错误,并让软件交付更快、更稳定。

  • 持续集成(CI, Continuous Integration):是指开发人员频繁地将代码合并到主分支,并通过自动化测试确保代码质量。
  • 持续交付(CD, Continuous Delivery):是指代码在通过 CI 的测试后,可以随时打包部署到生产环境,供团队进一步测试(一般需要人为批准后发布)。
  • 持续部署(CD, Continuous Deployment):是指代码通过所有测试后,自动部署到生产环境,无需人工干预。确保软件能稳定发布,可以随时发布到生产环境(一般可以自动测试后发布)。

随着持续交付和自动化部署的发展,开发人员和运维人员也创造了许多实用工具,比如:

  • 代码管理和构建工具
  • 一键启动服务的脚本
  • 标准化监控日志工具

对于单体架构的应用来说,自动化构建、测试和部署的流程通常都很顺畅。如果一个团队已经为单体架构搭建了自动化部署流程,那么增加更多的应用也不会觉得麻烦。持续交付的目标就是让部署变得“无聊”,无论是一两个应用,还是多个应用,只要部署依然稳定可靠,那就没什么可担心的。

虽然部署流程可以做到自动化,但运行微服务的方式和单体应用仍然有很大区别。微服务的运维管理通常更复杂,涉及到服务编排、监控、弹性伸缩等问题,因此,基础设施自动化在微服务架构中变得尤为重要。

2.8.即使是故障也需要处理

使用服务作为组件的一个后果是,应用程序必须具备容错能力,以应对服务的故障。任何一次服务调用都可能因供应方不可用而失败,客户端必须尽可能优雅地处理这种情况。与单体架构相比,这增加了额外的复杂性,这是微服务架构的一大缺点。因此,微服务团队需要持续思考服务故障对用户体验的影响。例如,NetflixSimian Army 在工作时间故意制造服务甚至整个数据中心的故障,以测试应用的容错性和监控能力。

这种在生产环境下进行自动化测试的做法,会让大多数运维团队感到胆战心惊,甚至可能需要放假一周来缓解压力。当然,这并不是说单体架构无法拥有成熟的监控体系,而是从实践经验来看,这种做法在单体架构中较少见。

由于服务随时可能出现故障,因此快速检测并尽可能自动恢复服务至关重要。微服务架构对应用的实时监控要求极高,不仅关注架构层面的指标(如数据库每秒处理多少请求),还关注业务层面的数据(如每分钟有多少订单提交)。语义化监控可以作为预警系统,提前发现异常,并通知开发团队进行调查和修复。

这对微服务架构尤为重要,因为微服务倾向于使用编排(choreography)和事件驱动的方式进行协作,这容易导致“涌现行为”(emergent behavior)。虽然很多人推崇这种自发涌现的特性,但实际上,涌现行为并不总是积极的。监控系统的作用就是尽早发现并纠正不良的涌现行为。

单体架构也可以做到像微服务那样透明,事实上,它应该做到这一点。但不同之处在于,运行在不同进程中的微服务如果断连,必须能够立即检测到,而在同一进程中的库(library)之间,这种透明度的重要性则相对较低。

微服务团队通常会为每个独立服务部署复杂的监控和日志系统,例如提供服务运行状态的仪表盘(Dashboard),以及各种运维和业务相关指标的展示。常见的监控内容包括熔断器(circuit breaker)状态、当前吞吐量、请求延迟等,这些都已成为微服务架构的常见实践。

2.9.渐进式和可替换的设计

微服务的实践者通常具有渐进式设计的背景,并将服务拆分视为一种工具,使应用开发人员能够在不降低变更速度的情况下更好地控制应用的更新。变更控制并不意味着减少变更,只要有合适的理念和工具,软件就可以实现频繁、快速且受控的迭代。

在尝试将一个软件系统拆分为多个组件时,必须决定如何划分这些部分,我们基于什么原则来拆分应用?组件的关键特性是独立替换和可升级性,也就是说,我们应该寻找那些可以独立重写而不影响其他组件的部分。事实上,许多微服务团队更进一步,他们默认许多服务会被废弃,而不是长期演进。

Guardian 网站就是一个典型案例,它最初是以单体架构构建的,但后来逐步向微服务架构演进。目前,该网站的核心仍然是单体架构,但他们更倾向于通过微服务的方式扩展新功能,而这些微服务会调用单体架构提供的 API。这种方式特别适用于一些临时性的功能,比如为某项体育赛事创建专门的页面。这类页面可以使用敏捷开发语言快速搭建,并在活动结束后直接移除。类似的模式在金融行业也很常见,比如针对某个市场机会新增的服务,可能只会存在几周或几个月,之后就会被废弃。

[!NOTE]

吐槽:简而言之,就是通过微服务架构来快速搭建和拆除临时功能,避免单体架构中的“臃肿”问题。

可替换性(Replaceability)是模块化设计的一个特例,其核心思想是通过变更模式来驱动模块化设计。也就是说,应该把那些经常一起变更的部分放在同一个模块中,而变更频率低的部分则应拆分到不同的服务中。如果两个服务经常需要一起修改,那可能意味着它们应该被合并成一个。

将组件拆分为独立服务后,还能带来更灵活的发布管理。在单体架构中,任何变更都需要重新构建和部署整个应用,而在微服务架构下,只需要重新部署修改过的服务即可,这大大简化了发布流程并提高了效率。然而,这种模式的缺点是,某个服务的变更可能会影响到其依赖方。传统的做法是通过版本管理来解决这个问题,但微服务架构更倾向于将版本管理作为最后的手段。实际上,我们可以通过让服务尽可能具备向后兼容性,从而减少对版本管理的依赖,提高系统的稳定性。

3.微服务的技术

可以学习以下技术栈来学习微服务。

  • 前端:React.jsVue.js
  • 后端:Go 语言 + 微服务工具集 Go kit
  • 通讯:gRPC
  • API:Swagger
  • 网关:Envoy(可以把 Envoy 通过 Ingress 集成进 Kubernetes,这里有一个开源项目就是干这个事的 contour
  • 日志监控:fluentd + ELK
  • 指标监控:Prometheus
  • 调用跟踪:Jaeger
  • 自动化运维:Docker + Kubernetes

http://www.kler.cn/a/540568.html

相关文章:

  • WidowX-250s 机械臂学习记录
  • Centos Ollama + Deepseek-r1+Chatbox运行环境搭建
  • SpringSecurity高级用法
  • 字符串高频算法:无重复字符的最长子串
  • vue学习5
  • FaceFusion如何设置公开链接和端口
  • Pycharm使用Anaconda创建的不同conda环境
  • 03-DevOps-安装并初始化Gitlab
  • torch_bmm验算及代码测试
  • 38.社区信息管理系统(基于springboothtml)
  • windows10 wsa 安卓子系统终结版
  • 网络协议课程笔记上
  • AUTOSAR 4.2.2版本中Dem 操作循环(Operation Cycle)的开启和关闭
  • Python实现GO鹅优化算法优化支持向量机SVM回归模型项目实战
  • JSON是什么
  • 从零到一:基于Rook构建云原生Ceph存储的全面指南(上)
  • The 2024 ICPC Asia East Continent Online Contest (II) (6/9/12)
  • JDK8 stream API用法汇总
  • STM32 RTC亚秒
  • 【高级架构师】多线程和高并发编程(三):锁(下)深入ReentrantReadWriteLock
  • Python——批量图片转PDF(GUI版本)
  • 2.10寒假作业
  • 反射:获取类中的成分、并对其进行操作
  • SpringCloud - Sentinel服务保护
  • 矩阵NFC碰一碰发视频的源码技术开发攻略,支持OEM
  • 【数据】Cassandra(列存储)