Spring Cloud(04)——Eureka的简介和部署使用

Spring Cloud(04)——Eureka的简介和部署使用

上一篇Spring Cloud(03)——构建支付模块和消费者订单模块以及工程重构中,我们搭建了一个简易的Rest服务,有RestFul API,服务提供者和服务消费者。下面来实现如何部署eureka注册中心!

1、Spring Cloud Eureka简介

  • Eureka 是 Netflix 微服务套件的一部分,基于 Netflix Eureka 做了二次封装,主要负责实现微服务架构中的服务治理功能。Eureka是Netflix中的一个开源框架,所以它可以利用Netfilix中其他的组件,如zull等。

  • Eureka 是一个基于 REST 的服务,并且提供了基于 Java 的客户端组件,能够非常方便地将服务注册到Eureka 中进行统一管理。

  • 服务治理是微服务架构中必不可少的一部分,阿里开源的 Dubbo 框架(Dubbo 中也有几种注册中心,基于 Zookeeper、基于 Redis等,不过用得最多的还是 Zookeeper 方式)就是针对服务治理的。服务治理必须要有一个注册中心,除了用 Eureka 作为注册中心外,我们还可以使用 Consul、Etcd、Zookeeper 等来作为服务的注册中心。

Eureka包含两个组件:Eureka Server和Eureka Client。

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

  • Eureka Client是一个java客户端,用于简化与Eureka Server的交互,客户端同时也就是一个内置的、使用轮询(round-robin)负载算法的负载均衡器。Eureka client可再分为Service ProviderService Consumer

    • Service Provider 服务提供方,将自身服务注册到Eureka,从而使服务消费方能够找到
  • Service Consumer服务消费方,从Eureka获取注册服务列表,从而能够消费服务

  • 在应用启动后,使用Eureka Client连接到Eureka Server并维持心跳连接,默认周期为30秒,如果Eureka Server在多个心跳周期内没有接收到某个节点的心跳,Eureka Server将会从服务注册表中把这个服务节点移除(默认90秒)。

  • Eureka Server之间通过复制的方式完成数据的同步,Eureka还提供了客户端缓存机制,即使所有的Eureka Server都挂掉,客户端依然可以利用缓存中的信息消费其他服务的API。综上,Eureka通过心跳检查、客户端缓存等机制,确保了系统的高可用性、灵活性和可伸缩性。

    以上摘自百度百科

2、Eureka和Zookeeper比较

在分布式系统领域有个著名的 CAP 定理:

  • C:Consistency ,一致性。
  • A: Availability,可用性。
  • P:Partition tolerance,网络分区容错。类似多机房部署,保证服务稳定性。

这三个特性在任何分布式系统中都不能同时满足,最多同时满足两个。

Eureka和Zookeeper的区别:

  • Zookeeper是CP,分布式协同服务,突出一致性。对ZooKeeper的的每次请求都能得到一致的数据结果,但是无法保证每次访问服务可用性。如请求到来时,zookeer正在做leader选举,此时不能提供服务,即不满足A可用性。

  • Euere是AP,高可用与可伸缩的Service发现服务,突出可用性。相对于Zookeeper而言,可能返回数据没有一致性,但是保证能够返回数据,服务是可用的。即不满足C一致性。

3、部署Eureka Server服务端

1、创建子模块 cloud-eureka-server7001

2、导入依赖

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

        <dependency>
            <groupId>com.cheng.springcloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>${project.version}</version>
        </dependency>

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

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>

              <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

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

3、编写配置文件

server:
  port: 7001

eureka:
  instance:
    hostname: localhost  # Eureka服务端实例名称
  client:
    register-with-eureka: false  # 由于该应用为注册中心, 所以设置为false, 代表不向注册中心注册自己
    fetch-registry: false # fetch-registry为false,表示我是一个注册中心,我的职责就是维护服务实例,并不需要去检索服务
    service-url:
    #设置与Eureka Server交互的地址,以后服务注册和查询都需要依赖这个地址
      defaultZone: http//${eureka.instance.hostname}:${server.port}/eureka/

4、编写主启动类

@SpringBootApplication
@EnableEurekaServer 
public class EurekaMain7001 {
    public static void main(String[] args) {
        SpringApplication.run(EurekaMain7001.class,args);
    }
}

5、测试

启动程序,访问请求http://localhost:7001/进行测试:

在这里插入图片描述

部署成功!

4、支付微服务8001注册进Eureka Server

Eureka Client客户端 cloud-provide-payment8001将注册进EurekaServer成为服务提供者

1、在服务提供者cloud-provide-payment8001模块添加依赖

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

2、在服务提供者配置文件中添加eureka的配置

#eureka的配置
eureka:
  client:
    service-url:
      defaultZone: http://localhost:7001/eureka/
    register-with-eureka: true #将自己注册进Eureka Server
    #是否从eurekaServer抓取已有的注册信息,默认为true。单个eureka无所谓,eureka集群必须设置为true,才能配合ribbon使用负载均衡
    fetchregistry: true
  instance:
    instance-id: springcloud-provider-dept-8001   #自定义状态信息

3、主启动类上加注解@EnableEurekaClient

4、测试

  1. 启动Eureka服务端 Eureka Server7001,
  2. 再启动服务提供者cloud-provide-payment8001模块

访问请求http://localhost:7001/进行测试:查看服务是否注册到注册中心,

在这里插入图片描述

在这里插入图片描述
注册成功!

5、订单微服务80注册进Eureka Server

Eureka Client客户端 cloud-consumer-order80将注册进EurekaServer成为服务消费者

1、在服务消费者cloud-consumer-order80模块添加依赖

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

2、在服务提供者配置文件中添加eureka和spring的配置(配置文件注意空格)

spring:
  application:
    name: cloud-order-service

#eureka的配置
eureka:
  client:
    service-url:
      defaultZone: http://localhost:7001/eureka/
    register-with-eureka: true #将自己注册进Eureka Server
    #是否从eurekaServer抓取已有的注册信息,默认为true。单个eureka无所谓,eureka集群必须设置为true,才能配合ribbon使用负载均衡
    fetchregistry: true

3、主启动类上加注解@EnableEurekaClient

4、测试

  1. 启动Eureka服务端 Eureka Server7001,
  2. 启动服务提供者cloud-provide-payment8001模块
  3. 启动服务消费者cloud-consumer-order80模块

访问请求http://localhost:7001/进行测试:发现两个微服务都注册进来了

在这里插入图片描述

6、搭建Eureka集群

6.1、Eureka集群原理

相互注册,相互守望,对外暴露

在这里插入图片描述

Eureka注册中心集群 实现了负载均衡+故障容错

6.2、Eureka集群环境搭建

1、参考cloud-eureka-server7001模块,新建cloud-eureka-server7002模块

  1. 复制7001的pom依赖到7002中
  2. 复制7001的配置文件到7002中,注意Eureka Server7002的端口号为7002
  3. 复制7001的主启动类及目录结构到7002中,7002主启动类名为EurekaMain7002

2、修改映射配置

  1. 找到C:\Windows\System32\drivers\etc目录下的hosts文件,

  2. 在hosts文件中添加映射:

    127.0.0.1  eureka7001.com
    127.0.0.1  eureka7002.com
    

修改完后就可以模拟两个Eureka Serve 服务端了(7001和7002)

3、修改两个Eureka Server服务端的yml配置文件

  1. 修改cloud-eureka-server7001的yml配置文件为:

    server:
      port: 7001
    
    eureka:
      instance:
        hostname: eureka7001.com  # Eureka服务端实例名称
      client:
        register-with-eureka: false  # 由于该应用为注册中心, 所以设置为false, 代表不向注册中心注册自己
        fetch-registry: false # fetch-registry为false,表示我是一个注册中心,我的职责就是维护服务实例,并不需要去检索服务
        service-url:
        #设置与Eureka Server交互的地址,以后服务注册和查询都需要依赖这个地址
          defaultZone: http://eureka7002.com:7002/eureka/22
    
  2. 修改cloud-eureka-server7002的yml配置文件为:

    server:
      port: 7002
    
    eureka:
      instance:
        hostname: eureka7002.com  # Eureka服务端实例名称
      client:
        register-with-eureka: false  # 由于该应用为注册中心, 所以设置为false, 代表不向注册中心注册自己
        fetch-registry: false # fetch-registry为false,表示我是一个注册中心,我的职责就是维护服务实例,并不需要去检索服务
        service-url:
        #设置与Eureka Server交互的地址,以后服务注册和查询都需要依赖这个地址
          defaultZone: http://eureka7001.com:7001/eureka/
    

4、测试

  1. 启动cloud-eureka-server7001模块

  2. 启动cloud-eureka-server7002模块

  3. 访问请求http://eureka7001.com:7001/,查看7001模块

在这里插入图片描述

  1. 访问请求http://eureka7002.com:7002/,查看7002模块

在这里插入图片描述

可以发现,两个集群之间相互注册了,一个由两个eureka节点组成的Eureka集群环境搭建成功!

6.3、订单、支付微服务注册进Eureka集群

将支付服务8001注册进Eureka集群

修改支付服务8001模块的yml配置文件里eureka的配置即可:

#eureka的配置
eureka:
  client:
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/   #集群版
    register-with-eureka: true #将自己注册进Eureka Server
    #是否从eurekaServer抓取已有的注册信息,默认为true。单个eureka无所谓,eureka集群必须设置为true,才能配合ribbon使用负载均衡
    fetchregistry: true

将订单服务80注册进Eureka集群

修改订单服务80模块的yml配置文件里eureka的配置即可:

#eureka的配置
eureka:
  client:
    service-url:
      #defaultZone: http://localhost:7001/eureka/   单机版
      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/   #集群版
    register-with-eureka: true #将自己注册进Eureka Server
    #是否从eurekaServer抓取已有的注册信息,默认为true。单个eureka无所谓,eureka集群必须设置为true,才能配合ribbon使用负载均衡
    fetchregistry: true

测试

  1. 启动cloud-eureka-server7001模块和cloud-eureka-server7002模块

  2. 启动支付服务8001模块

  3. 启动订单服务80模块

  4. 访问http://eureka7001.com:7001/和http://eureka7002.com:7002/,查看两个微服务是否注册到集群里?

    Eureka Server7001注册成功

在这里插入图片描述

Eureka Server7002注册成功
在这里插入图片描述

  1. 测试服务提供者8001提供的服务是否可以访问

    访问查询服务:http://localhost/consumer/payment/get/1

在这里插入图片描述

访问添加服务:http://localhost/consumer/payment/create?serial=%E7%A5%9E%E6%98%8E

在这里插入图片描述

测试成功!

6.4、配置支付微服务集群

1、参考支付模块cloud-provider-payment8001,新建cloud-provider-payment8002

  1. 将8001模块的pom依赖复制到8002模块中
  2. 把8001的java目录和resource目录复制到8002中
  3. 在yml配置文件中把8002模块的端口号改为8002
  4. 8002模块的主启动类名改为PaymentMain8002

2、修改8001模块和8002模块的controller

修改8001模块的controller

在原来的controller中加入端口号,用于区分服务提供者

@RestController
@Slf4j
public class PaymentController {

    @Resource
    private PaymentService paymentService;

    //用于获取配置文件中的端口号
    @Value("${server.port}")
    private String serverPort;


    @PostMapping(value = "/payment/create")
    public CommonResult create(@RequestBody Payment payment){
        int result = paymentService.create(payment);

        log.info("=======添加结果="+result);

        if (result > 0){
            return new CommonResult(200,"添加执行成功,serverPort="+serverPort,result);
        }else {
            return new CommonResult(500,"添加执行失败",null);
        }
    }

    @GetMapping(value = "/payment/get/{id}")
    public CommonResult getPaymentById(@PathVariable("id") Long id){
        Payment payment = paymentService.getPaymentById(id);

        log.info("=======查询结果="+payment);

        if (payment != null){
            return new CommonResult(200,"查询执行成功,serverPort="+serverPort,payment);
        }else {
            return new CommonResult(500,"查询id为"+id+"执行失败",null);
        }
    }


}

修改8002模块的controller

代码和上面一模一样,就不重复写了。

修改之后的支付模块8001和8002,在订单模块访问支付模块集群时,可以通过端口来区分访问的是哪个支付模块。

3、测试

  1. 启动cloud-eureka-server7001模块和cloud-eureka-server7002模块

  2. 启动支付服务8001和8002模块

  3. 启动订单服务80模块

  4. 访问http://eureka7001.com:7001/和http://eureka7002.com:7002/,查看支付微服务集群和订单微服务是否注册到eureka集群里?

    Eureka Server7001注册成功

    Eureka Server7002注册成功

  5. 测试支付微服务集群8001和8002提供的服务是否可以访问

    访问查询服务:http://localhost/consumer/payment/get/1

在这里插入图片描述

查询成功,但我们刷新浏览器重新访问时,端口号并不会变化,也就说明我们访问的支付服务一直是支付微服务集群里的8001模块,这并没有实现负载均衡。

这是因为我们在订单80模块的controller中,要访问的url固定了:所以我们访问的一直都是8001。

public static final String REST_URL_PREFIX = "http://localhost:8001";

实现RestTemplate负载均衡功能

因此在多个服务提供者(支付微服务)的情况下,服务消费者(订单微服务)访问服务提供者不适合再通过url访问,而要通过服务名访问,因为支付微服务集群里的各个服务名是一样的。

订单80模块的controller中,把通过地址访问改为通过服务名访问:

//public static final String REST_URL_PREFIX = "http://localhost:8001";
public static final String REST_URL_PREFIX = "http://CLOUD-PAYMENT-SERVICE";

使用@LoadBalanced注解赋予RestTemplate负载均衡的能力:

@Configuration
public class ConfigBean {

    @Bean
    @LoadBalanced
    public RestTemplate getRestTemplate(){
        return new RestTemplate();
    }
}

再次访问查询服务:http://localhost/consumer/payment/get/1

发现第一次访问的服务时8001

在这里插入图片描述

刷新浏览器,重新访问,访问的服务为8002了

在这里插入图片描述

此后不断刷新,将会轮流访问8001和8002服务,这就实现了默认的负载均衡机制——轮询

7、完善actuator微服务信息

Spring Boot的actuator(健康监控)功能提供了很多监控所需的接口,可以对应用系统进行配置查看、相关功能统计等。

自定义服务实例名称

1、在支付微服务8001,支付微服务8002和订单微服务80的yml配置文件中增加instance配置

8001

#注意:instance和client同级
  instance:
    instance-id: springcloud-provider-payment8001   #自定义状态信息

8002

  instance:
    instance-id: springcloud-provider-payment8002   #自定义状态信息

80

instance:
  instance-id: springcloud-consumer-order80

2、启动程序查看效果:

在这里插入图片描述

自定义服务实例名成功!

设置访问路径显示ip地址

在上面instance配置下面加一行配置:

8001

instance:
  instance-id: springcloud-provider-payment8001   
  prefer-ip-address: true  

8002

instance:
  instance-id: springcloud-provider-payment8002   
  prefer-ip-address: true  

80

instance:
  instance-id: springcloud-consumer-order80
  prefer-ip-address: true

查看效果:
在这里插入图片描述

定义状态信息

1、编写配置,info和eureka同级

info:
  app.name: springcloud-pengcheng
  company.name: wanli

2、点击状态信息的链接

在这里插入图片描述

3、页面跳转,并成功返回配置信息:
在这里插入图片描述

8、服务发现Discovery

对于注册进eureka里面的微服务,可以通过服务发现来获得该服务的信息

1、修改支付模块8001的controller

注入DiscoveryClient,增加一个方法

@Resource
private DiscoveryClient discoveryClient;


@GetMapping(value = "/payment/discovery")
public Object discovery(){
    //得到服务清单列表
    List<String> services = discoveryClient.getServices();
    for (String service : services) {
        log.info("服务列表:"+service);
    }
    //通过服务名获得该服务的所有服务实例
    List<ServiceInstance> instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE");
    for (ServiceInstance instance : instances) {
        log.info(instance.getServiceId()+"\t"+
                 instance.getHost()+"\t"+
                 instance.getPort()+"\t"+
                 instance.getUri()
        );
    }
    return this.discoveryClient;
}

2、在主启动类添加@EnableDiscoveryClient注解

3、测试

访问请求:http://localhost:8001/payment/discovery

在这里插入图片描述

可以看到eureka中已注册的服务名。

再看一下idea控制台的输出:

在这里插入图片描述

成功打印出eureka注册中心中所有已注册的服务名以及cloud-payment-service服务下所有服务实例的信息。

9、自我保护模式

在admin页面出现如下错误“EMERGENCY! EUREKA MAY BE INCORRECTLY CLAIMING INSTANCES ARE UP WHEN THEY’RE NOT. RENEWALS ARE LESSER THAN THRESHOLD AND HENCE THE INSTANCES ARE NOT BEING EXPIRED JUST TO BE SAFE.”,如下图:

在这里插入图片描述

说明Eureka进入了自我保护模式。

自我保护模式:某时刻一个微服务不能用了,Eureka不会立刻清理该服务,依旧会对该微服务的信息进行保存。

  • 保护模式,是Eureka 提供的一个特性,在默认的情况下,这个属性是打开的,而且也建议线上都使用这个特性。
  • 如果Eureka Server在一定时间内没有接收到某个微服务实例的心跳,Eureka Server将会注销该实例(默认90秒)。但是当网络分区故障发生时,微服务与Eureka Server之间无法正常通信,此时会触发Eureka Server进入保护模式,进入自我保护模式后,将会保护服务注册表中的信息,不再删除服务注册表中的数据。当网络故障恢复后,Eureka Server会自动退出自我保护模式

可以通过下面的配置将自我保护模式关闭,这个配置是在 eureka-server 中:

eureka:
  server:
    enable-self-preservation: false

自我保护模式关闭后,在eureka界面会给出提示:

在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

万里顾—程

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值