微服务架构 | 青训营笔记

80 阅读11分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 11 天

微服务架构

Created: February 4, 2023 11:05 PM Tags: golang note

微服务架构(Micro service Architecture)是一种架构概念,旨在通过将功能分解到各个离散的服务中以实现对大型应用的解耦。

传统开发模式与微服务的区别

单体式开发

image.png

我们以传统的单体式开发(Monolithic)为例,这是最简单的架构风格,所有的代码全都在一个项目中。开发人员可以只在自己电脑上就可以完成开发、调试、测试整个系统的功能,直接编译打包整个系统代码,创建一个可以发布的二进制版本。这种方式对于一个新团队的创立初期,需要迅速开始从0到1,抓住时机实现产品并推向市场,具有十分重要的意义。

但其明显存在许多坏处,例如代码严重耦合,不同模块相互引用,导致系统内的对象间依赖关系混乱;系统变更对部署影响大,每次发布的部署单元就是一个新版本的整个系统,系统内的任何业务逻辑调整都会导致整个系统的重新打包,大大提供了系统风险;开发效率低下,如果系统比较庞大,修改代码后执行编译需要花费很长时间,业务系统启动很慢。因此单体式开发比较适用于规模较小的区别,特别是需要快速推出原型实现,以质量换速度的场景。

垂直应用架构

image.png

将一个大型应用拆分成多个相互独立的小型应用成为解决单体应用的一种方案,这就是垂直架构(也成为“竖井式架构”)。垂直架构根据业务属性将一个大的单体应用拆分成多个模块或子系统,子系统之间没有直接关联。

垂直架构相较于单体架构而言,进行了部分解耦,但是不够彻底,在各个子系统相互依赖的代码和模块中,存在重复代码拷贝和模块功能重复开发的情况。

分布式架构

image.png

将系统演变为垂直应用架构之后,当垂直应用越来越多时,重复编写的业务代码就会越来越多。此时,我们需要将重复的代码抽象出来,形成统一的服务,供其他系统或者业务模块调用,这就是分布式架构。

这种架构的优点在于代码复用度变高;单一职责。而缺点在于各应用间相互调用,系统复杂度升高;系统耦合度升高;开发测试困难。

SOA 架构

image.png

在分布式架构下,当部署的服务越来越多时,重复的代码就会变得越来越多,不利于代码的复用和系统维护。为此,我们需要增加一个统一的调度中心对集群进行实时管理,这就是SOA(面向服务)架构。

这种架构的优点是通过注册中心解决了各个服务之间服务依赖和调用关系的自动注册与发现。缺点在于各服务之间存在依赖关系,如果某个服务出现故障,可能会造成服务器崩溃;以及服务之间的依赖与调用关系复杂,增加了测试和运维的成本。

微服务架构

image.png

微服务架构是在SOA架构的基础上进行进一步的扩展和拆分。而所谓的微服务,并不是越小越好,二手通过团队规模和业务复杂度有粗到细的划分过程,所遵循的原则是松耦合和高内聚。

  • 松耦合:修改一个服务不需要同时修改另一个,每个微服务都可以单独修改和发布。
  • 高内聚:把相关的事务放在一起,把不相关的排除出去,聚集在一起的事务只能干同一件事。

微服务和 SOA 的区别

  1. SOA喜欢重用,微服务喜欢重写

    SOA的主要目的是为了企业各个系统更加容易地融合在一起。说到SOA不得不说ESB (Enterprise Service Bus)。ESB是什么? 可以把ESB想象成一个连接所有企业级服务的脚手架。通过service broker,它可以把不同数据格式或模型转成canonical格式,把XML的输入转成CSV传给legacy服务,把SOAP 1.1服务转成 SOAP 1.2等等。它还可以把一个服务路由到另一个服务上,也可以集中化管理业务逻辑,规则和验证等等。它还有一个重要功能是消息队列和事件驱动的消息传递,比如把JMS服务转化成SOAP协议。各服务间可能有复杂的依赖关系。

    微服务通常由重写一个模块开始。要把整个巨石型的应用重写是有很大的风险的,也不一定必要。我们向微服务迁移的时候通常从耦合度最低的模块或对扩展性要求最高的模块开始,把它们一个一个剥离出来用敏捷地重写,可以尝试最新的技术和语言和框架,然 后单独布署。它通常不依赖其他服务。微服务中常用的API Gateway的模式主要目的也不是重用代码,而是减少客户端和服务间的往来。API gateway模式不等同与Facade模式,我们可以使用如future之类的调用,甚至返回不完整数据。

  2. SOA 喜欢水平服务,微服务喜欢垂直服务

    SOA设计喜欢给服务分层(如Service Layers模式)。我们常常见到一个Entity服务层的设计,美其名曰Data Access Layer。这种设计要求所有的服务都通过这个Entity服务层来获取数据。这种设计非常不灵活,比如每次数据层的改动都可能影响到所有业务层的服务。而每个微服务通常有它自己独立的data store。我们在拆分数据库时可以适当的做些去范式化(denormalization),让它不需要依赖其他服务的数据。

    微服务通常是直接面对用户的,每个微服务通常直接为用户提供某个功能。类似的功能可能针对手机有一个服务,针对机顶盒是另外一个服务。在SOA设计模式中这种情况通常会用到Multi-ChannelEndpoint的模式返回一个大而全的结果兼顾到所有的客户端的需求。

  3. SOA 喜欢自上而下,微服务喜欢自下而上

    SOA架构在设计开始时会先定义好服务合同(service contract)。它喜欢集中管理所有的服务,包括集中管理业务逻辑,数据,流程,schema,等等。它使用Enterprise Inventory和Service Composition等方法来集中管理服务。SOA架构通常会预先把每个模块服务接口都定义好。模块系统间的通讯必须遵守这些接口,各服务是针对他们的调用者。

    SOA架构适用于TOGAF之类的架构方法论。

    微服务则敏捷得多。只要用户用得到,就先把这个服务挖出来。然后针对性的,快速确认业务需求,快速开发迭代。

如何实现微服务

要实际的应用微服务,需要解决一下四点问题:

1、客户端如何访问这些服务?

2、每个服务之间如何通信?

3、如此多的服务,如何实现?

4、服务挂了,如何解决?(备份方案,应急处理机制)

客户端如何访问这些服务

原来的Monolithic方式开发,所有的服务都是本地的,UI可以直接调用,现在按功能拆分成独立的服务,跑在独立的一般都在独立的虚拟机上的 Java进程了。客户端UI如何访问他的?

后台有N个服务,前台就需要记住管理N个服务,一个服务下线/更新/升级,前台就要重新部署,这明显不服务我们 拆分的理念,特别当前台是移动应用的时候,通常业务变化的节奏更快。

另外,N个小服务的调用也是一个不小的网络开销。还有一般微服务在系统内部,通常是无 状态的,用户登录信息和权限管理最好有一个统一的地方维护管理(OAuth)。

所以,一般在后台N个服务和UI之间一般会一个代理或者叫API Gateway,他的作用包括:

① 提供统一服务入口,让微服务对前台透明

② 聚合后台的服务,节省流量,提升性能

③ 提供安全,过滤,流控等API管理功能

其实这个API Gateway可以有很多广义的实现办法,可以是一个软硬一体的盒子,也可以是一个简单的MVC框架,甚至是一个Node.js的服务端。他们最重要的作 用是为前台(通常是移动应用)提供后台服务的聚合,提供一个统一的服务出口,解除他们之间的耦合,不过API Gateway也有可能成为单点故障点或者性能的瓶颈。

每个服务之间如何通信

所有的微服务都是独立的Java进程跑在独立的虚拟机上,所以服务间的通信就是IPC(inter process communication),已经有很多成熟的方案。现在基本最通用的有两种方式:

同步调用:(1)REST(JAX-RS,Spring Boot);(2)RPC(Thrift, Dubbo)

异步消息调用:Kafka, Notify, MetaQ

同步和异步的区别在于,一般同步调用比较简单,一致性强,但是容易出调用问题,性能体验上也会差些,特别是调用层次多的时候。而异步消息的方式在分布式系统中有特别广泛的应用,他既能减低调用服务之间的耦合,又能成为调用之间的缓冲,确保消息积压不会冲垮被调用方,同时能保证调用方的服务体验,继续干自己该干的活,不至于被后台性能拖慢。不过需要付出的代价是一致性的减弱,需要接受数据最终一致性;还有就是后台服务一般要 实现幂等性,因为消息发送出于性能的考虑一般会有重复(保证消息的被收到且仅收到一次对性能是很大的考验)。

如何实现如此多的服务

在微服务架构中,一般每一个服务都是有多个拷贝,来做负载均衡。一个服务随时可能下线,也可能应对临时访问压力增加新的服务节点。服务之间如何相互感知?服务如何管理?

这就是服务发现的问题了。一般有两类做法,也各有优缺点。基本都是通过zookeeper等类似技术做服务注册信息的分布式管理。当服务上线时,服务提供者将自己的服务信息注册到ZK(或类似框架),并通过心跳维持长链接,实时更新链接信息。服务调用者通过ZK寻址,根据可定制算法, 找到一个服务,还可以将服务信息缓存在本地以提高性能。当服务下线时,ZK会发通知给服务客户端。

客户端做: 优点是架构简单,扩展灵活,只对服务注册器依赖。缺点是客户端要维护所有调用服务的地址,有技术难度,一般大公司都有成熟的内部框架支持,比如Dubbo。

服务端做:优点是简单,所有服务对于前台调用方透明,一般在小公司在云服务上部署的应用采用的比较多。

服务挂了如何解决

前面提到,Monolithic方式开发一个很大的风险是,把所有鸡蛋放在一个篮子里,一荣俱荣,一损俱损。而分布式最大的特性就是网络是不可靠的。通过微服务拆分能降低这个风险,不过如果没有特别的保障,结局肯定是噩梦。所以当我们的系统是由一系列的服务调用链组成的时候,我们必须确保任一环节出问题都不至于影响整体链路。

**相应的手段有很多:**重试机制;限流;熔断机制;;负载均衡;降级(本地缓存)。

参考资料:

微服务架构的一知半解

A Design Analysis of Cloud-based Microservices Architecture at Netflix