Spring Cloud 服务
集群管理困惑
- 服务实例太多怎么办 ?
- 服务调用关系太复杂怎么办 ?
- 服务调用出错怎么办 ?
- 配置信息散落在各个服务怎么办 ?
- 服务调用链路太长怎么办 ?
Spring Cloud 服务
- 服务治理 : 管理微服务中大量实例 (服务发现 、服务注册机制)变的自动化、透明化
- 服务网关 : 降低服务客户端与服务提供者之间耦合度,简化调用过程,提供一个API网关,优化面向客户端的API设计
- 服务容错 : 微服务提供服务隔离、服务熔断、和服务回退等面向服务端的有效容错机制
- 配置中心 : 管理散落在各处的服务配置信息,微服务提供一个配置中心集中化管理
- 链路追踪 : 监控服务状态,全链路的数据流转,对各个服务之间的调用过程进行统一管理
微服务技术体系
- 服务通信 :网络链接模式(长链接、短链接)、I/O模型(阻塞式I/O、非阻塞式I/O)、服务调用方式(同步、异步)
- 服务治理 :服务治理实现 自动化的注册 和 发现
- 服务路由 :请求到达集群,决定由哪一台机器进行请求响应
- 服务容错 :超时、重试、异步解耦、集群容错策略、服务隔离机制、服务 限流机制、服务熔断机制
- 服务网关 :请求监控、安全管理、路由规则、日志记录、访问控制、服务适配
- 服务配置 :对服务进行统一管理,管理的对象为 配置信息
微服务通信
- 网络链接模式 :长链接、短链接,长连接和短连接的产生在于客户端和服务器端采取的关闭策略
- Dubbo 框架就采用的是长连接 、Spring Cloud采用短链接
- I/O 模型也有阻塞式 I/O 和非阻塞式 I/O
- 阻塞式 I/O 实现简单,而非阻塞式 I/O 的性能更好
- 在微服务架构中,以服务网关而言,像Netflix 的 Zuul就是阻塞式 I/O,Spring 自研的 Spring Cloud Gateway则采用的是非阻塞式 I/O
- 服务调用机制 同步调用和异步调用两大类实现机制、通常都会采用异步转同步的实现机制
业务建模
- 领域驱动设计(Domain Driven Design,DDD)方法,通过识别领域中的各个子域、判断这些子域是否独立、考虑子域与子域的交互关系,从而明确各个界限上下文(Boundary Context)之间的边界
- 核心子域 :系统的核心业务属于核心子域
- 支撑子域 :专注于业务某一方面的子域
- 通用子域 : 基础设施的功能归属于通用子域
业务体系设计
- 电商业务为例
基础服务 : 消息服务、通知服务、路由服务、文件服务
通用服务 :账号服务、登陆服务、订单服务、会员服务、物流服务、供应商服务、聊天服务、库存服务
定制服务 :接口服务、总线服务、插件服务、开放服务、转换服务、升级服务
其他服务 :客服管理、风控服务、投诉服务
项目核心组件介绍
- 服务注册发现
- API 网关
- 消息处理
- 熔断器
- 配置中心
- 负载均衡
- 数据监控
Spring Cloud 常用组件
- 服务治理 : Spring Cloud Netflix Eurka
- 服务容错 :Spring Cloud Circuit Breaker
- 服务网关 :Spring Cloud Gateway
- 配置中心 :Spring Cloud Config
- 事件驱动 :Spring Cloud Stream
- 服务安全 :Spring Cloud Security
- 链路追踪 :Spring Cloud Sleuth
- 服务测试 :Spring Cloud Contract
服务治理
- 管理实例 :服务注册中心,服务注册中心是保存服务调用所需的路由信息的存储仓库
- 服务提供者和服务消费者进行交互的媒介,充当着服务注册和发现服务器的作用
- Dubbo、Spring Cloud 等主流的微服务框架都基于 Zookeeper、Eureka 等分布式系统协调工具构建了服务注册中心
服务路由
- 常见路由方案 :负载均衡,但负载均衡主要是服务分发,而不是解决路由,常用的静态、动态负载均衡方法无法实现精细的路由管理
- Spring Cloud 等主流的微服务框架也都内置了 Ribbon 等客户端负载均衡组件
- 常规实现路由方案,白名单、黑名单、需要路由的服务地址(IP)放入可以控制是否可见的路由池中进行路由
服务容错
- 集群容错策略 :以失效转移 Failover 为代表
- 服务冗余,即一个服务应该构建多个实例
- 常见集群容错策略 :Failover(失效转移)、Failback(失效通知)、Failsafe(失败安全)、Failfast(快速失败)
- Failover(失效转移) 最常见的容错粗略 :当发生服务调用异常时,请求会重新 在集群中查找下一个可用的服务 提供者实例
- Failover(失效转移) 会有最大重试次数限制
- 服务隔离机制 :以线程隔离、进程隔离为代表
- 对资源进行有效 的管理,避免因资源不可用,发生失败等 情况 导致 服务系统中其它资源变得 不可用。
- 在发生故障时,将故障的传播和影响范围有效的控制
- 主要处理对象还是应用线程隔离 _ 线程池。每个服务有自己的线程最大值设置
- Spring Cloud Circuit Breaker 同样对服务隔离提供了不同维度和粒度的支持
- 服务限流机制 :以滑动窗口、令牌桶算法为代表、及服务熔断机制
- 服务熔断
- 当系统出现异常情况时,能够直接熔断整个 服务的请求处理过程,避免一直等到请求处理完毕或 超时,避免资源浪费
- 当服务消费者向服务提供者发起远程调用时,服务熔断器会监控该次调用,如果调用的响应时间过长,服务熔断器就会中断本次调用并直接返回
- 服务熔断器会将所有的调用结果记录下来,如果发生异常调用次数达到一定的阈值则触发熔断
- 服务熔断开启后,服务调用将直接返回预定的 错误,而不执行真正的网络调用,同时熔断器内置时间间隔,当处理请求达到时间间隔进入半熔断状态
- Spring Cloud Circuit Breaker 中同样实现了服务熔断器组件
- 服务回退
- 临时、被动的处理机制、远程调用发生异常时,产生另外的 处理机制来应对异常,相当于返回一个默认的处理结果
- Spring Cloud Circuit Breaker 支持服务回退,开发人员只需要提供一个自定义回退方法(Fallback Method),就可以非常简单地使用这一机制来支持服务回退
- 专门用于实现服务熔断的 Spring Cloud Circuit Breaker 组件
- Netfix Hystrix
- Resilience4J
- Sentinel
- Spring Retry
- 服务雪崩
- 定义 :服务之间存在依赖调用,因为某一服务的不可用,而导致前面的调用方也不可用,所引发的连锁 反应,称之为服务雪崩
- 本质 :服务依赖失败
- 容错 : 将服务消费者 所受的影响降低到最低
服务网关
- 所有的客户端和消费端都通过统一的网关接入微服务,处理所有的非业务功能
- 完成客户端和服务端保温格式转换
- 可能还具有身份验证、监控、缓存、请求管理、静态响应处理等功能
- 制定灵活的路由策略。针对一些特定的 API,我们需要设置白名单、路由规则等各类限制
服务配置
- 配置中心通常需要依赖分布式协调机制,即通过 一定的方法确保配置信息在分布式环境中的各个服务中能得到实时、一致的管理
- 可以采用诸如 Zookeeper 等主流的开源分布式协调框架来构建配置中心
- Spring Cloud 也提供了专门的配置中心实现工具 Spring Cloud Config
服务安全
- 对单个服务而言 :每次服务访问都能与授权服务器进行集成以便获取访问 Token
- 对多服务调用而言 :确保 Token 在各个微服务之间的有效传播
- 通常使用 OAuth2 协议来实现对服务访问的授权机制,使用 JWT 技术来构建轻量级的认证体系
- Spring 家族也提供了 Spring Security 和 Spring Cloud Security 框架来完整这些组件的构建
服务监控
在 Spring Cloud 中,就提供了 Spring Cloud Sleuth 与 Zipkin 的集成方案
服务设计
业务建模
- 领域驱动设计(Domain Driven Design,DDD)方法,通过识别领域中的各个子域、判断这些子域是否独立、考虑子域与子域的交互关系,从而明确各个界限上下文(Boundary Context)之间的边界
- 核心子域 :系统的核心业务属于核心子域
- 支撑子域 :专注于业务某一方面的子域
- 通用子域 : 基础设施的功能归属于通用子域
业务体系设计
- 电商业务为例
基础服务 : 消息服务、通知服务、路由服务、文件服务
通用服务 :账号服务、登陆服务、订单服务、会员服务、物流服务、供应商服务、聊天服务、库存服务
定制服务 :接口服务、总线服务、插件服务、开放服务、转换服务、升级服务
其他服务 :客服管理、风控服务、投诉服务
组件选取
- 注册中心 :采用Spring Cloud Netflix 中的 Eureka(包括服务器端组件和客户端组件,客户端组件内嵌在各个业务微服务中,而服务端组件为独立)作为注册中心,主要服务为服务发现和服务注册,一般命名为 eureka-server
- 配置中心 : 基于Spring Cloud Config构建配置中心,存在服务器端组件和客户端组件,服务器端组件需要构建独立的配置服务,一般命名为 config-server
- API网关服务 :需要 构建独立的服务做路由、安全和监控等 功能。(Spring Cloud Netflix 中的Zuul 及 Spring自建的 Spring Cloud Gateway)
- 安全授权 :独立的OAuth2授权服务,生成服务访问所需的token信息,命名为 AUTH-server。 采用 Spring Cloud Security 所 提供的OAuth2协议。
- 展示服务链路(Zipkin服务):链路的可视化展示
案例地址 : https://github.com/tianyilan12/springcloud-demo
组件使用
服务治理
- 实现 自动化的服务注册 和 服务发现
- 实现方式 :Spring Cloud Netflix Eureka,还有很多种
- 需要原因 :自动扩容、服务的失败和 更新等因素,服务实例的运行状态也经常变化,需要机制将服务实例注册到服务注册中心
- 注册中心的客户端程序一般会 嵌入在服务体提供者和服务消费者内部
- 服务组成 :服务提供者客户端程序、服务调用者客户端程序、注册中心
- 服务启动时,服务提供者通过内部注册中心客户端程序自动将自身注册到注册中心。
- 服务消费者的注册中心客户端程序可以 从注册中心获取那些已经注册的服务实例信息
实现策略
- 状态变更管理 采用 发布-订阅模式
- 服务提供者根据服务定义发布服务,而消费者根据自己的需求进行订阅服务,当注册中心服务变化时,注册中心会将服务推送给消费者
- 服务 发布-订阅 的基本机制, 服务监听机制(服务消费者监控服务状态)当发现变化时,通过回调函数通知消费者,实现实时数据同步
- 轮询机制 :定时任务轮询、服务消费者定期调用注册中心服务列表更新本地缓存,数据同步有效性问题
实现工具
- Consul :分布式环境下服务发现与配置的开源工具
- ZooKeeper :分布式协调领域的代表性框架被广泛用于注册中心、配置中心、分布式锁等的构建场景 ,本质 服务监听机制
- Netflix Eureka :采用轮询机制,默认30秒
服务发现
- 客户端发现机制 :微服务主要是应用机制(在服务消费者内部保存一个服务列表)选择列表中的服务调用 需要负载均衡机制(客户端负载均衡 :Netflix Ribbon 组件)
- 服务器端发现机制
spring cloud netflix eureka 组件
- 作用 :实现服务治理
- 组成 :eureka组成 (客户端组件、服务端组件)
- 服务端
- 服务端 jar 包 :spring-cloud-starter-eureka-server
- 服务端启动类 : @EnableEurekaServer
- 客户端
- 客户端 jar 包 :spring-cloud-starter-netflix-eureka-client
- 客户端端启动类 : @EnableEurekaClient
Eureka 配置项
- 命令规则
- 控制 eurka 服务行为,以 eureka.server 开头
- 客户端配置需求 ,以 eureka.client 开头
- 服务实例 ,以 eureka.instance 开头
- Standalone 模式
- registerWithEureka :是否把当前的客户端实例注册到 Eureka 服务器
- fetchRegistry :否从 Eureka 服务器上拉取已注册的服务信息
- erviceUrl :配置服务地址,服务器集群是很有用
- Peer Awareness 模式
- eureka.instance.hostname :指定当前 Eureka 服务的主机名称
- eureka.client.serviceUrl.defaultZone : 用于指向集群中的其他 Eureka 服务器(将自己注册到其他的服务器上)
- 客户端服务
- spring.application.name=userservice 指定应用注册中心中的名字
- eureka.client 用于设置用户行为
- eureka.client.serviceUrl.defaultZone 指定的就是 Eureka 服务器的地址
- 服务缓存
- Eureka 服务器会缓存一份所有已注册的服务列表,并通过一定的定时机制对缓存数据进行更新
- 实现原理
- Eureka 集群服务器之间互相注册
- 服务注册 :客户端向服务器注册提供IP地址、端口等各项与服务发现相关的基本信息完成服务注册
- 服务续约 :客户端与服务器端通过短连接进行交互,所以需要客户端需要进行续约,每隔一段时间进行上报一次自己的状态
- 服务取消 :一段时间内,客户端没有给服务短发送心跳,或客户端主动上报取消,则服务端在服务列表中移除客户端
负载均衡
Ribbon组件
- 负载均衡组件,提供客户端负载均衡的工具
- 服务实例B将自己注册到Eureka服务器, 服务器A发送请求至 Ribbon组件, Ribbon组件到 Eureka服务器 获取服务列表,再将请求转发给列表中的服务器
- Ribbon 客户端组件提供了一系列完善的辅助机制用来确保服务调用过程的可靠性和容错性,包括连接超时和重试等
- @LoadBalanced 注解用于修饰发起 HTTP 请求的 RestTemplate 工具类,并在该工具类中自动嵌入客户端负载均衡功能
- @RibbonClient 注解来完全控制客户端负载均衡行为,这在需要定制化负载均衡算法等某些特定场景下非常有用,我们可以使用这个功能实现更细粒度的负载均衡配置
负载均衡策略
- 主要分成两大类,静态负载均衡、动态负载均衡
- 静态负责均衡 :随机(Random)、轮询(Round Robin)、加权轮询(Weighted Round Robin)
- 动态负责均衡 : 源IP哈希算法,最少连接数算法(BestAvailableRule),服务调用延时算法(WeightedResponseTimeRule)、AvailabilityFilteringRule 策略(检查 LoadBalancerStats 中记录的各个服务器的运行状态)
服务网关
网关的作用
- 客户端与微服务之间的隔离作用
- 非业务功能需求可以在网关进行集中处理
- 在服务者和消费者中间提供了一层反向代理,充当前置负载均衡器的作用
常见网关功能
- 请求监控
- 安全管理
- 路由规则
- 日志记录
- 访问控制
- 服务适配
常见网关方案介绍
Zuul 网关 : 集成 Netflix 中的 Zuul 网关 , 实现简单
Gateway 网关 :自研 Spring Cloud Gateway - 性能较好
Zuul网关
- 依赖包 :spring-cloud-starter-netflix-zuul
- 网关注解 :启动类 @EnableZuulProxy
- 自动成为 zuul 网关的入口
- 通过 @EnableZuulProxy 可以 使用Zuul各种内置过滤器 实现复杂的路由
配置实现
API 网关在其服务的消费者和提供者之间提供了一层反向代理,充当着前置负载均衡器的角色,所以,API 网关的定位决定了 Zuul 需要依赖 Ribbon
server:
port: 5555
eureka:
instance:
preferIpAddress: true
client:
registerWithEureka: true
fetchRegistry: true
serviceUrl:
defaultZone: http://localhost:8761/eureka/
Zuul 实现服务路由
服务地址 :http://zuulservice:5555/service (zuulservice 代表Zuul服务地址)
基于服务发现映射服务路由 :实现自动化服务路由,最常见也是最推荐的方式
映射规则 :匹配的规则就是直接将目标服务映射到服务名称上
http://localhost:5555/actuator/routes” 是 Zuul 提供的服务路由端点,展示了目前在 Zuul 中配置的服务路由信息
基于动态配置映射服务路由
- 对一些定制化需求
- 不使用默认的服务名称来命名目标服务
- 在各个请求路径之前加一个统一的前缀(Prefix)
zuul:
prefix: /springhealth
routes:
ignored-services: 'userservice'
userservice: /user/**
基于静态配置映射服务路由
- zuul 不依赖于 Eureka注册中心 的服务路由
- 可以使用自定义的路由规则完成与其他各种第三方系统的集成
- Zuul 会将该请求转发到外部的第三方服务http://thirdparty.com/thirdpartyservice中
zuul:
routes:
thirdpartyservice:
path: /thirdpartyservice/**
url: http://thirdparty.com/thirdpartyservice
Zuul 与 Ribbon进行整合
zuul:
routes:
thirdpartyservice:
path: /thirdpartyservice/**
serviceId: thirdpartyservice
// 关闭Ribbon于服务端的关联
ribbon:
eureka:
enabled: false
// 手动指定Ribbon服务列表
thirdpartyservice:
ribbon:
listOfServers: http://thirdpartyservice1:8080,http://thirdpartyservice2:8080
- Zuul 响应HTTP过程是典型的过滤器解构,内置的 ZuulFilter 实现过滤器组件实现此机制
- filterType() 代表过滤器的类型 :内置过滤器分为 PRE、ROUTING、POST 和 ERROR 四种
- filterOrder() 方法用于设置过滤器的执行顺序
Spring Cloud Gateway
- 性能好,但是实现复杂,Spring Cloud Gateway 的源码非常复杂,出现问题不容易排查和解决
- 还支持请求限流等面向服务容错方面的功能
基本架构
- Spring Cloud Gateway 中的核心概念有两个,一个是过滤器(Filter),一个是谓词(Predicate)
- 而所谓谓词,本质上是一种判断条件,用于将 HTTP 请求与路由进行匹配
- 内置了大量的谓词组件,可以分别对 HTTP 请求的消息头、请求路径等常见的路由媒介进行自动匹配以便决定路由结果
- Spring Cloud Gateway 最主要的开发工作就是配置谓词和过滤器规则
- 在上述配置中,我们设置了 Eureka 服务的地址并启用了服务发现机制,然后根据 Eureka 保存的服务名称和地址定义了三条路由规则:userroute、deviceroute 和 interventionroute 分别对应 user-service、device-service 和 intervention-service 这三个微服务。这里,我们也通过在各个服务名称前面加上“lb://”来实现客户端负载均衡
分布式配置中心
- Spring Cloud Config 框架来实现分布式配置中心
- 开发、测试、生产环境的配置文件统一保存在配置中心中
- 保证每个集群中所有服务内部保存的同一份配置信息能够得到同步的更新
- 配置中心,存在两个组成部分,即配置服务器和配置仓库
- 配置服务器的核心作用就是对接来自各个微服务的配置信息请求,这些微服务会通过配置服务器提供的统一接口获取存储在配置中心中的所需配置信息
- 确保对配置中心中所存储的各种配置信息进行统一维护
- 提供一种通知机制,确保配置信息变化之后能够告知各个微服务,以便各个微服务及时更新本地服务中的配置数据
配置中心工具
- Etcd : 它是一个轻量级分布式 Key-Value 对数据库,实现了数据更新、目录监听、分布式锁等功能特性
- Consul : Google 提供的开源框架,内置了服务注册与发现框架以及分布一致性协议实现机制,既可以用作配置中心,也可以用于构建注册中心
- Disconf : 百度开源的一个分布式配置管理工具,与 Spring 框架有很好的集成,在使用上也提供了友好的 Web 管理界面
- iamond : 阿里巴巴提供,把配置数据存储在 MySQL,在获取配置数据时采取定时拉取数据的模式,实现过程比较简单
Zooker实现
- 一种分布式协调工具,它对每个节点都可以设置监听器 Watcher
- 节点监听机制可以用来实现实时感知,即当某一个节点的信息有任何变动时,所有监听该节点的其他节点都可以实时获取通知,从而做出响应
- 对于配置中心而言,所有服务就是 Zookeeper 的客户端,这些服务通过对包含配置信息的 Zookeeper 节点进行监听就能获取配置信息更新内容
Spring Cloud Config
- Zookeeper 是把配置信息保存在其内部的节点上,这些节点本质上就是操作系统的文件系统
- Spring Cloud Config 同样可以将配置信息保存在文件系统中,但更多的场景是推荐使用 Git 等配置仓库来存储配置信息
- 在关键的配置变化通知机制上,Zookeeper 依赖其变更事件的发送和 Watcher 机制来通知客户端
- Spring Cloud Config 则会发送事件到 Spring Cloud Bus 消息总线,然后由消息总线通知相关的服务
客户端更新策略
- 重启客户端 : 重启客户端时,会重新获取服务器端的配置信息,从而实现配置更新
- 使用Spring Boot Actuator : 专门用来监测和管理系统运行状态的组件,可以获取应用系统运行时数据和配置信息,并进行统一分析
- 使用 Spring Cloud Bus : 实现消息总线的专用组件,集成了 RabbitMQ、Kafka 等主流消息中间件
Spring Cloud Bus
- 如何自动调用服务器端所暴露的 /actuator/bus-refresh 端点
- 客户端如何得知服务器端的配置信息已经更新
- 客户端如何实时获取服务器端所更新的配置信息