自己设计一个的轻量级的RPC框架–服务手动降级
前言
前面几篇博客将的是搭建了一个轻量级的RPC的基础功能。最近也在学习Spring cloud,发现除了一些基础的功能还包含例如服务的断路、配置中心、网关等功能、负载均衡(先实现了一个简单的轮询)。所以接下来自己的目标就是完成这些功能的简易版本。
服务的降级
什么是服务降级?当服务器压力剧增的情况下,根据实际业务情况及流量,对一些服务进行简单的处理(例如直接返回服务下线等),从而释放服务器资源以保证核心交易正常运作或高效运作。
服务的手动降级思路
1.zookeeper的叶子节点需要保存该服务的状态 例如正常状态是为true,降级状态为false。
2.需要一个前端页面展示所有的服务并可以进行修改其状态。
3.修改状态完毕之后需要通过zookeeper的watch的机制来通知所有的消费者服务状态发生变化
4.消费者需要定义当调用当服务降级之后的方法
通过以上思路就能完成一个简单的服务降级
zookeeper的改造
创建节点
将节点默认为true
zk.createNodeForTemporary("/RPCSERVER/"+entry.getKey()+"/"+hostAddress+":"+rpc.getPort(),"true");
watch
新增一个watch事件 用来通知服务降级
注意:这里要通过getDataByWatch();这个方法来再次注册watch。同理初始化服务的时候也要用这个注册watch
// 这个方法 == getDataByWatch() 当调用setData方法时候 会触发EventType.NodeDataChanged事件
this.zookeeper.getData(path, true, null)
else if(EventType.NodeDataChanged == eventType){//某节点的数据发生改变 节点注册
System.out.println(path);
String paths[] = path.split("/");
Map<String,Map<String,String>> Map = ZkServer.serviceMap.get(paths[3]);
Map<String, String> childMap;
try {
childMap = Map.get(new String(getData("/"+paths[2]+"/"+paths[3])));
Iterator<Map.Entry<String, String>> it = childMap.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<String, String> entry = it.next();
if(paths[4].equals(entry.getKey())){
System.out.println(entry.getValue());
String isTrue = new String(getDataByWatch("/"+paths[2]+"/"+paths[3]+"/"+paths[4]));
System.out.println(isTrue);
if(isTrue.equals("false")){
entry.setValue("false");
System.out.println("/"+paths[2]+"/"+paths[3]+"/"+paths[4]+"下线");
}else{
entry.setValue("true");
System.out.println("/"+paths[2]+"/"+paths[3]+"/"+paths[4]+"上线");
}
}
}
} catch (KeeperException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
修改状态
@RequestMapping("updateStatus")
@ResponseBody
public Map updateStatus(String serverName,String ip,String status){
try {
Boolean isTrue;
if(status.equals("false")){
isTrue = ZkServer.zk.setData("/RPCSERVER"+"/"+serverName+"/"+ip, "true");
}else{
isTrue = ZkServer.zk.setData("/RPCSERVER"+"/"+serverName+"/"+ip, "false");
}
if(isTrue){
return toSuccessJson("成功");
}else{
return toSuccessJson("失败");
}
} catch (Exception e) {
return toSuccessJson("失败");
}
}
失败调用实现
注解改造
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface RPCURL {
String className();
String methodName();
//新增
String failClassName() default "";
}
增加一个接口
public interface FailBack {
public String failBack();
}
修改调用代理类
if(isTrue.equals("true")){
String str[] = ipAndHost.split(":");
request.setClassName(className);
request.setMethodName(url.methodName());
request.setParameters(args);
requestLockMap.put(request.getRequestID(),request);
RPCRequestNet.connect(str[0], Integer.parseInt(str[1])).send(request);
requestLockMap.remove(request.getRequestID());
return request.getResult();
}else{
FailBack failBack = (FailBack) ZkServer.serverContext.getBean(url.failClassName());
return failBack.failBack();
}
消费端实现该接口
@RPCClient
public interface clientWorld {
@RPCURL(className="serverWorld2",methodName="message", failClassName = "fail")
public String message(String world);
}
@Service
public class Fail implements FailBack{
@Override
public String failBack() {
return "管理员跑路了";
}
}
前端页面
效果
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/15338.html