SpringCloud入门组件品尝
SpringCloud
1 Feign组件
1.1 基本使用
- 依赖
<!--springcloud整合的openFeign-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
- 开启Feign
@SpringBootApplication
@EnableEurekaClient
// 下面是关键注解
@EnableFeignClients
public class OrderApplication {
public static void main(String[] args) {
SpringApplication.run(OrderApplication.class,args);
}
}
- 编写feign接口
@FeignClient(name = "product-service")
public interface ProductFeignClient {
@GetMapping(value = "/product/{id}")
Product findById(@PathVariable("id") Long id);
}
- 远程调用
Product product = productFeignClient.findById(id);
1.2 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异常
1.3 Feign与Ribbon区别
Ribbon是一个客户端的负载均衡器,Feign是在Ribbon的基础上进行了封装
1.4 日志打印
feign:
client:
config:
service-product:
loggerLevel: FULL
logging:
level:
cn.itcast.order.fegin.ProductFeginClient: debug

2 高并发问题
传统Web服务的线程都是由tomcat统一管理的,这样其实会产生一个巨大的并发故障。

比如这种情况,突然某个接口的访问量占满了线程池,那么这样同时会导致整个服务体系瘫痪,所以我们为此提出了俩种解决方案:
- 线程隔离

每个接口独立线程池,即使某个接口遇到了流量洪水,其他接口一样可以正常访问。
- 服务限流
当某个服务达到访问阈值后直接进行报错,限流操作可以使用Redis嵌Lua脚本进行实现。
- 熔断降级
当下游服务器因为访问压力过大而响应变慢或失败时,上游服务为了保护系统整体的可用性,可以暂时切断对下游服务的调用,这种牺牲局部,保全整体的措施就叫熔断
3 熔断配置
3.1 RestTemplate
- 导入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
- 激活
@SpringBootApplication
@EnableEurekaClient
@EnableCircuitBreaker
public class OrderApplicationRest {
public static void main(String[] args) {
SpringApplication.run(OrderApplicationRest.class,args);
}
}
- 配置降级策略
@GetMapping("/buy/{id}")
@HystrixCommand(fallbackMethod = "orderFallBack")
public Product buy(@PathVariable("id") Long id){
Product product = restTemplate.getForObject("http://product-service/product/1", Product.class);
return product;
}
public Product orderFallBack(Long id){
System.out.println("id: "+ id );
Product product = new Product();
product.setProductName("熔断降级触发");
return product;
}
上面的配置实现了一个简单的熔断反馈方法处理,这种处理在于可以接受参数进行细节处理,但是Hystrix提供了一个全局的熔断降级方案。
@RestController
@RequestMapping("/order")
@DefaultProperties(defaultFallback = "orderFallBack")
public class OrderController {
private RestTemplate restTemplate;
@Autowired
public OrderController(RestTemplate restTemplate){
this.restTemplate = restTemplate;
}
@GetMapping("/buy/{id}")
@HystrixCommand
public Product buy(@PathVariable("id") Long id){
Product product = restTemplate.getForObject("http://product-service/product/1", Product.class);
return product;
}
public Product orderFallBack(){
Product product = new Product();
product.setProductName("统一熔断降级触发");
return product;
}
}
- 设置熔断时间阈值
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 5000 # 设置hystrix的超时时间为5000ms
3.2 Feign
- 引入依赖
开个玩笑,不需要,Feign已经继承了Hystrix
- 实现方法
这里的实现方法其实就是实现了熔断降级方法
@Component
public class ProductFeignClientFallBack implements ProductFeignClient{
@Override
public Product findById(Long id) {
Product product = new Product();
product.setProductName("触发熔断措施");
return product;
}
}
- 配置熔断类
@FeignClient(name = "product-service",fallback = ProductFeignClientFallBack.class)
public interface ProductFeignClient {
@GetMapping(value = "/product/{id}")
Product findById(@PathVariable("id") Long id);
}
3.3 监控
3.3.1 dashboard
- 引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>
- 暴露端口
management:
endpoints:
web:
exposure:
include: '*'
- 访问Web
http://localhost:9002/actuator/hystrix.stream

监控结果如图:

3.3.2 Turbine
在微服务架构体系中,每个服务都需要配置Hystrix DashBoard监控。如果每次只能查看单个实例的监控数据,就需要不断切换监控地址,这显然很不方便。要想看这个系统的Hystrix Dashboard数据就需要用到Hystrix Turbine。Turbine是一个聚合Hystrix 监控数据的工具,他可以将所有相关微服务的Hystrix 监控数据聚合到一起,方便使用。
建议独立工程
- 引入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-turbine</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>
- 开启服务
@SpringBootApplication
@EnableHystrix
@EnableHystrixDashboard
public class TurbineServerApplication {
public static void main(String[] args) {
SpringApplication.run(TurbineServerApplication.class,args);
}
}
- 服务配置
server:
port: 8031
spring:
application:
name: turbine-server
eureka:
client:
service-url:
defaultZone: http://localhost:9000/eureka
instance:
prefer-ip-address: true
turbine:
app-config: order-service
cluster-name-expression: "'default'"
- 数据监控
本方法与 3.3.1 操作类似,所以不再赘述
3.4 断路器
-
Closed:关闭状态(断路器关闭),所有请求都正常访问。代理类维护了最近调用失败的次数,如果某次调用失败,则使失败次数加1 如果最近失败次数超过了在给定时间内允许失败的阈值,则代理类切换到断开(Open)状态。此时代理开启了一个超时时钟,当该时钟超过了该时间,则切换到半断开(Half-Open)状态。该超时时间的设定是给了系统一次机会来修正导致调用失败的错误。
-
Open:打开状态(断路器打开),所有请求都会被降级。Hystix会对请求情况计数,当一定时间内失败请求百分比达到阈值,则触发熔断,断路器会完全关闭。默认失败比例的阈值是50%,请求次数最少不低于20次。
-
Half Open:半开状态,open状态不是永久的,打开后会进入休眠时间(默认是5S)。随后断路器会自动进入半开状态。此时会释放1次请求通过,若这个请求是健康的,则会关闭断路器,否则继续保持打开,再次进行5秒休眠计时。
环境准备:
- 在订单系统中加入逻辑:
判断请求的id:
如果id=1 :正常执行(正常调用微服务)
否则 :抛出异常
2.默认Hystrix中有触发断路器状态转换的阈值
触发熔断的最小请求次数:20
触发熔断的最小失败比率:50%
熔断器开启的时长:5s
3.4.1 配置熔断策略
circuitBreaker.requestVolumeThreshold=5
circuitBreaker.sleepWindowInMilliseconds=10000
circuitBreaker.errorThresholdPercentage=50
解读:
-
requestVolumeThreshold:触发熔断的最小请求次数,默认20
-
errorThresholdPercentage:触发熔断的失败请求最小占比,默认50%
-
sleepWindowInMilliseconds:熔断多少秒后去尝试请求
3.4.2 隔离策略
微服务使用Hystrix熔断器实现了服务的自动降级,让微服务具备自我保护的能力,提升了系统的稳定性,也较好的解决雪崩效应。其使用方式目前支持两种策略:
线程池隔离策略:使用一个线程池来存储当前的请求,线程池对请求作处理,设置任务返回处理超时时间,堆积的请求堆积入线程池队列。这种方式需要为每个依赖的服务申请线程池,有一定的资源消耗,好处是可以应对突发流量(流量洪峰来临时,处理不完可将数据存储到线程池队里慢慢处理)
信号量隔离策略:使用一个原子计数器(或信号量)来记录当前有多少个线程在运行,请求来先判断计数器的数值,若超过设置的最大线程个数则丢弃改类型的新请求,若不超过则执行计数操作请求来计数器+1,请求返回计数器-1。这种方式是严格的控制线程且立即返回模式,无法应对突发流量(流量洪峰来临时,处理的线程超过数量,其他的请求会直接返回,不继续去请求依赖的服务)

- hystrix.command.default.execution.isolation.strategy : 配置隔离策略
ExecutionIsolationStrategy.SEMAPHORE 信号量隔离
ExecutionIsolationStrategy.4.THREAD 线程池隔离 - hystrix.command.default.execution.isolation.maxConcurrentRequests : 最大信号量上限