Eureka服务注册、发现、集群


Eureka服务注册、发现、集群

1、什么是Eureka

  • Eureka:怎么读?
  • Netflix在设计Eureka时,遵循的就是AP原则
  • Eureka是Netflix的一个子模块,也是核心模块之一。Eureka是一个基于REST的服务,用于定位服务,以实现云端中间层服务发现和故障转移,服务注册与发现对于微服务来说是非常重要的,有了服务发现与注册,只需要使用服务的标识符,就可以访问到服务,而不需要修改服务调用的配置文件了,功能类似于Dubbo的注册中心,比如Zookeeper

2、原理讲解

  • Eureka的基本架构

    • SpringCloud封装了NetFlix公司开发的Eureka模块来实现服务注册和发现(对比Zookeeper)
    • Eureka采用了C-S的架构设计,EurekaServer作为服务注册功能的服务器,他是服务注册中心
    • 而系统中的其他微服务。使用Eureka的客户端连接到EurekaServer并维持心跳连接。这样系统的维护人员就可以通过EurekaServer来监控系统中各个微服务是否正常运行,SpringCloud的一些其他模块(比如Zuul)就可以通过EurekaServer来发现系统中的其他微服务,并执行相关的逻辑;
  • Eureka包含两个组件: Eureka ServerEureka Client。

  • Eureka Server提供服务注册服务,各个节点启动后,会在EurekaServer中进行注册,这样Eureka Server中的服务注册表中将会村粗所有可用服务节点的信息,服务节点的信息可以在界面中直观的看到。

  • Eureka Client是一个Java客户端,用于简化EurekaServer的交互,客户端同时也具备一个内置的,使用轮询负载算法的负载均衡器。在应用启动后,将会向EurekaServer发送心跳(默认周期为30秒)。如果Eureka Server在多个心跳周期内没有接收到某个节点的心跳,EurekaServer将会从服务注册表中把这个服务节点移除掉(默认周期为90秒)

  • 三大角色

    • Eureka Server:提供服务的注册于发现。
    • Service Provider:将自身服务注册到Eureka中,从而使消费方能够找到。
    • Service Consumer:服务消费方从Eureka中获取注册服务列表,从而找到消费服务。

3、环境搭建

1、导入依赖

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>springcloud</artifactId>
        <groupId>com.allen</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>springcloud-eureka-7001</artifactId>

    <dependencies>
        <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-eureka-server -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka-server</artifactId>
            <version>1.4.6.RELEASE</version>
        </dependency>

        <!--        热部署-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
        </dependency>
    </dependencies>

</project>

2、编写配置文件

application.yml

server:
  port: 7002

# eureka配置

eureka:
  instance:
    hostname: localhost # eureka服务端的实例名称
  client:
    register-with-eureka: false # 表示是否向注册中心注册自己
    fetch-registry: false # false表示自己为注册中心
    service-url:  # 监控访问地址
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/

3、开启这个功能

@EnableEurekaServer

4、配置类

package com.allen.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

/**
 * @author Allen
 * @date 2021/1/8 14:49
 */

@SpringBootApplication
@EnableEurekaServer
public class EurekaServer_7001 {

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

5、测试

在浏览器地址栏输入: http://localhost:7002/ , 出现如下界面

监控界面

注:若遇到无法启动的情况,可通过降级 springbootspringcloud 的版本依赖解决。

附:dubbo监控界面
dubbo监控界面

服务注册

1、导入依赖

首先在 8001 提供者端口,导入 Eureka 依赖

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>springcloud</artifactId>
        <groupId>com.allen</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>springcloud-provider-dept-8001</artifactId>

    <dependencies>
        <!--我们需要在此模块用到另一个模块的实体类,需要导入-->
        <dependency>
            <groupId>com.allen</groupId>
            <artifactId>springcloud-api</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
        </dependency>

        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
        </dependency>

        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.4</version>
        </dependency>

        <!--        test-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-test</artifactId>
        </dependency>

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

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

        <!--        热部署-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-eureka -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
            <version>1.4.6.RELEASE</version>
        </dependency>

    </dependencies>

</project>

2、编写配置文件

在 8001的 application.yml, 编写 eureka 配置

server:
  port: 8001

# mybatis配置
mybatis:
  type-aliases-package: com.allen.springcloud.pojo
  config-location: classpath:mybatis/mybatis-config.xml
  mapper-locations: classpath:mybatis/mapper/*.xml

# spring配置
spring:
  application:
    name: springcloud-provider-dept
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource  #数据源
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/db01?useUnicode=true&characterEncoding=utf-8&useSSL=false
    username: root
    password: 1005

# eureka配置, 服务注册到哪里
eureka:
  client:
    service-url:
      defaultZone: http://localhost:7002/eureka/

3、开启这个功能

在8001提供者启动类中开启Eureka: @EnableEurekaClient

package com.allen.springcloud;

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

/**
 * @author Allen
 * @date 2021/1/7 19:39
 */
//启动类
@SpringBootApplication
@EnableEurekaClient //在启动服务后,自动注册到Eureka中
public class DeptProvider_8001 {

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

4、测试

首先启动 7002 注册中心服务,然后启动 8001 提供者服务

信息配置

1、导入依赖

在 8001 服务端口,导入 spring-boot-starter-actuator

        <!--actuator完善监控信息-->
        <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-actuator -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
            <version>2.4.1</version>
        </dependency>

2、配置info

在 8001 服务的配置文件中,编写

# info配置
info:
  app.name: allen-springcloud
  company.name: hlgao666

3、测试

点击下图任意一个链接,

可看到输出如下信息:

自我保护机制

上图中红色字体即自我保护机制警告!

一句话总结: 某时刻某一个微服务不可以用了,eureka不会立刻清理,依旧会对该微服务的信息进行保存!

  • 默认情况下,如果EurekaServer在一定时间内没有接收到某个微服务实例的心跳,EurekaServe一一实例(默认90秒)。但是当网络分区故障发生时,微服务与EureKa之间无法止吊通,以得竹力制应能决这常危险了–因为微服务本身其实是健康的,此时本不应该注销这个服务。Eureka通过自我保护机制解决–当EurekaServer节点在短时间内丢失过多客户端时(可能反生网络分区故障)那么这个节点就会进入自我保护模式。一旦进入该模式,EureKaServVer就会保护服务注册节点的信息,不再删除服务注册表中的数据(也就是不会注销任何微服务)。当网络故障恢复后,该EurekaServer节点会自动退出自我保护模式。
  • 在自我保护模式中,EurekaServer会保护服务注册表中的信息,不再注销任何服务实例。当它收到的心跳数重新恢复到阈值以上时,该EurekaServer节点就会自动退出自我保护模式, 即宁可保留错误的服务注册信息,也不盲目注销任何可能健康的服务实例。一句话:好死不如赖活着
  • 综上,自我保护模式是一种应对网络异常的安全保护措施。它的架构哲学是宁可同时保留所有微服务(健康的微服务和不健康的微服务都会保留),也不盲目注销任何健康的微服务。使用自我保护模式,可以让Eureka
    集群更加的健壮和稳定
  • 在SpringCloud中,可以使用eureka.server.enable-self-preservation = false禁用自我保护模式【不推荐关闭自我保护机制】

服务发现

1、修改 8001 服务的 controller

package com.allen.springcloud.deptController;

import com.allen.springcloud.pojo.Dept;
import com.allen.springcloud.service.DeptService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.*;

import java.util.List;

/**
 * @author Allen
 * @date 2021/1/7 19:30
 */

//提供Restful服务
@RestController
public class DeptController  {

    @Autowired
    private DeptService deptService;

    //获取一些配置的信息,得到具体的微服务
    @Autowired
    private DiscoveryClient client;

    @PostMapping("/dept/add")
    public boolean addDept(Dept dept){
        return deptService.addDept(dept);
    }

    @GetMapping("/dept/get/{id}")
    public Dept queryDeptById(@PathVariable("id") Long id){
        return deptService.queryDeptById(id);
    }

    @GetMapping("/dept/list")
    public List<Dept> queryAll(){
        return deptService.queryAll();
    }

    //注册进来的微服务,获取一些消息
    @GetMapping("/dept/discovery")
    public Object discovery(){
        //获取微服务列表清单
        List<String> services = client.getServices();
        System.out.println(services);

        //得到一个具体的微服务信息,通过微服务applicationName
        List<ServiceInstance> instances = client.getInstances("SPRINGCLOUD-PROVIDER-DEPT");
        for (ServiceInstance instance : instances) {
            System.out.println(instance);
        }
        return this.client;
    }
}

2、开启注解 @EnableDiscoveryClient 服务发现

package com.allen.springcloud;

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;

/**
 * @author Allen
 * @date 2021/1/7 19:39
 */
//启动类
@SpringBootApplication
@EnableEurekaClient //在启动服务后,自动注册到Eureka中
@EnableDiscoveryClient  //服务发现
public class DeptProvider_8001 {

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

3、测试

重新 build 8001 服务,访问 http://localhost:8001/dept/discovery

弹出如下界面:

集群

为防止一个服务中心故障,需要开启多个服务中心,每个服务中心关联另外的服务中心。

1、修改服务端实例名称(模拟多个服务中心)

修改服务端实例名称

2、编写3个服务端,直接从7001拷贝

包括 application.yml、pom.xml、启动类

3、修改 application.yml

7002 application.yml

server:
  port: 7002

# eureka配置

eureka:
  instance:
    hostname: eureka7002.com # eureka服务端的实例名称
  client:
    register-with-eureka: false # 表示是否向注册中心注册自己
    fetch-registry: false # false表示自己为注册中心
    service-url:  # 监控访问地址
      # 单机: http://${eureka.instance.hostname}:${server.port}
      # 集群:(关联)
      defaultZone: http://eureka7003.com:7003, http://eureka7004.com:7004

7003 application.yml

server:
  port: 7003

# eureka配置

eureka:
  instance:
    hostname: eureka7003.com # eureka服务端的实例名称
  client:
    register-with-eureka: false # 表示是否向注册中心注册自己
    fetch-registry: false # false表示自己为注册中心
    service-url:  # 监控访问地址
      defaultZone: http://eureka7002.com:7002, http://eureka7004.com:7004

7004 application.yml

server:
  port: 7004

# eureka配置

eureka:
  instance:
    hostname: eureka7004.com # eureka服务端的实例名称
  client:
    register-with-eureka: false # 表示是否向注册中心注册自己
    fetch-registry: false # false表示自己为注册中心
    service-url:  # 监控访问地址
      defaultZone: http://eureka7002.com:7002, http://eureka7003.com:7003

8001 application.yml

defaultZone: 关联3个服务中心

server:
  port: 8001

# mybatis配置
mybatis:
  type-aliases-package: com.allen.springcloud.pojo
  config-location: classpath:mybatis/mybatis-config.xml
  mapper-locations: classpath:mybatis/mapper/*.xml

# spring配置
spring:
  application:
    name: springcloud-provider-dept
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource  #数据源
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/db01?useUnicode=true&characterEncoding=utf-8&useSSL=false
    username: root
    password: 1005

# eureka配置, 服务注册到哪里
eureka:
  client:
    service-url:
      defaultZone: http://eureka7002.com:7002/eureka/, http://eureka7003.com:7003/eureka/, http://eureka7004.com:7004/eureka/
  instance:
    instance-id: springcloud-provider-dept8001 #修改Eureka的默认描述信息

# info配置
info:
  app.name: allen-springcloud
  company.name: hlgao666

4、测试

依次开启7002、7003、7004、8001服务,访问 7002 端口

7002界面

点击上图的 eureka7004.com,跳转后界面如图

访问7004

依次再访问 http://eureka7002.com:7002/http://eureka7003.com:7003/ 时,是看不到服务的注册,虽然这3个注册中心构成了一个集群,但是只有当一个垮了之后,才会去访问下一个集群节点。 Eureka Client 在发送注册请求时,会按照 Eureka Server 集群节点 serviceUrlList 顺序逐个去尝试,如果有一个请求成功了,那么直接返回response ,不再去向其他节点请求。

在本例中服务注册请求在 eureka7004 中注册成功,即 eureka7004 对应的 Eureka Server服务的状态是UP,则不会向另外两个节点(eureka7002,eureka7003)发送请求,相应地页面上也就没有显示。一旦停止 eureka7004 服务注册中心,则 dept-8001 服务会向 eureka7002 发送注册请求。

可参考client重试机制: https://blog.csdn.net/qq_36960211/article/details/85273392


文章作者: Hailong Gao
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Hailong Gao !
评论
  目录