一,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之间无法正常通信,上述行为就非常危险,因为微服务正常,不应该注销。
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(数据一致性)。