Zuul的核心功能都是通过一个个过滤器(Filter)来实现的。本章,我就对Zuul的各种过滤器(Filter)进行讲解。Zuul一共有四种类型的过滤器,SpringCloud启动时会注入以下类型的过滤器(数字表示优先级):Pre过滤器:-3:ServletDetectionFilter-2:Servlet30WrapperFilter-1:FromBodyWrapperFilter1:DebugFilter5:PreDecorationFilterRoute过滤器:10:RibbonRoutingFilter100:SimpleHostRoutingFilter500:SendForward
本章,我将对SpringCloudNetflixZuul的初始化流程进行讲解。我们在使用Zuul时,基本都是引入spring-cloud-netflix-zuul依赖,然后在启动类上注解@EnableZuulProxy。那么,SpringCloud底层到底做了什么事情呢?一、初始化流程SpringBoot应用启动后,会去两个地方加载配置:扫描到@EnableZuulProxy注解,执行注解中的@Import操作;加载spring-cloud-netflix-zuul源码包META-INF目录下的spring.factories配置。我用下面这两张图表述SpringCloudNetflixZuu
从本章开始,我将讲解SpringCloudNetflix中的另一个组件——Zuul。Zuul就是微服务架构中的网关(gateway),我在《分布式系统从理论到实战》系列中已经对微服务架构中的API网关做了全面介绍,并且在实战篇中也对OpenResty这个网关进行了应用。本章,我将首先回顾Zuul的基本使用,接着会对Zuul的基本原理做一个讲解,为后续章节讲解Zuul的核心源码做铺垫。建议读者先去阅读SpringCloud的官方文档:https://docs.spring.io/spring-cloud-netflix/docs/2.2.5.RELEASE/reference/html/#rou
无论是与Feign整合,还是独立使用Hystrix,最终都会调用HystrixCommand.execute()触发Hystrix的工作流程。所以对源码的分析最终回到了NetflixHystrix本身。从本章开始,我将直接分析NetflixHystrix的源码,我们先从HystrixCommand开始,重点关注它的核心逻辑,忽略与RxJava相关的代码。这么说不是很准确,HystrixCommand提供了四种执行方法,但底层是一样的,本章仅以exetute进行分析。关于Hystrix的底层工作机制,最好的参考资料就是Netflix的官方文档:https://github.com/Netflix
上一章,我讲解了Hystrix整合Feign时的初始化流程。事实上,SpringCloudNetflixHystrix是可以单独使用的,本章我就来讲解Hystrix单独使用时的初始化流程。首先回顾一下,Hystrix独立使用时,一般就是利用@HystrixCommand注解:@SpringBootApplication@EnableEurekaClient@EnableFeignClients@EnableCircuitBreakerpublicclassServiceBApplication{publicstaticvoidmain(String[]args){SpringApplicati
本章,我将讲解Hystix与Feign组合使用时的初始化流程。通过Feign系列的学习,大家已经知道Feign在自动装配的时候,如果项目中有Hystrix相关的依赖,就会引入两个核心的Hystrix相关组件:HystrixTargeterHystrixFeign.builder()下图为Feign的公共组件的默认装配流程:在使用Feign时,最终就是生成一个动态代理类,那么可以猜想,当引入了Hystrix,这个动态代理类一定是集成了Hystrix的某些组件。一、初始化流程我用下面这张图表述集成Hystrix后,Feign的初始化流程:可以看到,与之前Feign系列中讲解的初始化流程最大区别有以
我之前讲解Hystrix时,都是使用原生的NetfilxHystrix,但实践中我们一般不会直接使用。所以本章,我将讲解如何在SpringCloud中使用Hystrix,SpringCloud对Hystrix进行了封装,我之前已经讲解过了Eureka、Ribbon、Feign,事实上,SpringCloudNetflixHystrix既可以独立使用,也可以和Feign整合在一起,本章我会分别讲解这两种使用方式。关于SpringCloudNetflixHystrix使用的更多介绍,可以参考官方文档:https://docs.spring.io/spring-cloud-netflix/docs/
从本章开始,我将讲解SpringCloudNetflix中的另一个组件——Hystrix。关于Hystrix的基本原理和原生使用方法,我其实已经在另一个系列——《分布式系统从理论到实战》中详细讲解过了,读者可以自己去阅读一下。本章,我也会带大家回顾一下Hystrix的原理,为后续讲解Hystrix与SpringCloud的整合做铺垫。一、核心功能Hystrix的核心功能有三个:资源隔离、熔断、降级。我们来一一看下它的基本原理。1.1资源隔离Hystrix进行资源隔离的基本思想是:将对某一个依赖服务的所有调用请求,全部隔离在同一份资源池内,不会去用其它的资源,一共有两种实现方案:线程池隔离和信号
了解了Feign是如何创建动态代理对象之后,我们就进入最后一个环节:Feign的请求流程。我们在使用Feign时,一般使用@Autowired注入,比如下面这样:@FeignClient("ServiceA")//ServiceA就是服务A的名称publicinterfaceServiceAClientextendsServiceAInterface{}@RestController@RequestMapping("/ServiceB/user")publicclassServiceBController{@AutowiredprivateService
我们在使用Feign时,一般使用@Autowired注入接口,比如下面这样:@FeignClient("ServiceA")//ServiceA就是服务A的名称publicinterfaceServiceAClientextendsServiceAInterface{}@RestController@RequestMapping("/ServiceB/user")publicclassServiceBController{@AutowiredprivateServiceAClientserviceA;}但是我们自己并没有实现ServiceAClient接
还是和讲解Ribbon的流程一样,在正式讲解Feign工作流程之前,我必须先将Feign客户端的配置原理讲清楚。Feign客户端也一共有三种级别的配置,优先级依次从高到低:基于@FeignClient的自定义配置;基于@EnableFeignClients的全局配置;基于org.springframework.cloud.openfeign.FeignClientsConfiguration的默认配置。也就是说,Feign客户端首先使用自定义配置,自定义配置中找不到再找全局配置,全局配置也找不到则使用默认配置。一、Feign客户端配置我们先来看下如何对Feign客户端进行配置,JavaBean
从本章开始,我将讲解SpringCloud中的另一个组件——Feign。Feign是什么?能解决什么样的问题?回顾一下我们之前使用RestTemplate+Ribbon+Eureka的方式来进行服务间的调用,每次调用服务接口,都必须像下面这样写代码:@RestControllerpublicclassServiceBController{@Bean@LoadBalancedpublicRestTemplategetRestTemplate(){returnnewRestTemplate();}@GetMapping(value="/greeting/{name}")publ
上一章,我讲到Ribbon对请求的核心处理流程是在ILoadBalancer中完成的,而SpringCloud默认提供的ILoadBalancer就是ZoneAwareLoadBalancer。本章,我就对ZoneAwareLoadBalancer和其它Ribbon核心组件进行分析,看看它们是如何与Eureka整合在一起,最终完成客户端负载均衡功能的。本章核心内容我用下面这张图来表述:一、负载均衡器构造默认负载均衡器是ZoneAwareLoadBalancer,它在构造时,会注入其它Ribbon核心组件(其实是把组件注入到父类的属性中)://ZoneAwareLoadBalancer.java
掌握了Ribbon初始化的底层原理和Eureka整合使用的流程。从本章开始,我就要开始讲解Ribbon的工作流程了。本章,我会先通过一个图讲解Ribbon与Eureka结合使用时的整体流程,后面再深入源码,讲解Ribbon的各个核心组件的底层实现。一、概述与Eureka结合使用时,我们通常会这样写程序:@RestControllerpublicclassServiceBController{@Bean@LoadBalancedpublicRestTemplategetRestTemplate(){returnnewRestTemplate();}@GetMapping(value="
本章,我将讲解与Eureka整合使用时,SpringCloudNetflixRibbon的初始化流程。掌握了SpringCloudNetflixRibbon的客户端配置的底层原理及其初始化流程,我们再学习Eureka的整合流程其实就很轻松了。读者可以先自己思考下,如果要与Eureka整合,需要对Ribbon做哪些改造?其实核心就是一点:如何在SpringBoot应用启动时,创建与Eureka功能相关的Ribbon客户端?一、初始化流程我们已经知道,SpringCloud会为我们创建一个RibbonLoadBalancerClient对象,作为默认的Ribbon客户端实现类,与此同时会根据Rib
在正式讲解Ribbon的工作流程之前,我必须先将Ribbon客户端的配置原理讲清楚。Ribbon客户端一共有三种级别的配置,优先级依次从高到低:基于@RibbonClient的自定义配置;基于@RibbonClients的全局配置;基于org.springframework.cloud.netflix.ribbon.RibbonClientConfiguration的默认配置。也就是说,Ribbon客户端首先使用自定义配置,自定义配置中找不到再找全局配置,全局配置也找不到则使用默认配置。我们必须搞清楚SpringCloudNetglixRibbon启动时,RibbonClient是如何进行装配
从本章开始,我将讲解SpringCloudNetfilx中的另一个核心组件——Ribbon。SpringCloudNetfilx提供了Ribbon作为客户端负载均衡组件,Ribbon本身很简单,所以我讲解的重点是SpringCloud是如何将NetflixRibbon集成到自己的技术体系中的。网上有很多文章讲Ribbon、Ribbon源码解析、讲SpringCloud怎么与Ribbon整合....balablabla,在我看来都几乎没有几篇能够将原生NetflixRibbon、SpringCloudNetflixRibbon以及SpringCloud整合NetflixRibbon的机制讲明白,
前面章节,我针对NetflixEureka的核心源码进行了讲解。SpringCloud在NetflixEureka的基础上封装了一层,将NetflixEureka整合到Spring技术体系中,也就是spring-cloud-netflix-eureka项目。这个项目仅仅是对NetflixEureka的一个封装,提供了一些SpringBoot的注解,让NetflixEureka更易于使用。本章,我们就来看看,SpringCloud是如何将NetflixEureka整合到springboot技术栈中的。本章主要分为两部分:Eureka-Server注解式启动、Eureka-Client注解式启动。
Eureka-Server集群是不区分主从节点的,所有节点都是对等的。当Eureka-Client向任意Eureka-Server发起注册、下线等请求时,Eureka-Server会将操作复制到集群中其它的Eureka-Server,以实现数据的最终一致性。Eureka-Server集群同步的整体流程如下:Eureka-Server启动时,解析配置文件中的其它server的url地址,构造一个个PeerEurekaNode,PeerEurekaNode就代表了一个Eureka-Server;启动一个定时任务,默认每隔10分钟,基于配置文件中的url来刷新Eureka-Server列表,即Pee
当Eureka-Server节点在短时间内丢失过多客户端时(可能发生了网络分区故障),那么这个节点就会进入自我保护模式。一旦进入该模式,Eureka-Server就会保护注册表中的信息,不再剔除注册表中的应用实例,也不接受新实例的注册。那么,Eureka-Server是*如何判断“短时间内丢失过多客户端”*呢?这里涉及两个核心概念:renewsLastMin:上一分钟所有实例的实际心跳次数,Eureka-Server会在内存中进行统计;expectedNumberOfRenewsPerMin:每分钟所有实例的期望最小心跳次数,通过总实例数乘以一个百分比(通过参数eureka.renewalPe
本章,我将讲解Eureka的应用实例剔除(eviction)机制。那么什么情况下会会发生剔除呢?正常情况下,应用实例下线时,会主动向Eureka-Server发起下线(cancel)请求。但应用实例有些时候会异常崩溃,或者机器发生宕机,此时就没有办法主动下线了。由于Eureka-Server是靠心跳来感知Eureka-Client存在的,所以一旦某个Client应用实例挂掉后,就不会再发送心跳了,那么Eureka-Server在一段时间内没有接收到心跳,就会把对应的应用实例剔除(eviction)。Eureka的服务剔除机制的源码本身并不难理解,最核心的是它的补偿时间机制和Lease过期判断,
本章,我将讲解Eureka的应用实例下线(cancel)机制。应用实例关闭时,Eureka-Client会向Eureka-Server发起下线(Cancel)应用实例的HTTP/DELETE请求。需要满足如下条件才可发起cancel请求:配置eureka.registration.enabled=true,即应用实例开启注册开关。默认为false。配置eureka.shouldUnregisterOnShutdown=true,即应用实例开启关闭时下线开关。默认为true。一、Eureka-Client发起下线Eureka-Client的shutdown()方法用来发起服务下线请求,这个方法需
本章,我将讲解Eureka的心跳(renew)机制。通过前面章节,我们已经知道Eureka-Client向Eureka-Server注册应用实例成功后,会获得租约(Lease)。所以,Eureka-Client向Eureka-Server发送心跳,其实就是进行续租(LeaseRenewal),避免租约过期,这样才能让Eureka-Server知道自己还活着。默认情况下,租约有效期为90秒,心跳(续租)频率为30秒。两者比例为1:3,也就是说,在网络异常等情况下,有三次重试机会。一、Eureka-Client发起续租Eureka-Client发起心跳(续租)的整体流程如下:DiscoveryCl
上一章,我详细讲解了Eureka-Client全量拉取注册表的机制和原理。本章,我将讲解增量拉取注册表的原理,整体流程我用下面这张图表示。本章,读者应当重点掌握增量数据保存的设计思路,以及数据同步的Hash比对机制。一、Eureka-Client拉取流程1.1定时调度任务DiscoveryClient在构造时,会启动一个定时调度任务,默认每隔30秒发送一次请求到Eureka-Server,拉取增量的注册表信息:DiscoveryClient(ApplicationInfoManagerapplicationInfoManager,EurekaClientConfigconfig,Abstrac
Eureka-Client完成自身的注册之后,接着我们就要来看Eureka-Client拉取注册表的逻辑了。Eureka-Client拉取注册表分为两种模式:全量拉取和增量拉取。默认配置下,Eureka-Client启动时,首先执行一次全量拉取注册表信息,然后在本地缓存,之后每30秒增量拉取,并跟本地缓存进行合并。本章,我将讲解全量拉取注册表的逻辑,整体流程我用下面这张时序图表示。本章,读者应当重点掌握Eureka-Server端的注册表多级缓存机制。一、Eureka-Client拉取流程1.1DiscoveryClient初始化DiscoveryClient在初始化时,会自动执行注册表的全量
上一章,我们讲解了客户端(Eureka-Client)发起注册的流程,先来回顾下整个流程:Eureka-Client内部有一个组件——InstanceInfoReplicator,它会定时调用EurekaClient.register()方法;最终调用了底层通讯组件EurekaHttpClient,发送一个http/json请求,调用Eureka-Server的一个restful接口完成注册。本章,我们就来看看服务端(Eureka-Server)接受注册的流程。Eureka-Server接受注册的核心过程,我用下面这张时序图表示:一、Lease租约应用实例注册的过程中,涉及了大量与租约(Lea
从本章开始,我们正式进入Eureka的服务注册流程的学习。Eureka服务注册,我将分两部分来讲解:客户端(Eureka-Client)发起注册流程和服务端(Eureka-Server)接受注册流程。Eureka-Client发起注册的核心过程,我用下面这张时序图表示:注意:在Eureka源码工程目录下,有一个eureka-examples模块,里面包含了很多使用示例,读者可以先去阅读下ExampleEurekaClient和ExampleEurekaService这两个示例:示例比较简单,我这里就不赘述了,本章主要讲解Eureka-Client发起注册的流程。一、发起注册流程1.1注册条件E
EurekaServerContext,代表了当前这个Eureka-Server的服务上下文,包含了服务需要的所有东西。可以这么说,整个Eureka-Server的初始化过程,最终的目的其实就是构建这个服务上下文:serverContext=newDefaultEurekaServerContext(eurekaServerConfig,serverCodecs,registry,peerEurekaNodes,applicationInfoManager);//将EurekaServerContext保存到EurekaServerContextHolder中,方便使用EurekaServer
既然Eureka-Server支持集群部署,那么在启动过程中必然涉及对集群的一些操作,所以Eureka抽象出一个PeerEurekaNodes的概念,这就代表了整个Eureka-Server集群节点集合。在Eureka-Server的启动过程中,会创建一个PeerEurekaNodes对象:PeerEurekaNodespeerEurekaNodes=getPeerEurekaNodes(registry,eurekaServerConfig,eurekaClient.getEurekaClientConfig(),serverCodecs,applicationInfoManager);本章
我们继续看Eureka-Server的启动流程,在完成了EurekaClient的构造和初始化后,EurekaBootStrap还会创建一个PeerAwareInstanceRegistry对象:PeerAwareInstanceRegistryregistry;if(isAws(applicationInfoManager.getInfo())){//忽略AWS相关...}else{registry=newPeerAwareInstanceRegistryImpl(eurekaServerConfig,eurekaClient.getEurekaClientConfig(),serverCo