您的位置:首页 > Web前端 > JavaScript

使用消息队列+js实现分布式服务器热切换业务处理功能

2015-01-12 08:32 676 查看
本文中的想法源自于最近对erlang的学习以及公司最近新业务需求的技术讨论,具体就是:假设分布式服务器原来用于处理阶乘运算,当需要更改为进行矩形面积计算或者圆形面积计算时,常规作法是停机更新服务器,然后重启,而我的想法是实现类似erlang的热切换功能,即不需要停机即可完成业务功能的切换。

该想法实现的demo中包含,主服务器和分布式服务器两部分。主服务器使用java实现,包含:分布式服务器注册和消息队列两个功能。分布式服务器使用html+js实现,主要实现业务功能的热切换和具体业务处理(阶乘,矩形面积计算,圆形面积计算),demo的流程图如下:



下面是主服务器的核心代码:

if(pathInfo.startsWith(path + "/msg")){
String receid = req.getParameter("receiver");
Receiver receiver = db.find(receid);
String msg = null;
//默认返回空消息
Message message = new Message();
message.setType(Message.TYPE_EMPTY);
msg = JSONObject.fromObject(message).toString();
if(receiver != null){ //如果该服务器已经注册,则看消息队列中是否有该分布式服务器的消息
String strId = req.getParameter("id"); //上次处理的消息id
System.out.println("last msg id:["+strId+"]");
if(StringUtils.isNotBlank(strId)){
//更新消息状态为完成,避免循环推送
long id = Long.parseLong(strId);
String status = req.getParameter("status");
Message lastMsg = msgQueue.get(id);
if(lastMsg != null){
System.out.println("更新消息状态:["+receid+","+id+","+status+"]");
lastMsg.setStatus(status);
if(lastMsg.getType().equals(Message.TYPE_BUSINESS) && status.equals(Message.STATUS_COMPLETE)){
//如果为切换业务处理器消息,则需要更新服务器记录中的业务处理器,以及将状态置为切换完成
//#########################################
receiver.setBusiness(((BusinessBody)lastMsg.getMessageBody()).getBusiness());
receiver.setStatus(Receiver.STATUS_COMPLETE);
//############################################
}
}
}
//当服务器的业务处理器处理完成时才能推送消息,避免因为分布式系统的异步请求,造成消息处理异常
if(receiver.getStatus().equals(Receiver.STATUS_COMPLETE)){
Message sendMsg = msgQueue.pull(receiver);
if(sendMsg != null){
if(sendMsg.getType().equals(Message.TYPE_BUSINESS)){
//#################################################
receiver.setStatus(Receiver.STATUS_UNCOMPLETE); //如果为切换业务处理器消息,则将服务器记录中的状态置为未完成切换,避免异步处理异常
//####################################################
}
msg = JSONObject.fromObject(sendMsg).toString();
System.out.println("分发新消息:["+receid + "," + msg + "]");
}
}
}
resp.setContentType("application/json");
resp.getWriter().write(msg);
}
该部分代码主要实现向分布式服务器推送消息,#号注释包围的代码部分是为了解决,分布式服务器采用异步ajax在切换业务功能时所带来的同步问题,即当需要切换业务功能时,可能网络延迟等原因导致,在下次交互周期时,业务功能没有完成切换,这时候,主服务器需要保证不能让分布式服务器获取到任何消息,避免分布式服务器的处理异常,具体实现采用状态标记,即当向分布式服务器推送切换业务功能的消息时,将数据库中服务器的状态标记为正在切换业务功能,每次取消息时,判断服务器是否已经完成业务功能切换,保证切换业务功能的同步。

下面是分布式服务器代码的核心部分:

SlaveUtil.send(slave.msgUrl, {"receiver":tmpResult.receiver, "id":tmpResult.id, "status": tmpResult.status}, true, "json", "get", function(data){
if(data.type == "Business"){ //如果为切换业务处理器消息
var orginHandler = slave.callbackName;
//##############################
slave.callbackName = data.messageBody.business; //修改本地系统的业务处理器名称
if($("#js_"+slave.callbackName).length == 0){ //如果新的业务处理器的js未加载,则先加载js文件
var path = slave.baseDir + "/" + slave.callbackName + ".js";
$("#js").append("<script id='js_"+slave.callbackName+"' type='text/javascript' src='"+path+"'>");
}
slave.callback = eval(data.messageBody.business); //字符串转函数,切换业务处理器
//#################################
var now = new Date();
$("#result").append("<p>"+now.toLocaleString() + ":[切换本地业务处理器完成:"+ orginHandler +" TO "+ slave.callbackName +"]</p>");
slave.result = new Result(slave.id, data.id, "2");
}else if(data.type == "Empty"){
//空消息不处理
}else{
var cb = slave.callback;
slave.result = cb(data); //处理消息
slave.result.receiver = slave.id;
}
}, function(xhr, status, err){
var now = new Date();
$("#result").append("<p>"+now.toLocaleString() + ":[请求数据错误:"+status+",错误:"+err+"]</p>");
});
上述代码中的#号注释包围部分就是最重要的热切换功能,主要就是从消息中取出新的业务处理名称,然后加载对应的js文件,然后切换业务功能,唯一需要注意的地方就是必须先加载文件才能切换业务功能。
整个想法的实现都很简单,最大受限的地方就是分布式系统采用js,需要浏览器,因此难以和操作系统进行交互,具体的实用性和性能还有待验证,在此只是分享一下我对于分布式服务器业务处理功能热切换的思路,整个demo的工程文件放在:http://download.csdn.net/detail/kliwin/8351723,具体用法参考工程中doc目录的re
8bc5
adme.txt文件,如有任何疑问或者想法,欢迎随时跟我交流(E-mail:kliwin@163.com),代码写的不咋样,只是保证功能和思路是正确的,希望不要介意,谢谢。最后贴一张demo的执行效果图:



内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  java javascript js 分布式
相关文章推荐