微服务架构的一知半解

5,409 阅读12分钟

1.前言

     《三国演义》开篇便讲道: "话说天下大势,分久必合,合久必分...."。其实经历的大部分事物都有这样的规律, 在软件系统设计中,也会经历这样的迭代演进。在两年多的微服务架构设计与实战中,笔者经历了从庞大的单体应用系统架构拆分成不同的众多的微服务应用,再将不同的微服务应用重组成有能力复用的中台,但总目的都是为了更好地支撑业务发展,提升软件开发的效率与质量。本篇主要想梳理微服务架构的一些基础知识,让大家对微服务架构有个全面系统的了解。

2.单体架构 VS 微服务架构

2.1 软件架构定义

         软件架构是构建应用系统所需要的一组结构,包括软件元素、元素之间的关系以及两者的属性。其中如何分解软件元素以及这些元素之间的关系,变得非常重要。一个好的软件架构具备两个特点:

  • 合理调配生产关系与生产力,让具备不同专业知识与技术栈的的人士都参与到软件系统开发中来, 高效地协同工作;
  • 能让各个软件元素有清晰的定义与职责,并有一套良好、高效的交互机制.

2.2 单体应用架构

       应用开发采用单体架构,所有的代码在一个代码仓库中管理,最后打包成一个部署包,运行在一个进程上。典型的有三层应用架构与六边形应用架构两种。

在项目初期,单体架构确实会给开发带来无与伦比的效率提升,单体架有以下的好处:

  • 应用开发简单,基本所有的代码都在一个仓库中管理;
  • 非常方便进行大规模的更改;
  • 容易测试,只需要写几个端对端的测试;
  • 部署简单明了,横向扩展非常容易.

但随着业务的扩张,业务模块数量与代码量都会急剧增加,这时单体架构的弊端逐渐突显:

  • 复杂度不断提升,模块之间的耦合度越来越高,维护成本很高;
  • 更新迭代周期变长,从代码提交到实际部署的周期会拉长,甚至有时都无法交付;
  • 难以扩展与迭代演进,使用过时的技术栈或组件一直无法升级.

2.3 微服务架构

      在讲述微服务架构之前一定要讲下经典的扩展立方体理论,扩展立方体定义了三种不同的扩展应用程序的方法:

  • X轴扩展在多个相同实例之间实现请求的负载均衡;
  • Y轴扩展根据功能将应用程序拆分为服务; 
  • Z轴扩展根据请求的属性路由请求.

微服务架构其实可以理解为”模块化设计"的扩展延伸,只是这些"功能模块"以单独的部署包的方式运行在各自的进程中。这样每个服务之间都是相互独立的,并且有自己的私有数据库,两者之间仅能通过API的方式进行通信。

从单体架构到微服务架构的演进也带来了以下好处:

  • 从代码管理来看,每个服务较小,大部分由于十几个接口或服务方法组成,非常容易维护;
  • 从运维管理来看,每个服务都可以独立部署,非常易于扩展; 
  • 从团队管理来看,可以更好地划分职责范围;
  • 从软件开发总体来看,可以使软件系统可持续性交付部署.

同样,微服务架构也具有以下弊端:

  • 服务的拆分和定义有一定的难度;
  • 增加了系统的复杂度,使开发、测试、部署都变得更加困难;
  • 在部署多个服务的功能时需要在协调开发团队.

3.微服务架构定义与组成

       微服务架构中需要考虑决策模型由多个模式组成。从层次上大致可分为应用相关、应用基础相关、基础设施相关三大层。

  • 应用相关模式: 服务拆分、数据库的架构、维护数据一致性问题、测试相关;
  • 应用基础设施相关模式: 边界问题、安全性、事务性消息、通信风格、可靠性、可监测性;
  • 基础设施相关模式: 应用/服务的部署、服务发现等.

3.1 服务拆分

将原来的单体应用系统分解为一系列的服务其实是有难度的,可以遵循以下两种分解策略:

  • 根据业务能力分解
  • 根据子域分解

3.2 通信方式

使用微服务架构的应用程序是分布式系统,进程间通信是重要组成部分,有以下几种通信模式:

  • 通信风格: 使用哪一种的进程间通信机制;
  • 服务发现: 客户端如何获得具体实例的真实IP地址;
  • 可靠性: 在服务不可用的情况下,如何确保服务之间的可靠通信;
  • 事务性消息: 如何将消息发送、事件发布、更新业务数据的数据库事务集成;
  • 外部API: 应用客户端如何与服务通信.

3.3 数据一致性模式

        在微服务架构下每个服务都有自己独立的数据库,原先在单应用架构下的2PC的事务机制在微服务架构中就不再适用,需要类似于分布式事务的中间件来保证数据的一致性。

3.4 可观测性

        在微服务架构下对,一个请求往往会经过多个服务实例的跳转,有关应用程序的性能问题如高延时等问题就比较难观测与解决,需要以下的模式来设计出一套可监测的服务:

  • 健康检查API:每个微服务应用需要一个可以返回健康状体的API;
  • 日志聚合: 把服务器节点的所有日志都写入一个集中式的日志服务器,可在这个服务器上进行日志搜索,并根据日志情况出发告警,典型的方案是Log路径+容器+ES;
  • 分布式链路跟踪:为每一个外部的请求分配一个唯一的ID,用于在各个服务之间的跟踪外部请求,newlic/skywalking;
  • 应用指标: 维护使用的指标,如调用计数;
  • 审计日志: 记录用户的行为;

3.5 部署相关模式

        部署一个单体应用是一个比较直观的操作,部署基于微服务的应用程序就要复杂得多,通常应有数十甚至上百个服务组成。传统的基于手工复制到服务器上的应用程序部署方式不再适用于微服务架构,需要一个高度自动化部署的基础设施,如可以管理需求任务、代码变更, 服务器资源环境于一身的部署平台。

3.6 安全相关

        在微服务架构中,用户身份、权限验证的工作通常由网关完成的,常见的解决方式是Outh2协议的访问令牌模式,由网关将访问令牌传递到服务,验证令牌并获取用户有关的信息。

3.7 测试相关

        单体架构的测试与微服务架构测试的方法与重点都不一样,由于服务粒度变小,微服务架构让测试变得更加简单,重点在于测试不同的服务是否协同工作,同时使用复杂的、缓慢和脆弱的端对端的测试来测试多个服务,以下模式可以通过单独测试服务来简化测试工作量与提升测试的效率:

  • 消费端驱动的测试: 验证服务满足客户端所期望的功能;
  • 的消费端契约测试: 验证服务的客户端可以正常与服务通信;
  • 服务组件测试: 在隔离环境中测试服务.

3.8 基础设施和边界问题的相关模式

在微服务架构中,每个服务必须实现许多跟基础设施相关的功能,如可观测性模式和服务发现模式,外部化配置模式等,需要开发出一个微服务架构的基础设施基座,这样在开发新的微服务业务时就可以在基座上快速接入与开发。

4.服务拆分

当时整个后台系统一样遇到了“单体地狱”的问题,所以决心拆分成若个领域微服务来缓解开发/部署上的一系列问题,主要遵循以下的拆分策略与指导原则。

4.1 拆分策略

        所有的出发点都是业务,首先要梳理出功能需求或用户故事用来定义出系统操作,然后将系统操作转化成一个个完整的请求,根据请求就可以初步定义出服务的具体职责与边界,然后再定义服务之间的接口和协作方式。

服务拆分的依据有两种:一种是从业务能力到服务,对业务能力的聚合能力边界与职责,另一种是根据DDD领域设计中的子域进行服务划分。

4.4 拆分的指导原则

  • 单一职责任(SRP): 原先指的是每个类只承载一个职责,在微服务架构中,指的是每个微服务都应该是尽可能小的,内聚的,并且能独立完成一个业务的闭环支撑。
  • 闭包原则(CPP): 定义是包中的所有类应该是对同类的变化的一个集合,如果对包做出修改,需要更新的类都应该在这个包内,在微服务架构中, 指的是当需求变化时,需要变更的服务组件范围是可控的最好是一个服务,最好在一个开发团队内就能完成。

4.5 拆分单体应用服务的难点

  • 网络延迟,请求在经过服务的层层转发后,通信链路会增加N倍,当然通信会延迟;
  • 进程间的通信导致可用性降低,微服务集群所在的网络的流量会增大,哪怕是在局域网内也会因为网络抖动或链路热点而导致可用性降低;
  • 在服务之间保持数据一致,获取一致的数据视图,不同数据库实例的事务较难实现.

5.进程间的通信

5.1 通信的方式

  • 一对一: 每个客户端请求由一个服务实例处理;
  • 一对多: 每个客户端请求由多个服务实例处理;
  • 同步模式: 客户端请求需要服务端实时响应,客户端等待响应时间可能会阻塞;
  • 异步模式: 客户端请求不会阻塞进程,服务端的响应可以是非实时的;

5.2 基于同步远程过程调用模式的通信

        远程过程调用的工作原理是,客户端中的业务逻辑调用代理接口,这个接口由远程过程调用代理适配类实现,调用代理会向服务发出请求,该请求由远程过程调用服务器适配类处理,该类通过接口调用服务的业务逻辑,然后将回复发送回过程调用代理,该代理将结果返回给客户端的业务逻辑。

        在整个远程调用过程中可能会发生网络超时、服务器端超出了处理的请求数等问题导致的客户端请求失败,可以使用hystrix组件来处理这些问题,保证服务的高可用,但是基于断路器模式属于“后知后觉”型,要实现服务发现主要有应用服务与平台服务两种发现模式。

  • 客户端发现模式: 服务实例使用服务注册表组册其网络位置,客户端从注册表中获取到可用服务实例的列表,并在它们之间进行负载均衡;
  • 平台层服务发现模式: 许多部署瓶体啊如Docker和Kubernetes都具有内置的服务注册表和服务发现机制,部署平台为每个服务提供DNS名称,虚拟IP地址和DNS名称,当客户顿啊向DNS名称和虚拟IP发出请求,部署平台自动将其路由到其中一个可用的服务实例.

5.3 基于异步消息模式的通信

       使用消息机制时,服务之间的通信采用异步交换消息的方式完成。发送方中的业逻辑调用发送接口,该接口封装底层通信机制,发送端由信息发送适配器类实现,该消息发送适配器类通过消息通道向接收器发送消息。调用接收器中的消息处理程序适配器类来处理消息。它调用接收方业务逻辑实现的接收端接口。任意数量的发送方都可以向消息通道发送消息,同样,任意数量的接收方都可以从消息通道中接收消息。

6.总结

        本篇主要是对微服务架构的一个系统性的介绍,对比了单体应用架构与微服务架构的优缺点,并在微服务架构设计中的需要重点考虑的方面如服务拆分、通信模式、可观测性、安全、部署相关等等相关模式,最后简述了服务拆分的策略与指导原则、远程过程调用与消息交互两种主要的进程间模式的工作原理。

参考文献

  • 《微服务架构设计模式》

-----------------------------------------------------------------------------------------

感谢你的关注!微信公众号(代码的色彩)。