pomelo之master服务器的启动
来源:互联网 发布:js 日期时间差 编辑:程序博客网 时间:2024/05/14 17:31
写完前面的两篇文章,一直走的都是master服务器的流程,那么这一篇就真正涉及到master服务器的启动过程了,在真正开始之前,先回顾一下前面的两篇文章。。
(1)创建app的过程,这部分主要要完成的功能是读入用户定义的配置参数,并保存和处理这些配置参数。
(2)启动app的过程,这部分主要要完成的功能是load组件,完成对组件的包装(前面已经对master组件进行了说明,在真正的master外面还有一个master的包装,代理它的启动等过程)
新来看看那个master的代理吧:
- /**
- * Component for master.
- */
- var Master = require('../master/master');
- /**
- * Component factory function
- *
- * @param {Object} app current application context
- * @return {Object} component instances
- */
- //相当于require之后得到的就是这个函数
- module.exports = function (app) {
- return new Component(app);
- };
- /**
- * Master component class
- *
- * @param {Object} app current application context
- */
- var Component = function (app) {
- this.master = new Master(app); //创建爱你master
- };
- var pro = Component.prototype;
- /**
- * Component lifecycle function
- *
- * @param {Function} cb
- * @return {Void}
- */
- pro.start = function (cb) {
- this.master.start(cb);
- };
- /**
- * Component lifecycle function
- *
- * @param {Boolean} force whether stop the component immediately
- * @param {Function} cb
- * @return {Void}
- */
- pro.stop = function (force, cb) {
- this.master.stop(cb);
- };
那么我们来看真正的master,首先来看看真正的master的构造:
- //用于创建master
- var Server = function(app) {
- this.app = app;
- this.masterInfo = app.getMaster(); //master的配置实在loadMaster的配置的时候读取的,这个时候获取master的配置
- this.registered = {}; //
- this.modules = []; //所有的模块
- //Default is the main master
- this.isSlave = false;
- this.masterConsole = admin.createMasterConsole({ //创建console
- port: this.masterInfo.port //master的端口
- });
- if(app.enabled('masterHA')){ //Zookeeper这部分暂时先搁置,因为以前完全不了解它
- this.zookeeper = Zookeeper.getClient(app);
- }
- };
前面的代码要是读入master的配置信息,然后创建master的console,那么接下来来看这个console是怎么创建的吧:
- module.exports.createMasterConsole = function(opts) {
- opts = opts || {};
- opts.master = true; //用于表示当前是master服务器
- return new ConsoleService(opts); //创建并返回console
- };
- var ConsoleService = function(opts) {
- EventEmitter.call(this); //让当前的对象可以处理事件
- this.port = opts.port; //获取端口号
- this.values = {};
- this.master = opts.master; //当前是否是master服务器
- this.modules = {};
- if(this.master) {
- this.agent = new MasterAgent(this); //构造master agent
- } else {
- this.type = opts.type;
- this.id = opts.id;
- this.host = opts.host;
- this.agent = new MonitorAgent({
- consoleService: this,
- id: this.id,
- type: this.type,
- info: opts.info
- });
- }
- };
- var MasterAgent = function(consoleService) {
- EventEmitter.call(this);
- this.consoleService = consoleService; //console
- this.server = null;
- this.idMap = {};
- this.typeMap = {};
- this.clients = {};
- this.reqId = 1;
- this.callbacks = {};
- this.state = ST_INITED;
- };
- util.inherits(MasterAgent, EventEmitter);
那么接下来来看master的start函数吧,它的代码比较长一些,需要一部分一部分的进行分析:
- Server.prototype.start = function(cb) {
- registerDefaultModules(this.app); //注册默认的modules
- loadModules(this, this.masterConsole); //载入module
- var self = this;
- this.masterConsole.start(function(err) { //启动console
- if(err) {
- cb(err);
- return;
- }
- startModules(self.modules, function(err) { //启动module
- if(err) {
- cb(err);
- return;
- }
- //If it is the back up, do note start server
- if(!self.app.enabled('masterHA')){
- logger.info('masterHA not enabled, start servers');
- starter.runServers(self.app); //启动其余的server
- cb();
- }else{
- self.zookeeper.start(function(err, result){
- if(err){
- logger.error('start zookeeper failed! err : %j', err);
- cb(err);
- return;
- }
- self.zookeeper.getLock(function(err, result){
- if(err || !result){
- self.isSlave = true;
- self.zookeeper.on('onPromote', self.onPromote.bind(self));
- cb();
- }else{
- self.zookeeper.setData(self.masterInfo, function(err){
- if(err){
- logger.error('set master info faild!');
- cb(err);
- return;
- }
- starter.runServers(self.app);
- cb();
- });
- }
- });
- });
- }
- });
- });
- this.masterConsole.on('disconnect', function(id, type, reason) { //设置disconnect事件
- crashLogger.info(util.format('[%s],[%s],[%s],[%s]', type, id, Date.now(), reason || 'disconnect'));
- var server = self.app.getServerById(id);
- if(!!server && server['auto-restart'] === 'true') {
- self.app.addServers(server);
- starter.run(self.app, server, function(err) {
- if(err) {
- cb(new Error("could not restart " + server.serverId + err), null);
- return;
- }
- });
- }
- });
- this.masterConsole.on('register', function(record) { //register事件
- starter.bindCpu(record.id, record.pid, record.host);
- });
- };
好了,那么首先来看看module的register的过程吧:
- var registerDefaultModules = function(app) {
- app.registerAdmin(require('../modules/watchdog'), {app: app, master: true});
- app.registerAdmin(require('../modules/console'), {app: app, starter: starter});
- if(app.enabled('systemMonitor')) {
- app.registerAdmin(admin.modules.systemInfo);
- app.registerAdmin(admin.modules.nodeInfo);
- app.registerAdmin(admin.modules.monitorLog, {path: pathUtil.getLogPath(app.getBase())});
- app.registerAdmin(admin.modules.scripts, {app: app, path: pathUtil.getScriptPath(app.getBase())});
- if(os.platform() !== 'win32') {
- app.registerAdmin(admin.modules.profiler, {isMaster: true});
- }
- }
- };
- Application.registerAdmin = function(moduleId, module, opts){
- var modules = this.get('__modules__');
- if(!modules) {
- modules = [];
- this.set('__modules__', modules);
- }
- if(typeof moduleId !== 'string') {
- opts = module; //这个是传进的参数
- module = moduleId;
- moduleId = module.moduleId;
- }
- modules.push({moduleId: moduleId, module: module, opts: opts}); //将它push进去
- };
- var loadModules = function(self, consoleService) {
- // load app register modules
- var modules = self.app.get('__modules__'); //获取module的信息
- if(!modules) {
- return;
- }
- var record, moduleId, module;
- for(var i=0, l=modules.length; i<l; i++){ //遍历所有的module
- record = modules[i];
- if(typeof record.module === 'function') { //一般情况下,这里都是一个函数,因为module的定义直接弄成了一个函数,可以看成构造函数
- module = record.module(record.opts, consoleService);//可以看成调用module的构造函数
- } else {
- module = record.module;
- }
- moduleId = record.moduleId || module.moduleId;
- if(!moduleId) {
- logger.warn('ignore an uname module.');
- continue;
- }
- consoleService.register(moduleId, module); //在console里面注册module,在console里面会将id和module关联起来保存
- self.modules.push(module);
- }
- };
那么这里module的register和load过程基本就差不多了,至于说这些module有什么用,还是留到以后涉及到了再说吧。。。
好吧,我们接下来来看看console的启动过程:
- ConsoleService.prototype.start = function(cb) {
- if(this.master) {
- this.agent.listen(this.port); //监听端口
- exportEvent(this, this.agent, 'register'); //如果agent发生了register事件,那么这里也要调用一次
- exportEvent(this, this.agent, 'disconnect');
- process.nextTick(function() {
- utils.invokeCallback(cb); //调用回调函数
- });
- } else {
- logger.info('try to connect master: %j, %j, %j', this.type, this.host, this.port);
- this.agent.connect(this.port, this.host, cb);
- exportEvent(this, this.agent, 'close');
- }
- exportEvent(this, this.agent, 'error');
- for(var mid in this.modules) {
- this.enable(mid); //遍历并enable当前所有保存的module,在master的loadmodule的过程,会将这些module保存到console里面来
- }
- };
好了接下来来看看module的start过程吧:
- var startModules = function(modules, cb) {
- // invoke the start lifecycle method of modules
- if(!modules) {
- return;
- }
- startModule(null, modules, 0, cb);
- };
- var startModule = function(err, modules, index, cb) {
- if(err || index >= modules.length) {
- cb(err);
- return;
- }
- var module = modules[index];
- if(module && typeof module.start === 'function') {
- module.start(function(err) {
- startModule(err, modules, index + 1, cb); //我晕,这里居然还是递归的进行start
- });
- } else {
- startModule(err, modules, index + 1, cb);
- }
- };
那么接下来来看是怎么进行其余的server的启动吧:
- starter.runServers = function(app) {
- var servers = app.getServersFromConfig();
- for (var serverId in servers) { //遍历所有的server
- this.run(app, servers[serverId]); //启动server
- }
- ;
- starter.run = function(app, server, cb) {
- env = app.get('env'); //当前环境,development或者production
- var cmd, key;
- if (isLocal(server.host)) { //host配置信息
- var options = [];
- if (!!server.args) {
- if(typeof server.args === 'string') {
- options.push(server.args.trim());
- } else {
- options.push(server.args);
- }
- }
- cmd = app.get('main'); //用于启动给的主要信息
- /*{ main: '/home/fjs/Desktop/pomelo/game-server/app.js',
- env: 'development',
- id: 'connector-server-1',
- host: '127.0.0.1',
- port: 4050,
- clientPort: 3050,
- frontend: 'true',
- serverType: 'connector' }*/
- options.push(cmd);
- options.push(util.format('env=%s', env)); //当前的环境
- for(key in server) { //将server的配置信息输入到命令启动行,例如host,port等
- if(key === 'cpu') {
- cpus[server['id']] = server[key];
- }
- options.push(util.format('%s=%s', key, server[key]));
- }
- starter.localrun(process.execPath, null, options, cb); //运行命令行
- } else {
- cmd = util.format('cd "%s" && "%s"', app.getBase(), process.execPath);
- var arg = server.args;
- if (arg !== undefined) {
- cmd += arg;
- }
- cmd += util.format(' "%s" env=%s ', app.get('main'), env);
- for(key in server) {
- if(key === 'cpu') {
- cpus[server['id']] = server[key];
- }
- cmd += util.format(' %s=%s ', key, server[key]);
- }
- starter.sshrun(cmd, server.host, cb);
- }
- };
这部分代码仿佛看起来挺复杂的,其实不然,因为大多数在前面的代码中都有涉及,无非是将要执行的命令行处理出来,然后待会用这些命令行参数来进行启动。。。那么就不细说了,直接来看localrun函数吧:
- //直接启动命令行
- starter.localrun = function (cmd, host, options, callback) {
- logger.info('Executing ' + cmd + ' ' + options + ' locally');
- spawnProcess(cmd, host, options, callback);
- };
那么其余server的启动也就差不多了,当然这部分还有一个插曲,那就是这里server的启动还需要分时本地服务器的,还是外地服务器的,其实看代码也就启动的过程有稍微的区别,别的也都差不多,就不细说了。。。
好了,那么整个master的启动过程大概就如下:
(1)创建masterconsole
(2)创建masteragent
(3)注册以及载入module
(4)启动console
(5)启动module
(6)启动其余的server
这里有一张图感觉应该能形容master的构成:
其实也就是说master服务器大多数的功能都是通过masterconsole进行的,而masterconsole又包含一个masteragent用于监听端口,以及一些处理。。
当然至于说master服务器的具体运行原理这里文章中并没有涉及,以后会补上,因为现在确实还不知道master干些什么事情。。。
- pomelo之master服务器的启动
- pomelo之master服务器的启动
- pomelo之server的启动。。
- pomelo 单独启动各个服务器
- pomelo服务器启动过程2
- Pomelo聊天服务器完美运行启动
- pomelo 服务器之间的通信
- nginx的worker-master启动之master进程
- pomelo源码解析之compnent组件启动
- Cocos2d-x之pomelo服务器框架
- Pomelo之application的start
- Pomelo之application的start
- pomelo的rpc服务器--remote组件
- pomelo服务器群消息变更的获知
- pomelo的rpc服务器--remote组件
- nginx的worker-master启动之worker进程
- Mesos源码分析(3): Mesos Master的启动之二
- Mesos源码分析(4): Mesos Master的启动之三
- 自定义UISearchBar 适配IOS6和IOS7 修改放大镜图标 修改光标颜色 修改边框颜色 placeholder颜色 设置文本框背景
- ThreadLocal
- iOS开发UI篇—UITabBarController简单介绍
- C++ MD5加密函数
- 基本的bash shell 命令
- pomelo之master服务器的启动
- delegate需清除
- 教你操作道路沿线标注
- jquery的图片播放插件 - colorbox
- [Android学习]Android部分基础学习路线图
- iOS开发UI篇—UITabBarController生命周期(使用storyoard搭建)
- Android Drawable Resource学习(九)、ClipDrawable
- 黑马程序员-正则表达学习笔记
- 类目代码展示(增加NSString的类目)