SpringCloud Day2

1 服务调用Feign入门

1.1 Feign简介

Feign是Netflix开发的声明式,模板化的HTTP客户端,其灵感来自Retrofit,JAXRS-2.0以及WebSocket.

  • Feign可帮助我们更加便捷,优雅的调用HTTP API。
  • 在SpringCloud中,使用Feign非常简单——创建一个接口,并在接口上添加一些注解,代码就完 成了。
  • Feign支持多种注解,例如Feign自带的注解或者JAX-RS注解等。
  • SpringCloud对Feign进行了增强,使Feign支持了SpringMVC注解,并整合了Ribbon和Eureka,
    从而让Feign的使用更加方便。

1.2 基于Feign的服务调用

首先我们需要有基础的eureka服务 消费者和服务提供者 可以参考day的springcloud代码

1.2.1 引入依赖

在消费者端引入依赖(order)

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

1.2.2 编写feign接口

写一个接口 配置参照如下

//这个name填写的值为 服务端的spring.application.name 属性
@FeignClient(name = "service-product")
public interface ProductFeignClient {
//    配置调用的接口
    @RequestMapping(value = "/product/{id}" ,method = RequestMethod.GET)
    public Product findById(@PathVariable("id") Long id);
}

1.2.3 在启动类上激活feign

可以删除启动类的RestTemplate的bean

@SpringBootApplication
@EntityScan("cn.itcast.order.entity")
//激活eurekaClient
@EnableEurekaClient
//激活Feign
@EnableFeignClients
public class OrderApplication {。。。}

1.2.4 编写接口

//这个name填写的值为 服务端的spring.application.name 属性
@FeignClient(name = "service-product")
public interface ProductFeignClient {
    // 配置调用的接口  对应的是product的服务接口
    @RequestMapping(value = "/product/{id}", method = RequestMethod.GET)
    Product findById(@PathVariable("id") Long id);
}

1.2.5 调用接口

@RestController
@RequestMapping("/order")
public class OrderController {
//自动注入ProductFeignClient接口  会自动去调用它 
    @Autowired
    ProductFeignClient productFeignClient;

    @RequestMapping(value = "/buy/{id}", method = RequestMethod.GET)
    public Product findById(@PathVariable Long id) {
        //定义一个Product类
        Product product = null;
        product = productFeignClient.findById(id);
        return product;
    }
}

直接访问地址 即可实现调用 http://localhost:9002/order/buy/1 以上操作都是消费者端进行

1.4 Feign的负载均衡

默认为轮询
Feign中本身已经集成了Ribbon依赖和自动配置,因此我们不需要额外引入依赖,也不需要再注册
RestTemplate 对象。另外,我们可以像上节课中讲的那样去配置Ribbon,可以通过 ribbon.xx 来进
行全局配置。也可以通过 服务名.ribbon.xx 来对指定服务配置:
参考day1的修改方法

2 服务调用Feign高级

2.1 Feign的配置

从Spring Cloud Edgware开始,Feign支持使用属性自定义Feign。对于一个指定名称的Feign
Client(例如该Feign Client的名称为 feignName ),Feign支持如下配置项:

feign:
	client:
		config:
			feignName: ##定义FeginClient的名称
				connectTimeout: 5000 # 相当于Request.Options
				readTimeout: 5000 # 相当于Request.Options
				# 配置Feign的日志级别,相当于代码配置方式中的Logger
				loggerLevel: full
				# Feign的错误解码器,相当于代码配置方式中的ErrorDecoder
				errorDecoder: com.example.SimpleErrorDecoder
				# 配置重试,相当于代码配置方式中的Retryer
				retryer: com.example.SimpleRetryer
				# 配置拦截器,相当于代码配置方式中的RequestInterceptor
				requestInterceptors:
					- com.example.FooRequestInterceptor
					- com.example.BarRequestInterceptor
				decode404: false

feignName:FeginClient的名称
connectTimeout : 建立链接的超时时长
readTimeout : 读取超时时长
loggerLevel: Fegin的日志级别
errorDecoder :Feign的错误解码器
retryer : 配置重试
requestInterceptors : 添加请求拦截器
decode404 : 配置熔断不处理404异常

2.2 请求压缩

3 服务注册与发现总结

在这里插入图片描述

4 微服务架构的高并发问题

使用 性能工具Jmetter来摸你高并发

4.2 系统负载过高存在的问题

4.2.1 问题分析

在微服务架构中,我们将业务拆分成一个个的服务,服务与服务之间可以相互调用,由于网络原因或者
自身的原因,服务并不能保证服务的100%可用,如果单个服务出现问题,调用这个服务就会出现网络
延迟,此时若有大量的网络涌入,会形成任务累计,导致服务瘫痪。

在SpringBoot程序中,默认使用内置tomcat作为web服务器。单tomcat支持最大的并发请求是有限
的,如果某一接口阻塞,待执行的任务积压越来越多,那么势必会影响其他接口的调用。

4.2.2 线程池的形式实现服务隔离

首先在消费者端引入坐标

<!--引入hystrix的坐标-->
        <dependency>
            <groupId>com.netflix.hystrix</groupId>
            <artifactId>hystrix-metrics-event-stream</artifactId>
            <version>1.5.12</version>
        </dependency>
        <dependency>
            <groupId>com.netflix.hystrix</groupId>
            <artifactId>hystrix-javanica</artifactId>
            <version>1.5.12</version>
        </dependency>

然后创建一个类 并且继承HystrixCommand< T >类
如下


public class OrderCommand extends HystrixCommand< Product > {

	private RestTemplate restTemplate;
	
	private Long id;

	public OrderCommand(RestTemplate restTemplate, Long id) {
		super(setter());
		this.restTemplate = restTemplate;
		this.id = id;
	}

	private static Setter setter() {

		// 服务分组
		HystrixCommandGroupKey groupKey = HystrixCommandGroupKey.Factory.asKey("order_product");
		// 服务标识
		HystrixCommandKey commandKey = HystrixCommandKey.Factory.asKey("product");
		// 线程池名称
		HystrixThreadPoolKey threadPoolKey = HystrixThreadPoolKey.Factory.asKey("order_product_pool");
		/**
		 * 线程池配置
		 *     withCoreSize :  线程池大小为10
		 *     withKeepAliveTimeMinutes:  线程存活时间15秒
		 *     withQueueSizeRejectionThreshold  :队列等待的阈值为100,超过100执行拒绝策略
		 */
		HystrixThreadPoolProperties.Setter threadPoolProperties = HystrixThreadPoolProperties.Setter().withCoreSize(50)
				.withKeepAliveTimeMinutes(15).withQueueSizeRejectionThreshold(100);

		// 命令属性配置Hystrix 开启超时
		HystrixCommandProperties.Setter commandProperties = HystrixCommandProperties.Setter()
				// 采用线程池方式实现服务隔离
				.withExecutionIsolationStrategy(HystrixCommandProperties.ExecutionIsolationStrategy.THREAD)
				// 禁止
				.withExecutionTimeoutEnabled(false);
		return Setter.withGroupKey(groupKey).andCommandKey(commandKey).andThreadPoolKey(threadPoolKey)
				.andThreadPoolPropertiesDefaults(threadPoolProperties).andCommandPropertiesDefaults(commandProperties);

	}

	@Override
	protected Product run() throws Exception {
		return restTemplate.getForObject("http://127.0.0.1:9001/product/"+id, Product.class);
	}

//	这个函数是如果出错了就会执行这个
	@Override
	protected Product getFallback(){
		Product product = new Product();
		product.setProductName("出错了");
		return product;
	}
}

改造controller层

@RestController
@RequestMapping("/order")
public class OrderController {

	@Autowired
	RestTemplate restTemplate;

	/**
	 */
	@RequestMapping(value = "/buy/{id}",method = RequestMethod.GET)
	public Product findById(@PathVariable Long id) {
	//用OrderCommand来调用方法
		return new OrderCommand(restTemplate,id).execute();
	}


}

5 服务熔断Hystrix入门

5.1 服务容错的核心知识

5.1.1 雪崩效应

在微服务架构中,一个请求需要调用多个服务是非常常见的。如客户端访问A服务,而A服务需要调用B
服务,B服务需要调用C服务,由于网络原因或者自身的原因,如果B服务或者C服务不能及时响应,A服
务将处于阻塞状态,直到B服务C服务响应。此时若有大量的请求涌入,容器的线程资源会被消耗完毕,
导致服务瘫痪。服务与服务之间的依赖性,故障会传播,造成连锁反应,会对整个微服务系统造成灾难
性的严重后果,这就是服务故障的“雪崩”效应
在这里插入图片描述

5.1.3 熔断降级

熔断这一概念来源于电子工程中的断路器(Circuit Breaker)。在互联网系统中,当下游服务因访问压
力过大而响应变慢或失败,上游服务为了保护系统整体的可用性,可以暂时切断对下游服务的调用。这
种牺牲局部,保全整体的措施就叫做熔断。

5.1.4 服务限流

限流可以认为服务降级的一种,限流就是限制系统的输入和输出流量已达到保护系统的目的。一般来说
系统的吞吐量是可以被测算的,为了保证系统的稳固运行,一旦达到的需要限制的阈值,就需要限制流
量并采取少量措施以完成限制流量的目的。比方:推迟解决,拒绝解决,或者者部分拒绝解决等等。

5.3 Rest实现服务熔断

(1)复制 shop_service_order 项目并命名为 shop_service_order_rest_hystrix(消费者)
(2)配置依赖

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

(3)开启熔断

在消费者的启动类上添加 @EnableCircuitBreaker 注解

(4)编写一个方法用于触发保护的方法

   /**
     * 降级方法
     * 返回值需要和受保护的方法返回值一样
     */
    public Product orderFallBack( Long id) {
        Product product = new Product();
        product.setProductName("触发降级保护");
        return product;
    }

(5)在需要保护的请求上添加@HystrixCommand注解 并设置fallbackMethod属性 属性值为自己定义的方法名


    @HystrixCommand(fallbackMethod = "orderFallBack")
    @RequestMapping(value = "/buy/{id}",method = RequestMethod.GET)
    public Product findById(@PathVariable Long id) {
        return new OrderCommand(restTemplate,id).execute();
    }
相应时间超过一秒就会触发保护如何设置   如下配置可设置成2秒触发
hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 2000 

如何配置全局的保护方法
首先创建一个方法 不能有参数

在对应的类上添加@DefaultProperties(defaultFallback = “defaultFallBack”)注解
属性值为自己定义的方法名

@RestController
@RequestMapping("/order")
@DefaultProperties(defaultFallback = "defaultFallBack")
public class OrderController {
    //注入restTemplate对象
    @Autowired
    private RestTemplate restTemplate;

    /**
     * 注入DiscoveryClient
     * springcloud获取元数据的工具类
     */
    @Autowired
    private DiscoveryClient discoveryClient;

    /**
     * 基于ribbon的形式调用远程微服务
     * 1.使用@LoadBalanced声明RestTemplate
     * 2.使用服务名称替换ip地址
     */
    @RequestMapping(value = "/buy/{id}",method = RequestMethod.GET)
    public Product findById(@PathVariable Long id) {
        return new OrderCommand(restTemplate,id).execute();
    }



    /**
     * 公共降级方法
     * 返回值需要和受保护的方法返回值一样
     */
    public Product defaultFallBack() {
        Product product = new Product();
        product.setProductName("触发降级保护");
        return product;
    }
    
    /**
     * 降级方法
     * 返回值需要和受保护的方法返回值一样
     */
    public Product orderFallBack( Long id) {
        Product product = new Product();
        product.setProductName("触发降级保护");
        return product;
    }

}

5.4 Feign实现服务熔断

SpringCloud Fegin默认已为Feign整合了hystrix,所以添加Feign依赖后就不用在添加hystrix,那么怎
么才能让Feign的熔断机制生效呢,只要按以下步骤开发:
(1)复制 shop_service_order 项目并命名为 shop_service_order_feign_hystrix
(2)修改application.yml在Fegin中开启hystrix
在Feign中已经内置了hystrix,但是默认是关闭的需要在工程的 application.yml 中开启对hystrix的
支持

feign:
 hystrix: #在feign中开启hystrix熔断
  enabled: true

(3)配置FeignClient接口的实现类
基于Feign实现熔断降级,那么降级方法需要配置到FeignClient接口的实现类中

@Component
public class ProductFeginClientCallBack implements ProductFeginClient {
/**
* 降级方法
*/
public Product findById(Long id) {
Product product = new Product();
product.setId(-1l);
product.setProductName("熔断:触发降级方法");
return product;
}
}

(4)修改FeignClient添加hystrix熔断
在@FeignClient注解中添加降级方法

@FeignClient(name="shop-service-product",fallback =ProductFeginClientCallBack.class)

fallback 属性是他的实现类

7 服务熔断Hystrix的替换方案

18年底Netflix官方宣布Hystrix 已经足够稳定,不再积极开发 Hystrix,该项目将处于维护模式。就目前
来看Hystrix是比较稳定的,并且Hystrix只是停止开发新的版本,并不是完全停止维护,Bug什么的依
然会维护的。因此短期内,Hystrix依然是继续使用的。但从长远来看,Hystrix总会达到它的生命周
期,那么Spring Cloud生态中是否有替代产品呢?

7.1 替换方案介绍

Alibaba Sentinel
Sentinel 是阿里巴巴开源的一款断路器实现,目前在Spring Cloud的孵化器项目Spring Cloud Alibaba
中的一员Sentinel本身在阿里内部已经被大规模采用,非常稳定。因此可以作为一个较好的替代品。
Resilience4J
Resilicence4J 一款非常轻量、简单,并且文档非常清晰、丰富的熔断工具,这也是Hystrix官方推荐的
替代产品。不仅如此,Resilicence4j还原生支持Spring Boot 1.x/2.x,而且监控也不像Hystrix一样弄
Dashboard/Hystrix等一堆轮子,而是支持和Micrometer(Pivotal开源的监控门面,Spring Boot 2.x
中的Actuator就是基于Micrometer的)、prometheus(开源监控系统,来自谷歌的论文)、以及
Dropwizard metrics(Spring Boot曾经的模仿对象,类似于Spring Boot)进行整合。

7.2 Sentinel概述

7.2.2 Sentinel与Hystrix的区别

在这里插入图片描述

7.2.4 名词解释

在这里插入图片描述

7.3 Sentinel中的管理控制台

(1)获取 Sentinel 控制台
可以从官方网站中下载最新版本的控制台 jar 包,下载地址如下:
https://github.com/alibaba/Sentinel/releases/download/1.6.3/sentinel-dashboard-1.6.3.jar
(2)启动
使用如下命令启动控制台:

java -Dserver.port=8080 -Dcsp.sentinel.dashboard.server=localhost:8080 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.6.3.jar

在这里插入图片描述

7.3.2 客户端能接入控制台

首先拥有基本的eureka注册中心 服务消费者和服务提供者 服务消费者 一个基于普通的rest一个基于feign

(1)首先在父工程中引用依赖

<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2.1.0.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>

然后子工程 (消费者)

<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>

(2)在子工程中添加Sentinel的地址

spring:
  cloud:
    sentinel:
      transport:
        dashboard: localhost:8080 #设置Sentinel的地址

(3) 配置熔断降级方法

@RestController
@RequestMapping("/order")
public class OrderController {
    @Autowired
    ProductFeignClient productFeignClient;

    @Autowired
    RestTemplate restTemplate;

    @GetMapping("/buy/{id}")
    @SentinelResource(value = "order", blockHandler = "orderblockHandler", fallback
            = "orderfallback")
    //blockHandler 属性设置熔断后的方法
    //fallback 属性设置异常后的方法
    public Product order(@PathVariable Long id) {
        return restTemplate.getForObject("http://shop-serviceproduct/product/1", Product.class);
    }

    //降级方法
    public Product orderblockHandler(Long id) {
        Product product = new Product();
        product.setId(-1l);
        product.setProductName("触发熔断降级方法");
        return product;
    }

    //降级方法
    public Product orderfallback(Long id) {
        Product product = new Product();
        product.setId(-1l);
        product.setProductName("触发抛出异常方法");
        return product;
    }

}

在需要被保护的方法上使用@SentinelResource注解进行熔断配置。与Hystrix不同的是,Sentinel对抛
出异常和熔断降级做了更加细致的区分,通过 blockHandler 指定熔断降级方法,通过 fallback 指定
触发异常执行的降级方法。对于@SentinelResource的其他配置如下表:
在这里插入图片描述
在这里插入图片描述
特别地,若 blockHandler 和 fallback 都进行了配置,则被限流降级而抛出 BlockException 时只会
进入 blockHandler 处理逻辑。若未配置 blockHandler 、 fallback 和 defaultFallback ,则被
限流降级时会将 BlockException 直接抛出

7.4.2 Rest实现熔断

Spring Cloud Alibaba Sentinel 支持对 RestTemplate 的服务调用使用 Sentinel 进行保护,在构造
RestTemplate bean的时候需要加上 @SentinelRestTemplate 注解。

@Bean
@LoadBalanced
@SentinelRestTemplate(fallback = "handleFallback", fallbackClass =
ExceptionUtil.class,
blockHandler="handleBlock",blockHandlerClass=ExceptionUtil.class)
public RestTemplate getRestTemplate() {
return new RestTemplate();
}

在这里插入图片描述
比如上述 @SentinelRestTemplate 注解中 ExceptionUtil 的 handleException 属性对应的方法
声明如下:

/**
* 熔断降级
*/
public class ExceptionUtil {
//限流熔断业务逻辑
public static SentinelClientHttpResponse handleBlock(HttpRequest request,
byte[] body,
ClientHttpRequestExecution
execution, BlockException ex) {
System.err.println("Oops: " + ex.getClass().getCanonicalName());
return new SentinelClientHttpResponse("限流熔断降级");
}
//异常熔断业务逻辑
public static SentinelClientHttpResponse handleFallback(HttpRequest
request, byte[] body,
ClientHttpRequestExecution
execution, BlockException ex) {
System.err.println("fallback: " + ex.getClass().getCanonicalName());
return new SentinelClientHttpResponse("异常熔断降级");
}
}

在这里插入图片描述

7.4.3 Feign实现熔断

Sentinel 适配了 Feign 组件。如果想使用,除了引入 sentinel-starter 的依赖外还需要 2 个步骤:
配置文件打开 sentinel 对 feign 的支持: feign.sentinel.enabled=true
加入 openfeign starter 依赖使 sentinel starter 中的自动化配置类生效:

(1) 引入依赖

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

(2) 开启sentinel 支持
在工程的application.yml中添加sentinel 对 feign 的支持

feign:
	sentinel:
		enabled: true

(3)配置FeignClient

//指定需要调用的微服务名称
@FeignClient(name="shop-service-product",fallback =
ProductFeginClientCallBack.class)
public interface ProductFeginClient {
//调用的请求路径
@RequestMapping(value = "/product/{id}",method = RequestMethod.GET)
public Product findById(@PathVariable("id") Long id);
}

(4)配置熔断方法

/**
* 实现自定义的ProductFeginClient接口
* 在接口实现类中编写熔断降级方法
*/
@Component
public class ProductFeginClientCallBack implements ProductFeginClient {
/**
* 降级方法
*/
public Product findById(Long id) {
Product product = new Product();
product.setId(-1l);
product.setProductName("熔断:触发降级方法");
return product;
}
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值