NET追求者BLOG 2020-01-06
应用服务架构一直处于不断演进的过程中,上图通过对比 5 种比较主流的架构模式,展示应用架构的演进历程和变化。
单体架构和竖井式架构都是围绕 web 容器打包及部署的架构模式,随着业务的快速发展,要求实现服务的快速迭代和快速交付,应用架构也由此演进为以服务为中心的架构模式。主流的面向服务的架构模式有:RPC 架构、ESB 中心化架构和微服务架构。
通过上述对比,我们不难发现,应用服务架构是在不断演进的,而且其演进背后存在一定的逻辑,服务架构的演进主要取决于以下 2 个维度:
关于微服务的定义,此处引用 ThoughtWorks 首席科学家 Martin Fowler 给出的描述。
其中以下特性值得特别注意:
Martin Fowler 对于微服务架构的表述更偏向学术上的定义,没有给出明确的落地标准或规范,只是提供了一些构建微服务架构的原则。
微服务架构模式有如此多的优点,那是不是所有的业务都要采用这种架构模式呢?又该如何筛选微服务?
左边图中,横坐标代表系统复杂度、纵坐标代表开发生产力、蓝色线表示微服务架构、绿色线表示单体架构。由图可知,当项目复杂度较低时,单体架构的生产力更高;随着项目复杂度越来越高,单体架构的生产力逐渐下降,微服务架构的生产力则显著提高。
鉴别出哪些业务需要使用微服务架构模式后,需要决定如何拆分和构建微服务。
如何进行服务拆分,是在微服务过程中业务方经常会问到的问题。
其实很多团队已经开始在做一些微服务化的工作,比如把大的工程拆分成不同的模块或子系统,这种对业务模块进行的静态划分,相当于已经完成了微服务改造的第一步拆分。
上图是 DDD(领域驱动设计)的开发模式,如果业务方案已经确定采用微服务的架构模式,在整个工程领域我们倾向于使用 DDD 模式来对业务架构和服务进行拆分。
DDD 是基于领域模型的建模而不是数据库表驱动的建模,需要我们对业务领域有深刻的洞察,了解服务的边界和上下文信息传递。
康威定律指出:在微服务架构和设计系统组织,其产生的设计等价于组织间的沟通结构。就是说微服务架构不仅是技术上的演进,同时对使用技术的组织提出了要求,拆分的服务是我们和服务之间的沟通方式。
我们采用微服务的 12 因子作为微服务建设的架构原则。微服务的 12 因子也叫云原生 12 因子,它提供了一种业务上云或微服务改造的最佳实践。重点介绍其中几个因子:
微服务看起来非常好,但其实是需要一个技术体系或平台体系来支撑的,如果没有这样一个服务架构平台体系的建设,不推荐使用微服务。
微服务架构建设分为 2 种思路:SDK 模式、ServiceMesh 模式。
典型代表是 SpringCloud,SpringCloud 是基于 SpringBoot 的一整套实现微服务的框架。SDK 模式的底层运行平台可以是 PaaS 平台,也可以是 Kuberneters 平台或 Docker 容器。
Istio 是 ServiceMesh 模式的典型代表。ServiceMesh 模式的优缺点与 SDK 模式正好相反。
SpringCloud 是基于 SpringBoot 发展而来的一整套成熟的微服务架构解决方案。SpringCloud 具有以下优势:
SpringCloud 本身也是一个逐渐演进的架构模式:最早是基于 IOC/AOP 的编程思想产生的;然后在 Spring 的基础上发展出 SpringBoot,基于注解的方式实现快速的应用开发;后来在 SpringBoot 的基础上开发出 SpringCloud 底层微服务构架。
上图展示了 SpringCloud 的技术生态,SpringCloud 技术栈包含了很多技术模块,比如 Ribbon、Zuul、Eureka、SpringCloud Stream 等,这些技术模块共同组成了 SpringCloud 生态圈,为开发者提供丰富的微服务架构基础设施支撑。
微服务和 SpirngCloud 的架构是比较复杂的,如配置管理、服务注册与发现、API 网关、打包部署调度、安全、服务故障自愈、流量控制和弹性伸缩等非功能需求,都是微服务需要包含的架构模块。上图中蓝色字表示 SpirngCloud、Kubernetes 等用来解决云原生和微服务架构问题的技术方案。
从图中可以看出微服务架构的复杂性,要想实现一套微服务架构来支撑和交付业务,需要在底层封装很多基础组件,构建一套底层基础架构来隔离底层的非功能需求,做到让业务系统无感知、平滑地对外提供服务。
SpringCloud 提供的框架或基础设施是一个半成品,我们在 SpirngCloud 的基础上进行了二次开发,抽象和封装了一些微服务架构的通用基础设施平台,不同的业务团队共享这些基础设施,降低技术学习和接入成本,让业务团队更专注于业务逻辑的实现,聚焦业务开发。
上图所示为宜信的微服务架构:
有别于其他的架构模式,微服务架构里出现了一个重要的基础设施变化 - 增加了微服务网关模块。网关主要解决的问题是:服务拆分之后,每一个服务粒度都比较小,服务之间的交互会呈现网状的结构,需要一个聚合的节点来聚合这些微服务。
因此我们在 SpringCloud 微服务架构的基础上二次开发出 SIA 微服务网关,如图所示,重点介绍其中的 2 个核心模块:
SIA 微服务网关的 4 种模式:同步托管式、同步注解式、异步托管式、异步注解式。
采用单一源码库进行代码管理,交付方式是容器交付,去中心化的设计。目前大部分生产环境和业务都采用同步托管模式。
在跟业务团队对接时,我们发现很多业务系统已经实现了一些独特的业务逻辑,难以迁移到网关,所以我们采用一种比较兼容的注解的方式去适应这些业务逻辑,在原有项目的基础上加一个注解,将它们纳入到整个网关管理体系中来。同步注解式是基于 SpringCloud-Zuul 1 实现的分布式微网关体系,管理业务方源码库,根据业务方环境进行交付。
SpringCloud 和 Zuul 使用的后端技术是基于 Servlet,其线程处理模型是一个请求对应一个线程,当请求量过多,线程栈溢出,就会占用非常多的资源,导致网关无法提供额外的线程资源来处理新进来的请求。因此我们采用了 SpringCloud 自研的 SCG 技术方案。
SpringCloud-Gateway 基于 Netty 和反应式编程模式,采用收敛式的线程处理模型,只要用少数线程就可以处理高并发的流量请求。目前已经实现了基于 SpringCloud-Gateway 的异步模式,当同步模式在线上运行过程中出现资源透支的情况,就选择使用异步模式。异步模式也分为 2 种:异步托管式、异步注解式。
通过单一源码库进行代码管理,采用容器交付。主要使用场景是流量型,如果业务多对高并发、高吞吐场景,建议使用异步托管式。
如果想在异步网关基础上做定制开发,可以使用异步注解的模式。
网关的 4 种模式来源于业务的需求:为兼容业务已有逻辑演进出注解模式;当出现性能瓶颈、资源浪费时,采用异步模式应对高并发流量。
上图是网关测试环境的一个截图, 包括上述 4 种模式。每一个小方格代表业务的一个网关组,方格中的小圆圈代表它属于哪一种网关。业务系统在选择网关模式时要做一个判断:诉求是支持业务的快速集成,还是对流量有一定要求。
如图将 SIA 微网关的核心 Feature 分成 2 个层面:
微服务网关贯穿了整个微服务生命周期的管理。
SIA 微服务网关的功能包括:
各功能模块对应的生命周期:
SIA 微服务网关作用于软件生命周期的各个阶段,通过标准协同、业务测试 / 前端后端沟通、服务模块复用、可视化管理、数据统计管控等实现业务的统一融合、降本增效。
2016 年,Gartner 发布了一个关于应用变化速率的报告《Pace-Layered Application Strategy》,以应用变化速率为标准将业务应用分为三层:
中台的目标是围绕业务组织进行可复用能力的有机整合,协助业务落地实施、改造、试错、转型,提升组织效率,降低系统成本。
中台和微服务有什么关系呢?微服务架构是面向开发的架构,很多基础服务可以沉淀到微服务架构里,同时,微服务架构把中台的能力快速释放出来,满足敏态业务快速变更的业务需求。
上图是路由管理里的一个截图,当一个大的单体或不同的服务要对外提供统一服务时,可以把服务聚合到网关上;同时一个巨型应用也可以通过网关分解成微服务。
微服务架构中有很多非功能需求,或者说是技术导向型的需求,包括日志管理、限流、蓝绿部署、版本管理等,可以通过组件的方式下沉到网关上,业务系统通过将服务与组件绑定实现对组件功能的复用。
我们还提供了一个插件机制,当业务有独特的需求,可以根据其业务逻辑在网关上进行功能的个性化定制。
在开发或前后端联调时,前后端可以通过网关服务文档中心的 Swagger UI 功能模块访问后端服务调用接口的分析。
只要在后端服务之上加一个 Swagger 注解,网关就可以把所有对外暴露的服务抓取出来,这相当于是一种契约式的开发。
我们对网关应用做了容错和保护机制,当然这也是 SpringCloud 本身自带的一个技术模块,我们的容错机制是基于 SpringCloud 的 Hystrix 实现的,当发现后端服务调用请求一直在返回错误时,会开启熔断,避免由于一直发送错误请求导致雪崩的情况发生。
除此之外,我们还会采用 Guava 限流的方式对服务进行保护。在大促或秒杀的场景下,会有大量请求进来,这时会通过限流来保护服务的稳定。
宜信微服务架构平台有一个很重要的功能是网关服务运行状态和后端连接状态可观测,提供了很多监控方面的功能组件,如图所示,可以统计当前请求的频率、服务健康度。
预警方面重点介绍网关拓扑图。当请求失败,当前链路出现异常,通过网关拓扑图可以快速跟踪和判断业务系统哪个节点出现问题,然后对有问题的节点进行摘除或其他操作。
我们的网关运行在 Docker 平台上,Docker 平台在出现问题或重启之后日志会丢失,我们的日志系统会把日志归集,存储到 ES 中,便于对历史日志溯源。
网关中有一个组件叫“监控统计”,这个模块默认是不打开的,如果你想对请求做延时,或者想看请求的明细调用情况,可以通过组件管理中打开这个组件,对容器的请求做统计和分析。监控统计组件会对当前请求的最大延迟、最小延迟、失败个数、平均延迟进行排序,一目了然。
构建微服务网关初期,业务同事比较关注我们的业务网关和别人的网关是否存在耦合问题,他的业务请求是否会影响到我。我们选用去中心的网关设计方式,同时通过 OAM 实现对所有网关节点的统一管理。
我们的微服务网关是按照 DDD 领域驱动模式来建设的,没有把网关绑定在某一个特殊的技术实现上,而是把它作为一个抽象封装来统一管理后端的节点,如果换一种技术实现也不会影响到前端业务的正常工作。因此在架构建设初期要考虑清楚你的业务系统和后端技术架构之间是否解耦。
虽然每一种开源方案在开源之前都经过了长时间的考验,但其实依然可能存在 bug,基于这些开源方案进行二次开发时仍可能遇到一些坑,我们会不断对开源系统进行 bug 修复和功能增强。
Zuul 本身存在性能瓶颈,当出现性能问题时,我们考虑是不是要用线程收敛的模式来增强网关的性能。
在网关应用中会遇到 Eureka 的 CAP 问题,因为 Eureka 消息注册以可用性(Availability)优先,在一致性(Consistency)上相对较弱。为解决这个问题,我们基于 Eureka 的特点提供 SynchSpeed 服务,如果业务需要保证状态一致性,可以开启这个服务。
这两个问题是指当云容器平台的状态发生变更,却没有及时通知到注册中心,导致服务在两个平台的状态不一致,这就需要做上下文关联系统(StakeHolder)的整合。
https://www.infoq.cn/article/jeXYsq2zsVc7rMZ8Mz9j