01:服务注册与发现+配置中心-Nacos+Eureka

一:Eureka

1.1:Eureka简介

Eureka是基于REST(Representational State Transfer)服务,主要以AWS云服务为支撑,提供服务发现并实现负载均衡和故障转移。我们称此服务为Eureka服务。

Eureka提供了Java客户端组件,Eureka Client,方便与服务端的交互。客户端内置了基于round-robin实现的简单负载均衡。

在Netflix,为Eureka提供更为复杂的负载均衡方案进行封装,以实现高可用,它包括基于流量、资源利用率以及请求返回状态的加权负载均衡。

Eureka包含两个组件:Eureka Server和Eureka Client

1.1.1:Eureka Server提供服务注册服务

各个微服务节点通过配置启动后,会在EurekaServer中进行注册,这样EurekaServer中的服务注册表中将会存储所有可用服务节点的信息,服务节点的信息可以在界面中直观看到。

1.1.2:EurekaClient通过注册中心进行访问

是一个Java客户端,用于简化Eureka Server的交互,客户端同时也具备一个内置的、使用轮询(round-robin)负载算法的负载均衡器。在应用启动后,将会向Eureka Server发送心跳(默认周期为30秒)。

如果Eureka Server在多个心跳周期内没有接收到某个节点的心跳,EurekaServer将会从服务注册表中把这个服务节点移除(默认90秒)

1.2:Eureka架构

1.3:Eureka中的一些概念

1.3.1:Register :服务注册

Eureka客户端向Eureka Server注册时,它提供自身的元数据,比如IP地址、端口等

1.3.2:Renew:服务续约

Eureka客户端会每隔30秒发送一次心跳来续约。通过续约来告知Eureka Server该客户端仍然存在。

1.3.3:Fetch Registries:获取注册列表信息

Eureka客户端从服务器获取注册表信息,将其缓存到本地。客户端会使用该信息查找其他服务,从而进行远程调用。该注册列表信息定期(每30秒)更新一次。

1.3.4:Cancel:服务下线

Eureka客户端在程序关闭时向Eureka服务器发送取消请求。

1.3.5:Eviction:服务剔除

在默认情况下,当Eureka客户端90秒没有向Eureka服务器发送续约,Eureka服务器就会将该服务实例从服务注册列表删除。

1.3.6:自我保护

Eureka会定时剔除没有续约的服务,那就可能会出现一种极端情况,网络发生了异常,所有的服务都没有续约,那么EurekaServer就会剔除掉所有的服务,这显然不合理,于是就有了自我保护机制,当短时间内(15min)如果续约失败的比例达到了设置的阈值(85%),就会触发自我保护机制,该机制下,EurekaServer不会剔除服务,等到正常后再退出自我保护机制。自我保护开关(eureka.server.enable-self-preservation=true)。

除了以上的特性外,Eureka的缓存机制也非常经典,下面详细介绍一下。

1.3.7:Eureka Server 数据存储

Eureka Server 的数据存储分了两层:数据存储层和缓存层。

数据存储层 记录注册到 Eureka Server 上的服务信息,缓存层是经过包装后的数据,可以直接在 Eureka Client 调用时返回。

Eureka Server 的数据存储层是双层的 ConcurrentHashMap

第一层的 ConcurrentHashMap 的 key=spring.application.name 也就是客户端实例注册的应用名;value 为嵌套的 ConcurrentHashMap。

第二层嵌套的 ConcurrentHashMap 的 key=instanceId 也就是服务的唯一实例 ID,value 为 Lease 对象,Lease 对象存储着这个实例的所有注册信息,包括 ip 、端口、属性等。

Eureka Server 缓存机制

Eureka Server 为了提供响应效率,提供了两层的缓存结构,将 Eureka Client 所需要的注册信息,直接存储在缓存结构中。

第一层缓存:readOnlyCacheMap,本质上是 ConcurrentHashMap,依赖定时从readWriteCacheMap 同步数据,默认时间为 30 秒。

readOnlyCacheMap : 是一个 CurrentHashMap 只读缓存,这个主要是为了供客户端获取注册信息时使用,其缓存更新,依赖于定时器的更新,通过和 readWriteCacheMap 的值做对比,如果数据不一致,则以 readWriteCacheMap 的数据为准。

第二层缓存:readWriteCacheMap,本质上是 Guava 缓存。

readWriteCacheMap 的数据主要同步于存储层。当获取缓存时判断缓存中是否没有数据,如果不存在此数据,则通过 CacheLoader 的 load 方法去加载,加载成功之后将数据放入缓存,同时返回数据。

readWriteCacheMap 缓存过期时间,默认为 180 秒,当服务下线、过期、注册、状态变更,都会来清除此缓存中的数据。

Eureka Client 获取全量或者增量的数据时,会先从一级缓存中获取;如果一级缓存中不存在,再从二级缓存中获取;如果二级缓存也不存在,这时候先将存储层的数据同步到缓存中,再从缓存中获取。

1.4:Eureka Server常用配置

java 复制代码
#服务端开启自我保护模式
eureka.server.enable-self-preservation=true
#扫描失效服务的间隔时间(单位毫秒,默认是60*1000)即60秒
eureka.server.eviction-interval-timer-in-ms= 60000
#间隔多长时间,清除过期的 delta 数据
eureka.server.delta-retention-timer-interval-in-ms=0
#请求频率限制器
eureka.server.rate-limiter-burst-size=10
#是否开启请求频率限制器
eureka.server.rate-limiter-enabled=false
#请求频率的平均值
eureka.server.rate-limiter-full-fetch-average-rate=100
#是否对标准的client进行频率请求限制。如果是false,则只对非标准client进行限制
eureka.server.rate-limiter-throttle-standard-clients=false
#注册服务、拉去服务列表数据的请求频率的平均值
eureka.server.rate-limiter-registry-fetch-average-rate=500
#设置信任的client list
eureka.server.rate-limiter-privileged-clients=
#在设置的时间范围类,期望与client续约的百分比。
eureka.server.renewal-percent-threshold=0.85
#多长时间更新续约的阈值
eureka.server.renewal-threshold-update-interval-ms=0
#对于缓存的注册数据,多长时间过期
eureka.server.response-cache-auto-expiration-in-seconds=180
#多长时间更新一次缓存中的服务注册数据
eureka.server.response-cache-update-interval-ms=0
#缓存增量数据的时间,以便在检索的时候不丢失信息
eureka.server.retention-time-in-m-s-in-delta-queue=0
#当时间戳不一致的时候,是否进行同步
eureka.server.sync-when-timestamp-differs=true
#是否采用只读缓存策略,只读策略对于缓存的数据不会过期。
eureka.server.use-read-only-response-cache=true


################server node 与 node 之间关联的配置#####################33
#发送复制数据是否在request中,总是压缩
eureka.server.enable-replicated-request-compression=false
#指示群集节点之间的复制是否应批处理以提高网络效率。
eureka.server.batch-replication=false
#允许备份到备份池的最大复制事件数量。而这个备份池负责除状态更新的其他事件。可以根据内存大小,超时和复制流量,来设置此值得大小
eureka.server.max-elements-in-peer-replication-pool=10000
#允许备份到状态备份池的最大复制事件数量
eureka.server.max-elements-in-status-replication-pool=10000
#多个服务中心相互同步信息线程的最大空闲时间
eureka.server.max-idle-thread-age-in-minutes-for-peer-replication=15
#状态同步线程的最大空闲时间
eureka.server.max-idle-thread-in-minutes-age-for-status-replication=15
#服务注册中心各个instance相互复制数据的最大线程数量
eureka.server.max-threads-for-peer-replication=20
#服务注册中心各个instance相互复制状态数据的最大线程数量
eureka.server.max-threads-for-status-replication=1
#instance之间复制数据的通信时长
eureka.server.max-time-for-replication=30000
#正常的对等服务instance最小数量。-1表示服务中心为单节点。
eureka.server.min-available-instances-for-peer-replication=-1
#instance之间相互复制开启的最小线程数量
eureka.server.min-threads-for-peer-replication=5
#instance之间用于状态复制,开启的最小线程数量
eureka.server.min-threads-for-status-replication=1
#instance之间复制数据时可以重试的次数
eureka.server.number-of-replication-retries=5
#eureka节点间间隔多长时间更新一次数据。默认10分钟。
eureka.server.peer-eureka-nodes-update-interval-ms=600000
#eureka服务状态的相互更新的时间间隔。
eureka.server.peer-eureka-status-refresh-time-interval-ms=0
#eureka对等节点间连接超时时间
eureka.server.peer-node-connect-timeout-ms=200
#eureka对等节点连接后的空闲时间
eureka.server.peer-node-connection-idle-timeout-seconds=30
#节点间的读数据连接超时时间
eureka.server.peer-node-read-timeout-ms=200
#eureka server 节点间连接的总共最大数量
eureka.server.peer-node-total-connections=1000
#eureka server 节点间连接的单机最大数量
eureka.server.peer-node-total-connections-per-host=10
#在服务节点启动时,eureka尝试获取注册信息的次数
eureka.server.registry-sync-retries=
#在服务节点启动时,eureka多次尝试获取注册信息的间隔时间
eureka.server.registry-sync-retry-wait-ms=
#当eureka server启动的时候,不能从对等节点获取instance注册信息的情况,应等待多长时间。
eureka.server.wait-time-in-ms-when-sync-empty=0

1.5:Eureka Client 常用配置

java 复制代码
#该客户端是否可用
eureka.client.enabled=true
#实例是否在eureka服务器上注册自己的信息以供其他服务发现,默认为true
eureka.client.register-with-eureka=false
#此客户端是否获取eureka服务器注册表上的注册信息,默认为true
eureka.client.fetch-registry=false
#是否过滤掉,非UP的实例。默认为true
eureka.client.filter-only-up-instances=true
#与Eureka注册服务中心的通信zone和url地址
eureka.client.serviceUrl.defaultZone=http://${eureka.instance.hostname}:${server.port}/eureka/

#client连接Eureka服务端后的空闲等待时间,默认为30 秒
eureka.client.eureka-connection-idle-timeout-seconds=30
#client连接eureka服务端的连接超时时间,默认为5秒
eureka.client.eureka-server-connect-timeout-seconds=5
#client对服务端的读超时时长
eureka.client.eureka-server-read-timeout-seconds=8
#client连接all eureka服务端的总连接数,默认200
eureka.client.eureka-server-total-connections=200
#client连接eureka服务端的单机连接数量,默认50
eureka.client.eureka-server-total-connections-per-host=50
#执行程序指数回退刷新的相关属性,是重试延迟的最大倍数值,默认为10
eureka.client.cache-refresh-executor-exponential-back-off-bound=10
#执行程序缓存刷新线程池的大小,默认为5
eureka.client.cache-refresh-executor-thread-pool-size=2
#心跳执行程序回退相关的属性,是重试延迟的最大倍数值,默认为10
eureka.client.heartbeat-executor-exponential-back-off-bound=10
#心跳执行程序线程池的大小,默认为5
eureka.client.heartbeat-executor-thread-pool-size=5
# 询问Eureka服务url信息变化的频率(s),默认为300秒
eureka.client.eureka-service-url-poll-interval-seconds=300
#最初复制实例信息到eureka服务器所需的时间(s),默认为40秒
eureka.client.initial-instance-info-replication-interval-seconds=40
#间隔多长时间再次复制实例信息到eureka服务器,默认为30秒
eureka.client.instance-info-replication-interval-seconds=30
#从eureka服务器注册表中获取注册信息的时间间隔(s),默认为30秒
eureka.client.registry-fetch-interval-seconds=30

# 获取实例所在的地区。默认为us-east-1
eureka.client.region=us-east-1
#实例是否使用同一zone里的eureka服务器,默认为true,理想状态下,eureka客户端与服务端是在同一zone下
eureka.client.prefer-same-zone-eureka=true
# 获取实例所在的地区下可用性的区域列表,用逗号隔开。(AWS)
eureka.client.availability-zones.china=defaultZone,defaultZone1,defaultZone2
#eureka服务注册表信息里的以逗号隔开的地区名单,如果不这样返回这些地区名单,则客户端启动将会出错。默认为null
eureka.client.fetch-remote-regions-registry=
#服务器是否能够重定向客户端请求到备份服务器。 如果设置为false,服务器将直接处理请求,如果设置为true,它可能发送HTTP重定向到客户端。默认为false
eureka.client.allow-redirects=false
#客户端数据接收
eureka.client.client-data-accept=
#增量信息是否可以提供给客户端看,默认为false
eureka.client.disable-delta=false
#eureka服务器序列化/反序列化的信息中获取"_"符号的的替换字符串。默认为"__"
eureka.client.escape-char-replacement=__
#eureka服务器序列化/反序列化的信息中获取"$"符号的替换字符串。默认为"_-"
eureka.client.dollar-replacement="_-"
#当服务端支持压缩的情况下,是否支持从服务端获取的信息进行压缩。默认为true
eureka.client.g-zip-content=true
#是否记录eureka服务器和客户端之间在注册表的信息方面的差异,默认为false
eureka.client.log-delta-diff=false
# 如果设置为true,客户端的状态更新将会点播更新到远程服务器上,默认为true
eureka.client.on-demand-update-status-change=true
#此客户端只对一个单一的VIP注册表的信息感兴趣。默认为null
eureka.client.registry-refresh-single-vip-address=
#client是否在初始化阶段强行注册到服务中心,默认为false
eureka.client.should-enforce-registration-at-init=false
#client在shutdown的时候是否显示的注销服务从服务中心,默认为true
eureka.client.should-unregister-on-shutdown=true

1.6:Eureka Instance 常用配置

java 复制代码
#服务注册中心实例的主机名
eureka.instance.hostname=localhost
#注册在Eureka服务中的应用组名
eureka.instance.app-group-name=
#注册在的Eureka服务中的应用名称
eureka.instance.appname=
#该实例注册到服务中心的唯一ID
eureka.instance.instance-id=
#该实例的IP地址
eureka.instance.ip-address=
#该实例,相较于hostname是否优先使用IP
eureka.instance.prefer-ip-address=false

1.7:Eureka注册中心组成

Eureka属于AP架构,高可用。

1.8:EurekaServer端源码--流程图

1:找到eurekaserver jar包,spi机制,找到其中的sping.factories文件,找到server服务端自动装配的类EurekaServerAutoConfiguration

2:此配置类中会配置一些Bean

  • EurekaServerConfig---初始化eureka相关配置
  • EurekaController---初始化接口,获取eurekaServer信息
  • PeerAwareInstanceRegistry---初始化集群注册表
  • PeerEurekaNodes---初始化集群节点集合
  • EurekaServerContext---基于eurekaServer注册配置表,集群节点集合及初始化eurekaServer上下文
  • EurekaServerBootstrap---启动eureka服务
  • FilterRegistrationBean---初始化Jersey过滤器

3:此配置类中@Import注解的实现类EurekaServerInitializerConfiguration,实现了SmartLifecycle接口并且定义了isAutoStartup返回true,SmartLifecycle继承自Lifecycle,就会调用到Lifecycle的start方法

SmartLifecycle继承了Lifecycle,LifecycleProcessor继承了Lifecycle并且其中定义了onRefresh方法,在spring启动时刷新上下文时候就会调用到此方法。调用链路如下:

  • spring启动刷新上下文------this.finishRefresh();
  • LifecycleProcessor().onRefresh();
  • this.startBeans(true);
  • DefaultLifecycleProcessor.this.doStart
  • start
  • start方法中新起了一个线程,启动eureka服务
  • 初始化上下文------this.eurekaServerBootstrap.contextInitialized(this.servletContext);
  • 发布eureka注册有效事件------this.publish(new EurekaRegistryAvailableEvent(this.getEurekaServerConfig()));
  • 发布eureka服务启动成功事件------this.publish(new EurekaServerStartedEvent(this.getEurekaServerConfig()));
  • contextInitialized方法中
    • 初始化eureka环境------this.initEurekaEnvironment();
    • 初始化上下文------this.initEurekaServerContext();
  • 初始化上下文------this.initEurekaServerContext()中------服务同步replicate
    • 从相邻节点复制注册表------this.registry.syncUp();
    • 获取相邻节点注册的服务实例------Applications apps = this.eurekaClient.getApplications();
    • 注册到本地------this.register(instance, instance.getLeaseInfo().getDurationInSecs(), true);
  • 初始化上下文------this.initEurekaServerContext()中------服务剔除evict
    • registry.openForTraffic(this.applicationInfoManager, registryCount);
    • 修改服务实例状态为UP------applicationInfoManager.setInstanceStatus(InstanceStatus.UP);
    • 开启一个定时任务,每隔60s清理没有续约的任务------postInit();
    • 定时任务------
    java 复制代码
    this.evictionTimer.schedule((TimerTask)this.evictionTaskRef.get(), 
                                this.serverConfig.getEvictionIntervalTimerInMs(), 
                                this.serverConfig.getEvictionIntervalTimerInMs());
    • 定时任务run方法-----EvictionTask.run()------com.netflix.eureka.registry.AbstractInstanceRegistry.EvictionTask#run

1.9:EurekaClient端源码--流程图

1.9.1:如何开启服务注册进Eureka服务

EurekaClient的开启可以使用@EnableDiscoveryClient注解,也可以不使用这个注解,因为这个注解中的属性autoRegister默认为TRUE,如果我们不想某个服务注册进Eureka可以将这个属性设置为false(@EnableDiscoveryClient(autoRegister= false))

1.9.2:Client端流程

  • EurekaClientAutoConfiguration中注解@AutoConfigureAfter中含有一个类EurekaDiscoveryClientConfiguration,
  • 这个类中会注入一个bean-Marker。此Marker正是EurekaClientAutoConfiguration所需要的,只有这个bean存在springboot才会在启动的时候注册这个EurekaClientAutoConfiguration-Bean.
  • EurekaClientAutoConfiguration中配置了很多的Bean EurekaClientConfigBean------初始化EurekaClient相关配置

    EurekaInstanceConfigBean------client实例相关配置信息

    EurekaServiceRegistry------服务注册

    EurekaHealthIndicator------心跳检测

    EurekaClient

  • 其中EurekaClient很重要,EurekaClient是对DiscoveryClient包装。
  • DiscoveryClient的构造函数中会初始化各种任务,在initScheduledTasks中会初始化定时拉取服务注册信息更新本地注册表和服务续约任务;初始化定时服务注册任务。后续具体流程请查看流程图。

二:Nacos

2.1:安装并运行Nacos

2.2:服务注册中心对比

2.1.1:Nacos 支持AP和CP模式的切换

C是所有节点在同一时间看到的数据是一致的;而A的定义是所有的请求都会收到响应。

C:Consistency(强一致性)

A:Availability(可用性)

P:Partition tolerance(分区容错性)

CAP理论关注粒度是数据,而不是整体系统设计的策略

//-----------------------------------------------------------------------------------------------------

最多只能同时较好的满足两个。

CAP理论的核心是:一个分布式系统不可能同时很好的满足一致性,可用性和分区容错性这三个需求,

因此,根据 CAP 原理将 NoSQL 数据库分成了满足 CA 原则、满足 CP 原则和满足 AP 原则三 大类:

CA - 单点集群,满足一致性,可用性的系统,通常在可扩展性上不太强大。

CP - 满足一致性,分区容忍必的系统,通常性能不是特别高。

AP - 满足可用性,分区容忍性的系统,通常可能对一致性要求低一些。

2.1.2:何时选择使用何种模式?

一般来说,

如果不需要存储服务级别的信息且服务实例是通过nacos-client注册,并能够保持心跳上报,那么就可以选择AP模式。当前主流的服务如 Spring cloud 和 Dubbo 服务,都适用于AP模式,AP模式为了服务的可能性而减弱了一致性,因此AP模式下只支持注册临时实例。

如果需要在服务级别编辑或者存储配置信息,那么 CP 是必须,K8S服务和DNS服务则适用于CP模式。

CP模式下则支持注册持久化实例,此时则是以 Raft 协议为集群运行模式,该模式下注册实例之前必须先注册服务,如果服务不存在,则会返回错误。

相关推荐
欢迎来到祖安!5 小时前
企业微信 API 接口能力介绍:支持消息收发、图片发送、表情互动、联系人管理等多场景应用
java·前端·数据仓库·spring cloud·企业微信
行百里er19 小时前
BlockingQueue:异步批量上报
spring boot·spring cloud·监控
wno7042 天前
Spring Cloud Hystrix Dashboard仪表盘
spring·spring cloud·hystrix
BUG指挥官2 天前
Redis已接入AI
数据库·人工智能·spring boot·redis·spring cloud
wno7043 天前
Spring Cloud Hystrix服务容错
spring·spring cloud·hystrix
苏渡苇3 天前
Spring Insight 里上报 Span 为什么用 JDK HttpClient 而不是 RestTemplate
java·后端·spring·spring cloud·springboot·性能监控
YOU OU4 天前
Spring Cloud Consul
spring cloud·consul·java-consul
重生之我是Java开发战士4 天前
【Spring Cloud】Eureka服务注册发现与LoadBalancer负载均衡
spring cloud·eureka·负载均衡
谢亮_vipxieliang4 天前
ValidX vs Google Guava Preconditions:验证 vs 断言
java·spring boot·后端·spring cloud·hibernate·guava
夏天拐跑了西瓜5 天前
Spring Cloud 微服务实战(八):Hystrix熔断降级——从服务雪崩到断路器模式
spring cloud·hystrix·微服务