SpringCloud组件

Eureka--服务注册发现

Eureka基本概念

Eureka主要就是用来注册服务的,其中包括两部分:Eureka Client、Eureka Server。目前同功能的组件:ZooKeeper、Nacos

  1. Register--服务注册

当Eureka Client向Eureka Service注册时,EurekaClient提供自身的元数据,比如IP地址、端口、运行状况指标的Url、主页地址等信息。

Eureka Client的PeerAwareInstanceRegisterImpl类的register()方法实现了服务的注册,并且向其他Eureka Server的Peer节点同步了该注册信息。

Eureka Server的ApplicationResource类中的addInstance()方法提供了服务的注册接口。

  1. Renew--服务续约

Eureka Client在默认的情况下会每隔30秒发送一次心跳来进行服务续约。通过服务续约来告知Eureka Server该Eureka Client仍按可用,没有出现故障。正常情况下,如果Eureka Server在90秒内没有收到Eureka Client的心跳,Eureka Server会降Eureka Client示例从注册列表中删除。注意:官网建议不要更改服务续约的间隔时间。

DiscoveryClient类的renew()方法进行续约。

  1. Fetch Registers--获取服务注册列表信息

Eureka Client从Eureka Server获取服务注册表信息,并将其缓存在本地。Eureka Client会使用服务注册列表信息查找其他服务的信息,从而进行远程调用。该注册列表信息会定时(每30秒)更新一次。

  1. Cancel--服务下线

Eureka Client在程序关闭时可以向Eureka Server发送下线请求,发送请求后,该客户端的示例信息将从Eureka Server的服务注册列表中删除。该下线请求不会自动完成,需要在程序关闭时调用

DiscoveryManager.getInstance().shutdownComponent()。

  1. Eviction--服务剔除

在默认情况下,Eureka Client连续90秒未向Eureka Server发送服务续约(即心跳)时,Eureka Server会将该服务实例从服务注册列表删除。

Eureka Client获取服务实例慢

  1. Eureka Client的注册慢。

Eureka Client启动后不是立即向Eureka Server注册的,而是有一个延迟向服务端注册的时间。在DefaultEurekaClientConfig类中可以看到有40秒延迟。

2、Eureka Server的相应缓存

Eureka Server维护每30秒更新一次相应缓存,可通过eureka.server.responseCacheUpdateIntervalMs来修改。

3、Eureka Client的缓存

Eureka Client保留注册表信息的缓存。该缓存每30秒更新一次。

4、LoadBalancer的缓存

Ribbon的负载平衡器从本地的Eureka Client获取服务注册列表信息。Ribbon本身还维护了缓存,以避免每次请求都需要从Eureka Client获取服务注册列表。此缓存每30秒刷新一次(ribbon.ServerListRefreshInterval配置)

Eureka、Nacos、Zookeeper的区别

ZooKeeper 的基本运行流程
  1. 选举 Leader(所以一般要求3个,或者以上)。

  1. 同步数据。

  1. 选举 Leader 过程中算法有多中,但最终的选举标准是一致的。

  1. Leader 被赋予最高的执行ID(竞选成功后的授权),其执行ID类似于Linux中的root权限。

  1. 集群中服务得到通知并一致的认可选出的 Leader。

  1. Leader 服务器宕机,进入1)步,再次进行 Leader 选举。

CAP
  1. 一致性(Consistency,C):在分布式系统中的所有数据备份,在同一时刻是否同样的值。(等同于所有节点访问同一份最新的数据副本)。

  1. 可用性(Availability,A):在一个分布式系统的集群中一部分节点故障后,该集群是否还能够正常响应客户端的读写请求。(对数据更新具备高可用性)。

  1. 分区容错性(Partition tolerance,P):大多数的分布式系统都分布在多个子网络中,而每个子网络就叫做一个区(partition)。分区容错的意思是,区间通信可能失败。

eureka内部是AP协议,即它可以保证服务的高可用,但是对于一致性的要求不高;

zookepper内部是CP协议,即它可以保证服务的数据一致性,但是对于服务的可用性要求不高;

nacos内部是AP/CP协议,默认AP协议,如果对一致性的要求比较高可以切换为CP协议。

Ribbon--负载均衡

RestTemplate

RestTemplate时是Spring Resources中一个访问第三方RESTful API接口的网络请求框架。RestTemplate的设计原则和其他Spring Template(例如JdbcTemplate、JmsTemplate)类似,都是为执行复杂任务提供了一个具有默认行为的简单方法。

RestTemplate是用来消费REST服务的,所以RestTemplate的主要方法都与REST的Http协议的一些方法紧密相连,例如HEAD、GET、POST、PUT、DELETE和OPTIONS等方法,这些方法在RestTemplate类对应的方法为headForHeaders()、getForObject()、postForObject()、put()和delete()等。

LoadBalancerClient

负载均衡器的核心类为LoadBalancerClient,LoadBalancerClient可以获取负载均衡的服务提供者的实例信息。负载均衡器LoadBalancerClient从Eureka Client获取服务注册列表信息,并将服务注册列表信息缓存一份。

在LoadBalancerClient调用choose()方法时,根据负载均衡策略选择一个服务实例的信息,从而进行负载均衡。也可以不从Eureka Client获取注册列表,而是自己维护一份注册列表。

源码解析

ServiceInstanceChooser

ServiceInstanceChooser接口有一个方法用于根据serviceId获取ServiceInstance,即通过服务名莱选择服务实例。

LoadBalancerClient

LoadBalancerClient是一个负载均衡客户端,有2个excute()方法,均用来执行请求,reconstructURI()用于重构Url。

RibbonLoadBalancerClient

RibbonLoadBalancerClient是LoadBalancerClient的实现类,通过choose()方法莱选择具体服务实例,该方法通过getServer()方法获取实例,最终是通过ILoadBalancer类来选择。

ILoadBalancer

ILoadBalancer子类为BaseLoadBalancer,BaseLoadBalancer的实现类DynamicServerListLoadBalancer

DynamicServiceListLoadBalancer

DynamicServiceListLoadBalancer需要配置IClientConfigIRule、IPingServerListServerListFilterILoadBalancer

IClientConfig

IClientConfig用于配置负载均衡的客户端,默认DefaultClientConfigImpl

IRule

IRule用户配置负载均衡的策略,IRule有3个方法:choose()根据key来获取server实例;setLoadBalancer()和getLoadBalancer()用来设置和获取ILoadBalancer,默认RoundRobinRule。

IRule根据不同算法和逻辑的处理负载均衡的策略类:

BestAvailableRule:选择最小请求数

ClientConfigEnableRoundRobinRule:轮询

RandomRule:随机选择server

RoundRobinRule:轮询选择server

RetryRule:根据轮询的方式重试

WeightResponseTimeRule:根据响应时间去分配一个weight,weight越低,被选择的可能性就越低。

ZoneAvoidanceRule:根据server的zone区域和可用性来轮询选择。

IPing

IPing用于向server发送“ping”,来判断该server是否有相应,从而判断该serer是否可用,只有isAlive()方法,默认DummyPing

IPing的实现类有PingUrl、PingConstant、NoOpPing、DummyPing和NIWSDiscoveryPing

PingUrl:真实地去ping某个url,判断其是否可用。

PingConstantL固定返回某服务是否可用,默认返回true,即可用。

NoOpPing:不去ping,直接返回true,即可用。

DummyPing:直接返回true,并实现了initWithNiwsConfig方法。

NIWSDiscoveryPing:根据DiscoveryEnabledServer地InstanceInfo地InstanceStatus去判断,如果为InstanceStatus。UP,则可用,否则不可用。

ServerList

ServerList是定义获取所有server的注册列表信息的接口。

ServerListFilter

ServerListFilter接口定义了可根据配置去过滤或者特性动态地获取符合条件地server列表地方法。

Loadbalancer注册表的获取

DynamicServerListLoadBalancer的构造函数中有一个initWithNiwsConfig()方法,该方法经过一系列的初始化配置,最终执行restOfInit()方法。在restOfInit()方法中,有一个updateListOfServers()的方法,该方法用来获取所有的ServerList的。

updateListOfServers()方法的源码最终由serverListImpl.getUpdatedListOfServers()获取所有的服务列表。

serverListImpl是ServerList接口的具体实现类,为DiscoverEnableNIWSServerList,该类有getInitalListOfServers()和getUpdatedListOfServers()方法。getUpdatedListOfServers()方法中有obtainServersViaDiscovery()方法,根据eurekaClientProvider.get()方法来获取EurekaClient的,再根据EurekaClient来获取服务注册列表信息。

总结:负载均衡器是从Eureka Client获取服务列表信息,并根据IRule的策略去路由,根据IPing去判断服务的可用性。

Loadbalancer注册表的刷新

在BaseLoadBalancer类的构造方法开启了一个PingTask任务,在setPingTask()方法中开启了ShutdownEnabledTimer的PingTask任务。在默认情况下,pingIntervalSeconds的值为10,即每10秒向Eureka Client发送一次心跳“ping”。

PingTask创建了一个Pinger对象,并执行了runPinger()方法。在runPinger()方法中根据pingerStrategy.pingServers(ping, allServers)来获取服务的可用性,如果该返回结果与之前相同,则不向Eureka Client获取注册列表;如果不同。则通知ServerStatusChangeListener

服务注册列表信息发生了改变,进行更新或者重新拉取。

总结:LoadBalancerClient是在初始化时向Eureka获取服务注册列表信息,并且每10秒向Eureka Client发送“ping”,来判断服务的可用性。如果服务可用性发生了改变或者服务数量和之前不一致,则更新或者重新拉取。LoadBalancerClient有了这些服务注册列表信息,就可以根据具体的IRule的策略来进行负载均衡。

RestTemplate类的Bean加上@LoadBalanced注解

在LoadBalancerAutoConfiguration类中,首先维护了一个被@LoadBalanced修饰的RestTemplate对象的List。在初始化的过程

中,通过调用customizer.customize(restTemplate)方法来给RestTemplate增加拦截器LoadBalancerInterceptor。

LoadBalancerInterceptor用于实时拦截,在LoadBalancerInterceptor中实现了负载均衡的方法。

总结
  1. Ribbion的负载均衡主要时通过LoadBalancerClient来实现,而LoadBalancerClient具体交给ILoadBalancer来处理,ILoadBalancer通过配置IRule、IPing等,向Eureka Client获取注册列表的信息,默认每10秒向EurekaClient发送一次“ping”,进而检查是否需要更新服务的注册列表信息。最后,在得到服务注册表信息后,ILoadBalancer根据IRule的策略进行负载均衡。

  1. RestTemplate加上@LoadBalance注解后,在远程调度时能够负载均衡,主要时维护了一个被@LoadBalanced注解的RestTemplate列表,并给该列表中的RestTemplate对象添加了拦截器。在拦截的方法中,将远程调度方法交给了Rbiion的负载均衡器LoadBalancerClient去处理,从而达到了负载均衡的目的。

Feign

远程调度其他服务。

FeignClient注解

value和name一样,是被调用的服务的ServiceId。

url()直接填写硬编码的Url地址。

decode404()即404是被解码,还是抛异常。

configuration()指明FeignClient的配置类,默认的配置类为FeignClientsConfiguration类,在缺省的情况下,该类注入了默认的Decoder、Encoder和Contract等配置的Bean。通过重写FeignClientsConfiguration类中的Bean,覆盖掉默认的配置Bean,从而达到自定义配置的目的。

fallback()为配置熔断器的处理类。

工作原理

在程序启动时,FeignClientsRegistrar类会检查是否有@EnableFeignClients注解,如果有则开启包扫描被@FeignClient注解的接口;连同接口和注解的信息一起取出,赋值给BeanDefinitionBuilder,然后根据BeanDefinitionBuilder得到BeanDefinition,最后将BeanDefinition注入到IoC容器中。

注入BeanDefinition之后,通过JDK动态代理,当调用Feign Client接口里面的方法时,该方法会被拦截,具体源码在ReflectiveFeign类中。

SynchronousMethodHandler类进行拦截处理,会根据参数生成RequestTemplate对象,该对象是Http请求的模板。在executeAndDecode()方法,通过Http Client进行Http请求来获取响应。

Feign使用HttpClient和OkHttp

在FeignRibbonClient的自动配置类FeignRibbonClientAutoConfiguration中,该类在工程启动时注入一些Bean,其中注入了一个BeanName为feignClient的Client类型的Bean。在缺省配置BeanName为FeignClient的Bean的情况下,会自动注入Client.Default这个对象,该对象使用的网络请求框架为HttpURLConnection。

从代码@ConditionalOnClass(AppacheHttpClient.class)注解可知,只要在pom文件加上HttpClient的Classpath即可。另外需要在配置文件application.yml中配置feign,httpclient.enaabled为true,从@ConditionalOnProperty注解可知,这个配置可以不写,默认请求就为true。

在工程pom文件加上feign-httpclient的依赖,Feign就会采用HttpClient作为网络请求框架,而不是默认的HttpURLConnection。

OkHttp同理。

Feign实现负载均衡

FeignRibbonClientAutoConfiguration配置了Client的类型(包括HttpURLConnection、OkHttp和HttpClient),最终向容器注入的是Client的实现类LoadBalancerFeignClient,即负载均衡客户端。LoadBalancerFeignClient类中的execute()方法有一个executeWithLoadBalancer()方法,即通过负载均衡的方式来执行网络请求。

在executeWithLoadBalancer()方法中有一个submit()方法,其中有一个selectServe()方法,该方法选择服务进行负载均衡,最终交给loadBalancerContext来处理。

总结

  1. 首先通过@EnableFeignClients注解开启FeignClient的功能,只有这个注解存在,才会在程序启动时开启对@FeignClient注解的包扫描。

  1. 根据Feign的规则实现接口,并在接口上面加上@FeignClient注解。

  1. 程序启动后,会进行包扫描,扫描所有的@FeignClient的注解的类,并将这些信息注入到IoC容器中。

  1. 当接口的方法被调用时,通过JDK的代理生成具体的RequestTemplate模板对象。

  1. 根据RequestTemplate再生成Http请求的Request对象。

  1. Request对象交给Client去处理,其中Client的网络请求框架可以时HttpURLConnection、HttpClient和OkHttp。

  1. 最后Client被封装到LoadBalanceClient类,这个类结合Ribbon做到负载均衡。

Hystrix

Hystrix是熔断器,主要作用如下:

防止单个服务的故障耗尽整个服务的Servlet容器(例如Tomcat)的线程资源;

快速失败机制,如果某个服务出现故障,则调用该服务的请求快速失败,而不是线程等待;

提供回退(fallback)方案,在请求发生故障时,提供设定好的回退方案;

使用熔断机制,防止故障扩散到其他服务;

提供熔断器的监控组件Hystrix Dashboard,可以实时监控熔断器的状态。

使用Hystrix Dashboard监控

在启动类加上@EnableHystrixDashboard注解,通过http://localhost:8080/hystrix.stream 返回检测数据;http://localhost:8080/hystrix 进入监控页面

使用Turbine聚合监控

在使用Hystrix Dashboard组件监控服务的熔断器状况时,每个服务都有一个Hystrix Dashboard主页,当服务数量很多时,监控

非常不方便,为了同时监控多个服务的熔断器的状况,Netflix开源了Hystrix的另一个组件Turbine。Turbine用于聚合多个Hystrix Dashboard主页,当服务数量很多时,监,

将多个hystrix Dashboard组件的数据放在一个页面展示,进行集中监控。

Ribbon、Feign、Hystrix超时问题

https://blog.csdn.net/qq_35388010/article/details/125448911

Zuul

路由网关组件。

主要作用

  1. Zull、Ribbon和Eureka相组合,可以实现智能路由和负载均衡的功能,Zuul能够将请求的流量按照相应策略分发到集群状态的多个服务实例。

  1. 网关将所有服务的API接口统一聚合,并统一对外暴露。外界系统调用API接口时,都是由网关对外暴露的API接口,外界系统调用API接口时,都是由网关对外暴露的API接口,外界系统不需要知道微服务系统中各服务相互调用的复杂性。微服务系统也保护了其内部微服务单元的API接口,防止其被外界直接调用,导致服务的敏感信息对外暴露。

  1. 网关服务可以做用户身份认证和权限认证,防止非法请求操作API接口,对服务器起到保护作用。

  1. 网关可以实现监控功能,实时日志输出,对请求进行记录。

  1. 网关可以用来实现流量监控,在高流量的情况下,对服务进行降级。

  1. API接口对内部服务分离出来,方便做测试。

工作原理

Zuul通过Servlet实现,通过自定义的ZuulServelt(类似Spring MVC的DsipatcServelt)来对请求进行控制。Zuul的核心是一系列过滤器,可以在Http请求的发起和相应返回期间执行一系列的过滤器。Zuul包括以下4种过滤器。

PRE过滤器:它在请求路由到具体的服务之前执行,这种类型的过滤器可以做安全验证,例如身份验证、参数验证等。

ROUTING过滤器:它用于将请求路由到具体的微服务实例。在默认情况下,它使用Http Client进行网络请求。

POST过滤器:它是请求已被路由到微服务后执行的。一般情况下,用作收集统计信息、指标,以及将响应传输到客户端。

ERROR过滤器:它是在其他过滤器发生错误时执行。

Zuul过滤器特性

Type(类型):Zuul过滤器的类型,这个类型决定过滤器在请求的哪个阶段起作用,例如:Pre、Post阶段等。

Execution Order(执行顺序):规定了过滤器的执行顺序,Order值越小,越先执行。

Criteria(标准):Filter执行所需的条件。

Action(行动):如果符合执行条件,则执行Action(即逻辑代码)。

Zuul过滤器执行流程

当一个客户端Request请求进入Zuul网关服务时,网关先进入“pre filter”,进行一系列的验证、操作或者判断。然后交给“routing filter”进行路由转发,转发到具体的服务实例进行逻辑处理、返回数据。当具体服务处理完后,最后由“post filter”进行处理,该类型的处理器处理完之后,将Response信息返回给客户端。

ZuulServelt

ZuulServelt是Zuul的核心Servelt。ZuulServelt的作用是初始化ZuulFilter,并编排这些ZuulFilter的执行顺序。该类有个service()方法,执行了过滤器执行的逻辑。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值