首页 > 技术文章 > 微服务架构以及服务治理

zly-go 2021-08-30 18:03 原文

 

什么是微服务

微服务是一种软件开发技术- 面向服务的体系结构(SOA)架构样式的一种变体,将应用程序构造为一组松散耦合的服务。在微服务体系结构中,服务是细粒度的,协议是轻量级的。
可以说微服务是SOA(面向服务架构)的一种最佳实践
单体服务与微服务

微服务定义

围绕业务功能构建的,服务关注单一业务,服务间采用轻量级的通信机制,可以全自动独立部署,可以使用不同的编程语言和数据存储技术。微服务架构通过业务拆分实现服务组件化,通过组件组合快速开发系统,业务单一的服务组件又可以独立部署,使得整个系统变得清晰灵活
相较于单体式服务

  • 微服务是松藕合的,无论是在开发阶段或部署阶段都是独立的。
  • 易于快速开发和快速迭代,一个服务可能就是专一的只干一件事, 能够被小团队单独开发。
  • 支持不同开发语言进行构建整套系统,易于和第三方应用系统集成
  • 能够快速响应, 局部修改容易, 一个服务出现问题不会影响整个应用。

微服务架构

直连模式

通常在微服务业务开发初期,所有的前端页面数据都是直接根据后端提供的API文档来进行对接
但是这个架构存在以下问题

  • App端和内部的API微服务存在一个强耦合的关系(包括接口耦合和域名耦合),任何一边的变化都会对另外一边造成一定影响。
  • 每个对外暴露的服务,都需要新的域名,增加了成本。
  • 内部API微服务对外暴露,存在安全风险。
  • 客户端需要多次请求来聚合数据,工作量巨大,延迟高。
  • 协议不利于统一,各个部门间有差异,需要端来兼容。
  • 多终端兼容逻辑复杂,每个服务都需要处理。
    在这里插入图片描述

BFF架构

BFF看做是一个后端微服务的代理服务,它主要做聚合和裁剪的逻辑,方便客户端接入和访问。可以看到,引入了BFF之后,降低了App端与后端微服务之间的耦合,从而避免了强耦合问题。也给后续服务演进带来很多优势。
在这里插入图片描述
但这样的BFF架构存在很严重的问题就是单点故障、严重的代码缺陷、流量洪峰都可能造成集群宕机
此外,根据康威定律,单块的BFF和多团队也出现了不匹配的问题,即团队之间沟通成本变低,交付成本也就会变高。最后,BFF里面除了多业务线的聚合裁剪逻辑,还引入了Cross-Cutting(跨横切面)的逻辑,比如安全认证、日志监控、限流熔断等等,因此需要进行分层处理,引入API网关层。

API网关+BFF

为了解决BFF的单点故障问题,将单块的BFF进行解耦拆分,针对不同的业务线引入独立的微服务集群。针对Cross-Cutting部分则单独拆出来做成API网关层,这样在网关的配合下,单块 BFF 实现了解耦拆分,各业务线团队可以独立开发和交付各自的微服务,研发效率大大提升。另外,把跨横切面逻辑从 BFF 剥离到网关上去以后,BFF 的开发人员可以更加专注业务逻辑交付,实现了架构上的关注分离。
在这里插入图片描述

微服务拆分

在拆分服务之前
1、首先要有一个持续集成的平台如K8S等,使得服务在拆分的过程中,功能的一致性,这种一致性不能通过人的经验来,而需要经过大量的回归测试集,并且持续的拆分,持续的演进,持续的集成,从而保证系统时刻处于可以验证交付的状态。
2、其次在接入层,API和UI要动静分离,API由API网关统一的管理,这样后端无论如何拆分,可以保证对于前端来讲,统一的入口,而且可以实现拆分过程中的灰度发布,路由分发,流量切分,从而保证拆分的平滑进行。而且拆分后的微服务之间,为了高性能,是不建议每次调用都进行认证鉴权的,而是在API网关上做统一的认证鉴权,一旦进入网关,服务之间的调用就是可信的。
3、对于数据库,需要进行良好的设计,不应该有大量的联合查询,而是将数据库当成一个简单的key-value查询,复杂的联合查询通过应用层进行数据聚合,或者通过Elasticsearch进行。如果数据库表之间耦合的非常严重,其实服务拆分是拆不出来的。
4、要做应用的无状态化,只有无状态的应用,才能横向扩展,这样拆分才有意义。

在实际项目中通常会采用几种不同的方式划分服务边界,
业务职能(Business Capability)
DDD 的限界上下文(Bounded Context)
用户群体拆分
压力模型拆分

微服务的拆分不是为了拆而拆

GRPC

什么是RPC

RPC(Remote Procedure Call)远程过程调用,简单的理解是一个节点请求另一个节点提供的服务,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。
比如有A,B两个服务部署在不同的服务器上,A服务需要调用B服务所提供的函数方法,但是由于不在同一个内存空间,所以就需要网络来进行远程调用,这种方式就叫RPC,诸如dubbo、Spring Cloud 、GRPC等都可以看做是RPC框架或者包含有RPC功能

GRPC

grpc是Google 于 2015 年对外开源的跨语言 RPC 框架,支持多种语言。
它的原理是通过 IDL(Interface Definition Language)文件定义服务接口的参数和返回值类型,然后通过代码生成程序生成服务端和客户端的具体实现代码,这样在 gRPC 里,客户端应用可以像调用本地对象一样调用另一台服务器上对应的方法。

RPC框架的优点:

  • 多语言:语言中立,支持多种语言。
  • 轻量级、高性能:序列化支持 PB(Protocol Buffer)和 JSON,PB 是一种语言无关的高性能序列化框架。
  • 可插拔
  • IDL:基于文件定义服务,通过 proto3 工具生成指定语言的数据结构、服务端接口以及客户端 Stub。
  • 移动端:基于标准的 HTTP2.0设计,支持双向流、消息头压缩、单 TCP 的多路复用、服务端推送等特性,这些特性使得 gRPC 在移动端设备上更加省电和节省网络流量。
    在这里插入图片描述

GRPC-HealthCheck健康监测

Health Checks用于探测服务器是否能够处理rpc请求。客户端到服务器的运行状况检查可以通过点对点或某些控制系统进行。服务器可能未准备好接受请求,正在关闭或其他原因,这时他会选择答复“unhealthy”。如果在某个时间段内未收到响应或响应说不健康,则客户端可以采取相应的措施。

在微服务架构中provider向discovery注册服务,consumer向discovery获取服务地址来请求。
在这里插入图片描述
但是如果consumer到provider不可达的情况下,而provider、consumer和discovery的网络通畅时就需要使用到HealthCheck来检测,如果为unhealthy状态就可以将provider下线,防止consumer报错。
在这里插入图片描述HealthCheck也可用于服务的优雅关机和平滑下线

服务发现

为什么需要使用服务发现

在传统运行在物理机器上的应用中,某个服务实例的网络地址一般是静态的,但是由于微服务地址是动态的,所以需要将所有服务放到同一组件统一管理。
在这里插入图片描述
而服务发现有两种主要的实现方式:

  • 若是客户端调用服务时,从注册中心获取全部服务地址,然后自己选择对应服务,则为客户端发现。
  • 若是客户端通过代理层获取到的只是一个具体的服务地址,则称服务端发现。

客户端发现&服务端发现

客户端发现

一个服务实例被启动时,它的网络地址会被写到注册表上,当服务实例终止时,再从注册表中删除。这个服务实例的注册表通过心跳机制动态刷新。客户端使用一个负载均衡算法,去选择一个可用的服务实例,来响应这个请求。
在这里插入图片描述

服务端发现

客户端通过负载均衡器向一个服务发送请求,这个负载均衡器会查询服务注册表,并将请求路由到可用的服务实例上。服务实例在服务注册表上被注册和注销。
在这里插入图片描述

服务发现-CAP定理

CAP 定理,简单的说就是分布式系统不可能同时满足 Consistency 一致性、Availability 可用性、Partition Tolerance 分区容错性三个要素。因为 Consistency、Availability 、Partition Tolerance 这三个单词的首字母分别是 C、A、P,所以这个结论被称为 CAP 理论。
在这里插入图片描述

CAP定理权衡

既然不可能同时满足 Consistency 一致性、Availability 可用性、Partition Tolerance 分区容错性三个要素就需要一定的权衡。

CA架构

不支持分区容错,只支持一致性和可用性。
不支持分区容错性,也就意味着不允许分区异常,设备、网络永远处于理想的可用状态,从而让整个分布式系统满足一致性和可用性。
但由于分布式系统是由众多节点通过网络通信连接构建的,设备故障、网络异常是客观存在的,而且分布的节点越多,范围越广,出现故障和异常的概率也越大,因此,对于分布式系统而言,分区容错 P 是无法避免的,如果避免了 P,只能把分布式系统回退到单机单实例系统。

CP架构

系统在遇到分区异常时,会持续阻塞整个服务,直到分区问题解决,才恢复对外服务,这样可以保证数据的一致性。选择 CP 的业务场景比较多,特别是对数据一致性特别敏感的业务最为普遍。比如在支付交易领域,Hbase 等分布式数据库领域,都要优先保证数据的一致性,在出现网络异常时,系统就会暂停服务处理。分布式系统中,用来分发及订阅元数据的 Zookeeper,也是选择优先保证 CP 的。因为数据的一致性是这些系统的基本要求,否则,银行系统 余额大量取现,数据库系统访问,随机返回新老数据都会引发一系列的严重问题。

AP架构

在系统遇到分区异常时,节点之间无法通信,数据处于不一致的状态,为了保证可用性,服务节点在收到用户请求后立即响应,那只能返回各自新老不同的数据。这种舍弃一致性,而保证系统在分区异常下的可用性,在互联网系统中非常常见。比如微博多地部署,如果不同区域的网络中断,区域内的用户仍然发微博、相互评论和点赞,但暂时无法看到其他区域用户发布的新微博和互动状态。对于微信朋友圈也是类似。还有如 12306 的火车购票系统,在节假日高峰期抢票时,偶尔也会遇到,反复看到某车次有余票,但每次真正点击购买时,却提示说没有余票。这样,虽然很小一部分功能受限,但系统整体服务稳定,影响非常有限,相比 CP,用户体验会更佳。

服务发现中心对比

AP

Eureka
在这里插入图片描述

Nacos

CP

ZooKeeper
在这里插入图片描述
ETCD

多租户

在一个微服务架构中允许多系统共存是利用微服务稳定性以及模块化最有效的方式之一,这种方式一般被称为多租户
多租户可以是测试系统、产品线、灰度发布
多租户技术可以实现多个租户之间共享系统实例,同时又可以实现租户的系统实例的个性化定制。通过使用多租户技术可以保证系统共性的部分被共享,个性的部分被单独隔离。通过在多个租户之间的资源复用,运营管理维护资源,有效节省开发应用的成本。而且,在租户之间共享应用程序的单个实例,可以实现当应用程序升级时,所有租户可以同时升级。同时,因为多个租户共享一份系统的核心代码,因此当系统升级时,只需要升级相同的核心代码即可。

多租户实现方式

给入站请求绑定上下文(如: HTTP Header),进程内使用 context 传递,跨服务使用元数据传递(如: opentracing baggage item),在这个架构中每一个基础组件都能够理解租户信息,并且能够基于租户路由隔离流量,同时在我们的平台中允许对运行不同的微服务有更多的控制,比如指标和日志。在微服务架构中典型的基础组件是日志、指标、存储、消息队列、缓存以及配置。基于租户信息隔离数据需要分别处理基础组件。
多租户架构本质上描述为:跨服务传递请求携带上下文(context),数据隔离的流量路由方案。
在这里插入图片描述

多租户数据隔离方式

独立数据库

一个租户一个数据库,这种方案的用户数据隔离级别最高,安全性最好,但成本较高。

共享数据库,独立 Schema

多个或所有租户共享Database,但是每个租户一个Schema(也可叫做一个user)。底层库比如是:DB2、ORACLE等,一个数据库下可以有多个SCHEMA

共享数据库,共享 Schema,共享数据表

租户共享同一个Database、同一个Schema,但在表中增加TenantID多租户的数据字段。这是共享程度最高、隔离级别最低的模式。即每插入一条数据时都需要有一个客户的标识。这样才能在同一张表中区分出不同客户的数据。

References

https://www.cnblogs.com/edisonchou/p/talk_about_what_is_bff_in_microservices.html(BFF架构演进)
http://dockone.io/article/8241(微服务拆分)
https://www.jianshu.com/p/1bf9a46efe7a(服务发现)
https://blog.csdn.net/qq40988670/article/details/105966202(CAP定理)
https://www.jianshu.com/p/3bfc9821858a(多租户架构)

 

推荐阅读