Spring 框架学习 (五)Spring Cloud

Spring Cloud

基于自己的理解

是什么

一系列组件构成,这些组件用于帮助构建微服务架构的系统。

解决什么问题

微服务架构在增加了系统的可维护性,可用性等基础上,增加了系统开发的复杂度:

  • 不同服务之间调用,需要知道每一个服务的地址
    • 对比不使用微服务架构(即使用一整个单独、庞大的系统)时,只要内部调用接口就好了
  • 服务调用时,使用HttpClient/RestTemplate写的代码稍显冗杂
    • 对比单独系统,同样只要内部调用接口就好了
  • 高可用部署时,需要负载均衡访问服务
    • 单独系统同样不存在这个问题
  • 外部调用系统接口时,需要知道系统每一个服务地址
    • 单独系统只有一个地址,所以不存在这个问题
  • 存在服务错误导致的雪崩问题,即如果一个服务挂掉不响应,则相应的上游业务会由于请求卡住,也全部挂掉。
    • 单独系统倒不能说不存在这个问题,但是可能没有这个概念。
  • 微服务数量上升,每个服务都有配置文件,不方便管理。尤其是可能有一些公共配置(比如数据库、redis),重复配置也比较麻烦

目前初步学习了一些Spring Cloud相关内容,里面的几个组件就是针对这些问题的。

怎么用

还是分组件来看

服务注册发现

这里包含一个注册服务(一个单独的进程/集群服务),和多个微服务。

每个微服务客户端向注册服务注册自己的地址,并且也可以从注册服务查询自己需要的微服务的地址。

在SpringBoot的AutoConfiguration的支持下,注册一般只要添加好相应的依赖,然后配置一下注册服务的地址。客户端就可以自动以应用的名字注册。

使用时,在应用中通过@EnableDiscoveryClient使能服务查询,通过注入的DiscoveryClient去找到所需要的服务,然后发送请求。服务的查找一般通过服务的名称,或者id。

        List<ServiceInstance> instances = discoveryClient.getInstances("service-name");
        ServiceInstance serviceInstance = instances.get(0);
		System.out.println(serviceInstance.getUri());//获取服务地址

这样各个客户端/微服务之间不需要写死其他服务的地址,而是通过名字去查询所需要的服务地址。

不同的注册服务

其实只试验了一下Eureka和Consul。

Eureka: 似乎已经停止维护了,可以通过SpringBoot启动一个Eureka服务。

Consul:是一个单独的二进制文件运行。可以进行健康检查等。

负载均衡

通过服务发现,如果一个服务注册了多个实例(高可用部署),那么会发现多个。

SpringCloud中包含LoadBalancerClient类可以被自动注册,他可以帮助我们自动在多个里选择用于调用的服务。

        ServiceInstance serviceInstance = loadBalancer.choose("service-name");
        System.out.println(serviceInstance.getUri());

Feign

Feign组件帮助简化调用其他服务代码的书写。

通过RestTemplate:

	public void doRequest() {
	
		... //获取服务地址等
		
        RestTemplate restTemplate = new RestTemplate();
        ResponseEntity<String> response = null;
        try {
            response = restTemplate.exchange(baseUrl,
                    HttpMethod.GET, getHeaders(), String.class);
        } catch (Exception ex) {
            System.out.println(ex);
        }
        System.out.println(response.getBody());
		
		...
	}
		
    private static HttpEntity<?> getHeaders() throws IOException {
        HttpHeaders headers = new HttpHeaders();
        headers.set("Accept", MediaType.APPLICATION_JSON_VALUE);
        return new HttpEntity<Object>(headers);
    }		

通过Feign:

	//配置Feign
	@FeignClient("service-name")
	public interface RpcService {
		@RequestMapping(method = RequestMethod.GET, value = "/doRequest")
		public Object getData();

	}
	
	//使用
    @Autowired
    private RpcService rpcService;
	
    public String doRequest() {
        rpcService.getData();
    }

这里@FeignClient注解会自动查找服务地址,而且还会自动进行负载均衡选择。

使用Feign时,应用配置类或者Main类需要添加@EnableFeignClients

服务熔断降级

熔断,就是当某个服务接口调用多次失败,下一次就不调用了。
而降级,就是熔断后所做的替代操作。

比如订单一直失败,这时候在下单,服务端就不去提交订单,而是直接显示,当前系统繁忙,请稍后再试。

熔断功能可以通过Hystrix实现。

使用

应用配置类需要增加@EnableCircuitBreaker注解开启熔断功能。

在需要熔断的服务上增加:

@HystrixCommand(fallbackMethod = "getDataFallBack")

这样会使用默认的配置进行熔断,比如10秒超过20次失败就会熔断,调用fallbackMethod处理。

内部上,使能服务熔断功能,会让服务内部创建一个线程池,用于处理发过来的请求,这样当请求响应不过来,线程池满了的话,也不会消耗其他系统资源。

微服务网关

网关作为微服务系统内部和外部之间的桥梁,外部系统不用知道内部微服务各个子服务的地址,也不用去注册发现服务去找地址(因为这对于一个外部应用来说仍显得麻烦),而是将所有请求发给微服务网关,由网关判断微服务的实际地址。

Zuul

Zuul似乎是Spring官方推荐的一个微服务网关。

Zuul本身也向配置中心注册,获取其他服务的中心,但是调用者只要调用Zuul的地址,就可以通过Zuul将请求转发给后端的实际服务。

Zuul通过配置,来判断入口请求转发给哪个服务。如:

zuul:
   routes:
      employee:
         path: /emp/**
         service-id: employee-service
      order:
         path: /order/**
         service-id: order-service

这里以emp开头的请求就会分发给employee-service服务,order开头的请求就会发送给order-service

这里通过service-idZuul会自动实现相同service-id的请求负载均衡。

配置中心

将配置放在一个公共服务里进行维护,这个服务就是配置中心。

Consul

除了作为注册发现服务,Consul提供了K/V存储功能,可以用于配置中心。

添加MAVEN依赖:

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

bootstrap.yml中配置注册中心:

spring:
   application:
      name: my-service
   profiles:
      active: dev	  
   cloud:
      consul:
         host: localhost
         config:
           enabled: true
           prefix: config
           data-key: data
           profileSeparator: '::'
           format: yaml
           watch:
              delay: 30  

按照上面的配置,启动时,默认会读取这几个key中的内容作为yaml格式的配置加载(在上方的具有高优先级):

config/my-service::dev/data
config/my-service/data
config/application::dev/data
config/application/data

这里的key看起来像是目录结构,其实/符号同样是作为key的一部分的。

猜你喜欢

转载自www.cnblogs.com/mosakashaka/p/12609186.html