前言
之前被各种事情耽搁了我的RPC框架,最近抽了一点时间继续写。上篇写了服务的手动降级,这篇主要写关于服务自动限流。
服务自动限流
通常情况下无论是客户端还是服务端都需要对于突发事件有相应的处理。
服务端:服务的降级和限流(面对突发的大流量,服务端的自我保护措施,例如直接停止服务或者1分钟仅限10次调用)
客户端:服务的容熔断(面对频繁超时等,客户端自动的处理)
服务自动限流思路
- 服务端需要初始化一个Map 存储相对于的服务和调用次数
- 需要有一个定时任务来触发一段时间内将调用次数清空
- 服务端调用服务要对这个次数做限制,超出返回服务暂停等字眼
初始化Map
public static Map<String,Integer> map = new ConcurrentHashMap<String, Integer>();
定时任务
//在zk初始化服务列表之后触发
//定时任务
public void startTask(){
System.out.println("*****************************************************");
//创建计时器
Timer timer = new Timer("开始执行任务-------------------");
//创建计时器任务(TimerTaskBean:是自定义的类,继承了TimerTask抽象类)
TimerTask task = new TimerTaskBean();
//调用计时器的schedule方法(时间表),此处的60000代表:在当前时间的60000毫秒之后,此线程会被唤醒
timer.schedule(task, 5, 60000);
System.out.println("定时任务已启动,于5秒后执行");
System.out.println("*****************************************************");
}
class TimerTaskBean extends TimerTask {
@Override
public void run() {
Map serverMap = InvokeServiceUtil.map;
Iterator<Map.Entry<String, Integer>> it = serverMap.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<String, Integer> entry = it.next();
entry.setValue(0);
}
}
}
调用改造
if(map.get(request.getClassName()).intValue() <5){
try {
Class implClass=Class.forName(request.getClassName());
Object[] parameters=request.getParameters();
int parameterNums=request.getParameters().length;
Class[] parameterTypes=new Class[parameterNums];
for (int i = 0; i <parameterNums ; i++) {
parameterTypes[i]=parameters[i].getClass();
}
Method method=implClass.getDeclaredMethod(request.getMethodName(),parameterTypes);
//获取到注册的服务bean
Object implObj=ZkServer.serverContext.getBean(StringUtil.toLowerCaseFirstOne(implClass.getSimpleName()));
result=method.invoke(implObj,parameters);
map.put(request.getClassName(), (map.get(request.getClassName()).intValue()+1));
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}else{
result = "服务已暂停";
}
效果
调用5次之后
1分钟之后