1、简述spring
spring cloud三步走,一导包,二依赖,三配置为咱们简化了太多东西,以致于不少东西知其然不知其因此然,了解底层实现以后对于一些问题咱们也能够快速的定位问题所在。缓存
spring cloud不少东西都是基于注解实现的,最开始接触的很迷,怎么一个注解就能够搞定这么多事情,那些配置是怎么加载到spring容器的?springboot
了解springboot的都会知道在jar包里面通常都会都有一个spring.factories的配置文件,里面配置了不少配置类得路径,这里就是加载相关配置类得入口。网络
其次就是针对springcloud里面注解,通常来讲在某个注解同级目录里面都会有xxxxxxxAutoConfiguration这样的配置类,里面会去初始化相关的bean,好比在EnableEurekaServer注解的同级目录就有EurekaServerAutoConfiguration这个玩意儿,而EurekaServerAutoConfiguration这个玩意儿就是配置在spring.factories里面的架构
2、、Eureka架构图及描述app
1.服务注册(register):Eureka Client会经过发送REST请求的方式向Eureka Server注册本身的服务,提供自身的元数据,好比ip地址、端口、运行情况指标的url、主页地址等信息。Eureka Server接收到注册请求后,就会把这些元数据信息存储在一个双层的Map中。
2.服务续约(renew):在服务注册后,Eureka Client会维护一个心跳来持续通知Eureka Server,说明服务一直处于可用状态,防止被剔除。Eureka Client在默认的状况下会每隔30秒(eureka.instance.leaseRenewallIntervalInSeconds)发送一次心跳来进行服务续约。
3.服务同步(replicate):Eureka Server之间会互相进行注册,构建Eureka Server集群,不一样Eureka Server之间会进行服务同步,用来保证服务信息的一致性。
4.获取服务(get registry):服务消费者(Eureka Client)在启动的时候,会发送一个REST请求给Eureka Server,获取上面注册的服务清单,而且缓存在Eureka Client本地,默认缓存30秒(eureka.client.registryFetchIntervalSeconds)。同时,为了性能虑,Eureka Server也会维护一份只读的服务清单缓存,该缓存每隔30秒更新一次。
5.服务调用:服务消费者在获取到服务清单后,就能够根据清单中的服务列表信息,查找到其余服务的地址,从而进行远程调用。Eureka有Region和Zone的概念,一个Region能够包含多个Zone,在进行服务调用时,优先访问处于同一个Zone中的服务提供者。
6.服务下线(cancel):当Eureka Client须要关闭或重启时,就不但愿在这个时间段内再有请求进来,因此,就须要提早先发送REST请求给Eureka Server,告诉Eureka Server本身要下线了,Eureka Server在收到请求后,就会把该服务状态置为下线(DOWN),并把该下线事件传播出去。
7.服务剔除(evict):有时候,服务实例可能会由于网络故障等缘由致使不能提供服务,而此时该实例也没有发送请求给Eureka Server来进行服务下线,因此,还须要有服务剔除的机制。Eureka Server在启动的时候会建立一个定时任务,每隔一段时间(默认60秒),从当前服务清单中把超时没有续约(默认90秒,eureka.instance.leaseExpirationDurationInSeconds)的服务剔除。
8.自我保护:既然Eureka Server会定时剔除超时没有续约的服务,那就有可能出现一种场景,网络一段时间内发生了异常,全部的服务都没可以进行续约,Eureka Server就把全部的服务都剔除了,这样显然不太合理。因此,就有了自我保护机制,当短期内,统计续约失败的比例,若是达到必定阈值,则会触发自我保护的机制,在该机制下,Eureka Server不会剔除任何的微服务,等到正常后,再退出自我保护机制。自我保护开关(eureka.server.enable-self-preservation: false)ide
3、EurekaServer源码流程梳理图微服务
首先推荐一个在线画图工具https://www.processon.com,按照流程图里面的类和方法去和源码对号入座。
工具
4、服务端注册接口和注册列表获取接口(2019.05.03补充)
性能
多级缓存设计思想:尽量保证了内存注册表数据不会出现频繁的读写冲突问题,进一步保证对Eureka Server的大量请求,都是快速从纯内存走,性能极高
1.在拉取注册表的时候:
首先从ReadOnlyCacheMap里查缓存的注册表。
若没有,就找ReadWriteCacheMap里缓存的注册表。
若是尚未,就从内存中获取实际的注册表数据。
2.在注册表发生变动的时候:
会在内存中更新变动的注册表数据,同时过时掉ReadWriteCacheMap。
此过程不会影响ReadOnlyCacheMap提供人家查询注册表。
默认每30秒Eureka Server会将ReadWriteCacheMap更新到
ReadOnlyCacheMap里
默认每180秒Eureka Server会将ReadWriteCacheMap里是数据失效
下次有服务拉取注册表,又会从内存中获取最新的数据了,同时填充 各级缓存。
存在的问题:
1.当咱们eureka服务实例有注册或下线或有实例发生故障,内存注册表虽然会及时更新数据,可是客户端不必定能及时感知到,可能会过30秒才能感知到,由于客户端拉取注册表实例这里面有一个多级缓存机制
2.服务剔除的不是默认90秒没心跳的实例,剔除的是180秒没心跳的实例(eureka的bug致使)
/** * Renew the lease, use renewal duration if it was specified by the * associated {@link T} during registration, otherwise default duration is * {@link #DEFAULT_DURATION_IN_SECS}. */ public void renew() { lastUpdateTimestamp = System.currentTimeMillis() + duration; }
加了两次duration值,com.netflix.eureka.lease.Lease#isExpired(long)
/** * Checks if the lease of a given {@link com.netflix.appinfo.InstanceInfo} has expired or not. * * Note that due to renew() doing the 'wrong" thing and setting lastUpdateTimestamp to +duration more than * what it should be, the expiry will actually be 2 * duration. This is a minor bug and should only affect * instances that ungracefully shutdown. Due to possible wide ranging impact to existing usage, this will * not be fixed. * * @param additionalLeaseMs any additional lease time to add to the lease evaluation in ms. */ public boolean isExpired(long additionalLeaseMs) { return (evictionTimestamp > 0 || System.currentTimeMillis() > (lastUpdateTimestamp + duration + additionalLeaseMs)); }
流程图: