pomelo-robot 使用
pomelo-robot 是一个用来对 pomelo 游戏框架进行性能测试的工具,也可以测试其他基于 socket.io 的服务的性能。该模块可以采用单机测试模式,也可以采用分布式测试模式。
一、目的
对游戏项目进行自动化的性能测试和分析,为游戏服务器提供机器人及其运行脚本,最终输出性能测试分析报告。目前主要考虑二种功能:运行简单指令的机器人 和 多线程的性能测试。
后者依赖于前者的功能实现,同时还可能考虑输出性能分析报告。
pomelo-robot 模块通过沙箱的方式执行用户自定义的 Javascript 脚本,运行中各客户端会自动把数据汇报给主节点,主节点把所有节点的测试数据进行清洗与合并,算出最大最小及平均响应时间等统计数据,然后定时发关给内置的HTTP服务器进行界面展示。
二、模块结构
模块内部运行结构如下:
"Master"负责收集所有"Client"的运行数据并展示统计结果。
"Client"负责在多个沙箱(“User”)中运行自定义脚本, 同时向"Master"汇报运行数据。
三、使用示例
新建NODEJS测试工程,工程目录结构如下图所示:
3.1 安装依赖库
npm install pomelo-robot
3.2 config.json配置
config.json分为二种运行环境本地开发或线上测试,文件内容如下:{
"dev":
{
"master":{"host": "127.0.0.1","port":8888,"webport":8889,"interval":500},
"apps":[{"host":"127.0.0.1","port":3050}],
"mysql":{"host":"pomelo.163.com","user":"xy","password":"dev","database":"Pomelo"},
"clients":["127.0.0.1"]
},
"prod":
{
"master":{"host": "app47v2.photo.163.org","port":8888,"webport":8889},
"apps":[{"host":"mon2.photo.163.org","port":3051}],
"mysql":{"host":"app56v1.photo.163.org","user":"xy","password":"dev","database":"Pomelo"},
"clients":["127.0.0.1","app47v3.photo.163.org","app47v4.photo.163.org"]
}
}
- master:主服务器的 IP,客户端通信端口,WEB 界面端口,间隔多少毫秒运行一个自定义JS脚本(如:lord.js)。
- apps:应用服务器即游戏服务器的对外提供的接口,支持多台服务器配置,客户端会均衡的连接各服务器。
- mysql:配置测试用的数据来源。
- clients:测试客户端,线上运行时采用 ssh 运行时,此模式需要各机器配置同样环境无密码的 ssh 登录。
3.3 实现自定义脚本配置
库本身对用户提供 Iuser 对象和 robot 对象,Iuser 示例中主要包括用户名和密码,robot 采用 event 的模式支持如 pomele client 类型的 request 和 on 方法。在"env.json"中配置自定义脚本路径:
"env": "prod",
"script": "/app/script/lord.js"
实现自定义脚本 LORD.JS:
// ...
var queryHero = require(cwd + '/app/data/mysql').queryHero;
function entry(host, port, token, callback) {
// 初始化socketClient
pomelo.init(host: host, port: port, log: true, function()
pomelo.request('connector.entryHandler.entry', token: token, function(data)
afterLogin(pomelo,data);
);
);
}
/app/data/mysql.js 中查找登录角色的代码如下:
// ...
queryHero = function(client,limit,offset,cb){
var users = [];
var sql = "SELECT User.* FROM User,Player where User.id = Player.userId and User.name like 'pomelo%' limit ? offset ? ";
// ...
}
上面的代码运行在沙箱中:首先登录游戏服务器,登录成功后回调 "afterLogin" 函数,用户可以进行后续的相关操作。
3.4 配置启动文件 app.js
示例启动文件app.js因为本身简单,直接负责了根据参数判断启动 master 服务或 client 服务。整体代码如下:
var Robot = require('pomelo-robot').Robot;
//服务相关配置
var envConfig = require('./app/config/env.json');
var config = require('./app/config/' + envConfig.env + '/config');
var robot = new Robot(config);
if (mode === 'master')
robot.runMaster(__filename);
else
var script = (process.cwd() + envConfig.script);
robot.runAgent(script);
//示例中第5个参数为mysql数据源分页参数
var i = 5;
var limit = process.argv[i++];
var offset= process.argv[i++];
//载入用户自定义的脚本。
var script = require('fs').readFileSync(process.cwd() + '/app/config/lord.js', 'utf8');
queryHero(client,limit,offset,function(error,users){ //启动Agent 服务
robot.runAgent(users,script)
});
}
上面代码示例,获得 Mysql 数据源的代码如下:
//数据库配置
var mysql =config[robot.env].mysql;
var Client = require('mysql').Client;
var client = new Client();
client.host = mysql.host;
client.user = mysql.user;
client.password = mysql.password;
client.database = mysql.database;
queryHero = function(client,limit,offset,cb){
var users = [];
var sql = "SELECT User.* FROM User,Player where User.id = Player.userId and User.name like 'pomelo%' limit ? offset ? ";
var args = [parseInt(limit),parseInt(offset)];
client.query(sql,args,function selectCb(error, results, fields) {
if (!!error) {
console.log('queryHero Error: ' + error.message);
cb(null,users);
}
for (var i = 0;i<results.length;i++) {
var user = {uid:results[i]['id'],username:results[i]['name'],passwd:results[i]['passwd']||'123'};
users.push(user);
};
cb(null,users);
});
};
3.5 运行测试
运行如下命令:node app.js master
默认启动开发环境,如需要启动线上测试环境,在线上 master 机器上执行 node app.js prod 即可。运行如下命令, 启动 "client" 服务:
node app.js client
可以在多台机器上启动"client"服务进行性能和压力测试WEB 界面会显示连接到 "master" 的 "client" 数量, 可以在 "Per Agent Users" 一栏中配置每个 "client" 将要运行的沙箱数量, 点击 "Go" 按钮通知所有的 "client" 开始运行。WEB 界面会定时获取后台数据进行展示。
打开浏览器访问如下地址:http://master-hostname-or-ip:8889
点击【准备】按钮,可以看到连接上来的客户端,当所有的客户端准备好了,点击运行即可。
管理界面会定时得到后台数据与展示出来。
运行界面如下图所示:


注意
当分布时使用时,各客户端配置的机器的目录是统一的,并且主节点能通过SSH无密码访问到各节点。另外,开发人员也可以自行登录到各客户端通过参数根据主服务器生成的命令手工启动。