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 以流量为切入点,从流量控制.熔断降级.系统负载保护等多个维度保护服务的稳定性.包括核心的独立类库,监 ...
随机推荐
- WPF - 模板查看工具:Show Me The Template及如何查看第三方主题
原文:WPF - 模板查看工具:Show Me The Template及如何查看第三方主题 在学习WPF的模板(DataTemplate.ItemsPanelTemplate.ControlTemp ...
- WPF LayoutTransform -改变布局
LayoutTransform会影响布局,让grid显示分割线时候,可以看出 <Window x:Class="wpf180709.Window1" xmlns=" ...
- GDI+ Bitmap与WPF BitmapImage的相互转换
原文:GDI+ Bitmap与WPF BitmapImage的相互转换 using System.Windows.Interop; //... // Convert BitmapImage to Bi ...
- WPF 绑定到集合
<Window x:Class="CollectionBinding.MainWindow" xmlns="http://schemas.micros ...
- CSS,让100%的宽度,自动减10,让100%的高度,自动减10,可以加减乘除
CSS,让100%的宽度,自动减10,让100%的高度,自动减10,可以加减乘除 实例: .add{ width: calc(100% - 10px); height: calc(100% - 10p ...
- 一款好用的视频转换gif的小软件——抠抠视频秀
在平常生活中,我们拍下来精彩的视频想要转换为gif动画,或是想要录制网页上的视频.电脑上的鼠标操作等等,大家可以使用以下这款很好用的视频转换gif的小软件——抠抠视频秀,这个软件操作简单 ...
- Win10版《芒果TV》获评2016年度Windows Store最佳官方/休闲娱乐应用(LiveSino和微软信仰中心联合评选)
微软信仰中心于2016年12月9日联合了 LiveSino 进行了最佳 Windows Store 应用特辑的投票评选,通过为期20天的海量用户投票,Win10版<芒果TV>荣获最佳官方应 ...
- C#函数参数前的修饰符
函数的形参前可以带三种修饰符,分别的out.ref.param. out:让函数可以输出“多个值”,并不是真正的输出多个值. ref:相当于引用传递,在函数内部赋值会影响变量的值. params:可变 ...
- UAC就不能一次添加、永久信任吗?
每次都要点击确定,感觉好麻烦. 而且阻碍了某些功能的实现.
- 小抄:选择 Unity 的对象生命周期管理员
Unity 框架提供了数种生命周期管理员,各有相同和相异之处.刚开始接触时,难免头昏. 制作这张小抄,只是为了要帮助自己理解和记忆.如果你也用 Untiy,或可参考看看. 文字說明: Transien ...