导读:《架构设计》系列为极客时间李运华老师《从0开始学架构》课程笔记。本文为第十部分。主要介绍了如何面向服务拆分架构,首先介绍了 SOA 架构,接着介绍了微服务架构,以及二者对比。微服务架构并非“银弹”,架构师要合理采用,避免掉入陷阱。

扫描文末二维码 关注公众号 回复 “架构设计” 获取架构设计笔记完整思维导图

面向服务拆分架构典型架构主要要 SOA 架构和微服务架构

SOA(Service Oriented Architecture)面向服务的架构

  • 企业各部门有独立的 IT 系统,比如人力资源系统、财务系统、销售系统,这些系统可能都涉及人员管理,各 IT 系统都需要重复开发人员管理的功能。
  • 各个独立的 IT 系统可能采购于不同的供应商,实现技术不同,企业自己也不太可能基于这些系统进行重构。
  • 随着业务的发展,复杂度越来越高,更多的流程和业务需要多个 IT 系统合作完成。由于各个独立的 IT 系统没有标准的实现方式(例如,人力资源系统用 Java 开发,对外提供 RPC;而财务系统用 C# 开发,对外提供 SOAP 协议),每次开发新的流程和业务,都需要协调大量的 IT 系统,同时定制开发,效率很低。

3 个关键概念

服务

所有业务功能都是一项服务,服务就意味着要对外提供开放的能力,当其他系统需要使用这项功能时,无须定制化开发。

ESB

  • ESB 的全称是 Enterprise Service Bus,中文翻译为“企业服务总线”
  • ESB 将企业中各个不同的服务连接在一起。因为各个独立的服务是异构的,如果没有统一的标准,则各个异构系统对外提供的接口是各式各样的。
  • SOA 使用 ESB 来屏蔽异构系统对外提供各种不同的接口方式,以此来达到服务间高效的互联互通。

松耦合

松耦合的目的是减少各个服务间的依赖和互相影响。

优缺点

优点

SOA 解决了传统 IT 系统重复建设和扩展效率低的问题

缺点

  • 引入了更多的复杂性。SOA 最广为人诟病的就是 ESB,ESB 需要实现与各种系统间的协议转换、数据转换、透明的动态路由等功能。
  • ESB 虽然功能强大,但现实中的协议有很多种,如 JMS、WS、HTTP、RPC 等,数据格式也有很多种,如 XML、JSON、二进制、HTML 等。ESB 要完成这么多协议和数据格式的互相转换,工作量和复杂度都很大,而且这种转换是需要耗费大量计算性能的,当 ESB 承载的消息太多时,ESB 本身会成为整个系统的性能瓶颈。

微服务

small、lightweight、automated,基本上浓缩了微服务的精华,也是微服务与 SOA 的本质区别所在

微服务陷阱

服务划分过细,服务间关系复杂

服务划分过细,单个服务的复杂度确实下降了,但整个系统的复杂度却上升了,因为微服务将系统内的复杂度转移为系统间的复杂度了。

服务数量太多,团队效率急剧下降

一个简单的需求开发就需要涉及多个微服务,光是微服务之间的接口就有 6 ~ 7 个,无论是设计、开发、测试、部署,都需要工程师不停地在不同的服务间切换。

调用链太长,性能下降

由于微服务之间都是通过 HTTP 或者 RPC 调用的,每次调用必须经过网络。

调用链太长,问题定位困难

系统拆分为微服务后,一次用户请求需要多个微服务协同处理,任意微服务的故障都将导致整个业务失败。然而由于微服务数量较多,且故障存在扩散现象,快速定位到底是哪个微服务故障是一件复杂的事情。

没有自动化支撑,无法快速交付

如果没有相应的自动化系统进行支撑,都是靠人工去操作,那么微服务不但达不到快速交付的目的,甚至还不如一个大而全的系统效率高。

没有服务治理,微服务数量多了后管理混乱

  • 服务路由:假设某个微服务有 60 个节点,部署在 20 台机器上,那么其他依赖的微服务如何知道这个部署情况呢?
  • 服务故障隔离:假设上述例子中的 60 个节点有 5 个节点发生故障了,依赖的微服务如何处理这种情况呢?
  • 服务注册和发现:同样是上述的例子,现在我们决定从 60 个节点扩容到 80 个节点,或者将 60 个节点缩减为 40 个节点,新增或者减少的节点如何让依赖的服务知道呢?

最佳实践

服务粒度

原则:微服务拆分粒度的“三个火枪手”原则,即一个微服务三个人负责开发

  • 从系统规模来讲,3 个人负责开发一个系统,系统的复杂度刚好达到每个人都能全面理解整个系统,又能够进行分工的粒度;如果是 2 个人开发一个系统,系统的复杂度不够,开发人员可能觉得无法体现自己的技术实力;如果是 4 个甚至更多人开发一个系统,系统复杂度又会无法让开发人员对系统的细节都了解很深。
  • 从团队管理来说,3 个人可以形成一个稳定的备份,即使 1 个人休假或者调配到其他系统,剩余 2 个人还可以支撑;如果是 2 个人,抽调 1 个后剩余的 1 个人压力很大;如果是 1 个人,这就是单点了,团队没有备份,某些情况下是很危险的
  • 从技术提升的角度来讲,3 个人的技术小组既能够形成有效的讨论,又能够快速达成一致意见;如果是 2 个人,可能会出现互相坚持自己的意见,或者 2 个人经验都不足导致设计缺陷;如果是 1 个人,由于没有人跟他进行技术讨论,很可能陷入思维盲区导致重大问题;如果是 4 个人或者更多,可能有的参与的人员并没有认真参与,只是完成任务而已。
  • “三个火枪手”的原则主要应用于微服务设计和开发阶段,如果微服务经过一段时间发展后已经比较稳定,处于维护期了,无须太多的开发,那么平均 1 个人维护 1 个微服务甚至几个微服务都可以。当然考虑到人员备份问题,每个微服务最好都安排 2 个人维护,每个人都可以维护多个微服务。

拆分方法

基于业务逻辑拆分

将系统中的业务模块按照职责范围识别出来,每个单独的业务模块拆分为一个独立的服务。

基于可扩展拆分
  • 将系统中的业务模块按照稳定性排序,将已经成熟和改动不大的服务拆分为稳定服务,将经常变化和迭代的服务拆分为变动服务。稳定的服务粒度可以粗一些,即使逻辑上没有强关联的服务,也可以放在同一个子系统中
  • 不稳定的服务粒度可以细一些,但也不要太细,始终记住要控制服务的总数量。
基于可靠性拆分

将系统中的业务模块按照优先级排序,将可靠性要求高的核心服务和可靠性要求低的非核心服务拆分开来,然后重点保证核心服务的高可用。具体拆分的时候,核心服务可以是一个也可以是多个,只要最终的服务数量满足“三个火枪手”的原则就可以。优点:

  • 避免非核心服务故障影响核心服务
  • 核心服务高可用方案可以更简单
  • 能够降低高可用成本
  • 基于性能拆分

基础设置

服务发现

手工配置工作量很大,配置文件可能要配几百上千行,几十个节点加起来后配置项就是几万几十万行了,人工维护这么大数量的配置项是一项灾难。微服务节点经常变化,可能是由于扩容导致节点增加,也可能是故障处理时隔离掉一部分节点,还可能是采用灰度升级,先将一部分节点升级到新版本,然后让新老版本同时运行。实现方式:

自理式,每个微服务自己完成服务发现。优点:1. 实现比较简单,因为这部分的功能一般通过统一的程序库或者程序包提供给各个微服务调用,而不会每个微服务都自己来重复实现一遍。2. 由于每个微服务都承担了服务发现的功能,访问压力分散到了各个微服务节点,性能和可用性上不存在明显的压力和风险。

代理式,微服务之间有一个负载均衡系统,由负载均衡系统来完成微服务之间的服务发现,优点:看起来更加清晰,微服务本身的实现也简单了很多;缺点:1. 可用性风险,一旦 LOAD BALANCER 系统故障,就会影响所有微服务之间的调用。2.性能风险,所有的微服务之间的调用流量都要经过 LOAD BALANCER 系统,性能压力会随着微服务数量和流量增加而不断增加,最后成为性能瓶颈。因此 LOAD BALANCER 系统需要设计成集群的模式,但 LOAD BALANCER 集群的实现本身又增加了复杂性。

不管是自理式还是代理式,服务发现的核心功能就是服务注册表,注册表记录了所有的服务节点的配置和状态,每个微服务启动后都需要将自己的信息注册到服务注册表,然后由微服务或者 LOAD BALANCER 系统到服务注册表查询可用服务

服务路由
  • 具体进行某次调用请求时,我们还需要从所有符合条件的可用微服务节点中挑选出一个具体的节点发起请求,这就是服务路由需要完成的功能。
  • 服务路由和服务发现紧密相关,服务路由一般不会设计成一个独立运行的系统,通常情况下是和服务发现放在一起实现的。
  • 无论放在哪里实现,服务路由核心的功能就是路由算法,常见的路由算法有:随机路由、轮询路由、最小压力路由、最小连接数路由等。
服务容错
  • 系统拆分为微服务后,单个微服务故障的概率变小,故障影响范围也减少,但是微服务的节点数量大大增加。从整体上来看,系统中某个微服务出故障的概率会大大增加
  • 微服务具有故障扩散的特点,如果不及时处理故障,故障扩散开来就会导致看起来系统中很多服务节点都故障了,因此需要微服务能够自动应对这种出错场景,及时进行处理。
  • 常见的服务容错包括请求重试、流控和服务隔离。通常情况下,服务容错会集成在服务发现和服务路由系统中。
提升开发效率

接口框架:提升内部服务的开发效率:

  • 微服务提倡轻量级的通信方式,一般采用 HTTP/REST 或者 RPC 方式统一接口协议
  • 在实践过程中,光统一接口协议还不够,还需要统一接口传递的数据格式
  • 接口框架不是一个可运行的系统,一般以库或者包的形式提供给所有微服务调用

    API 网关:提升与外部服务对接的效率:

  • 微服务需要一个统一的 API 网关,负责外部系统的访问操作
  • API 网关是外部系统访问的接口,所有的外部系统接⼊系统都需要通过 API 网关,主要包括接入鉴权(是否允许接入)、权限控制(可以访问哪些功能)、传输加密、请求路由、流量控制等功能。
提升测试和运维效率

自动化部署:自动化部署系统包括版本管理、资源管理(例如,机器管理、虚拟机管理)、部署操作、回退操作等功能。

自动化测试:

  • 包括代码级的单元测试、单个系统级的集成测试、系统间的接口测试,理想情况是每类测试都自动化
  • 如果因为团队规模和人力的原因无法全面覆盖,至少要做到接口测试自动化。

配置中心:配置中心包括配置版本管理、增删改查配置、节点管理、配置同步、配置推送等功能。

进一步提升运维效率

服务监控:系统拆分为微服务后,节点数量大大增加,导致需要监控的机器、网络、进程、接口调用数等监控对象的数量大大增加。 一旦发生故障,我们需要快速根据各类信息来定位故障。主要作用:

  • 实时搜集信息并进行分析,避免故障后再来分析,减少了处理时间。
  • 服务监控可以在实时分析的基础上进行预警,在问题萌芽的阶段发觉并预警,降低了问题影响的范围和时间。

服务监控需要搜集并分析大量的数据,因此建议做成独立的系统,而不要集成到服务发现、API 网关等系统中

服务跟踪:

  • 服务监控可以做到微服务节点级的监控和信息收集,但如果我们需要跟踪某一个请求在微服务中的完整路径,服务监控是难以实现的。因为如果每个服务的完整请求链信息都实时发送给服务监控系统,数据量会大到无法处理。
  • 服务监控和服务跟踪的区别可以简单概括为宏观和微观的区别。

服务安全:

  • 服务安全主要分为三部分:接入安全、数据安全、传输安全。
  • 服务安全可以集成到配置中心系统中进行实现,即配置中心配置微服务的接入安全策略和数据安全策略,微服务节点从配置中心获取这些配置信息,然后在处理具体的微服务调用请求时根据安全策略进行处理。由于这些策略是通用的,一般会把策略封装成通用的库提供给各个微服务调用。

微服务与 SOA 的关系

三种主要观点:

  • 微服务是 SOA 的实现方式
  • 微服务是去掉 ESB 后的 SOA
  • 微服务是一种和 SOA 相似但本质上不同的架构理念

服务粒度

  • SOA 的服务粒度要粗一些
  • 微服务的服务粒度要细一些

服务通信

  • SOA 采用了 ESB 作为服务间通信的关键组件,负责服务定义、服务路由、消息转换、消息传递,总体上是重量级的实现
  • 微服务推荐使用统一的协议和格式,例如,RESTful 协议、RPC 协议,无须 ESB 这样的重量级实现。

服务交付

  • SOA 对服务的交付并没有特殊要求,因为 SOA 更多考虑的是兼容已有的系统
  • 微服务的架构理念要求“快速交付”,相应地要求采取自动化测试、持续集成、自动化部署等敏捷开发相关的最佳实践。

应用场景

  • SOA 更加适合于庞大、复杂、异构的企业级系统,这也是 SOA 诞生的背景。
  • 微服务更加适合于快速、轻量级、基于 Web 的互联网系统,这类系统业务变化快,需要快速尝试、快速交付;同时基本都是基于 Web,虽然开发技术可能差异很大(例如,Java、C++、.NET 等),但对外接口基本都是提供 HTTP RESTful 风格的接口,无须考虑在接口层进行类似 SOA 的 ESB 那样的处理。

个人思考

SOA 架构在现代网络服务中使用的较少,主要用于传统软件行业。微服务架构在近些年比较流行,尤其在互联网行业面临多端复杂接入、场景也随之复杂,人们不得不寻求更适合的架构来解决这些问题。但是微服务并不是“银弹”,并不能毕其功于一役,而且微服务自身也有这样或那样的问题,链路错综复杂、功能分散等问题有时候反而降低了研发效率。因此,架构师要合理采用微服务架构。

reference

  1. 《从 0 开始学架构》 https://time.geekbang.org/col...


aneutron
6 声望2 粉丝