概述
from:http://blog.abreaking.com
访问端流量控制
博主面临的一个问题是,如何对该esb的调用者调用某个服务的次数进行控制。
也就是说:对于服务A,每个调用者调用该服务单位时间内调用次数不能超过阈值;反过来也一样,对于调用者,调用任意服务单位时间内的调用次数不能超过阈值。
那么此时,根据访问端的ip地址来标识某个调用源 origin,用服务的接口名srvName来标识调用的那个服务。
对于sentinel最基本的用法,参考:
https://mp.csdn.net/postedit/82116993
加入依赖
同样的,需要加入sentinel依赖
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-core</artifactId>
</dependency>
定义规则
那么此时,规则就不止一个了。我们改变一下定义规则的方法:
public void addRule(String resource,String origin){
List<FlowRule> rules = FlowRuleManager.getRules();
if(rules==null){
rules = new ArrayList<FlowRule>();
}
FlowRule rule = new FlowRule();
rule.setResource(resource); //资源名
rule.setGrade(RuleConstant.FLOW_GRADE_QPS); //限流阈值类型,此处为qps类型
rule.setCount(8); //限流阈值,表示每秒钟通过n次请求
rule.setLimitApp(origin); //对调用端进行控制
rules.add(rule);
FlowRuleManager.loadRules(rules);
}
如上,如果有新的规则, 直接放在FlowRuleManager中的规则List中去。限流阈值等先是写死的。
定义资源resource,调用端origin
为了模拟调用者调用那个服务这种情况,博主使用一种简单的方式来模拟:
通过url请求带参数来模拟,比如:客户端访问:http://127.0.0.1:8080/cc?srvName=hello。就表示:ip为127.0.0.1的调用端调用hello这个方法。
首先,需要定义好resource,origin。
String host = request.getRemoteHost();
String srvName = request.getParameter("srvName");
String resource = host+srvName;
String origin = host;
而后,就是初始化规则的问题。此时注意,并不是每次请求过来都要进行初始化,导致程序变慢不说,这一次的请求如果与上一次的请求不同源,会将上一次定义的规则给覆盖掉。
所以,定义一个List<String> resources存放resource,只有不同的调用端第一次请求时,才会添加新的规则到规则列表中。
if(!resources.contains(resource)){
synchronized(resources){
if(!resources.contains(resource)){
addNewRule4NewOrigin(resource,origin);
resources.add(resource);
}
}
}
整体Demo
最后,使用包围住需要进行流量控制代码块的。
@RequestMapping("/cc")
public String controlClient(HttpServletRequest request){
String host = request.getRemoteHost();
String srvName = request.getParameter("srvName");
String resource = host+srvName;
String origin = host;
if(!resources.contains(resource)){
synchronized(resources){
/**by liwei
* springmvc是单例模式,这里就没必要进行双重校验,
* 如果是非单例的servlet,要加上双重校验,防止重复添加了规则
*/
if(!resources.contains(resource)){
addNewRule4NewOrigin(resource,origin);
resources.add(resource);
}
}
}
String response = "";
Entry entry = null;
try {
ContextUtil.enter(resource,origin);
entry = SphU.entry(resource);
//我的代码块
response = execSrv(resource);
} catch (BlockException e1) {
e1.printStackTrace(); //直接将异常打出来
response = resource+e1.toString();
} finally {
if (entry != null) {
entry.exit();
}
ContextUtil.exit();
}
return response;
}
测试
写个测试方法,
@Test
public void test02() throws InterruptedException {
String host1 = "127.0.0.1";
String host2 = "192.168.236.1";
String srv = "hello";
for (int i = 0; i < 5; i++) {
String url = "http://"+host1+":8080/cc?srvName="+srv+i;
new Thread(new MyRunnable(url)).start();
}
for (int i = 0; i < 5; i++) {
String url = "http://"+host2+":8080/cc?srvName="+srv+i;
new Thread(new MyRunnable(url)).start();
}
Thread.sleep(2000);
}
class MyRunnable implements Runnable{
String url;
public MyRunnable(String url){
this.url = url;
}
@Override
public void run() {
for (int i = 0; i < 10; i++) {
String s = doPost(url);
System.out.println(s);
}
}
}
private String doPost(String url) {
HttpClient client = new DefaultHttpClient();
//发送get请求
HttpGet request = new HttpGet(url);
try {
HttpResponse response = client.execute(request);
String strResult = EntityUtils.toString(response.getEntity());
return strResult;
}catch (Exception e){
e.printStackTrace();
}
return null;
}
最后
以上就是殷勤雪碧为你收集整理的使用Sentinel对访问端流量控制的全部内容,希望文章能够帮你解决使用Sentinel对访问端流量控制所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复