Spring Cloud 五:Eureka自我保护,健康检查,事件监听使用

一,Eureka元数据

1,从EurekaServer获取

启动EurekaServier,启动EurekaClient注册到EurekaServer

访问http://euk-server1:7001/eureka/apps/EurekaClient 获取到EurekaClient实例信息:

<application>
<name>EUREKACLIENT</name>
<instance>
<instanceId>192.168.1.39:EurekaClient:7004</instanceId>
<hostName>euk-client1</hostName>
<app>EUREKACLIENT</app>
<ipAddr>192.168.1.39</ipAddr>
<status>UP</status>
<overriddenstatus>UNKNOWN</overriddenstatus>
<port enabled="true">7004</port>
<securePort enabled="false">443</securePort>
<countryId>1</countryId>
<dataCenterInfo class="com.netflix.appinfo.InstanceInfo$DefaultDataCenterInfo">
<name>MyOwn</name>
</dataCenterInfo>
<leaseInfo>
<renewalIntervalInSecs>30</renewalIntervalInSecs>
<durationInSecs>90</durationInSecs>
<registrationTimestamp>1605853910599</registrationTimestamp>
<lastRenewalTimestamp>1605872603029</lastRenewalTimestamp>
<evictionTimestamp>0</evictionTimestamp>
<serviceUpTimestamp>1605853910599</serviceUpTimestamp>
</leaseInfo>
<metadata>
<management.port>7004</management.port>
</metadata>
<homePageUrl>http://euk-client1:7004/</homePageUrl>
<statusPageUrl>http://euk-client1:7004/actuator/info</statusPageUrl>
<healthCheckUrl>http://euk-client1:7004/actuator/health</healthCheckUrl>
<vipAddress>EurekaClient</vipAddress>
<secureVipAddress>EurekaClient</secureVipAddress>
<isCoordinatingDiscoveryServer>false</isCoordinatingDiscoveryServer>
<lastUpdatedTimestamp>1605853910599</lastUpdatedTimestamp>
<lastDirtyTimestamp>1605853910549</lastDirtyTimestamp>
<actionType>ADDED</actionType>
</instance>
</application>

2,手写获取元数据

在EurekaClient中新建HelloController

@RestController
public class HelloController {
    
    
    @Autowired
    private EurekaDiscoveryClient eurekaDiscoveryClient;

    @RequestMapping("/getInstance")
    public List<ServiceInstance> getInstance(String clientName) {
    
    
        List<ServiceInstance> instances = eurekaDiscoveryClient.getInstances(clientName);
        return instances;
    }

    @RequestMapping("/hello")
    public String hello(){
    
    
        return "hello";
    }
}

请求访问:

http://euk-client1:7004/getInstance?clientName=EurekaClient

输出(表示EurekaClient在EurekaService中的实例信息):

[{
    
    
	"metadata": {
    
    
		"management.port": "7004"
	},
	"secure": false,
	"uri": "http://euk-client1:7004",
	"serviceId": "EUREKACLIENT",
	"instanceId": "192.168.1.39:EurekaClient:7004",
	"instanceInfo": {
    
    
		"instanceId": "192.168.1.39:EurekaClient:7004",
		"app": "EUREKACLIENT",
		"appGroupName": null,
		"ipAddr": "192.168.1.39",
		"sid": "na",
		"homePageUrl": "http://euk-client1:7004/",
		"statusPageUrl": "http://euk-client1:7004/actuator/info",
		"healthCheckUrl": "http://euk-client1:7004/actuator/health",
		"secureHealthCheckUrl": null,
		"vipAddress": "EurekaClient",
		"secureVipAddress": "EurekaClient",
		"countryId": 1,
		"dataCenterInfo": {
    
    
			"@class": "com.netflix.appinfo.InstanceInfo$DefaultDataCenterInfo",
			"name": "MyOwn"
		},
		"hostName": "euk-client1",
		"status": "UP",
		"overriddenStatus": "UNKNOWN",
		"leaseInfo": {
    
    
			"renewalIntervalInSecs": 30,
			"durationInSecs": 90,
			"registrationTimestamp": 1605873533416,
			"lastRenewalTimestamp": 1605873533416,
			"evictionTimestamp": 0,
			"serviceUpTimestamp": 1605873533416
		},
		"isCoordinatingDiscoveryServer": false,
		"metadata": {
    
    
			"management.port": "7004"
		},
		"lastUpdatedTimestamp": 1605873533416,
		"lastDirtyTimestamp": 1605873533392,
		"actionType": "ADDED",
		"asgName": null
	},
	"scheme": "http",
	"host": "euk-client1",
	"port": 7004
}]

3,自定义元数据

标准元数据:主机名,ip,端口,健康检查等信息。会被发布到注册表中,用于服务间调用

自定义元数据:远程客户端访问自定义属性。

eureka.instance.metadata-map:
  自定义key:自定义value

application.yaml

spring:
  application:
    name: EurekaClient
server:
  port: 7004
eureka:
  instance:
    hostname: euk-client1
    metadata-map: 
      bobo: 爱学习
  client:
    service-url:
      defaultZone: http://euk-server1:7001/eureka/

3-1:访问EurekaServer获取自己定义的元数据信息:

http://euk-server1:7001/eureka/apps/EurekaClient
<application>
<name>EUREKACLIENT</name>
<instance>
<instanceId>192.168.1.39:EurekaClient:7004</instanceId>
<hostName>euk-client1</hostName>
<app>EUREKACLIENT</app>
<ipAddr>192.168.1.39</ipAddr>
<status>UP</status>
<overriddenstatus>UNKNOWN</overriddenstatus>
<port enabled="true">7004</port>
<securePort enabled="false">443</securePort>
<countryId>1</countryId>
<dataCenterInfo class="com.netflix.appinfo.InstanceInfo$DefaultDataCenterInfo">
<name>MyOwn</name>
</dataCenterInfo>
<leaseInfo>
<renewalIntervalInSecs>30</renewalIntervalInSecs>
<durationInSecs>90</durationInSecs>
<registrationTimestamp>1605874332212</registrationTimestamp>
<lastRenewalTimestamp>1605874452194</lastRenewalTimestamp>
<evictionTimestamp>0</evictionTimestamp>
<serviceUpTimestamp>1605874332212</serviceUpTimestamp>
</leaseInfo>
<metadata>
<bobo>爱学习</bobo>
<management.port>7004</management.port>
</metadata>
<homePageUrl>http://euk-client1:7004/</homePageUrl>
<statusPageUrl>http://euk-client1:7004/actuator/info</statusPageUrl>
<healthCheckUrl>http://euk-client1:7004/actuator/health</healthCheckUrl>
<vipAddress>EurekaClient</vipAddress>
<secureVipAddress>EurekaClient</secureVipAddress>
<isCoordinatingDiscoveryServer>false</isCoordinatingDiscoveryServer>
<lastUpdatedTimestamp>1605874332212</lastUpdatedTimestamp>
<lastDirtyTimestamp>1605874332191</lastDirtyTimestamp>
<actionType>ADDED</actionType>
</instance>
</application>

3-2:通过EurekaClient2来获取EurekaClint1的元数据信息

@RestController
public class HelloController {
    
    

    @Autowired
    private EurekaDiscoveryClient eurekaDiscoveryClient;

    @RequestMapping("/meta-data")
    public Map<String, String> getMetaDataInfo(String applicationName) {
    
    
        Map<String, String> result = new HashMap<>();
        List<ServiceInstance> instances = eurekaDiscoveryClient.getInstances(applicationName);
        for (ServiceInstance instance : instances) {
    
    
            Map<String, String> metadata = instance.getMetadata();
            for (String s : metadata.keySet()) {
    
    
                result.put(s, metadata.get(s));
            }
        }
        return result;
    }
}

访问:

http://euk-client2:7005/meta-data?applicationName=EurekaClient

输出:

{
    
    "bobo":"爱学习","management.port":"7005"}

二,Eureka自我保护

默认情况下,Eureka Server在一定时间内,没有接收到某个微服务心跳,会将某个微服务注销(90S)。但是当网络故障时,微服务与Server之间无法正常通信,上述行为就非常危险,因为微服务正常,不应该注销。

扫描二维码关注公众号,回复: 12321543 查看本文章

Eureka Server通过自我保护模式来解决整个问题,当Server在短时间内丢失过多客户端时,那么Server会进入自我保护模式,会保护注册表中的微服务不被注销掉。当网络故障恢复后,退出自我保护模式。

思想:宁可保留健康的和不健康的,也不盲目注销任何健康的服务。

关闭自我保护:

eureka:
  server: 
    enable-self-preservation: false

自我保护机制的触发条件:

当每分钟心跳次数( renewsLastMin ) 小于 numberOfRenewsPerMinThreshold 时,并且开启自动保护模式开关( eureka.server.enable-self-preservation = true ) 时,触发自我保护机制,不再自动过期租约。

numberOfRenewsPerMinThreshold = expectedNumberOfRenewsPerMin * 续租百分比( eureka.server.renewalPercentThreshold, 默认0.85 )
expectedNumberOfRenewsPerMin = 当前注册的应用实例数 x 2

为什么乘以 2:
默认情况下,注册的应用实例每半分钟续租一次,那么一分钟心跳两次,因此 x 2 。

服务实例数:10个,期望每分钟续约数:10 * 2=20,期望阈值:20*0.85=17,自我保护少于17时 触发。

三,多网卡选择

1,ip注册

eureka:
  instance:
    prefer-ip-address: true
表示将自己的ip注册到EurekaServer上。不配置或false,表示将操作系统的hostname注册到server

2,服务器有多个网卡,eh0,eh1,eh2,只有eh0可以让外部其他服务访问进来,而Eureka client将eh1和eh2注册到Eureka server上,这样其他服务就无法访问该微服务了。

3,指定ip

eureka:
  instance:
    prefer-ip-address: true
    ip-address: 实际能访问到的Ip

如果设置了此时的ip-address,在元数据查看到就是此ip,其他服务也通过此ip来调用。

四,Eureka健康检查

由于server和client通过心跳保持 服务状态,而只有状态为UP的服务才能被访问。看eureka界面中的status。

比如心跳一直正常,服务一直UP,但是此服务DB连不上了,无法正常提供服务。

此时,我们需要将 微服务的健康状态也同步到server。只需要启动eureka的健康检查就行。这样微服务就会将自己的健康状态同步到eureka。配置如下即可。

在client端配置:将自己的健康状态传播到server。

eureka:
  client:
    healthcheck:
      enabled: true

五,Eureka配置

​ EurekaServerConfigBean:Eureka Server配置。

​ EurekaInstanceConfigBean:Eureka Client实例配置。

​ EurekaClientConfigBean:Eureka Client 客户端和服务端交互配置。

eureka:
  # EurekaServerConfigBean
  server: 
  	#关闭自我保护
    enable-self-preservation: false
    #清理服务间隔时间,毫秒
    eviction-interval-timer-in-ms: 5000
    
  # EurekaClientConfigBean
  client:
    healthcheck:
      #开启健康检查,需要引入actuator
      enabled: true
      
  # EurekaInstanceConfigBean
  instance: 
    #发送心跳给server的频率,每隔这个时间会主动心跳一次
    lease-renewal-interval-in-seconds: 1      
    #Server从收到client后,下一次收到心跳的间隔时间。超过这个时间没有接收到心跳EurekaServer就会将这个实例剔除
    lease-expiration-duration-in-seconds: 1   
client:
eureka: 

  

六,Eureka监听事件

EurekaInstanceCanceledEvent 服务下线事件

EurekaInstanceRegisteredEvent 服务注册事件

EurekaInstanceRenewedEvent 服务续约事件

EurekaRegistryAvailableEvent 注册中心可用事件

EurekaServerStartedEvent 注册中心启动

如在服务端监听EurekaInstanceRegisteredEvent 服务注册事件,那么当有服务注册过来时会收到事件:

@Component
public class CustomEvent {
    
    
    @EventListener
    public void listen(EurekaInstanceRegisteredEvent e){
    
    
        System.out.println(e.getInstanceInfo().getInstanceId()+"-------------->上线了");
    }
}

七,Eureka缺陷

由于集群间的同步复制是通过HTTP的方式进行,基于网络的不可靠性,集群中的Eureka Server间的注册表信息难免存在不同步的时间节点,不满足CAP中的C(数据一致性)。

猜你喜欢

转载自blog.csdn.net/u013277209/article/details/109864918