前言

  分布式环境下,服务直接相互调用,一个复杂的业务可能要调用多个服务,例如A -> B -> C -> D,当某个服务出现异常(调用超时、调用失败等)将导致整个流程阻塞崩溃,严重的整个系统都会崩掉,为了实现高可用,必要的保护机制必不可少

  本文记录限流、熔断、降级的实现处理

  限流

  我们采用令牌桶限流法,并自己实现一个简单令牌桶限流

  有个任务线程以恒定速率向令牌桶添加令牌

  一个请求会消耗一个令牌,令牌桶里的令牌大于0,才会放行,反正不允许通过

  1. /**
  2. * 简单的令牌桶限流
  3. */
  4. public class RateLimiter {
  5.  
  6. /**
  7. * 桶的大小
  8. */
  9. private Integer limit;
  10.  
  11. /**
  12. * 桶当前的token
  13. */
  14. private static Integer tokens = 0;
  15.  
  16. /**
  17. * 构造参数
  18. */
  19. public RateLimiter(Integer limit, Integer speed){
  20. //初始化桶的大小,且桶一开始是满的
  21. this.limit = limit;
  22. tokens = this.limit;
  23.  
  24. //任务线程:每秒新增speed个令牌
  25. new Thread(() ->{
  26. while (true){
  27. try {
  28. Thread.sleep(1000L);
  29.  
  30. int newTokens = tokens + speed;
  31. if(newTokens > limit){
  32. tokens = limit;
  33. System.out.println("令牌桶满了!!!");
  34. }else{
  35. tokens = newTokens;
  36. }
  37. } catch (InterruptedException e) {
  38. e.printStackTrace();
  39. }
  40. }
  41. }).start();
  42. }
  43.  
  44. /**
  45. * 根据令牌数判断是否允许执行,需要加锁
  46. */
  47. public synchronized boolean execute() {
  48. if (tokens > 0) {
  49. tokens = tokens - 1;
  50. return true;
  51. }
  52. return false;
  53. }
  54. }

  main简单测试

  1. public static void main(String[] args) {
  2. //令牌桶限流:峰值每秒可以处理10个请求,正常每秒可以处理3个请求
  3. RateLimiter rateLimiter = new RateLimiter(10, 3);
  4.  
  5. //模拟请求
  6. while (true){
  7. //在控制台输入一个值按回车,相对于发起一次请求
  8. Scanner scanner = new Scanner(System.in);
  9. scanner.next();
  10.  
  11. //令牌桶返回true或者false
  12. if(rateLimiter.execute()){
  13. System.out.println("允许访问");
  14. }else{
  15. System.err.println("禁止访问");
  16. }
  17. }
  18. }

  在SpringCloud分布式下实现限流,需要把令牌桶的维护放到一个公共的地方,比如Zuul路由,当然也可以同时针对具体的每个服务进行单独限流

  另外,guava里有现成的基于令牌桶的限流实现,引入

  1. <dependency>
  2. <groupId>com.google.guava</groupId>
  3. <artifactId>guava</artifactId>
  4. <version>26.0-jre</version>
  5. </dependency>

  具体用法这里就不阐述了

  我们找出之前的springcloud项目,在zuul-server中的AccessFilter过滤器进行限流,其他的都不变,只需要做如下修改

  PS:我这里为了方便测试,调小了令牌桶的大小,跟速率,正常情况下要服务器的承受能力来定

  1. /**
  2. * Zuul过滤器,实现了路由检查
  3. */
  4. public class AccessFilter extends ZuulFilter {
  5. //令牌桶限流:峰值每秒可以处理10个请求,正常每秒可以处理3个请求
    //PS:我这里为了方便测试,调小了令牌桶的大小,跟速率,正常情况下按服务器的承受能力来定
  6. private RateLimiter rateLimiter = new RateLimiter(2, 1);
  7.  
  8. //业务不变,省略其他代码...
  9.  
  10. /**
  11. * 过滤器的具体逻辑
  12. */
  13. @Override
  14. public Object run() {
  15. RequestContext ctx = RequestContext.getCurrentContext();
  16. HttpServletRequest request = ctx.getRequest();
  17. HttpServletResponse response = ctx.getResponse();
  18.  
  19. //限流
  20. if(!rateLimiter.execute()){
  21. try {
  22. ctx.setSendZuulResponse(false);
  23. ctx.setResponseStatusCode(200);
  24.  
  25. //直接写入浏览器
  26. response.setContentType("text/html;charset=UTF-8");
  27. PrintWriter writer = response.getWriter();
  28. writer.println("系统繁忙,请稍后在试!<br/>System busy, please try again later!");
  29. writer.flush();return null;
  30. } catch (Exception e) {
  31. e.printStackTrace();
  32. }
  33. }
  34.  
  35. //业务不变,省略其他代码..
  36. }
  37. }

  按照我们设置的值,一秒能处理一个请求,峰值一秒能处理两个请求,下面疯狂刷新进行测试

 

  熔断

  yml配置开启Hystrix熔断功能,进行容错处理

  1. feign:
  2. hystrix:
  3. enabled: true

  设置Hystrix的time-out时间

  1. hystrix:
  2. command:
  3. default:
  4. execution:
  5. isolation:
  6. thread:
  7. timeoutInMilliseconds: 5000 #毫秒
  8. #或者设置从不超时
  9. #timeout:
  10. # enabled: false

  在使用Feign调用服务提供者时配置@FeignClient的 fallback,进行容错处理(服务提供者发生异常),如果需要获取到异常信息,则要配置fallbackFactory<T>

  1. @FeignClient(name = "sso-server", path = "/",/*fallback = SsoFeign.SsoFeignFallback.class,*/fallbackFactory = SsoFeign.SsoFeignFallbackFactory.class)
  1. /**
  2. * 容错处理(服务提供者发生异常,将会进入这里)
  3. */
  4. @Component
  5. public class SsoFeignFallback implements SsoFeign {
  6.  
  7. @Override
  8. public Boolean hasKey(String key) {
  9. System.out.println("调用sso-server失败,进行SsoFeignFallback.hasKey处理:return false;");
  10. return false;
  11. }
  12. }
  1. /**
  2. * 只打印异常,容错处理仍交给 SsoFeignFallback
  3. */
  4. @Component
  5. public class SsoFeignFallbackFactory implements FallbackFactory<SsoFeign> {
  6. private final SsoFeignFallback ssoFeignFallback;
  7.  
  8. public SsoFeignFallbackFactory(SsoFeignFallback ssoFeignFallback) {
  9. this.ssoFeignFallback = ssoFeignFallback;
  10. }
  11.  
  12. @Override
  13. public SsoFeign create(Throwable cause) {
  14. cause.printStackTrace();
  15. return ssoFeignFallback;
  16. }
  17. }

  FallbackFactory也可以这样写

  1. /**
  2. * 容错处理
  3. */
    @Component
    public class SsoFeignFallbackFactory implements FallbackFactory<SsoFeign> {
  4.  
  5. @Override
  6. public SsoFeign create(Throwable cause) {
  7. //打印异常
  8. cause.printStackTrace();
  9.  
  10. return new SsoFeign() {
  11. @Override
  12. public Boolean hasKey(String key) {
  13. System.out.println("调用sso-server失败:return false;");
  14. return false;
  15. }
  16. };
  17. }
  18. }

  因为我们没有启动Redis,报错,但我们进行容错处理,所以还是返回了false

  降级

  当调用服务发送异常,容错处理的方式有多种,我们可以:

  1、重连,比如服务进行了限流,本次连接被限制,重连一次或N次就可以得到数据

  2、直接返回一个友好提示

  3、降级调用备用服务、返回缓存的数据等

  后记

  降级也可以叫做“备胎计划”...

  代码开源

  代码已经开源、托管到我的GitHub、码云:

  GitHub:https://github.com/huanzi-qch/springCloud

  码云:https://gitee.com/huanzi-qch/springCloud

SpringCloud系列——限流、熔断、降级的更多相关文章

  1. springBoot整合Sentinel实现降级限流熔断

    由于hystrix的停止更新,以及阿里Sentinel在历年双十一的贡献.项目中使用了Sentinel,今天我们来讲讲Sentinel的入门教程,本文使用1.6.3版本进行讲解 本文通过Sentine ...

  2. Hystrix介绍以及服务的降级限流熔断

    (dubbo熔断,Hystrix问的少) 无论是缓存层还是存储层都会有出错的概率,可以将它们视同为资源.作为并发量较大的系统,假如有一个资源不可用,可能会造成线程全部 hang (挂起)在这个资源上, ...

  3. 高可用服务设计之二:Rate limiting 限流与降级

    <高可用服务设计之二:Rate limiting 限流与降级> <nginx限制请求之一:(ngx_http_limit_conn_module)模块> <nginx限制 ...

  4. .net core使用ocelot---第四篇 限流熔断

    简介 .net core使用ocelot---第一篇 简单使用 .net core使用ocelot---第二篇 身份验证 .net core使用ocelot---第三篇 日志记录 前几篇文章我们陆续介 ...

  5. 0.9.0.RELEASE版本的spring cloud alibaba sentinel限流、降级处理实例

    先看服务提供方的,我们在原来的sentinel实例(参见0.9.0.RELEASE版本的spring cloud alibaba sentinel实例)上加上限流.降级处理,三板斧只需在最后那一斧co ...

  6. .Net微服务实践(四)[网关]:Ocelot限流熔断、缓存以及负载均衡

    目录 限流 熔断 缓存 Header转化 HTTP方法转换 负载均衡 注入/重写中间件 后台管理 最后 在上篇.Net微服务实践(三)[网关]:Ocelot配置路由和请求聚合中我们介绍了Ocelot的 ...

  7. DBPack 限流熔断功能发布说明

    上周我们发布了 v0.4.0 版本,增加了限流熔断功能,现对这两个功能做如下说明. 限流 DBPack 限流熔断功能通过 filter 实现.要设置限流规则,首先要定义 RateLimitFilter ...

  8. Dubbo学习系列之十(Sentinel之限流与降级)

    各位看官,先提个问题,如果让你设计一套秒杀系统,核心要点是啥???我认为有三点:缓存.限流和分离.想当年12306大面积崩溃,还有如今的微博整体宕机情况,感觉就是限流降级没做好,"用有限的资 ...

  9. SpringCloud微服务:Sentinel哨兵组件,管理服务限流和降级

    源码地址:GitHub·点这里||GitEE·点这里 一.基本简介 1.概念描述 Sentinel 以流量为切入点,从流量控制.熔断降级.系统负载保护等多个维度保护服务的稳定性.包括核心的独立类库,监 ...

随机推荐

  1. 多线程——继承Thread类别

    详细java此前使用多线程,让我们来看看下面的问题. 什么是多线程     简单的理解成:cpu"同一时候"运行多个任务,这就是多线程. (究其本质,当涉及到进程和线程的概念.上面 ...

  2. 关于WPF你应该知道的2000件事

    原文 关于WPF你应该知道的2000件事 以下列出了迄今为止为WPF博客所知的2,000件事所创建的所有帖子. 帖子总数= 1,201 动画 #7 - 基于属性的动画 #686 - 使用动画制作图像脉 ...

  3. WPF - 模板查看工具:Show Me The Template及如何查看第三方主题

    原文:WPF - 模板查看工具:Show Me The Template及如何查看第三方主题 在学习WPF的模板(DataTemplate.ItemsPanelTemplate.ControlTemp ...

  4. DirectX 图形流水线

    Direct3D 的可编程流水线用来为实时游戏渲染图形(一个词概括——实时渲染) 上面的图是Dx11的实时渲染流水线,Dx的几个版本都是向下兼容的. Input-Assembler Stage: 输入 ...

  5. ASP Get请求

    <!DOCTYPE html><html><head><meta http-equiv="Content-Type" content=&q ...

  6. C# 异步委托的使用

    using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threa ...

  7. CSS,让100%的宽度,自动减10,让100%的高度,自动减10,可以加减乘除

    CSS,让100%的宽度,自动减10,让100%的高度,自动减10,可以加减乘除 实例: .add{ width: calc(100% - 10px); height: calc(100% - 10p ...

  8. dotnetspider

    http://www.cnblogs.com/modestmt/p/5525467.html nuget :DotnetSpider2.Core

  9. layabox pc app web同步发布的工具

    http://layabox.com/ 或者vs + unity3d开发游戏

  10. 零元学Expression Blend 4 - Chapter 24 以实作了解Cover Flow功能

    原文:零元学Expression Blend 4 - Chapter 24 以实作了解Cover Flow功能 今天要介绍一个Silverlight Toolkit内好用且在图片展示操作上很常见的元件 ...