微服务全系列
1.微服务间的通讯
单体系统和微服务的区别
单体系统 | 微服务系统 |
---|---|
程序、数据、配置集中管理 | 按照功能拆分、微服务化、松耦合 |
开发效率低下 | 分模块快速迭代 |
发布全量,启动慢 | 平滑发布,快速启动 |
可靠性差 | 熔断、限流、降级,超时重试,异常离群 |
服务内直接调用 | 轻量级通信 |
技术单一 | 跨语言 |
- 微服务有诸多的有利条件,但是如果微服务的粒度比较细(按照业务功能拆分),则他们之间服务调用就会比较复杂,链路会比较长。
- 按照职能将服务进行了拆分,这时候从不同的客户端(如 Web、App、3rd)访问,就有可能访问不同的服务。而服务与服务之间又有上下游的协作,调用就变得错综复杂。
- 可能需要关注很多问题:
- 包括不同的技术栈不同的开发语言之间的上下游交互。
- 服务之间的注册与发现,请求认证,接入授权。
- 下游对上游进行调用的时候,上游怎么做负载均衡、故障注入、超时重复、熔断、降级、限流、ABTesting 等,端到端之间如何实现监控和 trace。
微服务通信的三个方面
1.基于网关的通信
没有网关的情况下进行通讯,如上图有 3 个客户端,在调用 4 个服务的接口。这种直连调用的方式有很多问题:客户端需要保存所有服务的地址,同时也需要实现一些系统级的容错策略。比如负载均衡、超时重试、服务熔断等,非常复杂,并且难以维护。因为是在各客户端保存的服务地址,一旦某个服务端出现问题或者发生迁移,所有的客户端都需要修改并且升级。另外如果再增加一个 E svc,所有的客户端也需要升级。而且在某些场景下存在跨域请求的问题,每个服务都需要实现独立的身份和权限认证等等。
客户端都需要修改并且升级。我们需要的是客户端不要有太大的变化。
如果我们在客户端和服务端增加一层网关,所有请求都经过网关转发到对应的下游服务,客户端只需要保存网关的地址并且只和网关进行交互,这样就大大简化了客户端的开发。
如果需要访问用户服务,只需要构造右边这个请求发给网关,然后由网关将请求转发给对应的下游服务。
可以将网关简单理解为:路由转发+治理策略,治理策略是指和业务无关的一些通用策略,包括:负载均衡,安全认证,身份验证,系统容错等等。网关作为一个 API 架构层,用来保护、增强和控制对服务的访问。
网关的主要功能
请求接入
1、为各种应用提供统一的服务接入
2、管理所有的接入请求:提供流量分流、代理转发、延迟、故障注入等能力
安全防护
用户认证、权限校验、黑白名单、请求过滤、防 web 攻击
治理策略
负载均衡、接口限流、超时重试、服务熔断、灰度发布、协议适配、流量监控、日志统计等
统一管理
1、提供配置管理工具
2、对所有服务进行统一管理
3、对中介策略进行统一管理
网关使用场景
蓝绿部署
前面看到,在单体应用中,部署是一件比较麻烦的事情,每次的改动,都需要把整个应用程序都发布启动一次。而且系统规模越大,部署过程越复杂,时间越长。
而在微服务架构中,模块部署起来相对更快,更容易。可以在短时间内对于同一个模块做多次部署,网关可以帮实现蓝绿部署。
如图所示之前的用户服务版本是 V1.0,然后部署 V1.1 版本,在网关上只需要做一个转发配置的修改,就可以迅速的将所有流量都流到新版本。
灰度发布
类似金丝雀的理念,对一次性升级版本感到担忧,可以先配置 5%的流量达到新版本,让部分人试用一下,等线上观察一段时间后,可以逐步增加对新版本的流量百分比,最终实现百分之百切流。
负载均衡
此能力需要依赖服务注册和服务发现。
服务熔断
网关还可以实现断路器的功能;如果某个下游忽然返回了大量错误,原因有可能是服务挂了或者网络问题或者服务器负载太高,如果此时继续给这个问题服务转发流量就可能会产生级联故障。
出问题的服务有可能产生雪崩,雪崩会沿着调用链向上传递,导致整个服务链都崩溃。
断路器可以停止向问题模块转发流量,在业务层面可以给用户返回一个服务降级之后的页面,开发人员就有相对充分的时间来定位和解决问题。
开源网关
2.基于 RPC 的通信
3.基于 ServiceMesh 的数据面(SideCar)的通信
2.微服务的注册与发现
微服务注册与发现类似于生活中的”电话通讯录”的概念,它记录了通讯录服务和电话的映射关系。在分布式架构中,服务会注册进去,当服务需要调用其它服务时,就这里找到服务的地址,进行调用。
- 先要把”好友某某”记录在通讯录中
- 拨打电话的时候通过通讯录中找到”好友某某”,并拨通回电话。
- 当好友某某电话号码更新的时候,需要通知到,并修改通讯录服务中的号码。
1、把 “好友某某” 的电话号码写入通讯录中,统一在通讯录中维护,后续号码变更也是更新到通讯录中,这个过程就是服务注册的过程。
2、后续我们通过”好友某某”就可以定位到通讯录中的电话号码,并拨通电话,这个过程理解为服务发现的过程。
微服务架构中的服务注册与发现结构如下图所示:
provider - 服务提供者
consumer - 服务消费者
register center - 注册中心
它们之间的关系大致如下:
- 每个微服务在启动时,将自己的网络地址等信息(微服务的
ServiceName
、IP
、Port
、MetaData
等)注册到注册中心,注册中心存储这些数据。 - 服务消费者从注册中心查询服务提供者的地址,并通过该地址调用服务提供者的接口。
- 各个微服务与注册中心使用一定机制(例如心跳)通信。如果注册中心与某微服务长时间无法通信,就会注销该实例。
优点如下:
1、解耦:服务消费者跟服务提供者解耦,各自变化,不互相影响
2、扩展:服务消费者和服务提供者增加和删除新的服务,对于双方没有任何影响
3、中介者设计模式:用一个中介对象来封装一系列的对象交互,这是一种多对多关系的中介者模式。
服务注册
如图中,为 Register 注册中心注册一个服务信息,会将服务的信息:ServiceName
、IP
、Port 以及服务实例MetaData
元数据信息写入到注册中心。当服务发生变化的时候,也可以更新到注册中心。
服务提供者(服务实例) 的服务注册模型是一种简单、容易理解、流行的服务注册模型,其在多种技术生态中都有所体现:
- 在
K8S
生态中,通过K8S Service
服务信息,和 Pod 的 endpoint(用来记录 service 对应的 pod 的访问地址)来进行注册。 - 在 Spring Cloud 生态中,应用名 对应 服务 Service,实例
IP + Port
对应 Instance 实例。比较典型的就是 A 服务,后面对应有多个实例做负载均衡。 - 在其他的注册组件中,比如 Eureka、Consul,服务模型也都是 服务 → 服务实例。
- 可以认为服务实例是一个真正的实体的载体,服务是对这些相同能力或者相同功能服务实例的一个抽象。
服务发现
- 服务发现实际就是我们查询已经注册好的服务提供者,比如
p->p.queryService(serviceName
),通过服务名称查询某个服务是否存在,如果存在, - 返回它的所有实例信息,即一组包含 ip 、 port 、
metadata
元数据信息的endpoints
信息。 - 这一组 endpoints 信息一般会被缓存在本地,如果注册中心挂掉,可保证段时间内依旧可用,这是去中心化的做法。对于单个 Service 后面有多个 Instance 的情况(如上图),做 load balance。
服务发现的方式一般有两种:
1、拉取的方式:服务消费方(Consumer)主动向注册中心发起服务查询的请求。
2、推送的方式:服务订阅/通知变更(下发):服务消费方(Consumer)主动向注册中心订阅某个服务,当注册中心中该服务信息发生变更时,注册中心主动通知消费者。
注册中心
注册中心提供的基本能力包括:提供服务注册、服务发现 以及 健康检查。
服务注册跟服务发现上面已经详细介绍了, 健康检查指的是指注册中心能够感知到微服务实例的健康状况,便于上游微服务实例及时发现下游微服务实例的健康状况。采取必备的访问措施,如避免访问不健康的实例。
主要的检查方式包括:
1、服务 Provider 进行 TTL 健康汇报(Time To Live,微服务 Provider 定期向注册中心汇报健康状态)。
2、注册中心主动检查服务 Provider 接口。
综合我们前面的内容,可以总结下注册中心有如下几种能力:
1、高可用
这个主要体现在两个方面。一个方面是,注册中心本身作为基础设施层,具备高可用;第二种是就是前面我们说到的去中心化,极端情况下的故障,短时间内是不影响微服务应用的调用的
2、可视化操作
常用的注册中心,类似 Eureka、Consul 都有比较丰富的管理界面,对配置、服务注册、服务发现进行可视化管理。
3、高效运维
注册中心的文档丰富,对运维的支持比较好,并且对于服务的注册是动态感知获取的,方便动态扩容。
4、权限控制
数据是具有敏感性,无论是服务信息注册或服务是调用,需要具备权限控制能力,避免侵入或越权请求
5、服务注册推、拉能力
这个前面说过了,微服务应用程序(服务的 Consumer),能够快速感知到服务实例的变化情况,使用拉取或者注册中心下发的方式进行处理。