php分布式限流解决方案,一个分布式限流的解决方案!

68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c6963656e73652d417061636865253230322e302d626c75652e7376673f6c6162656c3d6c6963656e736568747470733a2f2f696d672e736869656c64732e696f2f6d6176656e2d63656e7472616c2f762f696f2e6769746875622e666f72657a702f64697374726962757465642d6c696d69742d636f72652e7376673f6c6162656c3d6d6176656e25323063656e7472616c

这个项目干嘛的?

这个项目是一个Api限流的解决方案,采用的是令牌桶的方式。如果使用的Redis则是分布式限流,如果采用guava的LimitRater,则是本地限流。 分2给维度限流,一个是用户维度,一个Api维度,读者可自定义。仅支持Spring Boot项目。

怎么使用?

在boot-example工程,有完整的案例。可在Controller上限流,也可以在Spring Mvc的Interceptor或者Servlet的Filter上限流。

开启限流

在pom文件加上jar包:

io.github.forezp

distributed-limit-core

1.0.4

有2中方式,本地限流,只需要配置limit.type=local;采用Reis限流,配置limit.type=redis,以及redis的配置,如下:

#limit.type: local

limit.type: redis

spring:

redis:

host: localhost

port: 6379

# password: ee

database: 1

pool:

max-active: 8

max-wait: -1

max-idle: 500

min-idle: 0

timeout: 0

Controller上使用,基于注解、AOP

在Controller上加 @Limit注解,其中identifier为识别身份的,key为限流的key,limtNum为限制的次数,seconds为多少秒,后2个配置的作用是在多少秒最大的请求次数 。其中identifier和key支持Spel表达式。如果仅API纬度,则identifier 为空即可;如果仅用户纬度,key为空即可。

@RestController

public class TestController {

@GetMapping("/test")

@Limit(identifier = "forezp", key = "test", limtNum = 10, seconds = 1)

public String Test() {

return "11";

}

}

仅次操作就可以限流了。

另外如果是以注解的形式进行限流,如果以identifier即请求用户维度去限流,可以动态的设置的identifier的值,示例如下:

@Component

public class IndentifierInterceptor extends HandlerInterceptorAdapter {

@Override

public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

//获取用户的信息,比如解析Token获取用户名,

// 这么做主要是在基于@Limit注解在Controller的时候,能都动态设置identifier信息

// 从而以用户维度进行限流

String identifier = "forezp";

IdentifierThreadLocal.set( identifier );

return true;

}

}

在Web层的Interceptor、Filter上使用

直接贴代码了,比较简单。

@Component

public class WebInterceptor extends HandlerInterceptorAdapter {

private Map limitEntityMap = Maps.newConcurrentMap();

@Autowired

LimitExcutor limitExcutor;

public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

//限流2个维度: 用户和api维度

//比如用户名

String identifier = "forezp";

//api维度

String key = request.getRequestURI();

String composeKey = KeyUtil.compositeKey( identifier, key );

LimitEntity limitEntity = limitEntityMap.get( composeKey );

if (limitEntity == null) {

limitEntity = new LimitEntity();

limitEntity.setIdentifier( identifier );

limitEntity.setKey( key );

//这可以在数据库中配置或者缓存中读取,在这里我写死

limitEntity.setSeconds( 1 );

limitEntity.setLimtNum( 10 );

limitEntityMap.putIfAbsent( composeKey, limitEntity );

}

if (!limitExcutor.tryAccess( limitEntity )) {

throw new LimitException( "you fail access, cause api limit rate ,try it later" );

}

return true;

}

}

注册一下Interceptor:

@Configuration

public class WebConfig extends WebMvcConfigurerAdapter {

@Autowired

IndentifierInterceptor indentifierInterceptor;

@Autowired

WebInterceptor webInterceptor;

/**

* 注册 拦截器

*/

@Override

public void addInterceptors(InterceptorRegistry registry) {

registry.addInterceptor( indentifierInterceptor );

registry.addInterceptor( webInterceptor );

}

}

联系我

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值