Pomelo中是master服务器首先启动,然后在启动其他服务器的。那么当一个服务器启动时,它是如何获知此时整个服务器集群整体信息的?当服务器启动之后,后续服务器的添加或删除的信息是如何传递给该服务器的呢?
首先,当master服务器启动时,会创建masterAgent。
Pomelo-admin中的consoleService.js中:
var ConsoleService = function(opts) {
EventEmitter.call(this);
this.port = opts.port;
this.env = opts.env;
this.values = {};
this.master = opts.master;
this.modules = {};
this.commands = {
'list': listCommand,
'enable': enableCommand,
'disable': disableCommand
};
if (this.master) {
this.authUser = opts.authUser || utils.defaultAuthUser;
this.authServer = opts.authServer || utils.defaultAuthServerMaster;
this.agent = new MasterAgent(this, opts);
} else {
this.type = opts.type;
this.id = opts.id;
this.host = opts.host;
this.authServer = opts.authServer || utils.defaultAuthServerMonitor;
this.agent = new MonitorAgent({
consoleService: this,
id: this.id,
type: this.type,
info: opts.info
});
}
};
masterAgent管理了所有和monitorAgent的连接。Master服务器会监听所有的master端口。同时会启动waterdog模块(masterwatcher.js和watchdog.js)。
其他非master服务器启动时,会创建monitorConsoleService,并启动MonitorAgent且调用其connect函数,在连接成功之后会发送register消息。
当masterAgent收到register消息时,会调用doAuthServer,验证成功。之后会给MonitorAgent客户端发送register成功的消息,同时也触发了masterAgent的register事件。
MasterAgent.js
var doAuthServer = function(msg, socket, self, cb) {
var authServer = self.consoleService.authServer;
var env = self.consoleService.env;
authServer(msg, env, function(status) {
if (status !== 'ok') {
socket.emit('register', {
code: protocol.PRO_FAIL,
msg: 'server auth failed'
});
cb(new Error('server auth failed'));
return;
}
var record = addConnection(self, msg.id, msg.serverType, msg.pid, msg.info, socket);
socket.emit('register', {
code: protocol.PRO_OK,
msg: 'ok'
});
msg.info.pid = msg.pid;
self.emit('register', msg.info);
cb(null);
});
};
在consoleService中
exportEvent(self, self.agent, 'register');
var exportEvent = function(outer, inner, event) {
inner.on(event, function() {
var args = Array.prototype.slice.call(arguments, 0);
args.unshift(event);
outer.emit.apply(outer, args);
});
};// outer是MasterConsoleService inner是masterAgent event是register
最终触发了MasterConsoleService的register事件:
而在masterwatcher.js中 ,代码对register进行了register事件监听:
this.service.on('register', onServerAdd.bind(null,this));
var onServerAdd = function(module, record) {
logger.debug('masterwatcher receive add server event, with server: %j', record);
if(!record || record.type === 'client' || !record.serverType) {
return;
}
module.watchdog.addServer(record);//调用watchdog去添加服务器
};
最终还是调用了watchdog.js的notify方法,向那些向master订阅过的monitor发送有新成员加入的消息。
MonitorAgent收到register成功,设置标志位,并且触发当初ConsoleService的start函数传入的回调函数,这时候,会启动模块__watchdog__(monitorwatcher.js),非中心服务器,会调用subscribeRequest(this,this.service.agent, this.id, cb);向中心服务器获取已经注册的服务器服务器列表。即向mastermonitor发送subscribe请求以monitor消息的形式。
Monitorwatcher.js
var subscribeRequest = function(self, agent, id, cb) {
var msg = {action: 'subscribe', id: id};
agent.request(Constants.KEYWORDS.MASTER_WATCHER, msg, function(err, servers) {
if(err) {
logger.error('subscribeRequest request to master with error: %j', err.stack);
utils.invokeCallback(cb, err);
}
var res = [];
for(var id in servers) {
res.push(servers[id]);
}
addServers(self, res);
utils.invokeCallback(cb);
});
};
self.app.addServers(servers);
};
MasterAgent收到subscribe请求后,调用masterwatcher的masterHandler方法即__watchdog__的masterHandler函数进行处理订阅信息,把客户端加入订阅列表中,当有新的服务器加入的时候,会进行通知。并把当前所有服务器列表,传入回调函数,通过socket.emit('monitor', resp)函数,把所有服务器,通知给订阅服务器。
Monitorwatcher.js
var subscribeRequest = function(self, agent, id, cb) {
var msg = {action: 'subscribe', id: id};
agent.request(Constants.KEYWORDS.MASTER_WATCHER, msg, function(err, servers) {
if(err) {
logger.error('subscribeRequest request to master with error: %j', err.stack);
utils.invokeCallback(cb, err);
}
var res = [];
for(var id in servers) {
res.push(servers[id]);
}
addServers(self, res);
utils.invokeCallback(cb);
});
};
Monitoragent.js
MonitorAgent.prototype.request = function(moduleId, msg, cb) {
if (this.state !== ST_REGISTERED) {
logger.error('agent can not request now, state:' + this.state);
return;
}
var reqId = this.reqId++;
this.callbacks[reqId] = cb;
this.socket.emit('monitor', protocol.composeRequest(reqId, moduleId, msg));
};
服务器这边使用masterHandler进行处理:
MasterAgent.js
socket.on('monitor', function(msg) {
if (!registered) {
// not register yet, ignore any message
// kick connections
socket.disconnect();
return;
}
if (type === TYPE_CLIENT) {
logger.error('invalid message to monitor, but current connect type is client.');
return;
}
msg = protocol.parse(msg);
if (msg.respId) {
// a response from monitor
var cb = self.callbacks[msg.respId];
if (!cb) {
logger.warn('unknown resp id:' + msg.respId);
return;
}
delete self.callbacks[msg.respId];
utils.invokeCallback(cb, msg.error, msg.body);
return;
}
// a request or a notify from monitor
self.consoleService.execute(msg.moduleId, 'masterHandler', msg.body, function(err, res) {
if (protocol.isRequest(msg)) {
var resp = protocol.composeResponse(msg, err, res);
if (resp) {
socket.emit('monitor', resp);
}
} else {
//notify should not have a callback
logger.warn('notify should not have a callback.');
}
});
}); // end of on 'monitor'
Module.prototype.masterHandler = function(agent, msg, cb) {
if(!msg) {
logger.warn('masterwatcher receive empty message.');
return;
}
var func = masterMethods[msg.action];
if(!func) {
logger.info('masterwatcher unknown action: %j', msg.action);
return;
}
func(this, agent, msg, cb);
};
//实际上就是调用subscribe
var subscribe = function(module, agent, msg, cb) {
if(!msg) {
utils.invokeCallback(cb, new Error('masterwatcher subscribe empty message.'));
return;
}
module.watchdog.subscribe(msg.id);
utils.invokeCallback(cb, null, module.watchdog.query());
};
MonitorAgent收到monitor消息处理代码如下:
this.socket.on('monitor', function(msg) {
if (self.state !== ST_REGISTERED) {
return;
}
msg = protocol.parse(msg);
if (msg.command) {
// a command from master
self.consoleService.command(msg.command, msg.moduleId, msg.body, function(err, res) {
//notify should not have a callback
});
} else {
if (msg.respId) {
// a response from monitor
var cb = self.callbacks[msg.respId];
if (!cb) {
logger.warn('unknown resp id:' + msg.respId);
return;
}
delete self.callbacks[msg.respId];
utils.invokeCallback(cb, msg.error, msg.body);
return;
}
// request from master
self.consoleService.execute(msg.moduleId, 'monitorHandler', msg.body, function(err, res) {
if (protocol.isRequest(msg)) {
var resp = protocol.composeResponse(msg, err, res);
if (resp) {
self.socket.emit('monitor', resp);
}
} else {
//notify should not have a callback
logger.error('notify should not have a callback.');
}
});
}
});
就是调用:
Module.prototype.monitorHandler = function(agent, msg, cb) {
if(!msg || !msg.action) {
return;
}
var func = monitorMethods[msg.action];
if(!func) {
logger.info('monitorwatcher unknown action: %j', msg.action);
return;
}
func(this, agent, msg, cb);
};
也就是
var subscribeRequest = function(self, agent, id, cb) {
var msg = {action: 'subscribe', id: id};
agent.request(Constants.KEYWORDS.MASTER_WATCHER, msg, function(err, servers) {
if(err) {
logger.error('subscribeRequest request to master with error: %j', err.stack);
utils.invokeCallback(cb, err);
}
var res = [];
for(var id in servers) {
res.push(servers[id]);
}
addServers(self, res);
utils.invokeCallback(cb);
});
};
MonitorAgent收到monitor消息的时候,根据respid从callbacks中获取回调函数,即当初请求订阅时候传入的回调函数,在subscribeRequest中,回调函数调用addServers,通过app的addServers函数,把获取的服务器列表存入serverTypeMaps中,同时app会发送ADD_SERVERS消息,在组件proxy中会触发addServers函数,生成对每个服务器远程调用的代理。生成代理的时候,要求服务器要配置端口port,否则无法调用rpc。
这里面,官方的wiki说master方和monitor方 双方都有watchdog模块。仔细看看源码发现:master方的watchdog模块是由masterWatcher.js和watcherdog.js两个文件实现,而monitor则是由monitorWatcher.js实现,它没有watcherdog.js文件。
最后用张图来总结上述过程: