前言:本篇为 SpringCloud Greenwich版本模拟业务实战系列文章第二篇,上篇文章主要讲了服务治理、高可用安全的服务注册中心,那么本文将对ribbon、hystrix进行介绍,对其如何实现服务负载均衡,以及如何保证服务之间调用资源的隔离、以及发生紧急情况时对服务进行熔断降级操作进行详细讲解
一、组件介绍
1、Ribbon
ribbon是属于Netflix的一款基于客户端http、tcp负载均衡的一个小框架,何为客户端负载均衡,简单理解就是客户端获取了服务注册中心的所有注册数缓存在本地,并定时维护本地缓存的注册数据;客户端发起远程服务请求,则采用一系列的负载均衡策略从本地获取一个服务的地址数据并对其发送网络请求。
我们平常所了解的SpringCloud ribbon则是对Netflix的ribbon进行了一系列的封装,使其无缝对接SpringCloud环境开发,并且能够无缝对接各大主流服务治理框架,如Eureka、Consul等;就比如我们采用RestTemplate结合Ribbon对远程服务进行访问只需要加一个注解@LoadBalanced就可以起到对注册中心的所有服务进行负载均衡的作用,我们根本察觉不到其实他们已经自动整合了,这也归功于SpringCloud对其进行了如此完美的封装。也正因如此,许多入门小白会满头雾水,后续我也会针对SpringCloud各个组件的源码进行一系列的讲解。
2、Hystrix
Hystrix也是Netflix开源的一款,针对服务之间调用限制其可使用的 线程资源 、以及服务调用失败可以调用指定的 降级处理 方法、包括调用的目标服务实例如果不可访问了,会针对设定的熔断阈值(默认调用失败超过50%)对该服务实例进行 熔断处理 ,所有的服务在短期设定的时间内直接返回调用失败,如果设置了降级方法则会调用降级方法。
二、为何使用?
1、为什么要使用ribbon
其实这个问题相信大家已经都明白了,ribbon的主要功能就是客户端负载均衡,并且是对服务注册中心已经注册了的服务进行负载均衡,没有ribbon的话 我们得自己编写一套负载均衡机制,除非你的服务实例是单个的,但是这不太现实!还有 就是后面的feign 也是基于ribbon来进行服务实例的负载均衡调用。
2、为什么要使用hystrix
很简单
1、熔断机制 保证了阻断了不可用的服务,直接响应请求失败,不会再去重重复请求占用资源。
2、资源隔离 可以保证对某个依赖服务进行调用时哪怕请求再多,只耗费属于其的线程资源,并不会影响别的服务的调用。
3、降级策略 可设置服务调用失败后执行的方法。
所以正应为hystrix的强大,才使其成为高可用、稳定、健壮的SpringCloud微服务系统中必不可少的组件之一。
三、ribbon的使用
在使用ribbon之前(这里指SpringCloud 封装过后的ribbon),我们可以先了解一下原始的netfix ribbon大概是如何使用的
看上去还是挺简单的,但是当我们的SpringCloud给ribbon画龙点睛了一下,你会发现只要短短两三行代码,外加两三行配置,就可以无缝对接eureka乃至consul,并且只需要一个注解就可以为注册中心的各个服务进行负载均衡操作!
1、restTemplate + @LoadBalanced 使用ribbon负载均衡调用服务
在之前的 user-server 服务稍作修改,引入restTemplate,restTemplate是spring提供的一个非常强大的调用http rest接口的一款工具,不了解的可以去Google一下,这里不做赘述。
@RestController
@SpringBootApplication
@EnableEurekaClient
public class App {
@Bean
@LoadBalanced //加上此注解增加负载均衡功能,并使其能直接用服务名来进行调用
public RestTemplate restTemplate(){
return new RestTemplate();
}
@Autowired
RestTemplate restTemplate;
@GetMapping("/test")
@ResponseBody
public Object test(){
//使用restTemplate根据服务名调用,默认的restTemplate是没有此功能的
String str = restTemplate.getForObject("http://provider-goods-service/test",String.class);
return str;
}
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}
2、给 goods-server 加上一个测试controller,再复制一个goods-server run,并设置不同启动端口
测试controller
@GetMapping("/test")
@ResponseBody
public Object test(HttpServletRequest request){
return "调用成功 当前服务端口为:"+ request.getServerPort();
}
启动多个 goods-server
启动并查看eureka server是否注册上
3、多次访问 user-server /test 测试地址,查看结果
从请求结果我们可以看出我们的请求已经被负载均衡了。这里并不需要重复引用ribbon的依赖,因为spring-cloud-starter-netflix-eureka-client 已经引入ribbon依赖了。
整个负载均衡请求流程为 (前方高能)
看不太懂的小伙伴别急,先学会如何使用, 后续会有专门的源码讲解篇。
4、配置
--负载均规则略--
上面我们实现了对服务实例进行负载均衡,我们重复进行访问可以发现ribbon默认使用的轮询请求的方式来进行负载均衡,除了轮询请求(RoundRobinRule)外,还有一些其他比较常用的
- RandomRule - 随机选择服务
- WeightedResponseTimeRule 根据响应时间来配置权重,响应最快的权重高,反之则少
- BestAvailableRule 最少请求的服务
--常用配置项-
#针对单个服务配置路由规则,注意 配置的值 需要类全名(包名+类名);
provider-goods-service: #目标服务名
ribbon:
ConnectionTimeout: 400 #链接超时
ReadTimeout: 400 #读取超时
MaxAutoRetries: 1 #重试当前实例的次数
MaxAutoRetriesNextServer: 1 #服务实例切换重试次数
ServerListRefreshInterval: 30000 #刷新所服务列表间隔时间
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule #配置对应的规则,其他ribbon自带的规则 可查看IRule接口的实现类
#ribbon:
# ConnectionTimeout: 400 #链接超时
# ReadTimeout: 400 #读取超时
# MaxAutoRetries: 1 #重试当前实例的次数
# MaxAutoRetriesNextServer: 1 #服务实例切换重试次数
# ServerListRefreshInterval: 30000 #刷新所服务列表间隔时间
设为全局配置只需要把服务名去掉 使ribbon变成顶级配置即可,注意:NFLoadBalancerRuleClassName 在全局配置中无效,全局负载均衡规则配置如下 ⬇️
//针对所有服务配置路由规则,配置config
@Bean
public IRule iRule(){
return new RandomRule();//具体的负载均衡规则类
}
四、Hystrix的使用
1、添加依赖
虽然eureka依赖中也进行hystrix的引用,但是里面的引用在SpringCloud新版本中是无效的,依赖引用如下⬇️
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
2、注解方式使用hystrix、降级回调
- 我们之前的服务调用放到一个service中,创建 GoodsService类
@Service
public class GoodsService {
@Autowired
RestTemplate restTemplate;
@HystrixCommand(fallbackMethod = "testFallback")//服务调用失败后 执行降级回调方法,方法名不需要加括号
public String test(){
return restTemplate.getForObject("http://provider-goods-service/test",String.class);
}
//降级回调方法,返回参数和调用参数需要一致
public String testFallback(){
return "请求失败,此次请求已记录!";
}
}
如果在@HystrixCommand修饰的方法中有多个服务调用的话,任何一个服务的调用发生异常或者产生异常都会触发fallbackMethod的调用,如果触发了某些特定的异常不想触发fallback,则需要指定抛出的特定异常继承HystrixBadRequestException,或者在方法内部对可能抛出的异常进行try掉
- controller改动一下
@Autowired
GoodsService goodsService;
@GetMapping("/test")
@ResponseBody
public Object test(){
String str = goodsService.test();
return str;
}
- 启动类加如下注解 开启hystrix
@EnableCircuitBreaker //开启hystrix
3、hystrix熔断器、资源隔离、其他常用配置项
- 局部配置(方法1),作用于单个 @HystrixCommand 修饰的方法(不太推荐使用)
@HystrixCommand(
fallbackMethod = "testFallback", // 请求失败降级回调方法,值为方法名,不需要括号
commandProperties ={// 针对单个方法的配置
@HystrixProperty(name = "circuitBreaker.enabled", value = "true"),//开启熔断器,可不加默认为true
@HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "50"),//请求错误超过50%,开启熔断器
@HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "10"),//一个周期(十秒)内超过10个请求才进行进行容错率判断
@HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "10000"),//开启熔断器后过10秒再尝试访问
...
})
- 局部配置(方法2),基于hystrix commandKey,和配置文件来配置(推荐使用)
我们把之前@HystrixCommand 里面的配置都去掉,改动结果如下
@HystrixCommand(
commandKey = "testCommand",//为修饰的方法定义一个 commandKey,不设置默认取方法名为commandKey
fallbackMethod = "testFallback"// 请求失败降级回调方法,值为方法名,不需要括号
)
hystrix:
command:
testCommand: #commandKey,配置作用于指定的commandKey
# **********************==》》 常用的熔断器配置 《《==**********************
circuitBreaker:
enabled: true #默认为true,可不用配置
errorThresholdPercentage: 50 #一个监测周期(默认10s),请求失败率超过50%开启熔断器
requestVolumeThreshold: 10 #一个监测周期内,超过10个请求才进行进行容错率判断
sleepWindowInMilliseconds: 10000 #开启熔断器后过10s再尝试访问,默认5s
metrics:
rollingStats:
timeInMilliseconds: 10000 #请求监测周期时长(单位 ms),默认10000
numBuckets: 10 #每个监测周期,分为10个buckets,说白了就是 10秒的监测周期 分为十个buckets,每个buckets 1秒;每过一秒进行一次请求计算
#注意 timeInMilliseconds % numBuckets 必须为0 否则会触发异常
# **********************==》》 常用的资源隔离配置 《《==**********************
execution:
isolation:
strategy: THREAD # THREAD:线程隔离, SEMAPHORE:信号量隔离;默认线程隔离
thread:
timeoutInMilliseconds: 400 #占用线程调用接口的超时时间
interruptOnTimeout: true #占用线程超时 是否中断线程的执行
timeout:
enabled: true #开启超时限制
semaphore:
maxConcurrentRequests: 20 #信号量隔离下才有效,最大的信号量值,可以理解为 最大支持的并发数
fallback:
isolation:
semaphore:
maxConcurrentRequests: 20 #降级回调方法允许的最大调用
- 全局配置,在commandKey同级配置下 添加default的配置
hystrix:
command:
testCommand: #配置作用于指定的commandKey
# 配置项...
default: #配置作用于全局,但是优先级会比指定commandKey 的低
# 配置项...
4、总结
得益于springcloud的功劳才使得我们使用hystrix能够这么方便,当然hystrix的本质是不变的,对于一些大部分常用的功能配置都列出来了,可对实际的业务进行设置并测试;除了这些常用的配置 还有 线程池、请求合并 等配置
- 线程池(ThreadPoolProperties) 一般不太建议随便设置,除非你对自己的实力有 足够的自信,使用默认的配置在百分之八九十的业务场景中是完全没问题的
- 请求合并(CollapserProperties) 这个配置还是比较牛逼的,但是这一块的话除非的业务场景是并发请求量是特别大的可能会用得到,而且都是利弊性的;不过后续也会结合源码一起进行讲解,这样才能对其原理进行更深入的了解
有不足或者疑惑之处欢迎在下方留言~~