SpringCloud系列——限流、熔断、降级
前言
分布式环境下,服务直接相互调用,一个复杂的业务可能要调用多个服务,例如A -> B -> C -> D,当某个服务出现异常(调用超时、调用失败等)将导致整个流程阻塞崩溃,严重的整个系统都会崩掉,为了实现高可用,必要的保护机制必不可少
本文记录限流、熔断、降级的实现处理
限流
我们采用令牌桶限流法,并自己实现一个简单令牌桶限流
有个任务线程以恒定速率向令牌桶添加令牌
一个请求会消耗一个令牌,令牌桶里的令牌大于0,才会放行,反正不允许通过
/**
* 简单的令牌桶限流
*/
public class RateLimiter { /**
* 桶的大小
*/
private Integer limit; /**
* 桶当前的token
*/
private static Integer tokens = 0; /**
* 构造参数
*/
public RateLimiter(Integer limit, Integer speed){
//初始化桶的大小,且桶一开始是满的
this.limit = limit;
tokens = this.limit; //任务线程:每秒新增speed个令牌
new Thread(() ->{
while (true){
try {
Thread.sleep(1000L); int newTokens = tokens + speed;
if(newTokens > limit){
tokens = limit;
System.out.println("令牌桶满了!!!");
}else{
tokens = newTokens;
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
} /**
* 根据令牌数判断是否允许执行,需要加锁
*/
public synchronized boolean execute() {
if (tokens > 0) {
tokens = tokens - 1;
return true;
}
return false;
}
}
main简单测试
public static void main(String[] args) {
//令牌桶限流:峰值每秒可以处理10个请求,正常每秒可以处理3个请求
RateLimiter rateLimiter = new RateLimiter(10, 3);
//模拟请求
while (true){
//在控制台输入一个值按回车,相对于发起一次请求
Scanner scanner = new Scanner(System.in);
scanner.next();
//令牌桶返回true或者false
if(rateLimiter.execute()){
System.out.println("允许访问");
}else{
System.err.println("禁止访问");
}
}
}

在SpringCloud分布式下实现限流,需要把令牌桶的维护放到一个公共的地方,比如Zuul路由,当然也可以同时针对具体的每个服务进行单独限流
另外,guava里有现成的基于令牌桶的限流实现,引入
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>26.0-jre</version>
</dependency>
具体用法这里就不阐述了
我们找出之前的springcloud项目,在zuul-server中的AccessFilter过滤器进行限流,其他的都不变,只需要做如下修改
PS:我这里为了方便测试,调小了令牌桶的大小,跟速率,正常情况下要服务器的承受能力来定
/**
* Zuul过滤器,实现了路由检查
*/
public class AccessFilter extends ZuulFilter {
//令牌桶限流:峰值每秒可以处理10个请求,正常每秒可以处理3个请求
//PS:我这里为了方便测试,调小了令牌桶的大小,跟速率,正常情况下按服务器的承受能力来定
private RateLimiter rateLimiter = new RateLimiter(2, 1); //业务不变,省略其他代码... /**
* 过滤器的具体逻辑
*/
@Override
public Object run() {
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
HttpServletResponse response = ctx.getResponse(); //限流
if(!rateLimiter.execute()){
try {
ctx.setSendZuulResponse(false);
ctx.setResponseStatusCode(200); //直接写入浏览器
response.setContentType("text/html;charset=UTF-8");
PrintWriter writer = response.getWriter();
writer.println("系统繁忙,请稍后在试!<br/>System busy, please try again later!");
writer.flush();return null;
} catch (Exception e) {
e.printStackTrace();
}
} //业务不变,省略其他代码..
}
}
按照我们设置的值,一秒能处理一个请求,峰值一秒能处理两个请求,下面疯狂刷新进行测试

熔断
yml配置开启Hystrix熔断功能,进行容错处理
feign:
hystrix:
enabled: true
设置Hystrix的time-out时间
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 5000 #毫秒
#或者设置从不超时
#timeout:
# enabled: false
在使用Feign调用服务提供者时配置@FeignClient的 fallback,进行容错处理(服务提供者发生异常),如果需要获取到异常信息,则要配置fallbackFactory<T>
@FeignClient(name = "sso-server", path = "/",/*fallback = SsoFeign.SsoFeignFallback.class,*/fallbackFactory = SsoFeign.SsoFeignFallbackFactory.class)
/**
* 容错处理(服务提供者发生异常,将会进入这里)
*/
@Component
public class SsoFeignFallback implements SsoFeign { @Override
public Boolean hasKey(String key) {
System.out.println("调用sso-server失败,进行SsoFeignFallback.hasKey处理:return false;");
return false;
}
}
/**
* 只打印异常,容错处理仍交给 SsoFeignFallback
*/
@Component
public class SsoFeignFallbackFactory implements FallbackFactory<SsoFeign> {
private final SsoFeignFallback ssoFeignFallback; public SsoFeignFallbackFactory(SsoFeignFallback ssoFeignFallback) {
this.ssoFeignFallback = ssoFeignFallback;
} @Override
public SsoFeign create(Throwable cause) {
cause.printStackTrace();
return ssoFeignFallback;
}
}
FallbackFactory也可以这样写
/**
* 容错处理
*/
@Component
public class SsoFeignFallbackFactory implements FallbackFactory<SsoFeign> { @Override
public SsoFeign create(Throwable cause) {
//打印异常
cause.printStackTrace(); return new SsoFeign() {
@Override
public Boolean hasKey(String key) {
System.out.println("调用sso-server失败:return false;");
return false;
}
};
}
}
因为我们没有启动Redis,报错,但我们进行容错处理,所以还是返回了false

降级
当调用服务发送异常,容错处理的方式有多种,我们可以:
1、重连,比如服务进行了限流,本次连接被限制,重连一次或N次就可以得到数据
2、直接返回一个友好提示
3、降级调用备用服务、返回缓存的数据等
后记
降级也可以叫做“备胎计划”...
代码开源
代码已经开源、托管到我的GitHub、码云:
GitHub:https://github.com/huanzi-qch/springCloud
码云:https://gitee.com/huanzi-qch/springCloud
SpringCloud系列——限流、熔断、降级的更多相关文章
- springBoot整合Sentinel实现降级限流熔断
由于hystrix的停止更新,以及阿里Sentinel在历年双十一的贡献.项目中使用了Sentinel,今天我们来讲讲Sentinel的入门教程,本文使用1.6.3版本进行讲解 本文通过Sentine ...
- Hystrix介绍以及服务的降级限流熔断
(dubbo熔断,Hystrix问的少) 无论是缓存层还是存储层都会有出错的概率,可以将它们视同为资源.作为并发量较大的系统,假如有一个资源不可用,可能会造成线程全部 hang (挂起)在这个资源上, ...
- 高可用服务设计之二:Rate limiting 限流与降级
<高可用服务设计之二:Rate limiting 限流与降级> <nginx限制请求之一:(ngx_http_limit_conn_module)模块> <nginx限制 ...
- .net core使用ocelot---第四篇 限流熔断
简介 .net core使用ocelot---第一篇 简单使用 .net core使用ocelot---第二篇 身份验证 .net core使用ocelot---第三篇 日志记录 前几篇文章我们陆续介 ...
- 0.9.0.RELEASE版本的spring cloud alibaba sentinel限流、降级处理实例
先看服务提供方的,我们在原来的sentinel实例(参见0.9.0.RELEASE版本的spring cloud alibaba sentinel实例)上加上限流.降级处理,三板斧只需在最后那一斧co ...
- .Net微服务实践(四)[网关]:Ocelot限流熔断、缓存以及负载均衡
目录 限流 熔断 缓存 Header转化 HTTP方法转换 负载均衡 注入/重写中间件 后台管理 最后 在上篇.Net微服务实践(三)[网关]:Ocelot配置路由和请求聚合中我们介绍了Ocelot的 ...
- DBPack 限流熔断功能发布说明
上周我们发布了 v0.4.0 版本,增加了限流熔断功能,现对这两个功能做如下说明. 限流 DBPack 限流熔断功能通过 filter 实现.要设置限流规则,首先要定义 RateLimitFilter ...
- Dubbo学习系列之十(Sentinel之限流与降级)
各位看官,先提个问题,如果让你设计一套秒杀系统,核心要点是啥???我认为有三点:缓存.限流和分离.想当年12306大面积崩溃,还有如今的微博整体宕机情况,感觉就是限流降级没做好,"用有限的资 ...
- SpringCloud微服务:Sentinel哨兵组件,管理服务限流和降级
源码地址:GitHub·点这里||GitEE·点这里 一.基本简介 1.概念描述 Sentinel 以流量为切入点,从流量控制.熔断降级.系统负载保护等多个维度保护服务的稳定性.包括核心的独立类库,监 ...
随机推荐
- Android新的漏洞的应用程序中的发现!
最近,趋势科技发现一些Android中的漏洞应用程序内存.来发动攻击.我们调查了两个受影响的应用程序,大家来感受一下: .超过一千万次安装.及在下载页面拥有数十万笔用户留言的生产力应用程序(生产力应用 ...
- WPF 4 DataGrid 控件(进阶篇二)
原文:WPF 4 DataGrid 控件(进阶篇二) 上一篇<WPF 4 DataGrid 控件(进阶篇一)>中我们通过DataGridTemplateColumn 类自定义编辑 ...
- C#并口热敏小票打印机打印位图
原文:C#并口热敏小票打印机打印位图 最近一直在研究并口小票打印机打印图片问题,这也是第一次和硬件打交道,不过还好,最终成功了. 这是DEMO的窗体: 下面是打印所需要调用的代码: class ...
- StackExchange.Redis 封装类
using StackExchange.Redis; using System; using System.Collections.Generic; using System.Linq; using ...
- Window Features 总览
This overview discusses features of windows such as window types, states, size, and position. Window ...
- Socket 专题
Socket小白篇-附加TCP/UDP简介 Socket 网络通信的要素 TCP和UDP Socket的通信流程图 1.Socket 什么是Socket Socket:又称作是套接字,网络上的两个程序 ...
- 获取bing图片并自动设置为电脑桌面背景(使用 URLDownloadToFile API函数)
众所周知,bing搜索网站首页每日会更新一张图片,张张漂亮(额,也有一些不合我口味的),特别适合用来做电脑壁纸. 我们想要将bing网站背景图片设置为电脑桌面背景的通常做法是: 上网,搜索bing 找 ...
- 深入解析Android关机
下图详细阐释了Android的关机顺序. 第一步: 按住电源按钮半秒钟(500ms). 第二步: 之后,PhoneWindowManager.java 将捕获长按电源按钮这一事件并调用“interce ...
- 程序的开机关机重启,开机启动,休眠功能delphi实现(使用AdjustTokenPrivileges提升权限)
TShutDownStatus = (sdShutDown,sdReboot,sdLogOff,sdPowerOff); procedure ShutDown(sdStatus : TShutDown ...
- Linux命令执行顺序与管道命令
命令执行顺序控制 顺序执行多条命令:command1;command2;command3... 有选择执行命令:which command1 && command2 || comman ...