网站建设 开发网站关键词免费优化
目录
隔离和降级
FeignClient整合Sentinel
通过Feign设置服务降级
1.创建类实现FallbackFactory接口,并让这个类和使用@FeignClient的接口类绑定
2.让order-service服务的feign开启sentinel
3.测试,只开启order-service服务,而不开启user-order服务
总结:
线程隔离
线程隔离的实现方式
sentinel的线程隔离
1)配置隔离规则
2)jemter测试
总结
隔离和降级
虽然限流可以尽量避免因高并发而引起的服务故障,但服务还是会因为某些原因(服务自己出现问题)而故障。而要将这些故障控制在一定范围内,避免雪崩,就要靠线程隔离(舱壁模式)和熔断降级手段了
线程隔离就是:调用者在调用服务提供者时,给每个调用的请求分配独立线程池,出现故障时,最多消耗这个线程池内资源,避免把调用者的所有资源耗尽。
可以看到下图,我们已经规定了访问其他服务可以使用的最大线程数为10个,服务C出现问题,就只会有10个线程无法使用,而不会导致服务A中的所有线程都不可用,导致线程A宕机。
熔断降级:是在调用方这边加入断路器,统计对服务提供者的调用,如果调用的失败比例过高,则熔断该业务,不允许访问该服务的提供者了。
由下图可以看到,当服务A向服务D由两个请求都出现异常时,在服务A和服务D之间就会出现一道熔断墙,阻止服务A的其他请求向服务D(直接报错,抛异常)
我们发现不能处理的请求都是直接抛异常,终止请求,我们可以设置降级服务
如:如果访问queryById接口失败,就去访问queryByIdFalback接口作为备选
FeignClient整合Sentinel
SpringCloud中,微服务调用都是通过Feign来实现的,因此做客户端保护必须整合Feign和Sentinel。
通过Feign设置服务降级
在orderService微服务中会使用UserFeignClient去访问用户的信息
我们需要给UserFiegnClient的方法设置服务降级
User user = userFeignClient.queryById(order.getUserId());
1.创建类实现FallbackFactory接口,并让这个类和使用@FeignClient的接口类绑定
不要导错包 ,是feign.hystrix.FallbackFactory包下的FallbackFactory
import feign.hystrix.FallbackFactory;
//直接加@Component不能被启动类扫描到,因为与启动类不在同一个包
public class UserFeignClientFallbackFactory implements FallbackFactory<UserFeignClient> {//cause为远程调用UserFeignClient时出现的异常@Overridepublic UserFeignClient create(Throwable cause) {cause.printStackTrace();return new UserFeignClient() {
//重写UserFeign的所有方法,作为服务降级的备选处理方法@Overridepublic User queryById(Long id) {//设置默认用户信息User user = new User();user.setId(null);user.setAddress(null);user.setUsername("默认用户");return user;}@Overridepublic String getUser(String username, Integer age) {return "没有这个用户";}};}
}
维护到IoC容器中
@Beanpublic UserFeignClientFallbackFactory userFeignClientFallbackFactory(){return new UserFeignClientFallbackFactory();}
让UserFeignClient与UserFeignClientFallbackFactory绑定服务降级
//与FallbackFactory绑定降级服务
@FeignClient(value = "user-service",configuration = FeignConfig.class,fallbackFactory = UserFeignClientFallbackFactory.class)
public interface UserFeignClient {@RequestMapping("/user/{id}")//使用Get方式发送请求,获取到的响应数据反序列化成User类型User queryById(@PathVariable("id")Long id);//这里是把方法参数放到请求路径中,与controller相反@RequestMapping("/user/getUser")//使用@RequestParam注解让Feign知道这两个请求参数值是要加到url地址中的String getUser(@RequestParam("username") String username, @RequestParam("age") Integer age);
}
2.让order-service服务的feign开启sentinel
feign:httpclient:enabled: true # 开启feign对HttpClient的支持max-connections: 200 # 最大的连接数max-connections-per-route: 50 # 每个路径的最大连接数sentinel:enabled: true #与sentinel整合,开启服务降级
3.测试,只开启order-service服务,而不开启user-order服务
如果我们之前没有编写服务降级,就会直接报错,查不到用户信息,但是我们已经开启的服务降级
访问接口,返回的用户信息是我们设置的默认用户信心,服务降级成功
总结:
Feign整合Sentinel的步骤:
- 在application.yml中配置:feign.sentienl.enable=true
- 给FeignClient编写FallbackFactory并注册为Bean
- 将FallbackFactory配置到FeignClient
线程隔离
线程隔离的实现方式
线程隔离有两种方式实现:
-
线程池隔离
-
信号量隔离(Sentinel默认采用)
-
线程池隔离:给每个服务调用业务分别分配一个线程池,利用线程池本身实现隔离效果
优点:
- 支持主动超时:服务I的请求主线程到线程池时,如果线程池没有及时给出响应,就直接报错,支持主动超时
- 支持异步调用:服务I的请求主线程,访问到访问服务A的线程池时,线程池会自己抽出一个空闲线程去访问服务A,而不用请求主线程主动访问
缺点:
线程的二外开销大
信号量隔离:不创建线程池,而是计数器模式,记录业务使用的线程数量,达到信号量上限时,禁止新的请求。
优点:
轻量级,不需要额外的线程开销,一个线程执行到底
缺点:
- 不支持主动超时
- 不支持异步调用
sentinel的线程隔离
在添加限流规则时,可以选择两种阈值类型:
-
QPS:就是每秒的请求数,在快速入门中已经演示过
-
线程数:是该资源能使用用的tomcat线程数的最大值。也就是通过限制线程数量,实现线程隔离(舱壁模式)。
案例需求:给 order-service服务中的UserClient的查询用户接口设置流控规则,线程数不能超过 2。然后利用jemeter测试。
1)配置隔离规则
因为order-service服务的feign已经整合的sentinel,也会把feign接口的方法作为资源
选择feign接口后面的流控按钮:
这里设置了访问/user/{id}接口时,同时最多使用的线程数为2个
2)jemter测试
一瞬间同时创建10个线程
一次发生10个请求,有较大概率并发线程数超过2,而超出的请求会走之前定义的失败降级逻辑。
访问/user/{id}时同时使用的线程超过2时,就是触发线程隔离,然后服务降级
总结
线程隔离的两种手段是?
-
信号量隔离
-
线程池隔离
信号量隔离的特点是?
- 基于计数器模式,简单,开销小
线程池隔离的特点是?
- 基于线程池模式,有额外开销,但隔离控制更强