【Eureka运行原理及优化】

分布式服务发现 概念

“当一头牛拉不动车的时候,不要试图寻找一头更强壮的牛,而是用两头牛来拉车”

分布式系统是:由多个应用程序协同来完成任务的一种工作模式系统。

服务发现解决的问题

解耦、屏蔽程序之间IP及端口依赖

分布式系统中,程序之间通过一次或者多次远程调用或者数据传输完成任务。

调用程序我们首先需要知道被调用的程序在网络中的位置,在网络中地位程序的位置通过IP+端口号。但是这种方式存在两个问题:

  • IP地址没有任务特殊含义,不容易记忆和理解;

  • 当被调用的程序IP和端口号改变,调用者也需要同步修改地址;

通过服务发现,可以将程序之间对于IP+端口号的依赖转化为服务名的依赖,服务名可以根据业务功能等进行命名。

动态管理服务状态

在分布式系统中,我们说程序或者服务有可能宕掉(磁盘可能损坏、线程可能全部被占用,网络可能不稳定)。服务发现可以对服务的状态进行管理,当程序状态发生改变,可以第一时间通知程序的调用者,可以从两方面理解:

1、程序之间需要彼此知道对方的信息与状态;

2、对方程序状态发生改变能及时知晓;

Eureka是如何设计服务发现

注册中心

服务发现要做的是抽象程序标识达到解耦、屏蔽IP+端口号依赖以及程序状态的实时管理,要进行管理,首先会想到集权、集中、统一、设置机构等等,Eureka也是如此,要管理服务程序,首先要有一个统一的管理中心–注册中心。

基本概念

将注册中心作为服务发现中的管理者

Eureka也对管理者与非管理者进行了区分,负责管理的-注册中心(服务端),负责干活的程序(客户端),对应EurekaServer和EurekaClient

基本运行流程

客户端发起服务注册
服务端保存注册信息到注册表
客户端定时发生心跳检测
服务端服务剔除及自我保护
客户端发起服务下线
客户端或者服务端注册信息到本地内存
客户端整合服务发现

image-20211104232454812

1、客户端发起服务注册

客户端向服务端发生请求,将自身相关的信息提交给服务端。Eureka服务端提供一个接口,用来接收客户端服务注册的请求,服务端会一直监听这个接口,等待客户端调用。

客户端在启动时首先找到服务端以及自身的信息(分区、服务名称、IP、端口等),调用服务端提供的服务注册接口,将自身的信息发送过去。

配置信息: 可能在客户端的配置文件中,可能在配置中心统一配置。

2、服务端保存注册信息

服务端保存客户端请求发送的服务注册信息到本地内存注册表(注册表是服务发现的核心,基本所有的操作都是围绕注册表进行操作,注册表的添加、获取、更新、删除、同步等一系列操作。)

Eureka的注册表是一个双字典结构的数据,服务发现的目的是标识服务和服务状态的管理,所以注册表中有服务标识、服务基本信息、服务状态信息等

img

ConcurrentHashMap<String, Map<String, Lease<InstanceInfo>>> registry = new ConcurrentHashMap();
3、客户端定时发送心跳检测

客户端定时向服务端发送请求,告诉服务端自己运行正常

服务续约: 客户端只是在启动时注册服务信息,后续运行过程服务端不知道客户端是否运行正常,就无法对程序状态进行实时的管理。因此客户端定时不断的向服务端发送请求,告诉服务端自己运行正常。

具体实现,服务端提供一个续约接口,客户端通过定时任务不断的调用续约接口,服务端收到请求后,更新注册表中服务续约时间

img

4、服务端服务剔除和自我保护
  • **服务剔除:**如果服务端在一段时间,默认(90s)没有收到客户端心跳请求,服务端任务客户端挂掉了,就会从注册表中移除给客户端信息

有时候由于网络原因,客户端与服务端无法进行正常通信,但是客户端仍然运行正常,可以进行相互的访问,如果按照续约,那么所有的客户端就会从注册表中被移除,这样影响了那些正常运行的客户端

  • **自我保护:**服务端判断在15分钟内,有超过85%的客户端都没有进行服务续约,则进入自我保护;

进入自我保护机制,服务端不在剔除没有续约的客户端;

进入自我保护机制,服务端只接收新客户端的注册和服务查询;

假设如果总共有1000个服务 ,此时有3个服务因为网络抖动导致Eureka-Server收不到心跳,这会是非常正常的现象,但是我们的Eureka不能因为网络抖动把这三个收不到心跳的服务踢掉 。但是如果不开启自我保护机制这三个就会踢掉了。

5、客户端发送服务下线请求

客户端正常关闭,向服务端发送服务下线请求,服务会直接从注册表移除该客户端

6、客户端定时获取注册表信息

客户端定时向服务端发送请求,获取注册表信息,保存到本地内存。

在设计中,客户端本地也有一个注册表,还有一个定时器,定时从服务端更新注册表信息,保存到客户端本地内存

7、客户端整合服务发现

客户端消费者从本地注册表中获取客户方生产者服务信息,并进行后续的操作。

Eureka如何保证高可用和一致性

Eureka支持集群部署,不同区域、机房部署多个服务端实例,这样可以横向扩展服务发现的规模,当有一个服务端挂掉,其他服务端仍然可以正常运行,保证系统的高可用性,但是集群多个节点部署,必须要考虑的一个问题,就是数据一致性。

CAP理论

C(一致性):所有的节点上的数据时刻保持同步
A(可用性):每个请求都能接受到一个响应,无论响应成功或失败
P(分区容错):系统应该能持续提供服务,即使系统内部有消息丢失(分区)

image-20211031002129471

ReadOnlyCacheMap和ReadWriteCacheMap之间的数据同步

  • 由于我们取获取服务时,默认从readOnlyCacheMap中读取,由于readWriteCacheMap每隔30s才同步到readOnlyCacheMap,数据不是强一致性的,所以这是Eureka只实现了AP,没有实现C的原因。

    image-20211031105133609

从其他节点获取注册表,所以不保证节点间的状态一定是强一致,只能保证最终一致

集群同步,集群并没有扩大Eureka并没有扩大它的承受能力,只是实现了可用性。
在什么情况下会同步数据?我们从以下几个节点分析。

注册:第一个节点注册进来,只同步下一个节点。
续约:有新服务续约,自动同步到其他Eureka-Server。
下线:一直同步所有集群。
剔除:不同步,每个Server都有自己的剔除机制。

服务端数据同步

Peer To Peer同步模式

分布式系统中数据同步模式一般分为两种:主从模式、对等模式。

主从模式:集群中有一个主副本和多个从副本,主副本负责数据的写操作,然后将数据同步到其他从副本,从副本负责读操作。该模式主副本面临所有的写操作压力,可能会成为瓶颈,但是可以保证一致性。

对待模式:在集群中不存在主从副本,任何一个节点都可以进行读写操作,然后节点之间进行相互数据同步,优点是没有单点的写操作压力,缺点是进行数据同步和数据冲突是一个需要解决的问题。

Eureka中集群节点进行数据同步

img

Eureka分区

region:可以理解为地理上的分区,例如亚洲分区、华北地区等等,地区没有具体大小限制,根据实际情况合理划分。

zone:可以理解为region下的具体分区(机房),例如北京分区下有两个机房,可以划分出两个区域zone1、zone2.

通过分区管理,可以实现不同区域不同机房的服务进行就近调用,降低延迟。

一些配置

  • **客户端心跳发送时间间隔(eureka.instance.lease-renewal-interval-in-seconds):**默认30s

  • 客户端服务续约时间eureka.instance.lease-expiration-duration-in-seconds): 默认90s。当客户端最后一次发送心跳后,在该服务续约时间内如果没有再向服务端发送心跳链接,则服务器端可以对该服务进行剔除操作。 (客户端配置)

  • **服务端的服务剔除时间间隔(eureka.server.eviction-interval-timer-in-ms):**默认60 * 1000(60s )。在server服务端会定期的将没有心跳的服务剔除。 (服务端配置)

  • 阈值更新时间间隔renewalPercentThreshold) : eureka-server此次单位时间内收到的心跳总数 / 上次单位时间内收到的心跳总数(系统默认配置的因子值为0.85)的间隔时间**,默认为15分钟**。

  • 获取注册信息的时间间隔(eureka.client.registry-fetchI-interval-seconds ): 从eureka服务器注册表中获取注册信息的时间间隔(s),默认为30秒

  • 什么时候开启自我保护机制:Eureka Server有个阈值,当此次单位时间内收到的心跳总数 / 上次单位时间内收到的心跳总数小于阈值,就会触发自我保护机制,Eureka就认为本台EurekaServer节点可能网络出现故障,当做自身问题处理,不会去剔除客户端服务信息。(当然也存在可能真的是Eureka客户端服务节点真的都挂了,调用将会出现失败情况)

优化

服务测算

  • Eureka Server作为一个微服务注册中心,每秒钟要被请求多少次?一天要被请求多少次?

    ​ 比如有100个服务,每个服务部署20个实例。就是2000个实例。一个Eureka Client组件,它会每隔30秒请求一次Eureka Server,拉取变化的注册表。此外,每个服务实例上的Eureka Client都会每隔30秒发送一次心跳请求给Eureka Server。一个实例默认30秒发一次心跳,30秒拉取一次注册表。那Service每分钟接收到的请求量就是。2000 * 2 * 2 = 8000次。那一天能承受的量就是 8000 * 60 * 24 = 1152 w次请求,每天1000多万的访问量。

定时器Timer的优化

Eureka源码用了大量的Timer定时任务,由于Timer定时器存在以下缺陷:

  • Timer的缺陷:
    Timer在执行所有定时任务时只会创建一个线程,当存在多个任务时,其任务是串行执行的。由于Timer只会创建一个线程,那么在TimerTask抛出了一个未检出的异常,那么Timer线程就会被终止掉,导致其它任务都停止。Timer执行周期任务时依赖系统时间,如果当前系统时间发生变化会出现一些执行上的变化。
  • 建议使用ScheduledExecutorService

Eureka服务优化点

1、Eureka服务的快速下线

Eureka Server在启动时会创建一个定时任务,每隔一段时间(默认60秒),从当前服务清单中把超时没有续约(默认90秒)的服务剔除。我们可以把服务剔除这个定时任务间隔的时间设置得短一点,做到快速下线。防止拉取到不可用的服务。

eureka:  
	server:     
		eviction-interval-timer-in-ms: 1000 //比如1s
2、缓存优化

Eureka Server为了避免同时读写内存数据结构造成的并发冲突问题,采用了3级缓存机制来进一步提升服务请求的响应速度。

拉取注册表的步骤是:

首先从ReadOnlyCacheMap里查缓存的注册表。

若没有,就找ReadWriteCacheMap里缓存的注册表。

如果还没有,就从内存中registry中获取实际的注册表数据。

当新的服务注册,先更新注册表registry中的数据和ReadWriteCacheMap里缓存的数据,默认30s后把ReadWriteCacheMap里面的数据更新到ReadOnlyCacheMap

为了提高服务被发现的速度。我们可以做一些设置。

拉取服务的时候,不从ReadOnlyCacheMap里查,直接从ReadWriteCacheMap取。

eureka: 
	server:
		use-read-only-response-cache: false    # 关闭从ReadOnlyCacheMap拉取数据。

缩短ReadWriteCacheMap向ReadOnlyCacheMap同步的时间间隔,默认30秒,我们可以优化到1秒,这个根据自己的情况而定。

eureka: 
	server:
    response-cache-update-interval-ms: 1000  # 减少readWrite 和 readOnly 同步时间间隔。
3、客户端拉取注册表更及时

客户端会定时到eureka-server拉取注册表。默认情况下每30秒拉取一次。可以根据实际情况设置拉取时间间隔。

eureka:  
	client:   
		fetch-registry: true  
    registry-fetch-interval-seconds: 3   # 拉取注册表信息间隔时间
4、url顺序的打乱

我们在生产中配置eureka.client.service-url.defaultZone的时候,各个client端的配置尽量要随机一下,即打乱一下defaultZone中url的顺序。

原因:

在拉取注册表的时候,默认从第一个url开始拉取,拉取不到才从下一个拉取,并且最多只能拉取3个

在注册的时候,只会注册到第一个url,然后同步到后面的url,所以我们打乱了顺序以后,就减少了对某一个server的依赖,也降低了对某一个server的请求次数。

5、client心跳频率

默认情况下,client每隔30秒就会向服务端发送一次心跳。这个时间也可以适当调小一点。

eureka: 
	instance:   
  	lease-renewal-interval-in-seconds: 30   # 每间隔30s,向服务端发送一次心跳。 
6、服务端剔除客户端的时间间隔

默认情况下,server在90s之内没有收到client心跳,将服务踢出掉。为了让服务快速响应,可以适当地把这个时间改的小一点。

eureka: 
	instance:   
  	lease-expiration-duration-in-seconds: 90
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值