Spring Cloud笔记-Eureka服务注册与发现(五)

1.Eureka基础知识

服务治理:在传统的RPC远程调用框架中,管理每个服务与服务之间依赖关系比较复杂,需要使用服务治理,管理服务与服务之间依赖关系,可以实现服务调用、负载均衡、容错等,实现服务发现与注册。

Spring Cloud封装Netflix公司开发的Eureka模块来实现服务治理。

服务注册与发现:Eureka采用CS设计架构,Eureka Server是服务注册的中心,系统中其他服务,使用Eureka客户端连接到Eureka Server并维持心跳连接,系统维护人员可以通过Eureka Server监控系统中各个微服务的运行情况。

在服务注册与发现中,有一个注册中心,当服务启动的时候,会把当前服务器的信息(服务通讯地址等)以别名方式注册到注册中心。消费者/生产者以别名的方式去注册中心获取实际的通讯地址,然后再实现本地RPC调用。

RPC调用框架核心思想:存在一个注册中心,使用注册中心管理每个服务与服务之间的依赖关系,这就是服务治理的概念。

2.单机Eureka构建步骤

1.创建EurekaServer端,即服务注册中心

新建cloud-eureka-server7001模块,修改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>cloud2020</artifactId>
        <groupId>com.atguigu.springcloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>cloud-eureka-server7001</artifactId>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
        <dependency>
            <groupId>com.atguigu.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>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
</project>

添加application.yml配置文件,一定要注意这里的对齐格式,否则启动会报错。

server:
  port: 7001 # 端口号
eureka:
  instance:
    hostname: localhost # Eureka服务端实例名称
  client:
    register-with-eureka: false # 表示不向容器中心注册自己
    fetch-registry: false # 表示自己就是注册中心,职责是维护服务实例,不需要去检索服务
    service-url:
    # 设置与Eureka Server交互的地址,查询服务和注册服务都需要依赖这个地址
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/

创建主启动类,注意这里要带上@EnableEurekaServer注解。

package com.atguigu.springcloud;

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

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

启动服务,访问http://localhost:7001/测试,可以看到Spring Eureka的界面即为成功。

2.把EurekaClient端(cloud-provider-payment8001)注册到EurekaServer,作为服务提供者

修改cloud-provider-payment8001模块的pom.xml,添加Eureka-Client的坐标。

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

修改cloud-provider-payment8001的yml配置文件,添加Eureka相关的配置。

eureka:
  client:
    register-with-eureka: true # 表示将自己注册进EurekaServer
    # 表示是否从Eureka抓取已有的注册信息,默认为true,单点无所谓,集群时候,必须设置成true,才能配合Ribbon使用负载均衡
    fetch-registry: true
    service-url:
      defaultZone: http://localhost:7001/eureka

给cloud-provider-payment8001主启动类上添加@EnableEurekaClient注解。先启动EurekaServer,后启动EurekaClient,测试注册是否成功,在Eureka后台的Instances currently registered with Eureka,可以看到Application里的CLOUD-PAYMENT-SERVICE(这个名称对应cloud-provider-payment8001模块中yml配置文件的spring.application.name),它的Status是UP,表示注册成功了。

3.把EurekaClient端(cloud-consumer-order80)注册到EurekaServer,作为服务消费者

修改cloud-consumer-order80模块的pom.xml,添加Eureka-Client的坐标。

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

 修改cloud-consumer-order80的yml配置文件,添加Eureka相关的配置。

eureka:
  client:
    register-with-eureka: true # 表示将自己注册进EurekaServer
    # 表示是否从Eureka抓取已有的注册信息,默认为true,单点无所谓,集群时候,必须设置成true,才能配合Ribbon使用负载均衡
    fetch-registry: true
    service-url:
      defaultZone: http://localhost:7001/eureka
spring:
  application:
    name: cloud-order-service

给cloud-consumer-order80主启动类上添加@EnableEurekaClient注解。先启动EurekaService,后启动EurekaClient,正常情况下,在Eureka后台的Application中,应该可以看到两个微服务,此时说明服务注册成功了。

3.集群Eureka构建步骤

1.Eureka集群原理说明

服务注册:将服务信息注册到注册中心;服务发现:从注册中心获取服务信息;注册中心相当于存了一个key-value结构,key是服务名称,value是服务调用地址。

先启动Eureka服务注册中心,启动服务提供者,服务提供者会把服务调用地址以别名的方式注册进Eureka注册中心,启动服务消费者,消费者需要调用服务的时候,根据服务别名去注册中心查找服务获取真实RPC地址,通过Http请求实现远程调用,消费者获得的服务地址会缓存在JVM内存中,默认每隔30秒更新一次服务调用地址。

如果只有一个Eureka注册中心,如果出现故障了,那么整个服务环境就没法访问了,所以需要搭建Eureka注册中心集群,实现负载均衡和故障容错。

Eureka集群中,各个注册中心之间是互相注册,互相守望的关系。

2.Eureka集群环境构建

新建一个注册中心模块,命名为cloud-eureka-server7002,类比cloud-eureka-server7001做一下基本配置,下面修改集群配置。修改两个模块application.yml里的配置信息,将hostname改成eureka7001.com和eureka7002.com,并通过修改hosts文件,将它们都指向localhost,port对应修改成7001和7002。

127.0.0.1 eureka7001.com
127.0.0.1 eureka7002.com

因为前面提到了“相互注册”,那么defaultZone就要表达出来相互的意思,7001的defaultZone设置成http://eureka7002.com:7002/eureka/,7002的defaultZone设置成http://eureka7001.com:7001/eureka/,这就完成了相互注册的意思,如果有3个注册中心,那么需要满足1注册2和3,2注册1和3,3注册1和2这种样子,注册地址写在defaultZone中,用英文逗号分隔开。

# cloud-eureka-server7001配置文件
server:
  port: 7001 # 端口号
eureka:
  instance:
    hostname: eureka7001.com # Eureka服务端实例名称
  client:
    register-with-eureka: false # 表示不向容器中心注册自己
    fetch-registry: false # 表示自己就是注册中心,职责是维护服务实例,不需要去检索服务
    service-url:
    # 设置与Eureka Server交互的地址,查询服务和注册服务都需要依赖这个地址
      defaultZone: http://eureka7002.com:7002/eureka/
# cloud-eureka-server7002配置文件
server:
  port: 7002 # 端口号
eureka:
  instance:
    hostname: eureka7002.com # Eureka服务端实例名称
  client:
    register-with-eureka: false # 表示不向容器中心注册自己
    fetch-registry: false # 表示自己就是注册中心,职责是维护服务实例,不需要去检索服务
    service-url:
    # 设置与Eureka Server交互的地址,查询服务和注册服务都需要依赖这个地址
      defaultZone: http://eureka7001.com:7001/eureka/

先后启动7001,7002注册中心,在浏览器访问http://localhost:7001/http://localhost:7002/都可以访问到正确的Eureka页面,因为我们做过hosts映射,所以访问http://eureka7001.com:7001/http://eureka7002.com:7002/同样也能访问到。观察DS Replicas中的内容,如果7001中指向7002,7002中指向7001,那么就完成了相互注册,此时集群搭建成功。

这里多提一句,弹幕里有说可以不用创建7002项目的,大致思路如下:

在Run/Debug Configuration里,勾选“Allow parallel run”,即允许项目并行运行,启动第一个项目后,修改配置文件,再次运行这个项目,此时就相当于运行了两台配置文件不同的注册中心。

3.微服务注册进Eureka集群

只需要修改微服务的注册地址即可,之前只注册了一个注册中心,现在需要将yml中的defaultZone的值换成集群的即可,修改为http://eureka7001.com:7001/eureka, http://eureka7002.com:7002/eureka。先启动注册中心集群,再启动服务生产者,最后启动服务消费者,都启动之后,可以在Eureka注册中心集群的后台看到服务生产者和消费者已经注册进来了。

4.服务提供者微服务集群配置

参考cloud-provider-payment8001新建cloud-provider-payment8002,pom.xml→application.yml→主启动类→业务类。修改controller,带上端口号输出,用于标识。在查询和插入的代码里,将serverPort进行输出。注意,这里在复制mapper的时候,可能会出问题,我说下我的问题吧,测试的时候,提示找不到mapper对应的xml,仔细检查发现mapper文件的namespace和Dao的包名不一致,做一下修改即可。

@Value("${server.port}")
private String serverPort;

启动两台Eureka注册中心,两台服务提供者,一台服务消费者。启动成功后,访问两台注册中心,可以在DS Replicas中看到互相注册,在Instance currently registered with Eureka中看到一个CLOUD-ORDER-SERVICE和两个CLOUD-PAYMENT-SERVICE,说明服务注册是没有问题的,访问http://localhost:8001/payment/get/1http://localhost:8002/payment/get/1http://localhost/consumer/payment/get/1进行自测,没有报错,且能正确查询到内容即为正常。在访问多次http://localhost/consumer/payment/get/1后,输出的port都是8001,这是因为在OrderController中,我们把PAYMENT_URL写死了。所以每次都会访问8001,现在有8001和8002两台服务,我们就不能这么指定了,我们需要指定PAYMENT的服务名称,也就是Eureka中注册的服务名称,通过服务名称查找服务地址。

private static final String PAYMENT_URL = "http://CLOUD-PAYMENT-SERVICE";

访问http://localhost/consumer/payment/get/1,发现报错了,这是因为通过服务名查找服务地址的时候,一个服务名可能对应多个服务地址,我们需要指定访问策略,在RestTemplate的bean上添加@LoadBalanced注解,此时的访问策略就是轮询策略,再次访问http://localhost/consumer/payment/get/1,通过打印信息,可以验证这一点。

这里的@LoadBalanced注解赋予了RestTemplate负载均衡的能力,类似于Ribbon,后面Ribbon和Eureka整合后,消费者可以直接调用服务,而无需关心地址和端口号,负载均衡由Ribbon来完成。

4.Actuator微服务信息完善

在Eureka注册中心的Instance currently registered with Eureka的Status里,主机名有的是ip,有的是localhost,这里不规范,我们需要做一下完善。在8001和8002的yml配置文件中加入如下内容即可,注意缩进,instance结点和client结点是同级别的。

  instance:
    instance-id: payment8001 # 指定服务实例id
    prefer-ip-address: true # 访问路径可以显示IP地址

再次刷新服务注册中心,此时status里,看到的就是我们指定的instance-id,将鼠标放在上面,可以在浏览器左下角看到ip地址。

5.服务发现Discovery

对于注册进Eureka的微服务,可以通过服务发现来获取该服务的信息,这里拿8001做演示。引入DiscoveryClient属性,编写服务发现接口,输出DiscoveryClient对象的属性信息,这里的DiscoveryClient是org.springframework.cloud.client.discovery.DiscoveryClient包里的。在8001的主启动类添加@EnableDiscoveryClient注解。

通过浏览器访问http://localhost:8001/payment/discovery查看效果,在控制台就可以看到刚才是打印的信息。

@Resource
private DiscoveryClient discoveryClient;

@GetMapping("/payment/discovery")
public Object discovery() {
    // 获取所有的服务
    List<String> services = discoveryClient.getServices();
    for (String service : services) {
        System.out.println("Eureka中的服务:" + service);
    }
    // 根据服务名获取服务实例
    List<ServiceInstance> instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE");
    for (ServiceInstance instance : instances) {
        System.out.println(instance.getServiceId() + "\t" + instance.getHost() + "\t" + instance.getPort() + "\t" + instance.getUri());
    }
    return discoveryClient;
}

6.Eureka自我保护

保护模式是用于一组客户端和Eureka Server之间存在网络分区场景下的保护功能,一旦进入了保护模式,Eureka Server就会保护服务注册表中的信息,不再删除服务注册数据,也就是不注销任何微服务。某时刻,某个微服务不可用了(可能是网络不稳定,心跳包丢失等情况),Eureka注册中心并不会立刻清理,依旧会对服务信息进行保存。

默认情况下,Eureka Server发现某服务不可用了,会延迟90s,如果90s后,依旧没有接收到微服务的心跳包,此时,才会进行注销。在短时间内,当出现丢失大量服务实例心跳包的时候,Eureka Server会开启自我保护机制。

如果在Eureka Server看到“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.”,说明开启了保护模式,默认情况下,是开启的。

设计哲学:宁可保留错误的服务注册信息,也不盲目的注销任何可能健康的服务实例。

如果要关掉自我保护,可以在7001模块上的application.yml里添加如下配置,注意缩进,和client是同一级别的。

eureka:
  server:
    enable-self-preservation: false # 关闭自我保护机制
    eviction-interval-timer-in-ms: 2000 # 清理微服务间隔时间,单位为毫秒

启动Eureka Server 7001模块,访问http://eureka7001.com:7001/可以看到“THE SELF PRESERVATION MODE IS TURNED OFF. THIS MAY NOT PROTECT INSTANCE EXPIRY IN CASE OF NETWORK/OTHER PROBLEMS.”信息。

修改8001模块的yml文件,配置心跳包发送频率,注意缩进,结点位于eureka.instance下,同时,临时将这里的defaultZone改成单机,只访问7001,启动8001项目后,手动关闭,立刻去刷新Eureka Server,随着不断的刷新,2秒后,8001服务被移除。

eureka:
  instance:
    # Eureka客户端向服务端发送心跳时间间隔,单位为秒,默认为30秒
    lease-renewal-interval-in-seconds: 1
    # Eureka服务端在接收到最后一次心跳后等待的时间上限,单位为秒,默认是90秒,超过后,微服务将被剔除
    lease-expiration-duration-in-seconds: 2

 

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值