zoukankan      html  css  js  c++  java
  • 一、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的值可加快使客户端连接到其他服务的过程。在生产中,最好使用默认值,因为服务器中的内部计算对租约续订期进行了假设。

  • 相关阅读:
    C# 创建线程
    离最近发表时间代码
    ORA12154: TNS: 无法解析指定的连接标识符
    SQL和LINQ按年月、按类型显示文章篇数
    对象的序列化和反序列化
    父类与子类间的隐藏与重写
    C# 进程启动与关闭
    猫叫老鼠跑的事件例子
    第十八章 12判断string类型字符串是否为空 简单
    第十八章 11 string字符串的比较 简单
  • 原文地址:https://www.cnblogs.com/kjgym/p/12054961.html
Copyright © 2011-2022 走看看