Eureka--服务注册发现
Eureka基本概念
Eureka主要就是用来注册服务的,其中包括两部分:Eureka Client、Eureka Server。目前同功能的组件:ZooKeeper、Nacos。
Register--服务注册
当Eureka Client向Eureka Service注册时,EurekaClient提供自身的元数据,比如IP地址、端口、运行状况指标的Url、主页地址等信息。
Eureka Client的PeerAwareInstanceRegisterImpl类的register()方法实现了服务的注册,并且向其他Eureka Server的Peer节点同步了该注册信息。
Eureka Server的ApplicationResource类中的addInstance()方法提供了服务的注册接口。
Renew--服务续约
Eureka Client在默认的情况下会每隔30秒发送一次心跳来进行服务续约。通过服务续约来告知Eureka Server该Eureka Client仍按可用,没有出现故障。正常情况下,如果Eureka Server在90秒内没有收到Eureka Client的心跳,Eureka Server会降Eureka Client示例从注册列表中删除。注意:官网建议不要更改服务续约的间隔时间。
DiscoveryClient类的renew()方法进行续约。
Fetch Registers--获取服务注册列表信息
Eureka Client从Eureka Server获取服务注册表信息,并将其缓存在本地。Eureka Client会使用服务注册列表信息查找其他服务的信息,从而进行远程调用。该注册列表信息会定时(每30秒)更新一次。
Cancel--服务下线
Eureka Client在程序关闭时可以向Eureka Server发送下线请求,发送请求后,该客户端的示例信息将从Eureka Server的服务注册列表中删除。该下线请求不会自动完成,需要在程序关闭时调用
DiscoveryManager.getInstance().shutdownComponent()。
Eviction--服务剔除
在默认情况下,Eureka Client连续90秒未向Eureka Server发送服务续约(即心跳)时,Eureka Server会将该服务实例从服务注册列表删除。
Eureka Client获取服务实例慢
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 的基本运行流程
选举 Leader(所以一般要求3个,或者以上)。
同步数据。
选举 Leader 过程中算法有多中,但最终的选举标准是一致的。
Leader 被赋予最高的执行ID(竞选成功后的授权),其执行ID类似于Linux中的root权限。
集群中服务得到通知并一致的认可选出的 Leader。
Leader 服务器宕机,进入1)步,再次进行 Leader 选举。
CAP
一致性(Consistency,C):在分布式系统中的所有数据备份,在同一时刻是否同样的值。(等同于所有节点访问同一份最新的数据副本)。
可用性(Availability,A):在一个分布式系统的集群中一部分节点故障后,该集群是否还能够正常响应客户端的读写请求。(对数据更新具备高可用性)。
分区容错性(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需要配置IClientConfig、IRule、IPing、ServerList、ServerListFilter和ILoadBalancer
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中实现了负载均衡的方法。
总结
Ribbion的负载均衡主要时通过LoadBalancerClient来实现,而LoadBalancerClient具体交给ILoadBalancer来处理,ILoadBalancer通过配置IRule、IPing等,向Eureka Client获取注册列表的信息,默认每10秒向EurekaClient发送一次“ping”,进而检查是否需要更新服务的注册列表信息。最后,在得到服务注册表信息后,ILoadBalancer根据IRule的策略进行负载均衡。
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来处理。
总结
首先通过@EnableFeignClients注解开启FeignClient的功能,只有这个注解存在,才会在程序启动时开启对@FeignClient注解的包扫描。
根据Feign的规则实现接口,并在接口上面加上@FeignClient注解。
程序启动后,会进行包扫描,扫描所有的@FeignClient的注解的类,并将这些信息注入到IoC容器中。
当接口的方法被调用时,通过JDK的代理生成具体的RequestTemplate模板对象。
根据RequestTemplate再生成Http请求的Request对象。
Request对象交给Client去处理,其中Client的网络请求框架可以时HttpURLConnection、HttpClient和OkHttp。
最后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
路由网关组件。
主要作用
Zull、Ribbon和Eureka相组合,可以实现智能路由和负载均衡的功能,Zuul能够将请求的流量按照相应策略分发到集群状态的多个服务实例。
网关将所有服务的API接口统一聚合,并统一对外暴露。外界系统调用API接口时,都是由网关对外暴露的API接口,外界系统调用API接口时,都是由网关对外暴露的API接口,外界系统不需要知道微服务系统中各服务相互调用的复杂性。微服务系统也保护了其内部微服务单元的API接口,防止其被外界直接调用,导致服务的敏感信息对外暴露。
网关服务可以做用户身份认证和权限认证,防止非法请求操作API接口,对服务器起到保护作用。
网关可以实现监控功能,实时日志输出,对请求进行记录。
网关可以用来实现流量监控,在高流量的情况下,对服务进行降级。
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()方法,执行了过滤器执行的逻辑。