目录
1 服务调用Feign入门
1.1 Feign简介
1.2 基于Feign的服务调用
1.3 Feign和Ribbon的联系
1.4 负载均衡
2 服务调用Feign高级
2.1 Feign的配置
2.2 请求压缩
2.3 日志级别
2.4 源码分析
3 服务注册与发现总结
3.1 组件的使用方式
3.1.1 注册中心
3.1.2 服务调用
4 微服务架构的高并发问题
4.1 性能工具Jmetter
4.1.1 安装Jmetter
4.1.2 配置Jmetter
4.2 系统负载过高存在的问题
4.2.1 问题分析
4.2.2 线程池的形式实现服务隔离
5 服务熔断Hystrix入门
5.1 服务容错的核心知识
5.1.1 雪崩效应
5.1.2 服务隔离
5.1.3 熔断降级
5.1.4 服务限流
5.2 Hystrix介绍
5.3 Rest实现服务熔断
5.4 Feign实现服务熔断
6 服务熔断Hystrix高级
6.1 Hystrix的监控平台
6.1.1 搭建Hystrix DashBoard监控
编辑
编辑
6.1.2断路器聚合监控Turbine
6.2 熔断器的状态
6.3 熔断器的隔离策略
7 服务熔断Hystrix的替换方案
7.1 替换方案介绍
7.2 Sentinel概述
7.2.1 Sentinel简介
7.2.2 Sentinel与Hystrix的区别Sentinel
7.2.3 迁移方案
7.2.4 名词解释
7.3 Sentinel中的管理控制台
7.3.1 下载启动控制台
7.3.2 客户端能接入控制台
7.3.3 查看机器列表以及健康情况
7.4 基于Sentinel的服务保护
7.4.2 Rest实现熔断
7.4.3 Feign实现熔断
@GetMapping("/buy/{id}")
public Product order() {
Product product = restTemplate.getForObject("http://shop-service-product/product/1",Product.class);
return product;
}
org.springframework.cloud
spring-cloud-starter-openfeign
@SpringBootApplication
@EntityScan("cn.awen.order.entity")
//激活Feign
@EnableFeignClients
public class OrderApplication {
public static void main(String[] args) {
SpringApplication.run(OrderApplication.class,args);
}
}
(3)启动类激活FeignClient
/**
* 声明需要调用的微服务名称
* @FeignClient
* * name : 服务提供者的名称
*/
@FeignClient(name="service-product")
public interface ProductFeignClient {
/**
* 配置需要调用的微服务接口
*/
@RequestMapping(value="/product/{id}",method = RequestMethod.GET)
public Product findById(@PathVariable("id") Long id);
}
(4)配置请求提供者的调用接口
@RestController
@RequestMapping("/order")
public class OrderController {
@Autowired
private ProductFeignClient productFeignClient;
/**
*/
@RequestMapping(value = "/buy/{id}",method = RequestMethod.GET)
public Product findById(@PathVariable Long id) {
Product product = null;
product = productFeignClient.findById(id);
return product;
}
}
feign:
compression:
request: enabled: true # 开启请求压缩
mime-types: text/html,application/xml,application/json # 设置压缩的数据类型
min-request-size: 2048 # 设置触发压缩的大小下限
response: enabled: true # 开启响应压缩
#配置feign日志的输出
#日志配置 NONE : 不输出日志(高) BASIC: 适用于生产环境追踪问题
#HEADERS : 在BASIC的基础上,记录请求和响应头信息 FULL : 记录所有
feign:
client:
config:
service-product: #需要调用的服务名称
loggerLevel: FULL
logging:
level:
cn.itcast.order.feign.ProductFeignClient: debug
com.netflix.hystrix
hystrix-metrics-event-stream
1.5.12
com.netflix.hystrix
hystrix-javanica
1.5.12
(2)配置线程池
package cn.itcast.order.command;
import cn.itcast.order.entity.Product;
import com.netflix.hystrix.*;
import org.springframework.web.client.RestTemplate;
public class OrderCommand extends HystrixCommand {
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 {
System.out.println(Thread.currentThread().getName());
return restTemplate.getForObject("http://127.0.0.1/product/"+id, Product.class);
}
/**
* 降级方法
*/
@Override
protected Product getFallback(){
Product product = new Product();
product.setProductName("不好意思,出错了");
return product;
}
}
/**
* 使用OrderCommand调用远程服务
*/
@RequestMapping(value = "/buy/{id}",method = RequestMethod.GET)
public Product findById(@PathVariable Long id) {
return new OrderCommand(restTemplate,id).execute();
}
在微服务架构中,一个请求需要调用多个服务是非常常见的。如客户端访问A服务,而A服务需要调用B服务,B服务需要调用C服务,由于网络原因或者自身的原因,如果B服务或者C服务不能及时响应,A服务将处于阻塞状态,直到B服务C服务响应。此时若有大量的请求涌入,容器的线程资源会被消耗完毕,导致服务瘫痪。服务与服务之间的依赖性,故障会传播,造成连锁反应,会对整个微服务系统造成灾难性的严重后果,这就是服务故障的“雪崩”效应。
熔断这一概念来源于电子工程中的断路器(Circuit Breaker)。在互联网系统中,当下游服务因访问压力过大而响应变慢或失败,上游服务为了保护系统整体的可用性,可以暂时切断对下游服务的调用。这种牺牲局部,保全整体的措施就叫做熔断。所谓降级,就是当某个服务熔断之后,服务器将不再被调用,此时客户端可以自己准备一个本地的fallback回调,返回一个缺省值。 也可以理解为兜底。
org.springframework.cloud
spring-cloud-starter-netflix-hystrix
@SpringBootApplication
//激活hystrix
@EnableCircuitBreaker
@EntityScan("cn.itcast.order.entity")
public class RestOrderApplication {
@LoadBalanced
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
public static void main(String[] args) {
SpringApplication.run(RestOrderApplication.class,args);
}
}
@RestController
@RequestMapping("/order")
/**
* @DefaultProperties : 指定此接口中公共的熔断设置
* 如果过在@DefaultProperties指定了公共的降级方法
* 在@HystrixCommand不需要单独指定了
*/
//@DefaultProperties(defaultFallback = "defaultFallBack")
public class OrderController {
@Autowired
private RestTemplate restTemplate;
/**
* 使用注解配置熔断保护
* fallbackmethod : 配置熔断之后的降级方法
*/
@HystrixCommand(fallbackMethod = "orderFallBack")
@RequestMapping(value = "/buy/{id}",method = RequestMethod.GET)
public Product findById(@PathVariable Long id) {
if(id != 1) {
throw new RuntimeException("服务器异常");
}
return restTemplate.getForObject("http://service-product/product/1",Product.class);
}
/**
* 降级方法
* 和需要收到保护的方法的返回值一致
* 方法参数一致
*/
public Product orderFallBack(Long id) {
Product product = new Product();
product.setProductName("触发降级方法");
return product;
}
}
@RestController
@RequestMapping("/order")
/**
* @DefaultProperties : 指定此接口中公共的熔断设置
* 如果过在@DefaultProperties指定了公共的降级方法
* 在@HystrixCommand不需要单独指定了
*/
//@DefaultProperties(defaultFallback = "defaultFallBack")
public class OrderController {
@Autowired
private RestTemplate restTemplate;
/**
* 使用注解配置熔断保护
* fallbackmethod : 配置熔断之后的降级方法
*/
@HystrixCommand(fallbackMethod = "orderFallBack")
@RequestMapping(value = "/buy/{id}",method = RequestMethod.GET)
public Product findById(@PathVariable Long id) {
if(id != 1) {
throw new RuntimeException("服务器异常");
}
return restTemplate.getForObject("http://service-product/product/1",Product.class);
}
/**
* 指定统一的降级方法
* * 参数 : 没有参数
*/
public Product defaultFallBack() {
Product product = new Product();
product.setProductName("触发统一的降级方法");
return product;
}
}
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 3000 #默认的连接超时时间1秒,若1秒没有返回数据,自动的触发降级逻辑
org.springframework.cloud
spring-cloud-starter-netflix-hystrix
feign:
#开启对hystrix的支持
hystrix:
enabled: true
@Component
public class ProductFeignClientCallBack implements ProductFeignClient {
/**
* 熔断降级的方法
*/
public Product findById(Long id) {
Product product = new Product();
product.setProductName("feign调用触发熔断降级方法");
return product;
}
}
/**
* 声明需要调用的微服务名称
* @FeignClient
* * name : 服务提供者的名称
* * fallback : 配置熔断发生降级方法
* 实现类
*/
@FeignClient(name="service-product",fallback = ProductFeignClientCallBack.class)
public interface ProductFeignClient {
/**
* 配置需要调用的微服务接口
*/
@RequestMapping(value="/product/{id}",method = RequestMethod.GET)
public Product findById(@PathVariable("id") Long id);
}
org.springframework.boot
spring-boot-starter-actuator
org.springframework.cloud
spring-cloud-starter-netflix-hystrix
//激活hystrix
@EnableCircuitBreaker
#暴露所有端点
management:
endpoints:
web:
exposure:
include: '*'
org.springframework.cloud
spring-cloud-starter-netflix-hystrix
org.springframework.cloud
spring-cloud-starter-netflix-hystrix-dashboard
//激活hystrix
@EnableCircuitBreaker
//激活hytrix的web监控平台
@EnableHystrixDashboard
http://localhost:9003/hystrix
输入监控断点展示监控的详细数据:
http://localhost:9003/actuator/hystrix.stream
在微服务架构体系中,每个服务都需要配置Hystrix DashBoard监控。如果每次只能查看单个实例的监控数据,就需要不断切换监控地址,这显然很不方便。要想看这个系统的Hystrix Dashboard数据就需要用到Hystrix Turbine。Turbine是一个聚合Hystrix 监控数据的工具,他可以将所有相关微服务的 Hystrix 监控数据聚合到一起,方便使用。引入Turbine后,整个监控系统架构如下:
org.springframework.cloud
spring-cloud-starter-netflix-turbine
org.springframework.cloud
spring-cloud-starter-netflix-hystrix
org.springframework.cloud
spring-cloud-starter-netflix-hystrix-dashboard
server:
port: 8031
spring:
application:
name: hystrix-turbine
eureka:
client:
service-url:
defaultZone: http://localhost:9000/eureka/
instance:
prefer-ip-address: true
turbine:
# 要监控的微服务列表,多个用,分隔
appConfig: service-order
clusterNameExpression: "'default'"
@SpringBootApplication
//trubin配置
@EnableTurbine
@EnableHystrixDashboard
public class TurbinAppliation {
public static void main(String[] args) {
SpringApplication.run(TurbinAppliation.class,args);
}
}
熔断器有三个状态 CLOSED 、 OPEN 、 HALF_OPEN 熔断器默认关闭状态,当触发熔断后状态变更为OPEN ,在等待到指定的时间,Hystrix会放请求检测服务是否开启,这期间熔断器会变为 HALF_OPEN 半开启状态,熔断探测服务可用则继续变更为 CLOSED 关闭熔断器。
@Autowired
private RestTemplate restTemplate;
/**
* 使用注解配置熔断保护
* fallbackmethod : 配置熔断之后的降级方法
*/
@HystrixCommand(fallbackMethod = "orderFallBack")
@RequestMapping(value = "/buy/{id}",method = RequestMethod.GET)
public Product findById(@PathVariable Long id) {
if(id != 1) {
throw new RuntimeException("服务器异常");
}
return restTemplate.getForObject("http://service-product/product/1",Product.class);
}
这样如果参数是 id 为 1 ,一定失败,其它情况都成功。
hystrix:
command:
default:
circuitBreaker:
requestVolumeThreshold: 5 #触发熔断的最小请求次数,默认20 /10秒
sleepWindowInMilliseconds: 10000 #熔断多少秒后去尝试请求 默认 5 打开状态的时间
errorThresholdPercentage: 50 #触发熔断的失败请求最小占比,默认50%
hystrix:
command:
default:
execution:
isolation:
strategy: ExecutionIsolationStrategy.SEMAPHORE #信号量隔离
#strategy: # ExecutionIsolationStrategy.THREAD 线程池隔离
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)进行整合。
随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel 以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。
Sentinel 具有以下特征:
java -Dserver.port=8080 -Dcsp.sentinel.dashboard.server=localhost:8080 - Dproject.name=sentinel-dashboard -jar sentinel-dashboard.jar
com.alibaba.cloud
spring-cloud-alibaba-dependencies
2.1.0.RELEASE
pom
import
com.alibaba.cloud
spring-cloud-starter-alibaba-sentinel
spring:
cloud:
sentinel:
transport:
dashboard: localhost:8080 #sentinel控制台的请求地址
Spring Cloud Alibaba Sentinel 支持对 RestTemplate 的服务调用使用 Sentinel 进行保护,在构造RestTemplate bean的时候需要加上 @SentinelRestTemplate 注解。
public class ExceptionUtils {
/**
* 静态方法
* 返回值: SentinelClientHttpResponse
* 参数 : request , byte[] , clientRquestExcetion , blockException
*/
//限流熔断业务逻辑
public static SentinelClientHttpResponse handleBlock(HttpRequest request, byte[] body, ClientHttpRequestExecution execution, BlockException ex) {
return new SentinelClientHttpResponse("abc");
}
//异常降级业务逻辑
public static SentinelClientHttpResponse handleFallback(HttpRequest request, byte[] body,
ClientHttpRequestExecution execution, BlockException ex) {
return new SentinelClientHttpResponse("def");
}
}
com.alibaba.cloud
spring-cloud-starter-alibaba-sentinel
org.springframework.cloud
spring-cloud-starter-openfeign
#激活sentinel的支持
feign:
sentinel:
enabled: true
/**
* 声明需要调用的微服务名称
* @FeignClient
* * name : 服务提供者的名称
* * fallback : 配置熔断发生降级方法
* 实现类
*/
@FeignClient(name="service-product",fallback = ProductFeignClientCallBack.class)
public interface ProductFeignClient {
/**
* 配置需要调用的微服务接口
*/
@RequestMapping(value="/product/{id}",method = RequestMethod.GET)
public Product findById(@PathVariable("id") Long id);
}
@Component
public class ProductFeignClientCallBack implements ProductFeignClient {
/**
* 熔断降级的方法
*/
public Product findById(Long id) {
Product product = new Product();
product.setProductName("feign调用触发熔断降级方法");
return product;
}
}