SpringCloud组件基本使用 以及部分原理总结

  • eureka
  • eureka server
  • eureka服务端自我保护机制
  • eureka提供了四种监听事件
  • eureka client
  • Ribbon
  • 负载均衡过程
  • 总结
  • Feign
  • Hystrix
  • hystrix可以独立使用 脱离spring cloud
  • 和feign结合
  • hystrix隔离策略
  • zuul
  • 可自定义过滤器
  • 高可用
  • zuul总结
  • 配置中心
  • 链路追踪
  • 健康检查
  • spring cloud总结


eureka

eureka server

:
只作为注册中心使用,不具备任何业务性
eureka可以配合其他非java或者springboot应用使用,只要满足eureka规定的注册信息格式即可。
而获取注册信息等其他信息,只需要调用eureka对外提供的服务接口即可。

eureka服务端自我保护机制

当客户端有大量节点没有发送心跳至服务端,服务端可能会保留该节点,认为是网络问题。宁愿保存也不踢出。(计算公式:一分钟时间内,若接收心跳数小于 节点数 * 2 * 0.85 会触发自我保护机制,乘以二的原因是因为默认设置的心跳一分钟内发送两次)
eureka无法对注册的应用本身进行健康管理,只要持续发送心跳,即认为正常。当DB出问题时,服务本身就变得不可用,这种情况需要借助其他健康管理应用,如:admin

eureka提供了四种监听事件

  • EurekaInstanceCanceledEvent 服务下线事件
  • EurekaInstanceRegisteredEvent 服务注册事件
  • EurekaInstanceRenewedEvent 服务续约事件
  • EurekaRegistryAvailableEvent 注册中心可用事件
  • EurekaServerStartedEvent 注册中心启动

具体实现(服务下线事件),在server端:

@EventListener
public void listen(EurekaInstanceCanceledEvent e) {
	System.out.println(e.getServerId()+"下线事件");
}

eureka client

DiscoveryClient

  1. 初始化一堆信息
  2. 从拉取注册表信息
  3. 向server注册自己

初始化3个任务(三个任务分别是:向服务端发送的心跳向server端同步其他客户端的信息和状态在本应用状态发生变化时同步至server

Ribbon

Ribbon是一种作为客户端的负载均衡应用。
在eureka-client中使用Ribbon时, 不需要引入jar包,因为erueka-client已经包括ribbon的jar包了
Ribbon可以单独使用,作为一个独立的负载均衡组件。只是需要我们手动配置 服务地址列表。
Ribbon与Eureka配合使用时,Ribbon可自动从Eureka Server获取服务提供者地址列表(DiscoveryClient),并基于负载均衡算法,请求其中一个服务提供者实例。
Ribbon与OpenFeign和RestTemplate进行无缝对接,让二者具有负载均衡的能力。OpenFeign默认集成了ribbon。

Bean 类型

说明

ILoadBalancer

负载均衡器的抽象

IClientConfig

clien配置类

IRule

负载均衡策略

IPing

服务可用性检测

ServerList

服务列表获取

ServerListFilter

服务列表过滤

负载均衡过程

  1. 拦截请求。
  2. 获取url。
  3. 通过url中 serviceName 获取 List。
  4. 通过负载均衡算法选取一个ServiceInstance。
  5. 替换请求,将原来url中的 serviceName换成ip+port。

总结

  • 几种负载均衡。(硬,软(服务端,客户端(Ribbon))) Ribbon可以单独使用。需要提供服务地址列表。
  • 原理。拦截请求,然后替换地址(servicename到ip+port)。
  • 源码。ILoadBalancer,Map<服务名,ILoadBalancer>
  • @LoadBalanced,拦截器。(LoadBalancerInterceptor中intercept)
  • 自定义配置:java配置,yml配置。 自定义负载均衡策略

Feign

原理:

  1. 主程序入口添加@EnableFeignClients注解开启对Feign Client扫描加载处理。根据FeignClient的开发规范,定义接口并加@FeignClient注解。
  2. 当程序启动时,会进行包扫描,扫描所有@FeignClient注解的类,并将这些信息注入Spring IoC容器中。当定义的Feign接口中的方法被调用时,通过JDK的代理方式,来生成具体的RequestTemplate。当生成代理时,Feign会为每个接口方法创建一个RequestTemplate对象,该对象封装了HTTP请求需要的全部信息,如请求参数名、请求方法等信息都在这个过程中确定。
  3. 然后由RequestTemplate生成Request,然后把这个Request交给client处理,这里指的Client可以是JDK原生的URLConnection、Apache的HttpClient,也可以是Okhttp。最后Client被封装到LoadBalanceClient类,这个类结合Ribbon负载均衡发起服务之间的调用。

流程如下:

springcloud alibaba dubbo 心跳时间设置 springcloud心跳机制原理_负载均衡

两大流程

  • 程序启动时:接口的bean实例时如何初始化的,被@FeignClient修饰的接口类。构建Bean。
  • 网络调用时:调用上面类的方法时如何发送网络请求。

每一个请求 就是一个上下文

springcloud alibaba dubbo 心跳时间设置 springcloud心跳机制原理_分布式_02

与restTemplate的对比
RestTemplate,自由,更贴近httpclient,方便调用别的第三方的http服务。
feign,更面向对象一些,更优雅一些。

Hystrix

springcloud alibaba dubbo 心跳时间设置 springcloud心跳机制原理_spring_03

spring cloud 用的是 hystrix,是一个容错组件。 Hystrix实现了 超时机制和断路器模式。
Hystrix是Netflix开源的一个类库,用于隔离远程系统、服务或者第三方库,防止级联失败,从而提升系统的可用性与容错性。主要有以下几点功能:

  1. 为系统提供保护机制。在依赖的服务出现高延迟或失败时,为系统提供保护和控制。
  2. 防止雪崩。
  3. 包裹请求:使用HystrixCommand(或HystrixObservableCommand)包裹对依赖的调用逻辑,每个命令在独立线程中运行。
  4. 跳闸机制:当某服务失败率达到一定的阈值时,Hystrix可以自动跳闸,停止请求该服务一段时间。
  5. 资源隔离:Hystrix为每个请求都的依赖都维护了一个小型线程池,如果该线程池已满,发往该依赖的请求就被立即拒绝,而不是排队等候,从而加速失败判定。防止级联失败。
  6. 快速失败:Fail Fast。同时能快速恢复。侧重点是:(不去真正的请求服务,发生异常再返回),而是直接失败。
  7. 监控:Hystrix可以实时监控运行指标和配置的变化,提供近实时的监控、报警、运维控制。
  8. 回退机制:fallback,当请求失败、超时、被拒绝,或当断路器被打开时,执行回退逻辑。回退逻辑我们自定义,提供优雅的服务降级。
  9. 自我修复:断路器打开一段时间后,会自动进入“半开”状态,可以进行打开,关闭,半开状态的转换。

hystrix可以独立使用 脱离spring cloud

关注点:

  1. 继承hystrixCommand类
  2. 重写run
  3. 运行方法 fallback备选方法(程序发生非HystrixBadRequestException异常,运行超时,熔断开关打开,线程池/信号量满了。备选方法需要与运行方法返回值类型,参数类型一致(可以加上参数Throwable throwable获取异常)

两个开启注解@EnableCircuitBreaker,@EnableHystrix点进去看,其实一样。 @EnableHystrix中包含了@EnableCircuitBreaker。

和feign结合

feign自带Hystrix,但是默认没有打开,首先打开Hystrix。(从Spring Cloud Dalston开始,feign的Hystrix 默认关闭,如果要用feign,必须开启)

feign:
  hystrix:
    enabled: true

注解添加feignclient

@FeignClient(name = "service-sms",fallback = SmsClientFallback.class)

类,实现feignClient接口

import java.util.concurrent.TimeUnit;

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import com.online.taxi.common.dto.ResponseResult;
import com.online.taxi.common.dto.sms.SmsSendRequest;
import com.online.taxi.passenger.service.SmsClient;

@Component
public class SmsClientFallback implements SmsClient {
    // SmsClient 为对应的feign接口
	
	@Override
	public ResponseResult sendSms(SmsSendRequest smsSendRequest) {
		System.out.println("不好意思,我熔断了");
		
		return ResponseResult.fail(-3, "feign熔断");
	}

}

启动类添加

@EnableFeignClients
@EnableCircuitBreaker

hystrix隔离策略

  1. 信号量隔离
    其实就是个计数器,使用该方式,HystrixCommand将会在调用线程上执行,通过信号量限制单个服务提供者的并发量,开销相对较小(因为不用那么多线程池),并发请求受到信号量个数的限制。 线程隔离会带来线程开销,有些场景(比如无网络请求场景)可能会因为用开销换隔离得不偿失,为此hystrix提供了信号量隔离,当服务的并发数大于信号量阈值时将进入fallback。
  2. 线程池隔离(网络调用服务经常使用这个)
    使用该方式,HystrixCommand将会在单独的线程上执行,并发请求受线程池中线程数量的限制。不同服务通过使用不同线程池,彼此间将不受影响,达到隔离效果。
    此种隔离方式:将调用服务线程与服务访问的执行线程分割开来,调用线程能够空出来去做其他工作,而不至于因为服务调用的执行,阻塞过长时间。
    hystrix将使用独立的线程池对应每一个服务提供者,用于隔离和限制这些服务。于是某个服务提供者的高延迟或者资源受限只会发生在该服务提供者对应的线程池中。

对比:
线程池和信号量都支持熔断和限流。相比线程池,信号量不需要线程切换,因此避免了不必要的开销。但是信号量不支持异步,也不支持超时,也就是说当所请求的服务不可用时,信号量会控制超过限制的请求立即返回,但是已经持有信号量的线程只能等待服务响应或从超时中返回,即可能出现长时间等待。线程池模式下,当超过指定时间未响应的服务,Hystrix会通过响应中断的方式通知线程立即结束并返回。

springcloud alibaba dubbo 心跳时间设置 springcloud心跳机制原理_java_04


spring cloud中使用 主要是下面这个注解 线程池等各种配置都在里面

@HystrixCommand

附:
该包是用于检测服务健康状态的工具

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

zuul

Zuul是Netflix开源的微服务网关,网关会将服务名转换成具体服务的ip和端口,实际进行访问。 核心是一系列过滤器。这些过滤器可以完成以下功能。

  1. 是所有微服务入口,进行分发。
  2. 身份认证与安全。识别合法的请求,拦截不合法的请求。
  3. 监控。在入口处监控,更全面。
  4. 动态路由。动态将请求分发到不同的后端集群。
  5. 压力测试。可以逐渐增加对后端服务的流量,进行测试。
  6. 负载均衡。也是用ribbon。
  7. 限流。比如我每秒只要1000次,10001次就不让访问了。 (使用令牌桶 谷歌的包jmeter)

访问:http://localhost:9100/actuator/filters 可以看到所有的过滤器
包括以下四种

PRE: 在请求被路由之前调用,可利用这种过滤器实现身份验证。选择微服务,记录日志。
ROUTING:在将请求路由到微服务调用,用于构建发送给微服务的请求,并用http clinet(或者ribbon)请求微服务。
POST:在调用微服务执行后。可用于添加header,记录日志,将响应发给客户端。
ERROR:在其他阶段发生错误是,走此过滤器。

可自定义过滤器

集成zuulFilter类,实现以下四个方法

filterType:pre,routing,post,error定义过滤器类型
filterOrder:执行顺序,在谁前,在谁后,可以+1,-1
shouldFilter:此过滤器是否执行,true  false,可以写过滤器是否执行的判断条件。
run:具体执行逻辑,若用于用户校验,不通过可以直接返回给页面,servlet处理方式

高可用

zuul作为普通的服务。对外访问。前面加一层(nginx+keepalived)

zuul总结

zuul本质就是filter。
通过filter解析url来决定我们去访问哪个微服务。
发请求访问微服务,也是通过filter实现。
响应数据,也是通过filter实现。

配置中心

分布式配置中心包括3个部分:

  1. 存放配置的地方:git ,本地文件 等。
  2. config server。从 1 读取配置。
  3. config client。是config server 的客户端 消费配置。

配置都不会自己更新,都是需要触发client才去git上拉取的。或者触发 在config-server上查看配置时,才去git上拉取。

  • 环境部署之前,将所需的配置信息推送到配置仓库
  • 启动配置中心服务端,将配置仓库的配置信息拉取到服务端,配置服务端对外提供RESTful接口
  • 启动配置客户端,客户端根据 spring.cloud.config 配置的信息去服务器拉取相应的配置

只启动config-sever 的时候,仓库目录,只是单纯的一个文件目录,连git仓库都不算。
config-client职责:启动时去config-server 拿配置,缓存后,自己用。
好多书上说的是:config-server启动时,去拉取git,但我实践后,发现不是这样的。3个条件下才会拉取

  • 访问server 配置。
  • 启动client,client获取server。
  • 刷新client,或刷新server。

刷新分为自动刷新和手动刷新,自动刷新用到了mq以及程序的监听器来实现,流程图如下:

springcloud alibaba dubbo 心跳时间设置 springcloud心跳机制原理_spring_05

链路追踪

如果能跟踪每个请求,中间请求经过哪些微服务,请求耗时,网络延迟,业务逻辑耗时等。我们就能更好地分析系统瓶颈、解决系统问题。因此链路跟踪很重要。

链路追踪要考虑的几个问题

  1. 探针的性能消耗。尽量不影响 服务本尊。
  2. 易用。开发可以很快接入,别浪费太多精力。
  3. 数据分析。要实时分析。维度足够。

Sleuth是Spring cloud的分布式跟踪解决方案。 但是最好和zipkin 绑定使用,更易于检测。

健康检查

admin组件是spring cloud的健康检查解决方案,只是目前还在完善阶段

spring cloud总结

服务注册中心:eureka
服务调用:restTemplate,feign
负载均衡:ribbon
熔断:hystrix
配置中心:config-server,config-client
网关:zuul。
链路追踪:sleuth,zipkin。
上面这一套解决方案,足以应对日常的微服务搭建。