Spring Cloud -微服务发现与调用

简介

Spring Cloud 是一套基于 Spring Boot 框架的、完整的微服务解决方案,集成了市面上较好的微服务框架,从而简化了开发者的代码量,减少了各模块的开发成本。

注册与发现

Eureka是一个高可用的组件,是Spring Cloud默认的服务注册和发现模块,它没有后端缓存(因此可以在内存中完成)。每一个实例注册之后需要向注册中心发送心跳,在默认情况下,Eureka server也是一个Eureka client ,必须要指定一个 server,和Dubbo的Dubbo Admin类似,Eureka同样提供了一个基于WEB的管理界面,用于查看管理目前已经注册运行的服务。

EurekaServer提供了服务发现的能力,当每个微服务启动的时候,会向Eureka Server注册自己的信息,这些信息包含微服务的地址,端口,名称等,Eureka Server会存储这些信息。EurekaClient就是一个java的客户端,相当于一个消费者。

默认情况下,Eureka Server同时也是一个Eureka Client。多个Eureka Server实例,相互之间通过复制,实现注册表之间的数据同步。每个微服务启动后,会周期性的(30秒),向Eureka Server发送心跳,来续约自己的租期.如果在一定的周期内(90秒)没有接收到某个微服务实例的心跳,则Eureka Server会注销该实例.

构建服务发现者

引入依赖 spring-cloud-starter-netflix-eureka-server

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

添加yml配置,其中
eureka.client.registerWithEureka:false表示不需要将注册到server。
eureka.client.fetch-Registry:false 表示该应用为服务注册中心,职责为注册和发现服务,无需检索服务。
eureka.client.serviceUrl 表示服务与Eureka Server交互的地址,查询和注册服务都要依赖这个地址,设置默认地址为: http://localhost:8761/eureka/

server:
  # 端口号
  port: 8761

eureka:
  instance:
    hostname: localhost
  server:
    renewal-percent-threshold: 0.2
  client:
    # 是否向 Eureka 注册服务。该应用为服务注册中心,不需要自注册,设置为 false
    registerWithEureka: false
    # 该应用为服务注册中心,职责为注册和发现服务,无需检索服务,设置为 false
    fetchRegistry: false
    serviceUrl:
      #注册中心地址
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/

spring:
  application:
    #服务名称
    name: eureka-server

配置启动类, 添加@EnableEurekaServer 注解,开启Eureka 服务发现.

@SpringBootApplication
@EnableEurekaServer
public class EurekaserverApplication {

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

}

启动EurekaserverApplication , 访问 http://localhost:8761/

在这里插入图片描述

构建服务提供者

引入依赖spring-cloud-starter-netflix-eureka-client 以及 spring-boot-starter-web , 如果不引入 spring-boot-starter-web 依赖则可能发生如下错误

Description:

Field optionalArgs in org.springframework.cloud.netflix.eureka.EurekaClientAutoConfiguration$RefreshableEurekaClientConfiguration required a bean of type 'com.netflix.discovery.AbstractDiscoveryClientOptionalArgs' that could not be found.

The injection point has the following annotations:
	- @org.springframework.beans.factory.annotation.Autowired(required=true)

Action:

Consider defining a bean of type 'com.netflix.discovery.AbstractDiscoveryClientOptionalArgs' in your configuration.
<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
   <groupId>org.springframework.cloud</groupId>
   <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

添加客户端配置,其中
eureka.client.serviceUrl 表示将当前的微服务注册到哪个Eureka Server注册中心
eureka.instance.prefer-ip-address 表示将ip地址注册到Eureka Server
spring.application.name 表示当前应用的名称, 也是注册到Eureka Server的名称,服务与服务之间相互调用一般都是根据这个name。

server:
  port: 8762

eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/
  instance:
    prefer-ip-address: true

spring:
  application:
    name: eureka-microservice-client1

配置启动类, 添加@EnableEurekaClient 注解,向注册中心注册一个微服务。

@SpringBootApplication
@EnableEurekaClient
public class Eurekaclient1Application {

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

启动成功,访问 http://localhost:8761/ 可以看到 eureka-microservice-client1 已经成功注册到注册中心。

在这里插入图片描述

按如上操作,注册第二个微服务 eureka-microservice-client2 , 修改yml 配置 server.port:8763 以及spring.application.name:eureka-microservice-client2

如果还需要其它服务,依上所述继续进行服务注册。

Eureka /actuator/info不显示

从注册中心点击查看,发现/actuator/info不显示。

在这里插入图片描述

解决方案:

1、添加应用监控与管理依赖spring-boot-starter-actuator

<!--应用监控与管理actuator-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

2、增加 yml 配置

#应用监控与管理actuator配置, 对info端点进行暴露设置
management:
  endpoints:
    web:
      exposure:
        include: "*"

3、重新注册(启动),/actuator/info 访问成功。

添加用户认证

为了服务安全,可以添加用户认证,服务提供者需要登录才能进行服务注册。

服务端配置

在Eureka Server 引入 spring-cloud-starter-security 依赖

<!--增加cloud -security支持-->
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-security -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-security</artifactId>
    <version>2.2.0.RELEASE</version>
</dependency>

添加用户认证配置

spring:
 # springboot2.0+版本开启用户认证配置
  security:
    user:
      name: user
      password: 123456

重启服务端, 访问 http://localhost:8761/ , 可以看到会有登录验证,用户名和密码就是上面添加的配置。
在这里插入图片描述

客户端配置

由于服务端添加了用户认证,故而客户端连接时也需要携带用户名及密码。

server:
  port: 8762

eureka:
  user: user
  password: 123456
  client:
    serviceUrl:
      #defaultZone: http://localhost:8761/eureka/
      defaultZone: http://${eureka.user}:${eureka.password}@localhost:8761/eureka/
  instance:
    prefer-ip-address: true

spring:
  application:
    name: eureka-microservice-client1

客户端重启, 服务正常注册。

服务端开启用户认证后客户端无法登录

Spring Cloud 2.0 以上的 security 默认启用了 csrf 检验,客户端注册时可能会触发如下错误

com.netflix.discovery.shared.transport.TransportException: Cannot execute request on any known server

解决方法: 在Eureka Server 配置 security 的 csrf 检验为 false 。

/**
 * spring Cloud 2.0 以上的security默认启用了csrf检验,要在Eureka Server端配置 security 的 csrf 检验为 false
 */
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable();
        super.configure(http);
    }

}

服务间调用

首先各服务之间添加各自的控制类

eureka-microservice-client1

@RestController
public class TestController {
    
    @GetMapping("test")
    public String test(){
        return "eureka-microservice-client1";
    }
    
}

eureka-microservice-client2

@RestController
public class TestController {
    
    @GetMapping("test")
    public String test(){
        return "eureka-microservice-client2";
    }
    
}

RestTemplate 调用

在启动类Eurekaclient1Application 和 Eurekaclient2Application注入RestTemplate Bean .

@Bean
public RestTemplate restTemplateInstance(){
    //配置HTTP超时时间
    HttpComponentsClientHttpRequestFactory httpRequestFactory = new HttpComponentsClientHttpRequestFactory();
    httpRequestFactory.setConnectionRequestTimeout(1000 * 30);
    httpRequestFactory.setConnectTimeout(1000 * 30);
    httpRequestFactory.setReadTimeout(1000 * 30);
    RestTemplate restTemplate = new RestTemplate(httpRequestFactory);
    restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
    return restTemplate;
}

控制器分别添加已 RestTemplate 方式请求的方法。

eureka-microservice-client1

@RestController
public class TestController {

    @Autowired
    private RestTemplate restTemplate;
    
    @GetMapping("test")
    public String test(){
        return "eureka-microservice-client1";
    }

    @GetMapping("connectClient2")
    public String connectClient2(){
        return restTemplate.getForObject("http://localhost:8763/test", String.class);
    }

}

eureka-microservice-client2

@RestController
public class TestController {

    @Autowired
    private RestTemplate restTemplate;
    
    @GetMapping("test")
    public String test(){
        return "eureka-microservice-client2";
    }

    @GetMapping("connectClient1")
    public String connectClient1(){
        return restTemplate.getForObject("http://localhost:8762/test", String.class);
    }

}

访问 http://localhost:8763/connectClient1http://localhost:8762/connectClient2 可以看到对应客户端的 test 方法被调用。

Feign 调用

引入依赖spring-cloud-starter-openfeign

<dependency>
   <groupId>org.springframework.cloud</groupId>
   <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

启动类添加@EnableFeignClients注解, basePackages 属性对应项目中的 FeignClient 包

@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients(basePackages = "com.example.eurekaclient1.feignclient")
public class Eurekaclient1Application {

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

com.example.eurekaclient1.feignclient 中添加 EurekaClient2 接口

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

/**
 * 定义一个feign接口,通过@ FeignClient(“服务名”),来指定消费哪个服务。
 */
@FeignClient(name = "eureka-microservice-client2") 
public interface EurekaClient2 {

    // values请求地址就是users用户服务中该控制器的接口地址
    @RequestMapping(value = "/test",method = RequestMethod.GET)
    String test();

}

控制器添加对Feign接口的调用

@RestController
public class TestController {

    @Autowired
    private EurekaClient2 eurekaClient2;

    @GetMapping("test")
    public String test(){
        return "client1";
    }

    @RequestMapping("testFeign")
    public String testFeign(){
        System.out.println("调用feign接口");
        return eurekaClient2.test();
    }

}

访问 http://localhost:8762/testFeign ,接口响应成功, 返回 eureka-microservice-client2。
其它客户端类似配置。

其它问题

自我保护模式

服务端启动后界面出现一串红色字体, Eureka进入自我保护模式。

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的保护机制,它保护了因网络等问题造成的短暂的服务不可用的实例,避免频繁注册服务对整个系统造成影响。

进入条件

如果最近一分钟实际接收到的心跳值 Renews 除以期望的心跳阈值 Renews threshold小于等于0.85,即 Renews/Renews threshold ≤ 0.85

计算方法

一些参数默认值
  • 最低阈值 : 默认 1
  • 一分钟接收到的心跳次数 : 默认为2,心跳检测默认30s一次
Renews threshold(Eureka注册中心期望接收到的心跳值)
  • 服务注册中心不注册(eureka.client.registerWithEureka: false):
    最低阈值 + 一分钟接收到的心跳次数 * 客户端数量, 即:1+2*n

  • 服务注册中心注册(eureka.client.registerWithEureka: true): 1+2*(n+1)

Renews (注册中心实际接收到的心跳值)
  • 服务注册中心不注册(eureka.client.registerWithEureka: false): 一分钟接收到的心跳次数 * 客户端数量
  • 服务注册中心注册: 2*(n+1)

解决方案

调整eureka.server.renewal-percent-threshold 的值。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值