一、Eureka 的简单使用

一、Eureka 的简单使用

本文不是初学开始的,在有点基础上的是查漏补缺。

起言:服务治理概念

Spring Cloud 提供了多种组件发现的支持,例如 Eureka、Consul、Zookeeper等。

一个服务治理组件应该具有以下三个功能:

服务注册表

服务治理组件的核心,它用来记录各个微服务的信息,比如说微服务的名称、IP、端口等。服务注册组件提供查询 API 和管理 API,查询 API 用来查询可用的微服务实例,管理 API用于服务的注册和注销。

服务注册与发现

  • 服务注册是指微服务在启动时,将自己的信息注册到服务治理组件上的过程。
  • 服务发现是指查询可用微服务列表及其网络地址的机制。

服务检查

服务治理组件使用一定机制定时检测已注册的服务,是否在线,或者是否无法连接等,若发现无法访问,就会从服务注册表中移除该实例,进行下线操作。

一、What's Eureka

Eureka Netflix 开源的服务发现组件,本身是一个基于 REST 的服务。它包含 Server 和 Client 两部分。Spring Cloud 将它继承自了子项目 Spring Cloud Netflix 中。以下六点内容取自周立的《Spring Cloud 与 Docker 微服务架构与实战》第二版,对 Eureka的一些特性描述得还不错,先来看看:

  • Eureka Server提供了服务发现的能力,微服务启动时,会向 Eureka 发送自己的信息(ip、port、微服务名称等),Eureka Server 会将这些信息存储起来;
  • Eureka Client 是一个 Java 客户端,用于简化与 Eureka 的交互。只需要几行配置文件、注解就可以实现注册到 Eureka上;
  • 微服务启动后,会周期性(默认30 s)向 Eureka Server 发送心跳以续约自己的“租期”;
  • 如果 Eureka Server 在一定的时间内没有收到某个微服务实例的心跳, Eureka Server 将注销该实例(默认为90 s);
  • 默认情况下,Eureka Server 同时也是 Eureka Client。多个 Eureka Server 实例相互之间通过复制的方式来实现服务注册表中数据的同步;
  • Eureka Client 会缓存服务注册表中的信息。这种方式有一定的优势——首先,不需要每次都请求查询 Eureka Server,从而降低了 Eureka Server的压力;其次,即使 Eureka Server 所有节点都宕掉,服务消费者依然可以使用缓存中的信息找到服务提供者并完成调用。

综上所述:Eureka 通过心跳检测机制、客户端缓存机制,提高了系统的灵活性,可伸缩性和可用性。

二、How to use Eureka

2.1 Maven 依赖

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>

注意:E 版本 之前(包括E版本)是引入spring-cloud-starter-eureka-server

2.2 关于配置文件(重要)

我在本地新建了一个Spring Boot 工程,在 appication.yml里面配置如下:

# server参数
server:
  port: 8761
  tomcat:
    uri-encoding: utf-8

# spring 参数
spring:
  application:
    name: pro-eureka

# Eureka 参数
eureka:
  instance:
    # 实例的主机名称
    hostname: localhost
  client:
    # 不要向注册中心 Eureka 注册它自己
    register-with-eureka: false
    # 是否从 Eureka Server 获取注册信息,默认为 true,当前是单点的 Eureka Server,不需要同步其他节点的数据,所以false
    fetch-registry: false
    service-url:
      # 指定服务注册中心地址,这里指向了本服务,假如多个地址,直接使用逗号分隔
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/

2.3 主类配置

然后在主类上添加@EnableEurekaServer注解。这样子就可以简单启动一个 Eureka 了。

需要注意的是,最后的defaultZone参数不写时,默认就是http://localhost:8761/eureka

三、微服务注册

3.1 Maven 依赖

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

3.2 配置文件(重要)

server:
  port: 9001
  tomcat:
    uri-encoding: UTF-8

spring:
  application:
    name: pro-product

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka
  instance:
    # 启用ip配置,如果不配置该属性或将该属性配置成 false,则表示注册微服务所在操作系统的 hostname 到 Eureka Server
    prefer-ip-address: true
    # 实例名称  最后呈现地址:ip:2000
    instance-id: ${spring.cloud.client.ip-address}:${server.port}

最终在 Eureka 界面看到的将是:

3.3 主类配置

在主类上添加 @EnableEurekaClient注解即可。

package com.kjgym.product;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

/**
 * 注意这里也可使用 @EnableEurekaClient
 * 但由于 spring cloud 是灵活的,注册中心支持 eureka、consul、zookeeper等
 * 若写了具体的注册中心注解,则当替换成其他注册中心时,又需要替换成对应的注解了。
 * 所以 直接使用 @EnableDiscoveryClient 启动发现。
 * 这样在替换注册中心时,只需要替换相关依赖即可。
 * @author kangjia
 */
@SpringBootApplication
@EnableDiscoveryClient
public class ProductApplication {

    public static void main(String[] args) {
        SpringApplication.run(ProductApplication.class, args);
    }

}

注意:

  1. Spring Cloud Edgware 以及更高的版本中,只需要添加相关依赖,即可实现自动注册。
  2. 如果不想将服务注册到 Eureka Server ,可以设置 spring.cloud.service-registry.auto-registration.enabled=false 或者是直接在主类上添加 @EnableDiscoveryClient(autoRegister = false)

四、Eureka 的自我保护机制

当出现以下文字:

默认情况下,如果Eureka Server在一定时间内没有接收到某个微服务实例的心跳,Eureka Server将会注销该实例(默认90秒)。但是当网络分区故障发生时,微服务与Eureka Server之间无法正常通信,这就可能变得非常危险了,因为微服务本身是健康的,此时本不应该注销这个微服务。

Eureka Server通过“自我保护模式”来解决这个问题,当Eureka Server节点在短时间内丢失过多客户端时(可能发生了网络分区故障),那么这个节点就会进入自我保护模式。一旦进入该模式,Eureka Server就会保护服务注册表中的信息,不再删除服务注册表中的数据(也就是不会注销任何微服务)。当网络故障恢复后,该Eureka Server节点会自动退出自我保护模式。

自我保护模式是一种对网络异常的安全保护措施。使用自我保护模式,而让Eureka集群更加的健壮、稳定。

开发阶段可以通过配置:eureka.server.enable-self-preservation=false关闭自我保护模式。

生产阶段,理应以默认值进行配置。

五、给 Eureka 一个用户认证

5.1 Maven 依赖

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-security</artifactId>
</dependency>

5.2 配置文件

# server参数
server:
  port: 8761
  tomcat:
    uri-encoding: utf-8

# spring 参数
spring:
  application:
    name: pro-eureka
  security:
    user:
      password: 123456
      name: kangjia

# Eureka 参数
eureka:
  instance:
    hostname: localhost
  client:
    # 不要向 Eureka 注册它自己
    register-with-eureka: false
    # 不去检索其他的服务,因为注册中心本身职责就是维护服务实例,它不需要去检索其它服务
    fetch-registry: false
    service-url:
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/

5.3 Java 代码

package com.kjgym.peureka;

import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

/**
 * 
 * @author kangjia
 */
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().ignoringAntMatchers("/eureka/**");
        super.configure(http);
    }
}

注意:

Spring Cloud Finchley及更高版本必须添加这一段,在Edgware以及更早的版本中无需这一步骤。

5.3 启动项目

浏览器输入 http://localhost:8761,则自动跳转到如下页面:

输入上文 在配置文件里配置的用户名和密码,即可登录。

注意:

不设置这段内容,账号默认是user密码是一个随机值,该值会在启动时打印出来

5.4 向带认证 Eureka 注册客户端

客户端的配置要改成 defaultZone: http://kangjia:123456@localhost:8761/eureka/,否则注册不了。

六、Eureka 元数据

官网译文:值得花费一些时间来了解Eureka元数据的工作原理,因此您可以在平台上使用有意义的方式使用它。有用于信息的标准元数据,例如主机名,IP地址,端口号,状态页和运行状况检查。这些将发布在服务注册表中,并由客户端用于以直接方式联系服务。可以将其他元数据添加到中的实例注册中eureka.instance.metadataMap,并且可以在远程客户端中访问此元数据。通常,除非让客户端知道元数据的含义,否则其他元数据不会更改客户端的行为。在本文档后面将介绍几种特殊情况,其中Spring Cloud已经为元数据映射分配了含义。

6.1 实例:在上文的 Eureka Client 配置文件中修改:

server:
  port: 9001
  tomcat:
    uri-encoding: UTF-8

spring:
  application:
    name: pro-product

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka
  instance:
    # 启用ip配置 这样在注册中心列表中看见的是以ip+端口呈现的
    prefer-ip-address: true
    # 实例名称  最后呈现地址:ip:2000
    instance-id: ${spring.cloud.client.ip-address}:${server.port}
    metadata-map:
      myData: 我是可怜的自定数据

新建 DemoController.java:

server:
  port: 9001
  tomcat:
    uri-encoding: UTF-8

spring:
  application:
    name: pro-product

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka
  instance:
    # 启用ip配置 这样在注册中心列表中看见的是以ip+端口呈现的
    prefer-ip-address: true
    # 实例名称  最后呈现地址:ip:2000
    instance-id: ${spring.cloud.client.ip-address}:${server.port}
    metadata-map:
      myData: 我是可怜的自定数据

6.2 新建一个 Java 类:

package com.kjgym.product;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

/**
 * @author kangjia@xxx.com
 * @date 2019/12/16 17:33
 */
@RestController
public class TestController {

    @Autowired
    DiscoveryClient discoveryClient;

    @GetMapping("/hello")
    public List<ServiceInstance> sayHello() {
        return discoveryClient.getInstances("pro-product");
    }
}

6.3 启动项目,在浏览器访问 http://localhost:9001/hello

[
  {
    "host": "10.0.8.194",
    "port": 9001,
    "metadata": {
      "management.port": "9001",
      "myData": "我是可怜的自定数据"
    },
    "secure": false,
    "uri": "http://10.0.8.194:9001",
    "serviceId": "PRO-PRODUCT",
    "instanceId": "10.0.8.194:9001",
    "instanceInfo": {
      "instanceId": "10.0.8.194:9001",
      "app": "PRO-PRODUCT",
      "appGroupName": null,
      "ipAddr": "10.0.8.194",
      "sid": "na",
      "homePageUrl": "http://10.0.8.194:9001/",
      "statusPageUrl": "http://10.0.8.194:9001/actuator/info",
      "healthCheckUrl": "http://10.0.8.194:9001/actuator/health",
      "secureHealthCheckUrl": null,
      "vipAddress": "pro-product",
      "secureVipAddress": "pro-product",
      "countryId": 1,
      "dataCenterInfo": {
        "@class": "com.netflix.appinfo.InstanceInfo$DefaultDataCenterInfo",
        "name": "MyOwn"
      },
      "hostName": "10.0.8.194",
      "status": "UP",
      "overriddenStatus": "UNKNOWN",
      "leaseInfo": {
        "renewalIntervalInSecs": 30,
        "durationInSecs": 90,
        "registrationTimestamp": 1576564038125,
        "lastRenewalTimestamp": 1576564188072,
        "evictionTimestamp": 0,
        "serviceUpTimestamp": 1576564038126
      },
      "isCoordinatingDiscoveryServer": false,
      "metadata": {
        "management.port": "9001",
        "myData": "我是可怜的自定数据"
      },
      "lastUpdatedTimestamp": 1576564038126,
      "lastDirtyTimestamp": 1576564038063,
      "actionType": "ADDED",
      "asgName": null
    },
    "scheme": null
  }
]

可以看到,自定义的数据也出现在了结果 JSON 里。

七、Eureka 的 REST 接口

八、排除 Jersey 依赖

默认情况下,EurekaClient使用Jersey进行HTTP通信。如果希望避免来自Jersey的依赖关系,可以将其从依赖关系中排除。Spring Cloud基于Spring自动配置传输客户端RestTemplate。以下示例显示排除了Jersey:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    <exclusions>
        <exclusion>
            <groupId>com.sun.jersey</groupId>
            <artifactId>jersey-client</artifactId>
        </exclusion>
        <exclusion>
            <groupId>com.sun.jersey</groupId>
            <artifactId>jersey-core</artifactId>
        </exclusion>
        <exclusion>
            <groupId>com.sun.jersey.contribs</groupId>
            <artifactId>jersey-apache-client4</artifactId>
        </exclusion>
    </exclusions>
</dependency>

九、为什么注册服务这么慢

成为实例还涉及到注册表的周期性心跳(通过客户端serviceUrl),默认持续时间为30秒。直到实例,服务器和客户端在其本地缓存中都具有相同的元数据后,客户端才能发现该服务(因此可能需要3个心跳)。您可以通过设置更改周期eureka.instance.leaseRenewalIntervalInSeconds。将其设置为小于30的值可加快使客户端连接到其他服务的过程。在生产中,最好使用默认值,因为服务器中的内部计算对租约续订期进行了假设。

原文地址:https://www.cnblogs.com/kjgym/p/12054961.html