pomelo服务器群消息变更的获知
来源:互联网 发布:带网络机顶盒的电视机 编辑:程序博客网 时间:2024/05/22 13:14
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.jsMonitorAgent.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);};//实际上就是调用subscribevar 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文件。
最后用张图来总结上述过程:
- pomelo服务器群消息变更的获知
- pomelo 服务器之间的通信
- 获知自己所在的DNS服务器(windows下)
- pomelo之master服务器的启动
- pomelo的rpc服务器--remote组件
- pomelo的rpc服务器--remote组件
- pomelo之master服务器的启动
- SVN 服务器地址的变更
- CString的一点获知
- pomelo消息推送
- Pomelo网易开源基于Node.js的游戏服务器框架pomelo
- 服务器架构浅析--pomelo
- pomelo服务器搭建
- 游戏服务器框架pomelo
- 服务器变更对客户端的影响
- 如何获知KDE的版本
- 如何获知Android的版本号
- (pomelo系列入门教程)深入浅出node.js游戏服务器开发——基于Pomelo的MMO RPG开发
- tar命令使用
- org.hibernate.MappingException: Could not determine type for: java.util.List, at table: user, for...
- HttpClient
- std::string::find() 和 std::string::npos
- c# 反射的使用
- pomelo服务器群消息变更的获知
- 进程间通信方式(IPC)
- MyEclipse应用程序服务器入门指南(上)
- 古巴开设免费Wi-Fi
- jQuery上传插件Uploadify 3.2使用
- [新书推荐]A Practical Introduction to Computer Vision with OpenCV
- 指尖时刻:百度移动营销生态体系
- C#集合排序
- mysql条件查询(联合两张表查询 O2P)