Spring-Cloud:Discovery


概述

  • 认识microservices
  • 设置service registry(服务注册中心)
  • Registering 和 discovering services(注册和发现服务)

认识microservices

1. 传统的Monoliths application(单一应用)的特点

  • *复杂: * 传统单一应用代码库越大,理解整个应用的每个组件就越困难
  • *更难测试: * 随着应用的发展,全面的测试更加困难
  • 更容易出现库冲突
  • *伸缩性问题: * 扩展更困难,效率低
  • *技术决策要根据整体: * 整个应用选了语言框架等,新的决策只能在此基础上选择
  • 开发周期更长

2. Microservice architecture(微服务架构)特点

  • *简单: *微服务是一种小的应用,相比传统的单一应用更简单

  • *容易测试: * 应用越小越容易测试

  • 不太容易出现库冲突

  • *良好的伸缩性: *更容易扩展

  • 每个微服务都可以选择不同的技术,不需要根据整体进行决策

  • *开发方便: *可以频繁的将其发布到生产环境

  • **缺点: ** 远程调用会增加网络延迟

设置service registry(服务注册中心)

1. 认识Eureka

  • Spring Cloud由几个独立的子项目组成,每个子项目都以某种方式支持微服务开发,其中一个子项目就是Spring Cloud Netflix,其中包含了一个组件Eureka,即Netflix service registry

  • 所有微服务将通过service registry(Eureka)发现彼此

  • Eureka 作为微服务应用的所有服务的中央注册中心,其本身也是一个微服务,由于其特性,最好创建在其他服务创建之前

2. Ribbon

Services register

  • 由上图可以看出,other-service决定使用哪一个some-service,更好的方式是使用一种客户端负载均衡(load-balancing)算法来决定,这就是Ribbon的作用

  • Ribbon是一个客户端负载均衡器,它代表other-service进行选择some-service

  • 与单一的集中服务进行负载均衡不同,Ribbon客户端负载均衡器,对于每一个发送请求的客户端都是本地的

  • 对比集中式的负载均衡器,Ribbon有一些优势,因为每一个客户端本地都有一个负载均衡器,因此,可以根据不同的客户端使用不同的负载均衡算法,并且可以根据客户端数量伸缩

3. 开始创建

  • 使用Spring Initializr创建一个新的project,引入Eureka Server即可,生成Maven依赖如下
<dependency>
 <groupId>org.springframework.cloud</groupId>
 <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
  • 默认使用spring-cloud.version版本,也可以自定义版本
<properties>
 ...
 <spring-cloud.version>Finchley.SR1</spring-cloud.version>
</properties>
...
<dependencyManagement>
 <dependencies>
 <dependency>
 <groupId>org.springframework.cloud</groupId>
 <artifactId>spring-cloud-dependencies</artifactId>
 <version>${spring-cloud.version}</version>
 <type>pom</type>
 <scope>import</scope>
 </dependency>
 </dependencies>
</dependencyManagement>
  • Spring启动器增加注解@EnableEurekaServer
@SpringBootApplication
@EnableEurekaServer
public class ServiceRegistryApplication {
 public static void main(String[] args) {
     SpringApplication.run(ServiceRegistryApplication.class, args);
 }
}
  • Eureka默认监听的是8080端口,项目启动之后从浏览器打开http://localhost:8080即可查看Eureka详情

  • Eureka还提供了一个REST API,通过http://localhost:8080/eureka/apps可以获取注册中心的所有服务实例

    <applications>
    <versions__delta>1</versions__delta>
    <apps__hashcode/>
    </applications>

4. 配置Eureka

  • 基本配置application.yml

    eureka:
      instance:
        hostname: localhost
      client: #开发环境下如果就一个eureka实例,则关闭下列选项
        fetch-registry: false #默认为true,eureka可以从其他eureka实例上获取注册表
        register-with-eureka: false #默认为true,在其他eureka实例上将自己注册为服务
        service-url:
          defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka
      server:
        enable-self-preservation: false #默认为true,默认情况下要求服务实例注册自己,且毎30秒给eureka发送注册更新信息
                                        #如果超过90秒没有收到服务续期,那么会取消该实例注册,进入自我保护模式
                                        #生产环境下: 应开启此模式,设置为true
    server:
      port: 8080 #默认端口
  • 虽然单个Eureka实例在开发环境下很便利,但是在生产环境下为了高可用性,可能需要配置多个

    • *方式一: * Spring Cloud Services 提供了Eureka生产环境下的实施,只需要一个configuration server 和 一个circuit breaker dashboard即可

    • *方式二: * 最简单的方式直接使用profiles属性配置两个Eureka实例,分别启动两个Eureka服务即可

      spring:
        profiles: eureka-1
        application:
          name: eureka-1
      server:
        port: 8761
      eureka:
        instance:
          hostname: localhost
        client:
          service-url:
            defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka
      ---
      spring:
        profiles: eureka-2
        application:
          name: eureka-2
      server:
        port: 8762
      eureka:
        instance:
          hostname: localhost
        client:
          service-url:
            defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka

Registering 和 discovering services(注册和发现服务)

1. 概述

  • 如果没有服务注册,那么Eureka Service registry是无用的,如果other services想要发现并使用你的服务,需要你的服务作为客户端注册到service registryservice registry client

  • 为了使你的服务允许作为service registry client ,需要引入Eureka client依赖

    <dependency>
     <groupId>org.springframework.cloud</groupId>
     <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>
  • Eureka client依赖项中提供了发现服务所需要的内容,包含Eureka's client-side libiaryRobbin load balancer

  • 只需要添加此依赖项,将启用你的应用作为Eureka service registry的一个客户端,当应用启动时,默认情况下它将尝试去连接运行与本地的Eureka server 并将自己注册到Eureka service registry中,默认名字为UNKNOWN

2. 配置Eureka client

  • 配置在Eureka中的注册名(即给应用定义名称):不设置的情况下为UNKNOWN

    spring:
     application:
     name: ingredient-service
  • 设置随机端口,防止端口冲突

    server:
     port: 0 #启动时会随机使用可用的端口
  • 生产环境下地址配置:(可能不是localhost,并且配置多个,如果向第一个注册失败,可以改向第二个注册,更可靠)

    eureka:
     client:
     service-url:
     defaultZone: http://eureka1.tacocloud.com:8761/eureka/,
                   http://eureka2.tacocloud.com:8762/eureka/

3. 使用服务

  • 服务在Eureka中注册成功之后,other services就可以发现并使用它
  • Spring Cloud提供了Ribbon客户端负载均衡策略进行服务的选择,因此无需考虑多个相同服务选择问题
  • Eureka中使用服务有两种方式:
    • load-balanced RestTemplate / load-balanced WebClient(响应式编程)
    • Feign-generated client interfaces
3.1 通过RestTemplate使用服务
  • 创建load-balanced RestTemplate的bean

    @Bean
    @LoadBalanced
    public RestTemplate restTemplate() {
     return new RestTemplate();
    }
  • 注入bean并使用

    @Component
    public class IngredientServiceClient {
     private RestTemplate rest;
     public IngredientServiceClient(@LoadBalanced RestTemplate rest) {
     this.rest = rest;
     }
         //使用
        public Ingredient getIngredientById(String ingredientId) {
         return rest.getForObject(
         "http://ingredient-service/ingredients/{id}", //此处没有URL硬编码方式,而是使用应用注册名
         Ingredient.class, ingredientId);
        }
    }
3.2 通过WebClient方式使用服务(针对响应式编程)
  • 创建bean

    @Bean
    @LoadBalanced
    public WebClient.Builder webClientBuilder() {
     return WebClient.builder();
    }
  • 注入并使用bean

    @Component
    public class IngredientServiceClient {
     private WebClient.Builder wcBuilder;
     public IngredientServiceClient(
     @LoadBalanced WebClient.Builder webclientBuilder wcBuilder) {
     this.wcBuilder = wcBuilder;
     }
        public Mono<Ingredient> getIngredientById(String ingredientId) {
         return wcBuilder.build()
         .get()
         .uri("http://ingredient-service/ingredients/{id}", ingredientId)
         .retrieve().bodyToMono(Ingredient.class);
        }
    }
3.3 使用Feign创建基于接口的服务客户端
  • Feign是一个客户端库,通过一种独特的丶接口驱动的方法来定义一个REST客户端,简单的说就是通过此库可以很方便的创建使用REST API的客户端

  • 引入Maven依赖

    <dependency>
     <groupId>org.springframework.cloud</groupId>
     <artifactId>spring-cloud-starter-openfeign</artifactId>
    </dependency>
  • 启用配置Configuration

    @Configuration
    @EnableFeignClients
    public RestClientConfiguration {
    }
  • 创建客户端接口(启动时Feign会自动实现该接口)

    @FeignClient("ingredient-service")
    public interface IngredientClient {
     @GetMapping("/ingredients/{id}")
     Ingredient getIngredient(@PathVariable("id") String id);
    }
  • 使用定义的客户端

    @Controller
    @RequestMapping("/ingredients")
    public class IngredientController {
     private IngredientClient client;
     @Autowired
     public IngredientController(IngredientClient client) {
     this.client = client;
     }
     @GetMapping("/{id}")
     public String ingredientDetailPage(@PathVariable("id") String id,
     Model model) {
     model.addAttribute("ingredient", client.getIngredient(id));
     return "ingredientDetail";
     }
    }

文章作者: Bryson
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Bryson !
评论
 上一篇
Spring-Cloud:Config Spring-Cloud:Config
概述 Config Server 使用共享配置属性 使用应用与特定应用程序的配置属性 保证配置属性安全 动态更新配置属性 Config Server1. 认识1.1 引入bootstrap.yml bootstrap.yml(bootst
2020-08-19
下一篇 
  目录